Namespaces
Variants

Access specifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Access specifiers
friend specifier

Class-specific function properties
Special member functions
Templates
Miscellaneous

Dans une spécification-de-membre d'une classe/structure ou d'une union , définit l'accessibilité des membres suivants.

Dans un spécificateur-de-base d'une déclaration de classe dérivée , définissez l'accessibilité des membres hérités de la classe de base suivante.

Table des matières

Syntaxe

public : déclarations-de-membres (1)
protected : déclarations-de-membres (2)
private : déclarations-de-membres (3)
public classe-de-base (4)
protected classe-de-base (5)
private classe-de-base (6)
1) Les membres déclarés après le spécificateur d'accès ont un accès membre public.
2) Les membres déclarés après le spécificateur d'accès ont un accès membre protégé.
3) Les membres déclarés après le spécificateur d'accès ont un accès membre privé.
4) Héritage public : les membres publics et protégés de la classe de base listés après le spécificateur d'accès conservent leur accès membre dans la classe dérivée.
5) Héritage protégé : les membres publics et protégés de la classe de base listés après le spécificateur d'accès sont des membres protégés de la classe dérivée.
6) Héritage privé : les membres publics et protégés de la classe de base listés après le spécificateur d'accès sont des membres privés de la classe dérivée.

Les membres privés de la classe de base sont toujours inaccessibles à la classe dérivée, qu'il s'agisse d'un héritage public, protégé ou privé.

Explication

Le nom de chaque membre de classe (statique, non-statique, fonction, type, etc.) possède un « accès membre » associé. Lorsqu'un nom de membre est utilisé n'importe où dans un programme, son accès est vérifié, et s'il ne satisfait pas aux règles d'accès, le programme ne compile pas :

#include <iostream>
class Example
{
public:             // toutes les déclarations après ce point sont publiques
    void add(int x) // la fonction membre "add" a un accès public
    {
        n += x;     // OK : Example::n privé peut être accédé depuis Example::add
    }
private:            // toutes les déclarations après ce point sont privées
    int n = 0;      // le membre "n" a un accès privé
};
int main()
{
    Example e;
    e.add(1); // OK : Example::add public peut être accédé depuis main
//  e.n = 7;  // erreur : Example::n privé ne peut pas être accédé depuis main
}

Les spécificateurs d'accès donnent à l'auteur de la classe la capacité de décider quels membres de la classe sont accessibles aux utilisateurs de la classe (c'est-à-dire l' interface ) et quels membres sont destinés à l'usage interne de la classe (l' implémentation ).

En détail

Tous les membres d'une classe (corps des fonctions membres , initialiseurs des objets membres, et l'ensemble des définitions de classes imbriquées ) ont accès à tous les noms auxquels la classe peut accéder. Une classe locale au sein d'une fonction membre a accès à tous les noms auxquels la fonction membre peut accéder.

Une classe définie avec le mot-clé class a un accès privé pour ses membres et ses classes de base par défaut. Une classe définie avec le mot-clé struct a un accès public pour ses membres et ses classes de base par défaut. Une union a un accès public pour ses membres par défaut.

Pour accorder l'accès à des fonctions ou classes supplémentaires aux membres protégés ou privés, une déclaration d'amitié peut être utilisée.

L'accessibilité s'applique à tous les noms sans considération de leur origine, donc un nom introduit par une typedef ou using declarations (sauf les constructeurs hérités) est vérifié, et non le nom auquel il fait référence :

class A : X
{
    class B {};   // B est privé dans A
public:
    typedef B BB; // BB est public
};
void f()
{
    A::B y;  // erreur : A::B est privé
    A::BB x; // OK : A::BB est public
}

L'accès aux membres n'affecte pas la visibilité : les noms des membres privés et hérités privés sont visibles et pris en compte par la résolution de surcharge, les conversions implicites vers les classes de base inaccessibles sont toujours considérées, etc. La vérification de l'accès aux membres est la dernière étape après l'interprétation de toute construction linguistique donnée. L'intention de cette règle est que remplacer tout private par public n'altère jamais le comportement du programme.

La vérification d'accès pour les noms utilisés dans les arguments par défaut des fonctions ainsi que dans les paramètres de template par défaut est effectuée au point de déclaration, et non au point d'utilisation.

Les règles d'accès pour les noms des fonctions virtuelles sont vérifiées au point d'appel en utilisant le type de l'expression utilisée pour désigner l'objet pour lequel la fonction membre est appelée. L'accès du final overrider est ignoré :

struct B
{
    virtual int f(); // f est public dans B
};
class D : public B
{
private:
    int f(); // f est privé dans D
};
void f()
{
    D d;
    B& b = d;
    b.f(); // OK : B::f est public, D::f est invoqué même s'il est privé
    d.f(); // erreur : D::f est privé
}

