EPFL
Faculté Informatique & Communications
Cours d'informatique

Mini-Référence :
POO : Héritage Multiple

Concept de base

Nous avons vu que la notion d'héritage permet de dériver des classes plus spécialisées (sous-classes) à partir de classes préexistantes (super-classes), implémentant ainsi la relation «est-un». Qu'en est-il lorsque l'on souhaite dériver une sous-classe de plusieurs super-classes à la fois ?

Cela s'appelle «l'héritage multiple». Il faut savoir que l'héritage multiple n'existe pas dans tous les langages orientés objets, mais il est possible en C++. Cela se fait simplement en ajoutant plusieurs classe dans la partie héritage. Par exemple :

class Ovovivipare : public Ovipare, public Vivipare {
     /* définition des attributs et des méthodes
      * spécifiques à la  sous-classe            */
     ...
};

A priori aucune nouvelle difficulté donc, si ce n'est de bien faire attention au fait que l'ordre est important. Dans l'exemple précédent, un Ovovivipare est avant tout un Ovipare et est aussi (ensuite) un Vivipare. Ceci importe dans l'ordre d'appel des constructeurs et des destructeurs.

Accès aux membres ambigus

Un souci pratique intervient cependant lorsque l'on souhaite accéder à un membre (i.e. attribut ou méthode) qui existe avec le même nom dans plusieurs des super-classes : lequel appeler et comment l'appeler ?

Ce serait par exemple le cas dans l'exemple précédent si les classes Ovipare et Vivipare avaient chacune une méthode afficher().

Il y a trois moyens pour cela :

  1. ne rien faire et laisser le programmeur-utilisateur décider (mais il peut toujours le faire, en fait !) en utilisant l'opérateur de résolution de portée :
    Ovovivipare requin;
    
    requin.Vivipare::afficher();
        
  2. décider une fois pour toute au niveau de la classe :
    class Ovovivipare : public Ovipare, public Vivipare {
        ...
        using Vivipare::afficher;
    };
        
  3. offrir un membre du même nom (masquage) :
    class Ovovivipare : public Ovipare, public Vivipare {
        ...
        void afficher() const;
    };
    ...
    void Ovovivipare::afficher () const
    {
    ...
    }
    

Classes virtuelles

Un autre souci, plus sérieux car conceptuel, intervient lorsqu'une classe hérite de deux classes (héritage multiple) lesquelles héritent de la même classe commune. Cette situation est illustrée par l'un ou l'autre des diagrammes suivants :

classe non virtuelle classe virtuelle
Quel héritage ?

La question de conception à se poser ici est de savoir si la classe la plus spécialisée (Ovovivipare dans l'exemple précédent) est une (figure de droite) ou plusieurs (figure de gauche) réalisation(s) de la super-classe héritée plusieurs fois.

Dans l'exemple précédent, on peut sans crainte, je crois, pouvoir affirmer qu'un Ovovivipare est un Animal. C'est donc le schéma de droite que l'on souhaite.

Dans ce cas on dit que la classe Animal est «virtuelle». Ce terme, à mon avis mal choisi, veut juste dire que la classe ne sera présente qu'une seule fois en cas d'héritage multiple via des classes intermédiaires. C'est en fait plus l'héritage (via certaines des classes intermédiaires) que la classe elle même qui est virtuel !

Un tel héritage (qui donc dans notre exemple doit se déclarer au niveau de Ovipare (et de Vivipare) pour un futur potentiel Ovovivipare : beurk !!) s'écrit :

class Vivipare : public virtual Animal
{...};

class Ovipare : public virtual Animal
{...};

Mais ATTENTION alors : dans une dérivation virtuelle, la super-classe virtuelle doit être initialisée par sa classe la plus dérivée.
La sous-classe la plus dérivée doit donc effectuer elle-même un appel au constructeur de la super-classe virtuelle :

Ovovivipare::Ovovivipare(...)
: Animal(...), Ovipare(...), ...
{...}

Note : on pourrait aussi imaginer des situations (plus rares car dans la plupart des cas je préférerais alors utiliser l'encapsulation : «possède» plutôt que «est-un». Si vous me trouvez un bon exemple je suis preneur !) où on n'a pas besoin d'héritage (pardon, de classe) virtuel(le) et où la présence des deux super-classes est conceptuellement correcte (figure de gauche ci-dessus). Dans un tel cas, pas besoin des «virtual», les deux instances seront alors bien présentes.


Dernière mise à jour : $Date: 2009-09-11 17:10:52 +0200 (Fri, 11 Sep 2009) $  ($Revision: 25 $)