Freigeben über


Memberzugriffssteuerung (C++)

Mit Zugriffssteuerelementen können Sie die public Schnittstelle einer Klasse von den private Implementierungsdetails und den Membern trennen, die protected nur von abgeleiteten Klassen verwendet werden. Der Zugriffsspezifizierer gilt für alle Member, die danach deklariert werden, bis der nächste Zugriffsspezifizierer ermittelt wird.

class Point
{
public:
    Point( int, int ) // Declare public constructor.;
    Point();// Declare public default constructor.
    int &x( int ); // Declare public accessor.
    int &y( int ); // Declare public accessor.

private:                 // Declare private state variables.
    int _x;
    int _y;

protected:      // Declare protected function for derived classes only.
    Point ToWindowCoords();
};

Der Standardzugriff befindet private sich in einer Klasse und public in einer Struktur oder Vereinigung. Zugriffsspezifizierer in einer Klasse können beliebig oft in jeder Reihenfolge verwendet werden. Die Zuordnung des Speichers für Objekte von Klassentypen ist implementierungsabhängig. Compiler müssen jedoch die Zuweisung von Membern zu nacheinander höheren Speicheradressen zwischen Zugriffsbezeichnern garantieren.

Memberzugriffssteuerung

Zugriffstyp Bedeutung
private Klassenmember, die als private deklariert wurden, können nur von Memberfunktionen und Freunden (Klassen oder Funktionen) der Klasse verwendet werden.
protected Klassenmember, die als protected deklariert wurden, können von Memberfunktionen und Freunden (Klassen oder Funktionen) der Klasse verwendet werden. Darüber hinaus können sie von Klassen verwendet werden, die aus der Klasse abgeleitet sind.
public Klassenmermber, die von public deklariert wurden, können von einer beliebigen Funktion verwendet werden.

Mit der Zugriffssteuerung können Sie verhindern, dass Objekte auf andere, nicht zweckgemäße Art und Weise verwendet werden. Dieser Schutz geht verloren, wenn explizite Typkonvertierungen (Umwandlungen) ausgeführt werden.

Hinweis

Die Zugriffssteuerung ist auf alle Namen gleich anwendbar: Memberfunktionen, Memberdaten, geschachtelte Klassen und Enumeratoren.

Zugriffssteuerung in abgeleiteten Klassen

Zwei Faktoren steuern, auf welche Member einer Basisklasse in einer abgeleiteten Klasse zugegriffen werden kann. Dieselben Faktoren steuern den Zugriff auf geerbte Member in der abgeleiteten Klasse:

  • Gibt an, ob die abgeleitete Klasse die Basisklasse mithilfe des public Zugriffsbezeichners deklariert.

  • Entspricht dem Zugriff auf den Member in der Basisklasse.

Die folgende Tabelle zeigt die Interaktion zwischen diesen Faktoren und wie der Zugriff auf Basisklassenmember bestimmt wird.

Memberzugriff in Basisklasse

private protected public
Mit jedem Ableitungszugriff immer unerreichbar private in abgeleiteter Klasse, wenn Sie private Ableitung verwenden private in abgeleiteter Klasse, wenn Sie private Ableitung verwenden
protected in abgeleiteter Klasse, wenn Sie protected Ableitung verwenden protected in abgeleiteter Klasse, wenn Sie protected Ableitung verwenden
protected in abgeleiteter Klasse, wenn Sie public Ableitung verwenden public in abgeleiteter Klasse, wenn Sie public Ableitung verwenden

Das folgende Beispiel veranschaulicht die Zugriffsableitung:

// access_specifiers_for_base_classes.cpp
class BaseClass
{
public:
    int PublicFunc(); // Declare a public member.
protected:
    int ProtectedFunc(); // Declare a protected member.
private:
    int PrivateFunc(); // Declare a private member.
};

// Declare two classes derived from BaseClass.
class DerivedClass1 : public BaseClass
{
    void foo()
    {
        PublicFunc();
        ProtectedFunc();
        PrivateFunc(); // function is inaccessible
    }
};

class DerivedClass2 : private BaseClass
{
    void foo()
    {
        PublicFunc();
        ProtectedFunc();
        PrivateFunc(); // function is inaccessible
    }
};

int main()
{
    DerivedClass1 derived_class1;
    DerivedClass2 derived_class2;
    derived_class1.PublicFunc();
    derived_class2.PublicFunc(); // function is inaccessible
}

In DerivedClass1 ist die Memberfunktion PublicFunc ein public Member und ProtectedFunc ist ein protected Member, da BaseClass eine public Basisklasse ist. PrivateFunc ist für private und für BaseClass keine abgeleiteten Klassen zugänglich.

In DerivedClass2 werden die Funktionen PublicFunc und ProtectedFunc als private Member betrachtet, da BaseClass eine private Basisklasse ist. Erneut, PrivateFunc ist für private und für BaseClass keine abgeleiteten Klassen zugänglich.

Sie können eine abgeleitete Klasse ohne einen Basisklassen-Zugriffsspezifizierer deklarieren. In einem solchen Fall wird die Ableitung berücksichtigt private, wenn die abgeleitete Klassendeklaration das class Schlüsselwort verwendet. Die Ableitung berücksichtigt public, wenn die abgeleitete Klassendeklaration das struct Schlüsselwort verwendet. Beispielsweise folgender Code:

class Derived : Base
...

entspricht:

class Derived : private Base
...

Ebenso folgender Code:

struct Derived : Base
...

entspricht:

struct Derived : public Base
...

Members, die als private Zugriff deklariert sind, können nicht auf Funktionen oder abgeleitete Klassen zugreifen, es sei denn, diese Funktionen oder Klassen werden mithilfe der friend Deklaration in der Basisklasse deklariert.

