Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
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:
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 VBase
public
Basisklasse deklariert, während LeftPath
als VBase
deklariertprivate
.