Question Différence entre héritage privé, public et protégé


Quelle est la différence entre public, private, et protected héritage en C ++? Toutes les questions que j'ai trouvées sur SO traitent de cas spécifiques.


813
2018-05-13 20:47


origine


Réponses:


Pour répondre à cette question, j'aimerais d'abord décrire les accesseurs des membres dans mes propres mots. Si vous le savez déjà, passez à la rubrique "suivant".

Il y a trois accesseurs que je connais: public, protected et private.

Laisser:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Tout ce qui est conscient de Base est également conscient que Base contient publicMember.
  • Seuls les enfants (et leurs enfants) sont conscients que Base contient protectedMember.
  • Personne d'autre Base est conscient de privateMember.

Par "est conscient de", je veux dire "reconnaître l'existence de, et donc être en mesure d'accéder".

prochain:

La même chose arrive avec l'héritage public, privé et protégé. Considérons une classe Base et une classe Child qui hérite de Base.

  • Si l'héritage est public, tout ce qui est conscient de Base et Child est également conscient que Child hérite de Base.
  • Si l'héritage est protected, seulement Childet ses enfants sont conscients qu'ils héritent de Base.
  • Si l'héritage est private, personne d'autre que Child est conscient de l'héritage.

902
2018-05-13 20:49



class A 
{
public:
    int x;
protected:
    int y;
private:
    int z;
};

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

NOTE IMPORTANTE: Les classes B, C et D contiennent toutes les variables x, y et z. C'est juste une question d'accès.

A propos de l'utilisation de l'héritage protégé et privé, vous pouvez lire ici.


1221
2017-09-03 11:27



Limiter la visibilité de l'héritage empêchera le code de voir qu'une classe hérite d'une autre classe: les conversions implicites de la dérivée vers la base ne fonctionneront pas, et static_cast de la base à la dérivée ne fonctionnera pas non plus.

Seuls les membres / amis d'une classe peuvent voir l'héritage privé et seuls les membres / amis et les classes dérivées peuvent voir l'héritage protégé.

Publique héritage

  1. IS-A héritage. Un bouton est une fenêtre, et partout où une fenêtre est nécessaire, un bouton peut être passé aussi.

    class button : public window { };
    

protégé héritage

  1. Protégé mis en œuvre-en-termes-de. Rarement utile. Utilisé dans boost::compressed_pair dériver de classes vides et économiser de la mémoire en utilisant une optimisation de classe de base vide (l'exemple ci-dessous n'utilise pas de modèle pour rester sur le point):

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

privé héritage

  1. Mis en œuvre-en-termes-de. L'utilisation de la classe de base sert uniquement à implémenter la classe dérivée. Utile avec les traits et si la taille compte (les traits vides qui ne contiennent que des fonctions utiliseront l'optimisation de la classe de base vide). Souvent endiguement est la meilleure solution, cependant. La taille des chaînes est critique, c'est donc un usage souvent vu ici

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

Publique membre

  1. Agrégat

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. Accesseurs

    class window {
    public:
        int getWidth() const;
    };
    

protégé membre

  1. Fournir un accès amélioré pour les classes dérivées

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

privé membre

  1. Conserver les détails de mise

    class window {
    private:
      int width;
    };
    

Notez que les lancers de style C permettent intentionnellement de lancer une classe dérivée vers une classe de base protégée ou privée d'une manière définie et sûre et de lancer dans l'autre direction aussi. Cela devrait être évité à tout prix, car cela peut rendre le code dépendant des détails de la mise en œuvre - mais si nécessaire, vous pouvez utiliser cette technique.


98
2017-09-03 16:04



Cela a à voir avec la façon dont les membres publics de la classe de base sont exposés à partir de la classe dérivée.

  • public -> les membres publics de la classe de base seront publics (généralement par défaut)    
  • protected -> les membres publics de la classe de base seront protégés    
  • privé -> les membres publics de la classe de base seront privés

Comme le souligne Litb, l'héritage public est un héritage traditionnel que vous verrez dans la plupart des langages de programmation. C'est-à-dire qu'il modélise une relation "IS-A". L'héritage privé, quelque chose d'AFAIK propre au C ++, est une relation "IMPLEMENTÉE EN TERMES DE". C'est toi qui veux utilisation l'interface publique dans la classe dérivée, mais ne veut pas que l'utilisateur de la classe dérivée ait accès à cette interface. Beaucoup soutiennent que dans ce cas, vous devriez agréger la classe de base, c'est-à-dire au lieu d'avoir la classe de base comme base privée, faire dans un membre de dérivée afin de réutiliser la fonctionnalité de la classe de base.


61
2018-05-13 20:49



Ces trois mots clés sont également utilisés dans un contexte complètement différent pour spécifier modèle d'héritage de visibilité.

Cette table rassemble toutes les combinaisons possibles du modèle de déclaration de composant et d'héritage présentant l'accès résultant aux composants lorsque la sous-classe est complètement définie.

enter image description here

Le tableau ci-dessus est interprété de la manière suivante (regardez la première ligne):

si un composant est déclaré comme Publique et sa classe est hérité comme Publique la résultante accès est Publique.

Un exemple:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

L'accès résultant pour les variables p, q, r en classe Sous-marin est aucun.

Un autre exemple:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

L'accès résultant pour les variables y, z en classe Sous est protégé et pour variable x est aucun.

Un exemple plus détaillé:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Maintenant, définissons une sous-classe:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

La classe définie nommée Sub qui est une sous-classe de la classe nommée Super ou ça Sub classe est dérivée de la Super classe. le Sub classe n'introduit ni de nouvelles variables ni de nouvelles fonctions. Cela signifie-t-il que tout objet de Sub classe hérite de tous les traits après la Super classe étant en fait une copie d'un Super objets de classe?

