Héritage virtuel.

Quand l'héritage peut poser des ambiguités.

virtual

Voir version :

Pas de dépendances

Télécharger :

#include <iostream>
#include <cstdlib>

using namespace std;

class Mere
{
protected:
    char a[100];
public:
    Mere(){}
};

class Fille1:public Mere
{
protected:
    char b[1000];
public:
    Fille1(){}
};

class Fille2:public Mere
{
protected:
    char c[1000];
public:
    Fille2(){}
};

class PetiteFille:public Fille1,public Fille2
{
protected:
    char d[10000];
public:
    PetiteFille(){}
    //void plouf(){ a[0] = 2;}   // a1
    //void plouf(){Fille1::Mere::a[0] = 2;}   // a2
};

int main()
{
    cout << "size mere = " << sizeof(Mere) << endl;
    cout << "size fille1 = " << sizeof(Fille1) << endl;
    cout << "size fille2 = " << sizeof(Fille2) << endl;
    cout << "size petitefille = " << sizeof(PetiteFille) << endl;
    //PetiteFille pf;   // a0
    //pf.plouf();       // a0
    
    system("pause");
    return 0;
}



Commentaires


  Cas tordu :

  Fille1 et Fille2 sont toutes les 2 fille de Mere.
  Et PetiteFille hérite des deux.

  J'ai fait expres de mettre comme taille 100,1000,10000 pour les tailles, pour que ça saute aux yeux.
  Si on lance le prog, on voit les sizeof : ils confirment que fille1 et fille2 contiennent un héritage simple. 1100 = 1000 + 100 = Mere + Fille1 ou Mere + Fille2
  Ils confirment aussi que PetiteFille contient 2 centaines : donc littéralement, en mémoire, une instance de PetiteFille contient : 12200 -> 2*Mere, Fille1, Fille2, PetiteFille


  Mere              Mere
   |                 |
   |                 |
  Fille1            Fille2
     \               /             
      \             /
       \           /
        \         /
         PetiteFille

  De ce fait, si, dans PetiteFille, j'essaie de modifie a, va-t-il aller modifier la Mere via Fille1 ou Fille2 ?
  --> Il suffit de lui demander !

  Activez les lignes marquées a0 et a1
  Compilez....
  --> Erreur : ambiguité. La compilo vous dit qu'il ne sait pas s'il va modifier le a de la Mere via Fille1 et Fille2
  Normal ! Pourquoi ce serait plus l'un que l'autre ?

  Désactivez la ligne a1 et activez la a2
  --> ici, j'explicite la route, avec des opérateurs :: pour dire quelle variable je veux modifier.
  ça compile donc (note : sous les anciennes versions de Visual C++ 6.0, il se peut que ça coince, mais ce sont des problemes dus a Visual C++ 6.0)


// Heritage virtuel

  Voyons maintenant ce qu'est un héritage virtuel.

  déclarez maintenant les 2 classes Fille comme cela : (ajoutez juste le mot virtual en fait)
  class Fille1:virtual public Mere
  class Fille2:virtual public Mere

  Puis réactivez les lignes a0 et a1. (désactivez a2)

  Lancez, ça marche !!!
  Plus d'ambiguités.
  Mais surtout, une size étrange :

  12108 (12116 si vous etes en 64 bits)
  Comment l'expliquer ?

  12108, c'est 12100 + 8 octets
  Donc c'est 1* PetiteFille, Fille1, Fille2 et UNE SEULE FOIS Mere cette fois... + 8 octets....

  Nous avons donc affaire a ce schéma maintenant :


            Mere
         /       \
        /         \
       /           \ 
      /             \
  Fille1            Fille2
     \               /             
      \             /
       \           /
        \         /
         PetiteFille


  Il n'y a plus qu'une seule classe classe Mere : donc plus d'ambuguités si je vais chercher la variable a depuis "PetiteFille"

  Mais alors, que sont ces 8 octets de plus ?
  Ce sont 2 pointeurs qui partent, respectivement de Fille1 et de Fille2 vers la Mere.
  c'est un mécanisme interne puissant.

  Si vous regardez les sizeof de Fille1 (et Fille2), vous voyez 1104 -> toutes les données + 1 pointeur
  Si on instancie juste Fille1, le pointeur ne sera pas utilisé : car Fille1 ne dérivant qu'une fois de Mere, on instancie ses données.
  Si on instancie PetiteFille, alors l'héritage virtuel ne fera pas doublons de Mere, et utilisera les pointeurs ainsi rajoutés pour gérer cela automatiquement.

  Note : en 64 bits, les pointeurs ne font plus 4 octets, mais 8 octets : donc la taille sera légerement différente.


Laissez un commentaire / post a comment