Membres privés et protégés: C ++


276

Quelqu'un peut-il m'éclairer sur la différence entre private et les protectedmembres des classes?

Je comprends des meilleures conventions de pratique que les variables et les fonctions qui ne sont pas appelés en dehors de la classe devraient être private- mais en regardant mon MFC projet, MFC semble favorable protected.

Quelle est la différence et laquelle dois-je utiliser?

Réponses:


374

Les membres privés ne sont accessibles que dans la classe qui les définit.

Les membres protégés sont accessibles dans la classe qui les définit et dans les classes qui héritent de cette classe.

Edit: Les deux sont également accessibles par les amis de leur classe, et dans le cas des membres protégés, par les amis de leurs classes dérivées.

Edit 2: Utilisez tout ce qui a du sens dans le contexte de votre problème. Vous devez essayer de rendre les membres privés chaque fois que vous le pouvez pour réduire le couplage et protéger l'implémentation de la classe de base, mais si ce n'est pas possible, utilisez des membres protégés. Consultez la FAQ C ++ pour une meilleure compréhension du problème. Cette question sur les variables protégées pourrait également aider.


12
Le lien vers C ++ FAQ Lite a été déplacé vers isocpp.org/wiki/faq/basics-of-inheritance
avner

134

Les membres publics d'une classe A sont accessibles à tous et à tous.

Les membres protégés d'une classe A ne sont pas accessibles en dehors du code de A, mais sont accessibles à partir du code de toute classe dérivée de A.

Les membres privés d'une classe A ne sont pas accessibles en dehors du code de A ou du code d'une classe dérivée de A.

Donc, en fin de compte, choisir entre protégé ou privé répond aux questions suivantes: Quelle confiance êtes-vous prêt à accorder au programmeur de la classe dérivée?

Par défaut , supposez que la classe dérivée n'est pas fiable et rendez vos membres privés . Si vous avez une très bonne raison de donner libre accès aux internes de la classe mère à ses classes dérivées, vous pouvez les faire protéger.


La classe dérivée doit être un type de votre classe et les données protégées de la classe de base font partie des données de la classe dérivée. Le rédacteur de la classe dérivée est censé gérer correctement ces données ou il s'agit d'un bogue. Cependant, les données privées d'une classe de base ne sont pas contrôlées par l'auteur de la classe dérivée.
CashCow

@CashCow the protected data of the base class is part of the data of the derived class.En effet. N'est-il pas préférable, alors, que l'écrivain de la classe dérivée déclare ces données dans sa classe, au lieu des miennes? ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug.Dans le modèle NVI, le but est de tout rendre privé, y compris pour limiter les dommages que le rédacteur de classe dérivé pourrait causer à la hiérarchie. Les méthodes protégées sont déjà un problème potentiel. Je ne suis pas convaincu qu'aggraver cela en utilisant l'état protégé est la bonne approche.
paercebal

Cela pourrait être, ce qui nécessiterait d'avoir des "getters" virtuels dans la classe de base pour y accéder. Et bien que vous puissiez avoir des classes intermédiaires pour effectuer les différentes manières d'implémenter le modèle de données, il n'est pas toujours pratique de le faire. Par exemple, un "modèle", courant dans les langages qui n'ont pas de modificateur "const" bien que non nécessaire la plupart du temps en C ++ est d'avoir une classe de base en lecture seule et des classes dérivées accessibles en écriture. En C ++, cela peut aussi être agréable simplement parce que vous voulez plus d'une façon possible de charger (initialiser) les données.
CashCow

Il existe différentes façons de procéder. Faites vos amis de cours de sérialisation. Mettez toutes vos données dans une structure avec accès public mais votre classe a un membre privé de cette variable .... Des membres protégés et des classes dérivées pour les charger depuis n'importe quelle source est parfois plus facile.
CashCow

63

Les membres protégés sont accessibles à partir de classes dérivées. Les particuliers ne le peuvent pas.

class Base {

private: 
  int MyPrivateInt;
protected: 
  int MyProtectedInt;
public:
  int MyPublicInt;
};

class Derived : Base
{
public:
  int foo1()  { return MyPrivateInt;} // Won't compile!
  int foo2()  { return MyProtectedInt;} // OK  
  int foo3()  { return MyPublicInt;} // OK
};‌‌

class Unrelated 
{
private:
  Base B;
public:
  int foo1()  { return B.MyPrivateInt;} // Won't compile!
  int foo2()  { return B.MyProtectedInt;} // Won't compile
  int foo3()  { return B.MyPublicInt;} // OK
};

En termes de "meilleures pratiques", cela dépend. S'il y a même une faible possibilité que quelqu'un veuille dériver une nouvelle classe de votre classe existante et ait besoin d'accéder aux membres internes, rendez-les protégés, pas privés. S'ils sont privés, votre classe peut devenir difficile à hériter facilement.