Non. Ce n'est pas le cas.

Si nous compilons le code suivant, nous n'obtiendrons rien d'autre que des erreurs de compilation indiquant que put et get les méthodes sont inaccessibles. Pourquoi?

Lorsque nous omettons le spécificateur de visibilité, le compilateur suppose que nous allons appliquer le soi-disant héritage privé. Cela signifie que tout Publique composants de superclasse se transforment en privé accès, les composants de la superclasse privée ne seront pas accessibles du tout. Cela signifie par conséquent que vous n'êtes pas autorisé à utiliser ce dernier dans la sous-classe.

Nous devons informer le compilateur que nous voulons conserver la politique d'accès précédemment utilisée.

class Sub : public Super { };

Ne pas être induit en erreur: cela ne signifie pas que les composants privés de la Super   classe (comme la variable de stockage) deviendra publique dans un   manière un peu magique. Privé les composants resteront privé, Publiquerestera Publique.

Objets du Sub classe peut faire "presque" les mêmes choses que leurs frères et sœurs plus âgés créés à partir de la Super classe. "Presque" parce que le fait d'être une sous-classe signifie également que le classe perdu l'accès aux composants privés de la superclasse. Nous ne pouvons pas écrire une fonction membre du Sub classe qui serait capable de manipuler directement la variable de stockage.

C'est une restriction très sérieuse. Y a-t-il une solution de contournement?

Oui.

Le troisième niveau d'accès est appelé protégé. Le mot-clé protected signifie que le composant marqué avec se comporte comme un public lorsqu'il est utilisé par l'une des sous-classes et ressemble à un privé au reste du monde. - Ceci est vrai uniquement pour les classes héritées publiquement (comme la classe Super dans notre exemple) -

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

Comme vous le voyez dans l'exemple de code, nous avons une nouvelle fonctionnalité Sub classe et il fait une chose importante: il accède à la variable de stockage de la classe Super.

Cela ne serait pas possible si la variable était déclarée privée. Dans la fonction principale scope, la variable reste cachée, donc si vous écrivez quelque chose comme:

object.storage = 0;

Le compilateur vous informera que c'est un error: 'int Super::storage' is protected.

Enfin, le dernier programme produira la sortie suivante:

storage = 101

40
2018-06-07 16:56



Member in base class : Private   Protected   Public   

Type d'héritage  :Objet hérité en tant que:

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

34
2017-09-09 05:25



1) Héritage public:

une. Les membres privés de la classe Base ne sont pas accessibles dans la classe Derived.

b. Les membres protégés de la classe Base restent protégés dans la classe Derived.

c. Les membres publics de la classe Base restent publics dans la classe Derived.

Ainsi, d'autres classes peuvent utiliser des membres publics de la classe Base via l'objet de classe Derived.

2) Héritage protégé:

une. Les membres privés de la classe Base ne sont pas accessibles dans la classe Derived.

b. Les membres protégés de la classe Base restent protégés dans la classe Derived.

c. Les membres publics de la classe Base deviennent également des membres protégés de la classe Derived.

Ainsi, les autres classes ne peuvent pas utiliser les membres publics de la classe Base via l'objet de classe Derived; mais ils sont disponibles pour la sous-classe de Derived.

3) Héritage privé:

une. Les membres privés de la classe Base ne sont pas accessibles dans la classe Derived.

b. Les membres protégés et publics de la classe Base deviennent des membres privés de la classe Derived.

Par conséquent, aucun membre de la classe Base ne peut être accédé par d'autres classes via l'objet de classe Derived, car elles sont privées dans la classe Derived. Donc, même sous-classe de Derived La classe ne peut pas y accéder.


22
2018-05-26 04:42



L'héritage public modélise une relation IS-A. Avec

class B {};
class D : public B {};

chaque D  est un  B.

L'héritage privé modélise une relation IS-IMPLEMENTED-USING (ou quelque chose de ce genre). Avec

class B {};
class D : private B {};

une D est ne pas une Bmais tous les D utilise son B dans sa mise en œuvre. L'héritage privé peut toujours être éliminé en utilisant confinement à la place:

class B {};
class D {
  private: 
    B b_;
};

Ce Daussi, peut être mis en œuvre en utilisant B, dans ce cas en utilisant son b_. Le confinement est un couplage moins serré entre les types que l'héritage, donc en général, il devrait être préféré. Parfois, l'utilisation de l'endiguement au lieu de l'héritage privé n'est pas aussi pratique que l'héritage privé. Souvent, c'est une excuse boiteuse pour être paresseux.

Je ne pense pas que quelqu'un sache quoi protected modèles d'héritage. Au moins, je n'ai pas encore vu d'explication convaincante.


19
2017-09-03 12:34



Si vous héritez publiquement d'une autre classe, tout le monde sait que vous héritez et vous pouvez être utilisé de manière polymorphique par n'importe qui à travers un pointeur de classe de base.

Si vous héritez protégé, seules vos classes enfants pourront vous utiliser de manière polymorphe.

Si vous héritez en privé, seul vous serez en mesure d'exécuter des méthodes de classe parent.

Ce qui symbolise essentiellement les connaissances que le reste des classes a sur votre relation avec votre classe parente


12
2017-09-03 11:27



Les membres de données protégés peuvent être accédés par toutes les classes qui héritent de votre classe. Les membres de données privées, cependant, ne peuvent pas. Disons que nous avons ce qui suit:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

De votre extension à cette classe, référencement this.myPrivateMember ne fonctionnera pas. cependant, this.myProtectedMember volonté. La valeur est toujours encapsulée, donc si nous avons une instanciation de cette classe appelée myObj, puis myObj.myProtectedMember ne fonctionnera pas, il est donc similaire à un membre de données privé.


9
2018-05-13 20:57