Contrôle d'accès aux membres (C++)

Les contrôles d’accès vous permettent de séparer l’interface public d’une classe des détails de l’implémentation private et des protected membres qui ne sont utilisés que par des classes dérivées. Le spécificateur d'accès s'applique à tous les membres déclarés après lui jusqu'à ce que le spécificateur d'accès suivant soit rencontré.

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();
};

L’accès par défaut se trouve private dans une classe et public dans un struct ou une union. Les spécificateurs d'accès dans une classe peuvent être utilisés autant de fois que nécessaire dans n'importe quel ordre. L’allocation de stockage pour les objets de types de classes dépend de l’implémentation. Toutefois, les compilateurs doivent garantir l’attribution de membres à des adresses mémoire successivement supérieures entre les spécificateurs d’accès.

Contrôle d'accès aux membres

Type d'accès Signification
private Les membres de classe déclarés comme private pouvant être utilisés uniquement par les fonctions membres et les amis (classes ou fonctions) de la classe.
protected Les membres de classe déclarés comme protected pouvant être utilisés par les fonctions membres et les amis (classes ou fonctions) de la classe. En outre, ils peuvent être utilisés par des classes dérivées de la classe.
public Les membres de classe déclarés comme public pouvant être utilisés par n’importe quelle fonction.

Le contrôle d’accès vous empêche d’utiliser des objets de manière à ce qu’ils ne soient pas destinés à être utilisés. Cette protection est perdue lorsque vous effectuez des conversions de types explicites (casts).

Remarque

Le contrôle d'accès s'applique également à tous les noms : fonctions membres, données membres, classes imbriquées et énumérateurs.

Contrôle d'accès dans les classes dérivées

Deux facteurs contrôlent les membres d'une classe de base qui sont accessibles dans une classe dérivée. Ces mêmes facteurs contrôlent l'accès aux membres hérités dans la classe dérivée :

  • Indique si la classe dérivée déclare la classe de base à l’aide du spécificateur d’accès public .

  • Quel est l'accès au membre de la classe de base.

Le tableau suivant montre l'interaction entre ces facteurs et la procédure de détermination de l'accès au membre de la classe de base.

Accès au membre de la classe de base

private protected public
Toujours inaccessible avec n’importe quel accès dérivation private dans la classe dérivée si vous utilisez private la dérivation private dans la classe dérivée si vous utilisez private la dérivation
protected dans la classe dérivée si vous utilisez protected la dérivation protected dans la classe dérivée si vous utilisez protected la dérivation
protected dans la classe dérivée si vous utilisez public la dérivation public dans la classe dérivée si vous utilisez public la dérivation

L’exemple suivant illustre la dérivation d’accès :

// 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
}

Dans DerivedClass1, la fonction PublicFunc membre est un public membre et ProtectedFunc est membre protected , car BaseClass il s’agit d’une public classe de base. PrivateFuncest à BaseClass, et il est private inaccessible à toutes les classes dérivées.

Dans DerivedClass2, les fonctions PublicFunc et ProtectedFunc sont considérées comme private membres, car BaseClass il s’agit d’une private classe de base. Là encore, PrivateFunc c’est private à BaseClass, et il est inaccessible à toutes les classes dérivées.

Vous pouvez déclarer une classe dérivée sans spécificateur d'accès de classe de base. Dans ce cas, la dérivation est considérée private si la déclaration de classe dérivée utilise le class mot clé. La dérivation est considérée public si la déclaration de classe dérivée utilise la struct mot clé. Par exemple, le code suivant :

class Derived : Base
...

équivaut à :

class Derived : private Base
...

De même, le code suivant :

struct Derived : Base
...

équivaut à :

struct Derived : public Base
...

Les membres déclarés comme ayant private accès ne sont pas accessibles aux fonctions ou aux classes dérivées, sauf si ces fonctions ou classes sont déclarées à l’aide de la friend déclaration dans la classe de base.

Un union type ne peut pas avoir de classe de base.

Remarque

Lors de la spécification d’une private classe de base, il est conseillé d’utiliser explicitement l’mot clé private afin que les utilisateurs de la classe dérivée comprennent l’accès aux membres.

Contrôle d'accès et membres statiques

Lorsque vous spécifiez une classe de base comme private, elle affecte uniquement les membres non statiques. Les membres publics static sont toujours accessibles dans les classes dérivées. Toutefois, l’accès aux membres de la classe de base à l’aide de pointeurs, de références ou d’objets peut nécessiter une conversion, qui applique à nouveau le contrôle d’accès. Prenons l’exemple suivant :

// 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;
}

Dans le code précédent, le contrôle d'accès interdit la conversion d'un pointeur vers Derived2 en un pointeur vers Base. Le this pointeur est implicitement de type Derived2 *. Pour sélectionner la CountOf fonction, this doit être convertie en type Base *. Une telle conversion n’est pas autorisée, car Base il s’agit d’une private classe de base indirecte en Derived2. La conversion en private type de classe de base est acceptable uniquement pour les pointeurs vers des classes dérivées immédiates. C’est pourquoi les pointeurs de type Derived1 * peuvent être convertis en type Base *.

Un appel explicite à la CountOf fonction, sans utiliser de pointeur, de référence ou d’objet pour le sélectionner, n’implique aucune conversion. C’est pourquoi l’appel est autorisé.

Les membres et amis d’une classe dérivée, Tpeuvent convertir un pointeur en T pointeur vers une private classe de base directe de T.

Accès aux fonctions virtuelles

Le contrôle d’accès appliqué aux virtual fonctions est déterminé par le type utilisé pour effectuer l’appel de fonction. La substitution des déclarations de la fonction n’affecte pas le contrôle d’accès pour un type donné. Par exemple :

// 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;
}

Dans l’exemple précédent, l’appel de la fonction GetState virtuelle à l’aide d’un pointeur pour taper VFuncBase des appels VFuncDerived::GetStateet GetState est traité comme public. Toutefois, l’appel à GetState l’aide d’un pointeur à type VFuncDerived est une violation de contrôle d’accès, car GetState elle est déclarée private dans la classe VFuncDerived.

Attention

La fonction virtuelle GetState peut être appelée en utilisant un pointeur vers la classe de base VFuncBase. Cela ne signifie pas que la fonction appelée est la version de classe de base de cette fonction.

Contrôle d'accès avec héritage multiple

Dans les treillis à héritage multiple impliquant des classes de base virtuelles, un nom donné est accessible via plusieurs chemins. Comme un contrôle d'accès différent peut être appliqué le long de ces différents chemins, le compilateur choisit le chemin qui fournit le plus souvent l'accès. Consultez la figure suivante :

Diagram showing access along the paths of an inheritance graph.

Le diagramme montre la hiérarchie d’héritage suivante : la classe VBase est la classe de base. Class LeftPath hérite de VBase à l’aide de VBase virtuel private . la classe RightPath hérite également de VBase, mais utilise VBase virtuel public . Enfin, la classe Dérivée hérite de la classe LeftPath et de la classe RightPath à l’aide public de LeftPath, public RightPath.

Chemins d’accès d’un graphique d’héritage

Dans cette figure, un nom déclaré dans la classe VBase est toujours accessible via la classe RightPath. Le chemin d’accès approprié est plus accessible, car RightPath déclare VBase en tant que public classe de base, tandis que LeftPath le chemin d’accès est VBaseprivateplus accessible.

Voir aussi

Informations de référence sur le langage C++