3
Je vous prie de différer: s'il y a une faible possibilité qu'aucune sous-classe n'en ait besoin, rendez-la privée. Sauf si vous avez l' intention de sous-classer votre classe, utilisez le modèle de méthode de modèle.
xtofl

23

La raison pour laquelle MFC privilégie la protection est qu'il s'agit d'un cadre. Vous souhaitez probablement sous-classer les classes MFC et dans ce cas, une interface protégée est nécessaire pour accéder aux méthodes qui ne sont pas visibles pour une utilisation générale de la classe.


9

Tout dépend de ce que vous voulez faire et de ce que vous voulez que les classes dérivées puissent voir.

class A
{
private:
    int _privInt = 0;
    int privFunc(){return 0;}
    virtual int privVirtFunc(){return 0;}
protected:
    int _protInt = 0;
    int protFunc(){return 0;}
public:
    int _publInt = 0;
    int publFunc()
    {
         return privVirtFunc();
    }
};

class B : public A
{
private:
    virtual int privVirtFunc(){return 1;}
public:
    void func()
    {
        _privInt = 1; // wont work
        _protInt = 1; // will work
        _publInt = 1; // will work
        privFunc(); // wont work
        privVirtFunc(); // wont work
        protFunc(); // will work
        publFunc(); // will return 1 since it's overridden in this class
    }
}

6

Les attributs et les méthodes marqués comme protected- contrairement aux attributs privés - sont toujours visibles dans les sous-classes.

À moins que vous ne vouliez pas utiliser ou fournir la possibilité de remplacer la méthode dans les sous-classes possibles, je les ferais private.


2
Une classe dérivée peut remplacer les fonctions virtuelles privées de sa base
James Hopkin

6

Bien sûr, jetez un œil à la question sur les variables des membres protégés . Il est recommandé d'utiliser private par défaut (tout comme le classfont ses C ++ ) pour réduire le couplage. Les variables membres protégées sont le plus souvent une mauvaise idée, les fonctions membres protégées peuvent être utilisées par exemple pour le modèle de méthode de modèle.


C'est drôle, j'ai édité ça sur mon post avant de voir le vôtre. Surévalué parce que les oiseaux d'une plume tombent sur le même lien :)
Firas Assaad

4

Les membres protégés ne sont accessibles qu'aux descendants de la classe et par code dans le même module. Les membres privés ne sont accessibles que par la classe dans laquelle ils sont déclarés et par le code dans le même module.

Bien sûr, les fonctions d'amis jettent cela par la fenêtre, mais bon.


4

les membres privés ne sont accessibles qu'à partir de la classe, les membres protégés sont accessibles dans la classe et les classes dérivées. C'est une caractéristique de l'héritage dans les langages OO.

Vous pouvez avoir un héritage privé, protégé et public en C ++, qui déterminera à quelles classes dérivées peuvent accéder dans la hiérarchie d'héritage. C #, par exemple, n'a qu'un héritage public.


3

