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 deklariert wurden, private können nur von Memberfunktionen und Freunden (Klassen oder Funktionen) der Klasse verwendet werden.
protected Klassenmember, die deklariert wurden, können protected 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 einer beliebigen Funktion verwendet werden können.

Die Zugriffssteuerung verhindert, dass Sie Objekte auf die Art und Weise verwenden, wie sie nicht verwendet werden sollen. Dieser Schutz geht verloren, wenn Sie explizite Typkonvertierungen (Umwandlungen) vornehmen.

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
Immer unzugänglich mit jedem Ableitungszugriff privatein abgeleiteter Klasse, wenn Sie Ableitung verwenden private privatein abgeleiteter Klasse, wenn Sie Ableitung verwenden private
protectedin abgeleiteter Klasse, wenn Sie Ableitung verwenden protected protectedin abgeleiteter Klasse, wenn Sie Ableitung verwenden protected
protectedin abgeleiteter Klasse, wenn Sie Ableitung verwenden public publicin abgeleiteter Klasse, wenn Sie Ableitung verwenden public

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, die Memberfunktion PublicFunc ist ein public Element und ProtectedFunc ist ein protected Element, da es sich um BaseClass eine public Basisklasse handelt. PrivateFunc ist private , BaseClassund auf alle abgeleiteten Klassen kann nicht zugegriffen werden.

In DerivedClass2, die Funktionen PublicFunc und ProtectedFunc werden als Member betrachtet private , da es sich um BaseClass eine private Basisklasse handelt. PrivateFunc Auch hier kann privateBaseClassnicht auf abgeleitete Klassen zugegriffen werden.

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

class Derived : Base
...

entspricht:

class Derived : private Base
...

Ebenso folgender Code:

struct Derived : Base
...

entspricht:

struct Derived : public Base
...

Elemente, 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, die private Schlüsselwort (keyword) explizit zu verwenden, damit Benutzer der abgeleiteten Klasse den Memberzugriff verstehen.

Zugriffssteuerung und statische Member

Wenn Sie eine Basisklasse als privateangeben, 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 mithilfe von Zeigern, Verweisen oder Objekten kann jedoch eine Konvertierung erfordern, wodurch die Zugriffssteuerung 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 es sich um eine private indirekte Basisklasse handelt.Derived2 Die Konvertierung in einen private Basisklassentyp ist nur für Zeiger auf direkt abgeleitete Klassen zulässig. Aus diesem Grund können Zeiger vom Typ Derived1 * in Typ Base *konvertiert werden.

Ein expliziter Aufruf der CountOf Funktion ohne Verwendung eines Zeigers, Verweises oder Objekts, um sie auszuwählen, impliziert keine Konvertierung. Deshalb ist der Anruf zulässig.

Member und Freunde einer abgeleiteten Klasse Tkönnen einen Zeiger T in einen Zeiger in einen Zeiger in eine private direkte Basisklasse konvertieren.T

Zugriff auf virtuelle Funktionen

Die auf Funktionen angewendete virtual Zugriffssteuerung wird durch den Typ bestimmt, der zum Aufrufen der Funktion verwendet wird. Das Überschreiben von Deklarationen der Funktion wirkt sich nicht auf die Zugriffssteuerung für einen bestimmten Typ aus. 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 die virtuelle Funktion GetState mithilfe eines Zeigers zum Eingeben VFuncBase von Aufrufen aufgerufen VFuncDerived::GetStateund GetState als publicbehandelt. Das Aufrufen GetState eines Zeigers zum Eingeben VFuncDerived eines Zeigers ist jedoch eine Zugriffssteuerungsverletzung, da GetState sie in der Klasse VFuncDeriveddeklariert private ist.

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. Siehe folgende Abbildung:

Diagram showing access along the paths of an inheritance graph.

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. Der richtige Pfad ist barrierefreier, da RightPath er als public Basisklasse deklariert VBase wird, während LeftPath er VBase als private.

Siehe auch

C++-Programmiersprachenreferenz