polymorphisme - tp c++ heritage




Différence entre héritage privé, public et protégé (11)

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


Privé:

Les membres privés d'une classe de base ne sont accessibles qu'aux membres de cette classe de base.

Publique:

Les membres publics d'une classe de base peuvent être accédés par les membres de cette classe de base, les membres de sa classe dérivée ainsi que les membres qui sont en dehors de la classe de base et de la classe dérivée.

Protégé:

Les membres protégés d'une classe de base peuvent être accédés par les membres de la classe de base ainsi que par les membres de sa classe dérivée.

En bref:

privé : base

protégé : base + dérivé

public : base + derived + tout autre membre


C'est essentiellement la protection d'accès des membres publics et protégés de la classe de base dans la classe dérivée. Avec l'héritage public, la classe dérivée peut voir les membres publics et protégés de la base. Avec l'héritage privé, ça ne peut pas. Avec protected, la classe dérivée et toutes les classes dérivées de celle-ci peuvent les voir.


Ces trois mots-clés sont également utilisés dans un contexte complètement différent pour spécifier le 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.

Il se lit de la manière suivante (jetez un oeil à la première rangée):

Si un composant est déclaré public et que sa classe est héritée en tant que public, l' accès qui en résulte est public .

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 dans la classe Subsub est none .

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 dans la classe Sub est protégé et pour la 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 Super ou cette Sub classe est dérivée de la classe Super . La classe Sub n'introduit ni de nouvelles variables ni de nouvelles fonctions. Cela signifie-t-il que tout objet de la classe Sub hérite de tous les traits après que la classe Super soit en fait une copie des objets d'une classe Super ?

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 les méthodes put et get sont inaccessibles. Pourquoi?

Lorsque nous omettons le spécificateur de visibilité, le compilateur suppose que nous allons appliquer l' héritage dit privé . Cela signifie que tous les composants de la superclasse publique se transforment en accès privé, 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 vous laissez pas induire en erreur : cela ne signifie pas que les composants privés de la classe Super (comme la variable de stockage) deviendront des composants publics d'une manière quelque peu magique. Les composants privés resteront privés , le public restera public .

Les objets de la classe Sub peuvent faire "presque" la même chose que leurs frères et sœurs plus âgés créés à partir de la classe Super . "Presque" parce que le fait d'être une sous-classe signifie aussi que la classe a perdu l'accès aux composants privés de la superclasse . Nous ne pouvons pas écrire une fonction membre de la classe Sub 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 lui se comporte comme un public lorsqu'il est utilisé par l'une des sous-classes et ressemble à un composant privé au reste du monde . - Ceci n'est vrai que 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 le code d'exemple, nous avons une nouvelle fonctionnalité pour la classe Sub et elle fait une chose importante: elle 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 une error: 'int Super::storage' is protected .

Enfin, le dernier programme produira la sortie suivante:

storage = 101

J'ai trouvé une réponse facile et j'ai pensé à la poster pour ma future référence aussi.

C'est à partir des liens http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}

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érencer this.myPrivateMember ne fonctionnera pas. Cependant, this.myProtectedMember sera. La valeur est toujours encapsulée, donc si nous avons une instanciation de cette classe appelée myObj , alors myObj.myProtectedMember ne fonctionnera pas, c'est donc une fonction similaire à un membre de données privé.


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 vers 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é.

héritage public

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

héritage protégé

  1. Protégé mis en œuvre-en-termes-de. Rarement utile. Utilisé dans boost::compressed_pair pour dériver des classes vides et économiser de la mémoire en utilisant l'optimisation de la classe de base vide (l'exemple ci-dessous n'utilise pas de template 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!
      }
    };
    

héritage privé

  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, le confinement est la meilleure solution. La taille des cordes 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();
      }
    };
    

membre public

  1. Agrégat

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

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

membre protégé

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

membre privé

  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.


Résumé:

  • Privé: personne ne peut le voir, sauf dans la classe
  • Protégé: Privé + les classes dérivées peuvent le voir
  • Public: le monde peut le voir

Lors de l'héritage, vous pouvez (dans certaines langues) changer le type de protection d'un membre de données dans une certaine direction, par exemple de protégé à public.


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


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. Ainsi, même une sous-classe de la classe Derived ne peut pas y accéder.


Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

Basé sur this exemple pour Java ... Je pense qu'une petite table vaut mille mots :)


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 here .







access-specifier