Namensräume
Varianten
Aktionen

Zugriffsspezifizierer

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Zugriffsspezifizierer
friend-Spezifizierer

Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

In einer Member-Spezifikation einer Klasse/Struktur oder Union definieren sie die Zugänglichkeit nachfolgender Member.

In einer Basis-Spezifikation einer abgeleiteten Klasse definieren sie die Zugänglichkeit geerbter Member der nachfolgenden Basisklasse.

Inhalt

[bearbeiten] Syntax

public : Member-Deklarationen (1)
protected : Member-Deklarationen (2)
private : Member-Deklarationen (3)
public Basisklasse (4)
protected Basisklasse (5)
private Basisklasse (6)
1) Die nach dem Zugriffsmodifizierer deklarierten Member haben öffentlichen Memberzugriff.
2) Die nach dem Zugriffsmodifizierer deklarierten Member haben geschützten Memberzugriff.
3) Die nach dem Zugriffsmodifizierer deklarierten Member haben privaten Memberzugriff.
4) Öffentliche Vererbung: Die öffentlichen und geschützten Member der nach dem Zugriffsmodifizierer aufgeführten Basisklasse behalten ihren Memberzugriff in der abgeleiteten Klasse.
5) Geschützte Vererbung: Die öffentlichen und geschützten Member der nach dem Zugriffsmodifizierer aufgeführten Basisklasse werden zu geschützten Membern der abgeleiteten Klasse.
6) Private Vererbung: Die öffentlichen und geschützten Member der nach dem Zugriffsmodifizierer aufgeführten Basisklasse werden zu privaten Membern der abgeleiteten Klasse.

Die privaten Member der Basisklasse sind für die abgeleitete Klasse unabhängig von öffentlicher, geschützter oder privater Vererbung immer unzugänglich.

[bearbeiten] Erklärung

Der Name jedes Klassen-Members (statisch, nicht-statisch, Funktion, Typ, etc.) hat einen zugeordneten "Memberzugriff". Wenn ein Membername irgendwo im Programm verwendet wird, wird sein Zugriff überprüft, und wenn er die Zugriffsregeln nicht erfüllt, kompiliert das Programm nicht.

#include <iostream>
 
class Example
{
public:             // all declarations after this point are public
    void add(int x) // member "add" has public access
    {
        n += x;     // OK: private Example::n can be accessed from Example::add
    }
private:            // all declarations after this point are private
    int n = 0;      // member "n" has private access
};
 
int main()
{
    Example e;
    e.add(1); // OK: public Example::add can be accessed from main
//  e.n = 7;  // error: private Example::n cannot be accessed from main
}

Zugriffsmodifizierer geben dem Autor der Klasse die Möglichkeit zu entscheiden, welche Klassenmember für die Benutzer der Klasse zugänglich sind (d.h. die Schnittstelle) und welche Member für die interne Nutzung der Klasse bestimmt sind (die Implementierung).

[bearbeiten] Im Detail

Alle Member einer Klasse (Körper von Memberfunktionen, Initialisierer von Memberobjekten und die gesamte Definition von geschachtelten Klassen) haben Zugriff auf alle Namen, auf die die Klasse zugreifen kann. Eine lokale Klasse innerhalb einer Memberfunktion hat Zugriff auf alle Namen, auf die die Memberfunktion zugreifen kann.

Eine mit dem Schlüsselwort class definierte Klasse hat standardmäßig privaten Zugriff für ihre Member und ihre Basisklassen. Eine mit dem Schlüsselwort struct definierte Klasse hat standardmäßig öffentlichen Zugriff für ihre Member und ihre Basisklassen. Eine Union hat standardmäßig öffentlichen Zugriff für ihre Member.

Um zusätzlichen Funktionen oder Klassen Zugriff auf geschützte oder private Member zu gewähren, kann eine Friend-Deklaration verwendet werden.

Die Zugänglichkeit gilt für alle Namen, unabhängig von ihrer Herkunft, so dass ein Name, der durch einen Typedef oder eine using-Deklaration (außer konstruktorenvererbende) eingeführt wird, überprüft wird, nicht der Name, auf den er verweist.

class A : X
{
    class B {};   // B is private in A
public:
    typedef B BB; // BB is public
};
 
void f()
{
    A::B y;  // error: A::B is private
    A::BB x; // OK: A::BB is public
}

Der Memberzugriff beeinflusst nicht die Sichtbarkeit: Namen von privaten und privat geerbten Membern sind sichtbar und werden bei der Überladungsauflösung berücksichtigt, implizite Konvertierungen zu unzugänglichen Basisklassen werden weiterhin berücksichtigt usw. Die Überprüfung des Memberzugriffs ist der letzte Schritt, nachdem ein bestimmter Sprachkonstrukt interpretiert wurde. Die Absicht dieser Regel ist, dass das Ersetzen von private durch public niemals das Verhalten des Programms verändert.

Die Zugriffsprüfung für Namen, die in Standard-Funktionsargumenten sowie in den Standard- Template-Parametern verwendet werden, erfolgt an der Stelle der Deklaration, nicht an der Stelle der Verwendung.

Die Zugriffsregeln für die Namen von virtuellen Funktionen werden am Aufrufpunkt unter Verwendung des Typs des Ausdrucks überprüft, der verwendet wird, um das Objekt zu bezeichnen, für das die Memberfunktion aufgerufen wird. Der Zugriff auf den endgültigen Überschreiber wird ignoriert.

struct B
{
    virtual int f(); // f is public in B
};
 
class D : public B
{
private:
    int f(); // f is private in D
};
 
void f()
{
    D d;
    B& b = d;
 
    b.f(); // OK: B::f is public, D::f is invoked even though it's private
    d.f(); // error: D::f is private
}