privé = accessible uniquement par le vaisseau-mère (classe de base) (c'est-à-dire que seuls mes parents peuvent entrer dans la chambre de mes parents)

protégé = accessible par le vaisseau-mère (classe de base) et ses filles (c'est-à-dire que seuls mes parents peuvent aller dans la chambre de mes parents, mais ont donné à leur fils / fille la permission d'entrer dans la chambre des parents)

public = accessible par le vaisseau-mère (classe de base), la fille et tout le monde (c'est-à-dire que seuls mes parents peuvent aller dans la chambre de mes parents, mais c'est une fête à la maison - mi casa su casa)


2

Puisqu'aucune fonction de membre public n'est nécessaire pour récupérer et mettre à jour les membres protégés dans la classe dérivée, cela augmente l'efficacité du code et réduit la quantité de code que nous devons écrire. Cependant, le programmeur de la classe dérivée est censé savoir ce qu'il fait.


Vous pouvez toujours utiliser une fonction en ligne implémentée dans la déclaration de classe. Le compilateur optimisera cela (et ce serait un bon moyen d'appliquer un accès en lecture seule à une variable membre privée, par exemple).
Paul Sanders

2

privateest préféré pour les données des membres. Les membres des classes C ++ sont privatepar défaut.

publicest préféré pour les fonctions de membre, bien que ce soit une question d'opinion. Certaines méthodes au moins doivent être accessibles.publicest accessible à tous. C'est l'option la plus flexible et la moins sûre. Tout le monde peut les utiliser et tout le monde peut en abuser.

privaten'est pas accessible du tout. Personne ne peut les utiliser en dehors de la classe et personne ne peut en abuser. Pas même dans les classes dérivées.

protectedest un compromis car il peut être utilisé dans des classes dérivées. Lorsque vous dérivez d'une classe, vous avez une bonne compréhension de la classe de base et veillez à ne pas abuser de ces membres.

MFC est un wrapper C ++ pour l'API Windows, il préfère publicet protected. Les classes générées par Visual Studio Assistant ont un mélange laid protected, publicetprivate les membres. Mais il y a une certaine logique pour les classes MFC elles-mêmes.

Les membres tels que SetWindowTextsont publicparce que vous devez souvent accéder à ces membres.

Des membres tels que OnLButtonDown, gèrent les notifications reçues par la fenêtre. Ils ne devraient pas être accessibles, donc ils le sont protected. Vous pouvez toujours y accéder dans la classe dérivée pour remplacer ces fonctions.

Certains membres doivent faire des threads et des boucles de messages, ils ne doivent pas être accessibles ou remplacés, ils sont donc déclarés comme private

Dans les structures C ++, les membres sont publicpar défaut. Les structures sont généralement utilisées pour les données uniquement, pas pour les méthodes, la publicdéclaration est donc considérée comme sûre.


1
Vous écrivez «Les membres des classes C ++ sont protégés par défaut». Selon la norme, ils sont privés ou publics par défaut, selon le mot clé utilisé dans la définition (14p3). Microsoft s'écarte-t-il de la norme ici?
Alexander Klauer

@AlexanderKlauer J'avais tort, c'est privatepar défaut dans Visual Studio. C'est aussi privatepar défaut dans gcc, ce n'est jamais publicpar défaut. À moins que je ne me trompe à nouveau. Je ne trouve pas la norme à laquelle vous faites référence.
Barmak Shemirani

Désolé, j'aurais dû être plus précis. Je faisais référence à la norme C ++ 17. La norme C ++ 11 a le même libellé dans 11p3. Pourriez-vous mettre à jour votre réponse? Merci!
Alexander Klauer

1

Un membre privé n'est accessible que dans la même classe où il a déclaré où en tant que membre protégé, il est accessible dans la classe où il est déclaré avec les classes héritées par lui.


1
  • Privé : il s'agit d'un spécificateur d'accès. Par défaut, les variables d'instance (membre) ou les méthodes d'une classe en c ++ / java sont privées. Pendant l'héritage, le code et les données sont toujours hérités mais ne sont pas accessibles en dehors de la classe. Nous pouvons déclarer nos données membres comme privées afin que personne ne puisse modifier directement nos variables membres et nous pouvons fournir des getters et setters publics afin de changer nos membres privés. Et ce concept est toujours appliqué dans la règle commerciale.

  • Protégé : c'est également un spécificateur d'accès. En C ++, les membres protégés sont accessibles dans la classe et à la classe héritée mais pas en dehors de la classe. En Java, les membres protégés sont accessibles au sein de la classe, à la classe héritée ainsi qu'à toutes les classes du même package.


0

Un membre protégé de la classe de base non statique est accessible aux membres et amis de toutes les classes dérivées de cette classe de base en utilisant l'une des options suivantes:

  • Un pointeur vers une classe dérivée directement ou indirectement
  • Une référence à une classe dérivée directement ou indirectement
  • Un objet d'une classe dérivée directement ou indirectement

0

Privé: accessible par les fonctions des membres de la classe et la fonction ami ou la classe ami. Pour la classe C ++, il s'agit du spécificateur d'accès par défaut.

Protégé: accessible par les fonctions membres de la classe, la fonction ami ou la classe ami et les classes dérivées.

  • Vous pouvez conserver la variable ou la fonction des membres de la classe (même les typedefs ou les classes internes) comme privées ou protégées selon vos besoins.
  • La plupart du temps, vous conservez le membre de la classe en tant que privé et ajoutez des fonctions get / set à encapsuler. Cela aide à la maintenance du code.
  • La fonction généralement privée est utilisée lorsque vous souhaitez garder vos fonctions publiques modulaires ou éliminer le code répété au lieu d'écrire du code entier dans une seule fonction. Cela aide à la maintenance du code.

Reportez-vous à ce lien pour plus de détails.


-2

les modificateurs d'accès privés et protégés ne font qu'un et permettent d'accéder aux membres protégés de la classe de base en dehors de la portée de la classe de base dans la classe enfant (dérivée). Il en va de même pour l'héritage. Mais avec le modificateur privé, les membres de la classe de base ne sont accessibles que dans la portée ou le code de la classe de base et ses fonctions ami uniquement '' ''


5
Quelle valeur votre réponse ajoute-t-elle aux autres réponses?
Hermann Döppes
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.