Access specifiers
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.
Sommaire
Syntaxe
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é. ExplicationLe 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 :
Exécuter ce code
#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étailToutes les déclarations de membres d'une classe (y compris celles définies en dehors de la classe) ont accès à tous les noms auxquels la classe peut accéder. Une classe locale dans une fonction membre a accès à tous les noms auxquels la fonction membre peut accéder. Une classe définie avec le mot‑clé Pour accorder l'accès à des fonctions ou classes supplémentaires aux membres protected ou private, une déclaration d'amitié peut être utilisée. L'accessibilité s'applique à tous les noms sans égard à leur origine, donc un nom introduit par un typedef ou une déclaration using (sauf les constructeurs hérités) est vérifié, et non le nom auquel il se réfère : 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
}
L'accès aux membres n'affecte pas la visibilité : les noms des membres private et des membres hérités en private sont visibles et pris en compte par la résolution de surcharge, les conversions implicites vers des 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 du langage. L'intention de cette règle est que remplacer un La vérification d'accès pour les noms utilisés dans les arguments de fonction par défaut ainsi que dans les paramètres de modèle 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 dernier remplaceur est ignoré : 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
}
Un nom qui est private selon la recherche de nom non qualifiée peut être accessible par recherche de nom qualifiée : 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
};
Un nom accessible par plusieurs chemins dans le graphe d'héritage a l'accès du chemin le plus permissif : 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
}
};
Un nombre quelconque de spécificateurs d'accès peut apparaître dans une classe, dans n'importe quel ordre.
Lorsqu'un membre est redéclaré dans la même classe, il doit l'être sous le même accès membre : struct S
{
class A; // S::A is public
private:
class A {}; // error: cannot change access
};
Accès public aux membresLes 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ésLes 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ésLes 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éritageVoir les classes dérivées pour la signification de l'héritage public, protected et private. Mots-clésRapports de défautsLes rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||