Ein Name, der nach einer uneingeschränkten Namenssuche privat ist, kann durch eine qualifizierte Namenssuche zugänglich sein.

class A {};
 
class B : private A {};
 
class C : public B
{
    A* p;   // error: unqualified name lookup finds A as the private base of B
    ::A* q; // OK: qualified name lookup finds the namespace-level declaration
};

Ein Name, der über mehrere Pfade im Vererbungsgraphen zugänglich ist, hat den Zugriff des Pfades mit dem meisten Zugriff.

class W
{
public:
    void f();
};
 
class A : private virtual W {};
 
class B : public virtual W {};
 
class C : public A, public B
{
    void f()
    {
        W::f(); // OK: W is accessible to C through B
    }
};

Beliebig viele Zugriffsmodifizierer können innerhalb einer Klasse in beliebiger Reihenfolge erscheinen.

Member-Zugriffsmodifizierer können das Layout der Klasse beeinflussen: Die Adressen von nicht-statischen Datenmembern sind nur garantiert ansteigend in der Reihenfolge der Deklaration für die Member, die nicht durch einen Zugriffsmodifizierer getrennt sind(bis C++11)denselben Zugriff haben(seit C++11).

(bis C++23)

Für Standard-Layout-Typen müssen alle nicht-statischen Datenmember denselben Zugriff haben.

(seit C++11)

Wenn ein Member innerhalb derselben Klasse neu deklariert wird, muss dies unter demselben Memberzugriff geschehen.

struct S
{
    class A;    // S::A is public
private:
    class A {}; // error: cannot change access
};

[bearbeiten] Öffentlicher Memberzugriff

Öffentliche Member sind Teil der öffentlichen Schnittstelle einer Klasse (andere Teile der öffentlichen Schnittstelle sind die Nicht-Memberfunktionen, die durch ADL gefunden werden).

Ein öffentlicher Member einer Klasse ist überall zugänglich.

class S
{
public:
    // n, E, A, B, C, U, f are public members
    int n;
    enum E {A, B, C};
    struct U {};
    static void f() {}
};
 
int main()
{
    S::f();     // S::f is accessible in main
 
    S s;
    s.n = S::B; // S::n and S::B are accessible in main
 
    S::U x;     // S::U is accessible in main
}

[bearbeiten] Geschützter Memberzugriff

Geschützte Member bilden die Schnittstelle einer Klasse zu ihren abgeleiteten Klassen (die sich von der öffentlichen Schnittstelle der Klasse unterscheidet).

Ein geschützter Member einer Klasse ist nur zugänglich

1) für die Member und Freunde dieser Klasse;
2) für die Member und Freunde jeder abgeleiteten Klasse dieser Klasse, aber nur, wenn die Klasse des Objekts, über das auf den geschützten Member zugegriffen wird, diese abgeleitete Klasse oder eine abgeleitete Klasse dieser abgeleiteten Klasse ist.
struct Base
{
protected:
    int i;
private:
    void g(Base& b, struct Derived& d);
};
 
struct Derived : Base
{
    friend void h(Base& b, Derived& d);
    void f(Base& b, Derived& d) // member function of a derived class
    {
        ++d.i;                  // OK: the type of d is Derived
        ++i;                    // OK: the type of the implied '*this' is Derived
//      ++b.i;                  // error: can't access a protected member through
                                // Base (otherwise it would be possible to change
                                // other derived classes, like a hypothetical
                                // Derived2, base implementation)
    }
};
 
void Base::g(Base& b, Derived& d) // member function of Base
{
    ++i;                          // OK
    ++b.i;                        // OK
    ++d.i;                        // OK
}
 
void h(Base& b, Derived& d) // Friend of Derived
{
    ++d.i;                  // OK: friend of Derived can access a protected 
                            // member through an object of Derived
//  ++b.i;                  // error: friend of Derived is not a friend of Base
}
 
void x(Base& b, Derived& d) // non-member non-friend
{
//  ++b.i;                  // error: no access from non-member
//  ++d.i;                  // error: no access from non-member
}

Wenn ein Zeiger auf einen geschützten Member gebildet wird, muss in seiner Deklaration eine abgeleitete Klasse verwendet werden.

struct Base
{
protected:
    int i;
};
 
struct Derived : Base
{
    void f()
    {
//      int Base::* ptr = &Base::i;    // error: must name using Derived
        int Base::* ptr = &Derived::i; // OK
    }
};

[bearbeiten] Privater Memberzugriff

Private Member bilden die Implementierung einer Klasse sowie die private Schnittstelle für die anderen Member der Klasse.

Ein privater Member einer Klasse ist nur für die Member und Freunde dieser Klasse zugänglich, unabhängig davon, ob sich die Member auf demselben oder auf unterschiedlichen Instanzen befinden.

class S
{
private:
    int n; // S::n is private
public:
    S() : n(10) {}                    // this->n is accessible in S::S
    S(const S& other) : n(other.n) {} // other.n is accessible in S::S
};

Die explizite Umwandlung (C-Stil und Funktionsstil) ermöglicht die Umwandlung von einem abgeleiteten lvalue in eine Referenz auf seine private Basis, oder von einem Zeiger auf eine abgeleitete Klasse in einen Zeiger auf seine private Basis.

[bearbeiten] Vererbung

Siehe abgeleitete Klassen für die Bedeutung von öffentlicher, geschützter und privater Vererbung.

[bearbeiten] Schlüsselwörter

public, protected, private

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 1873 C++98 protected-Member waren für Freunde von abgeleiteten Klassen zugänglich. unzugänglich gemacht.