Un nom qui est privé selon la recherche de nom non qualifiée , peut être accessible via la recherche de nom qualifiée :

class A {};
class B : private A {};
class C : public B
{
    A* p;   // erreur : la recherche de nom non qualifié trouve A comme base privée de B
    ::A* q; // OK : la recherche de nom qualifié trouve la déclaration au niveau du namespace
};

Un nom accessible par plusieurs chemins dans le graphe d'héritage possède l'accessibilité du chemin le plus accessible :

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 est accessible à C via B
    }
};

N'importe quel nombre de spécificateurs d'accès peut apparaître dans une classe, dans n'importe quel ordre.

Les spécificateurs d'accès des membres peuvent affecter la disposition de la classe : les adresses des membres de données non statiques sont uniquement garanties d'augmenter dans l'ordre de déclaration pour les membres non séparés par un spécificateur d'accès (jusqu'à C++11) avec le même accès (depuis C++11) .

(jusqu'à C++23)

Pour les types à disposition standard , tous les membres de données non statiques doivent avoir le même accès.

(depuis C++11)

Lorsqu'un membre est redéclaré dans la même classe, il doit le faire avec le même accès membre :

struct S
{
    class A;    // S::A est public
private:
    class A {}; // erreur : impossible de modifier l'accès
};

Accès public aux membres

Les membres publics constituent une partie de l'interface publique d'une classe (les autres parties de l'interface publique sont les fonctions non-membres trouvées par ADL ).

Un membre public d'une classe est accessible partout :

class S
{
public:
    // n, E, A, B, C, U, f sont des membres publics
    int n;
    enum E {A, B, C};
    struct U {};
    static void f() {}
};
int main()
{
    S::f();     // S::f est accessible dans main
    S s;
    s.n = S::B; // S::n et S::B sont accessibles dans main
    S::U x;     // S::U est accessible dans main
}

Accès aux membres protégés

Les membres protégés constituent l'interface d'une classe envers ses classes dérivées (ce qui est distinct de l'interface publique de la classe).

Un membre protégé d'une classe est uniquement accessible

1) aux membres et amis de cette classe ;
2) aux membres et amis de toute classe dérivée de cette classe, mais uniquement lorsque la classe de l'objet par lequel le membre protégé est accédé est cette classe dérivée ou une classe dérivée de cette classe dérivée :
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) // fonction membre d'une classe dérivée
    {
        ++d.i;                  // OK : le type de d est Derived
        ++i;                    // OK : le type du '*this' implicite est Derived
//      ++b.i;                  // erreur : impossible d'accéder à un membre protégé via
                                // Base (sinon il serait possible de modifier
                                // d'autres classes dérivées, comme un hypothétique
                                // Derived2, implémentation de base)
    }
};
void Base::g(Base& b, Derived& d) // fonction membre de Base
{
    ++i;                          // OK
    ++b.i;                        // OK
    ++d.i;                        // OK
}
void h(Base& b, Derived& d) // Ami de Derived
{
    ++d.i;                  // OK : l'ami de Derived peut accéder à un membre
                            // protégé via un objet de Derived
//  ++b.i;                  // erreur : l'ami de Derived n'est pas ami de Base
}
void x(Base& b, Derived& d) // non-membre non-ami
{
//  ++b.i;                  // erreur : aucun accès depuis un non-membre
//  ++d.i;                  // erreur : aucun accès depuis un non-membre
}

Lorsqu'un pointeur vers un membre protégé est formé, il doit utiliser une classe dérivée dans sa déclaration :

struct Base
{
protected:
    int i;
};
struct Derived : Base
{
    void f()
    {
//      int Base::* ptr = &Base::i;    // erreur : doit être nommé en utilisant Derived
        int Base::* ptr = &Derived::i; // OK
    }
};

Accès aux membres privés

Les membres privés constituent l'implémentation d'une classe, ainsi que l'interface privée pour les autres membres de la classe.

Un membre privé d'une classe est uniquement accessible aux membres et amis de cette classe, indépendamment du fait que les membres se trouvent sur la même instance ou sur des instances différentes :

class S
{
private:
    int n; // S::n est privé
public:
    S() : n(10) {}                    // this->n est accessible dans S::S
    S(const S& other) : n(other.n) {} // other.n est accessible dans S::S
};

La conversion explicite (style C et style fonction) permet de convertir un lvalue dérivé en référence vers sa base privée, ou un pointeur vers un dérivé en pointeur vers sa base privée.

Héritage

Voir les classes dérivées pour la signification de l'héritage public, protected et private.

Mots-clés

public , protected , private

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement correct
CWG 1873 C++98 les membres protégés étaient accessibles aux amis des classes dérivées rendus inaccessibles