Ein union Typ kann keine Basisklasse haben.

Hinweis

Bei der Angabe einer private Basisklasse ist es ratsam, das private Schlüsselwort explizit zu verwenden, damit Benutzer der abgeleiteten Klasse den Memberzugriff verstehen.

Zugriffssteuerung und statische Member

Wenn Sie eine Basisklasse als private angeben, wirkt sie sich nur auf nicht statische Member aus. Öffentliche statische Member sind in den abgeleiteten Klassen immer noch zugänglich. Der Zugriff auf Member der Basisklasse mit Zeigern, Referenzen oder Objekten kann jedoch eine Konvertierung erfordern, bei der die Zugriffskontrolle erneut angewendet wird. Betrachten Sie das folgende Beispiel:

// access_control.cpp
class Base
{
public:
    int Print();             // Nonstatic member.
    static int CountOf();    // Static member.
};

// Derived1 declares Base as a private base class.
class Derived1 : private Base
{
};

// Derived2 declares Derived1 as a public base class.
class Derived2 : public Derived1
{
    int ShowCount();    // Nonstatic member.
};

// Define ShowCount function for Derived2.
int Derived2::ShowCount()
{
    // Call static member function CountOf explicitly.
    int cCount = ::Base::CountOf();     // OK.

    // Call static member function CountOf using pointer.
    cCount = this->CountOf();  // C2247: 'Base::CountOf'
                               // not accessible because
                               // 'Derived1' uses 'private'
                               // to inherit from 'Base'
    return cCount;
}

Im vorherigen Code verhindert die Zugriffssteuerung die Konvertierung von einem Zeiger auf Derived2 in einen Zeiger auf Base. Der this Zeiger ist implizit vom Typ Derived2 *. Um die CountOf Funktion auszuwählen, this muss in Typ Base * konvertiert werden. Eine solche Konvertierung ist nicht zulässig, da Base eine private indirekte Basisklasse für Derived2 ist. Die Konvertierung in einen private Typ der Basisklasse ist nur für Zeiger auf direkte abgeleitete Klassen akzeptabel. Daher können Zeiger vom Typ Derived1 * in den Typ Base * konvertiert werden.

Ein expliziter Aufruf der CountOf-Funktion, ohne Verwenden eines Zeigers, Verweises oder Objekts zum Auswählen keine Konvertierung impliziert. Deshalb ist der Aufruf zulässig.

Member und Friends einer abgeleiteten Klasse T können einen Zeiger auf T in einen Zeiger auf eine private direkte Basisklasse von T konvertieren.

Zugriff auf virtuelle Funktionen

Die auf virtual-Funktionen angewendete Zugriffssteuerung wird durch den Typ bestimmt, der zum Aufrufen der Funktion verwendet wird. Überschreiben von Deklarationen der Funktion wirkt sich nicht auf die Zugriffssteuerung für einen angegebenen Typ aus. Zum Beispiel:

// access_to_virtual_functions.cpp
class VFuncBase
{
public:
    virtual int GetState() { return _state; }
protected:
    int _state;
};

class VFuncDerived : public VFuncBase
{
private:
    int GetState() { return _state; }
};

int main()
{
   VFuncDerived vfd;             // Object of derived type.
   VFuncBase *pvfb = &vfd;       // Pointer to base type.
   VFuncDerived *pvfd = &vfd;    // Pointer to derived type.
   int State;

   State = pvfb->GetState();     // GetState is public.
   State = pvfd->GetState();     // C2248 error expected; GetState is private;
}

Im vorherigen Beispiel wird das Aufrufen der virtuellen Funktion GetState mithilfe eines Zeigers auf Aufrufe des Typs VFuncBase, VFuncDerived::GetState und GetState als public behandelt. Jedoch mithilfe GetState eines Zeigers auf den Typ VFuncDerived aufzurufen, ist eine Verletzung der Zugriffssteuerung, da GetState in der Klasse private deklariert istVFuncDerived.

Achtung

Die virtuelle Funktion GetState kann mithilfe eines Zeigers auf die Basisklasse VFuncBase aufgerufen werden. Dies bedeutet nicht, dass die aufgerufene Funktion die Basisklassenversion dieser Funktion ist.

Zugriffssteuerung mit mehrfacher Vererbung

In den Mehrfachvererbungsgittern, die virtuelle Basisklassen betreffen, kann ein angegebener Name über mehrere Pfade erreicht werden. Da unterschiedliche Zugriffssteuerungen entlang dieser verschiedenen Pfaden angewendet werden können, wählt der Compiler den Pfad aus, der den umfangreichsten Zugriff gewährt. Dies wird in der folgenden Abbildung veranschaulicht:

Diagramm, das den Zugriff entlang der Pfade eines Vererbungsdiagramms zeigt.

Das Diagramm zeigt die folgende Vererbungshierarchie: Klasse VBase ist die Basisklasse. Class LeftPath erbt von VBase mithilfe von virtual private VBase. class RightPath erbt auch von VBase, aber mit virtual public VBase. Schließlich erbt die abgeleitete Klasse von der Klasse LeftPath und der Klasse RightPath mithilfe von public LeftPath, public RightPath.

Access-Along-Pfade eines Vererbungsdiagramms

In der Abbildung wird ein Name, der in der Klasse VBase deklariert wird, immer durch die Klasse RightPath erreicht. Auf den rechten Pfad kann einfacher zugegriffen werden, da RightPath als VBasepublic Basisklasse deklariert, während LeftPath als VBase deklariertprivate.

Siehe auch

C++-Programmiersprachenreferenz