VII. Héritage multiple

  1. Mise en œuvre de l'héritage multiple :

Supposons une situation dites simple, nous allons retravailler notre classe dérivé pointcol afin quel hérite de la classe point et d'une autre classe coul(qui est une classe contenant le code d'une couleur).

Voici la définition de nos deux classes de base :

class point			class coul
     {			             {
      int x,y;		              short coul;
    public:			     public:
      point(...){...}                 coul(...){...}
     ~point(){...}                   ~coul(){...}
      affiche(){...}                  affiche(){...}
     };                              );

Nous pouvons définir une classe pointcol dérivé de ces deux classe :

class pointcol :public point , public coul
	{
	 .
	 .
	 .
	};

Notez que nous sommes justes contenté de remplacé une mention de classe de base par une liste de classes de base. Au sein de cette classe nous pouvons définir de nouveaux membre ou des fonction utilisant les composante des classes de base.

Pour le constructeur, il y à simplement appel des deux constructeur des classe de bases au lieu d'un seul :

pointcol(.....):point(....), coul(...)

L'ordre d'appel des constructeurs est le suivant :

Comme dans le cas de l'héritage simple on peut dans les fonctions membre de la classe dérivé utilisé les fonctions membre publique et protégé des classes de bases. Lorsque plusieurs fonctions porte le même nom on peut lever l'ambiguïté en utilisant l'opérateur de résolution de porté. La même démarche s'applique pour des données membre portant le même nom.

  1. Les classes virtuelle :

Supposons que nous disposions de deux classe B et C hérité tout deux de la classe A, nous voulons crée un classe D qui héritée de B et C, ors B et C, hérite tout deux de A, donc dans D nous aurons un double héritage de A. Dans ces conditions les données et fonctions membre vont apparaître deux fois dans D. Cela ne pose pas de problème réel pour les fonctions membre, mais pour les données membre ils seront dupliqué deux fois.

Nous aurons à tout moment deux jeux de données. Nous devons donc empêcher le double héritage, nous allons donc demander à C++ de n'introduire qu'une seule fois la classe A. Pour cela nous allons utiliser le mot clé virtual. Ce mot clé placé devant la déclaration d'héritage de B par A et de C par A empêcheras lors d'héritage ultérieur la double duplication des données membre de A :

class B : public virtual A{.....};
class C : public virtual A{......};
class D : public B, public C {.....};

Avec ou sans virtual les classes B et C se comporte normalement tant quelles n'ont pas de descendant commun.

  1. Constructeur et destructeur dans une classe virtuelle :

Dans l'exemple du paragraphe précédent nous faisons appel aux constructeurs de B et C qui eux même font appel au constructeur de A. Si les classe B et C ne définissent pas A comme une classe virtuelle c'est comme si nous possédions deux classes A1 et A2 parfaitement identique. Par contre si A est une classe virtuelle, comme B et C font appel au constructeur de A, nous ne savons lequel sera prit en compte. Pour levé cette ambiguïté le choix des données a transmettre à A ne se fera plus dans B ni C mais dans D :

D(int n, int p, double z) :B(n,p,z), A(n,p) 

Bien entendu, il sera inutile de précisé des informations pour A dans les constructeurs B et de C.

En ce qui concerne l'appel des constructeur, le constructeur d'une classe virtuelle est toujours appelé en premier.

  1. Exemple d'héritage multiple : Liste chainée de point
  1. Liste chaînée :

Une liste chaîné est ensemble d'élément ou chaque élément pointe sur le suivant. Nous allons définir en entier la classe liste qui sera parfaitement réutilisable dans cette état. La liste chaîné possède un pointeur qui pointe sur le premier élément de la liste. puis chaque élément pointe sur le suivant jusqu'à ce que le dernier pointeur égal NULL.


# include <stddef.h>  // pour la définition de NULL

struct element
	{
	 element *suivant;	//pointeur sur l'élément suivant
	 void* contenu;    //pointeur sur un objet quelconque
	};

class liste
	{
	 element *debut;    //pointeur sur le premier élément
	 element *courant  //pointeur sur l'élément courant
 public:
	liste()					//constructeur
		{debut=NULL;courant=debut;)
	~liste();				//destructeur

void ajoute(void *);		//ajoute un élément en fin de liste

void supprimer(void *);  //supprime un élément en début de liste

void premier()
	{
	 courant=debut;      //positionne courant sur le premier élément
	}

void * prochain()   //fournit l'adresse de l'élément courant
	{			//est positionne courant sur le suivant
	 void * adel=NULL;
	 if(courant!=NULL)
		{
		 adel=courant->contenu;
		 courant=courant->suivant;
		}
	 return adel;
	}

int fini(){return(courant==NULL);}  //retourne 1 si la fin de la liste
  	};                                   //est atteinte

liste::~liste()
	{
	 element *suivant;
	 courant=debut;
	 while(courant!=NULL)
		{
		 suivant=courant->suivant;
		 delete courant;
		 courant=suivant;
		}
	}

void liste::ajoute(void *chose)
	{
	 element* adel=new element;

	 while(courant!=NULL)
		{
		 suivant=courant->suivant;
		 courant=suivant;
		}
	 
	 adel->suivant=NULL;
	 adel->contenu=chose;
	 courant->suivant=adel;
	 courant=debut;
	}
	 
void liste::supprimer()
	{
	 element* suiv;
	 courant=debut;
	 suiv=courant->suivant;
	 delete courant;
	 debut=suiv;
	}

Maintenant nous allons définir notre classe point ainsi que la classe dérivé:


class point
	{
	 int x,y;
	
 public:
	 point(int abs,int ord): x(ord), y(abs)
	 ~point(){}
	 void affiche(){cout<<"Coordonées :"<<x<<" "<<y<<endl;}
	};

 

class liste_point: public liste, public point
	{
	 
 public:
	 liste_point(){}
	 void affiche();
	};

void liste_point::affiche()
	{
	 premier();
	 while(!fini() )
		{
		 point *ptr=(point *)prochain();
		 ptr->affiche();
		}

Voilà maintenant vous en savait un peut plus sur le C++ et la programmation orientés objets et vous pouvez donc crée vos propre classe et vos propre application.

Il est bon de savoir que JAVA est un langage développé à partir du C++, la notions de classe y est fondamental, mais l'héritage multiple en a était supprimé.