Guru Of the Week n° 39 : héritage multiple - troisième partie

| Herb Sutter | Traduction par l'équipe de la rubrique C++ |

Difficulté : 4 / 10
Il est facile de redéfinir des fonctions héritées virtuelles – tant que vous n'essayez pas de redéfinir une fonction virtuelle qui a la même signature dans les deux classes de base. Ça peut arriver même quand les classes de base ne proviennent pas de vendeurs différents !

Retrouvez l'ensemble des Guru of the Week sur la page d'index.

N'hésitez pas à commenter cet article ! Commentez

- Titre : Guru Of the Week n° 39 : héritage multiple - troisième partie

- Auteurs : Herb Sutter, Traduction par l'équipe de la rubrique C++

- Parution : 26 juillet 2012

- Licence : Copyright ® 2009 Herb Sutter. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Problème

- II. Solution

- II-A. Renommer les fonctions virtuelles

- III. Remerciements

I - Problème

Considérons les deux classes suivantes :

class B1 {
public:
virtual int ReadBuf( const char* );
// ?
};

class B2 {
public:
virtual int ReadBuf( const char* );
// ?
};

Elles sont clairement destinées à être toutes les deux utilisées comme classes de base, mais elles sont sans lien l'une avec l'autre – leurs fonctions ReadBuf sont destinées à faire des choses différentes et les classes proviennent de différents vendeurs de bibliothèques.

Montrez comment écrire une classe D, qui dérive publiquement de B1 et B2 et qui redéfinit les deux fonctions indépendantes ReadBuf pour faire des choses différentes.

II - Solution

Montrez comment écrire une classe D, qui dérive publiquement de B1 et B2 et qui redéfinit les deux fonctions indépendantes ReadBuf pour faire des choses différentes.

Voici la tentative naïve qui ne fonctionnera pas :

class D : public B1, public B2 {
public:
int ReadBuf( const char* );
// overrides both B1::ReadBuf and B2::ReadBuf
};

Elle redéfinit LES DEUX fonctions avec la même implémentation, alors que le but de la question était de redéfinir les deux fonctions pour faire des choses différentes. Vous ne pouvez pas simplement « intervertir » les comportements dans ce D::ReadBuf en fonction de la façon dont il est appelé, parce qu'une fois que vous êtes à l'intérieur de D::ReadBuf, il n'y a aucun moyen de dire quelle interface de base doit être utilisée (si une interface de base a effectivement été utilisée).

II-A - Renommer les fonctions virtuelles

Si les deux fonctions dérivées avaient des signatures différentes, il ne devrait pas y avoir de problème : on se contenterait de les redéfinir indépendamment, comme d'habitude. L'astuce, dans ce cas, est de modifier d'une manière ou d'une autre la signature d'au moins une des deux fonctions héritées.

La façon de changer la signature d'une fonction de classe de base consiste à créer une classe intermédiaire qui dérive de la classe de base, à déclarer une nouvelle fonction virtuelle et à forcer la version héritée pour appeler la nouvelle fonction :

class D1 : public B1 {
public:
virtual int ReadBufB1( const char* p ) = 0;

int ReadBuf( const char* p ) {  // redéfinition de l'héritage
return ReadBufB1( p );      // pour appeler la nouvelle fonction
}
};

class D2 : public B2 {
public:
virtual int ReadBufB2( const char* p ) = 0;

int ReadBuf( const char* p ) {  // redéfinition de l'héritage
return ReadBufB2( p );      // pour appeler la nouvelle fonction
}
};

D1 et D2 peuvent aussi avoir besoin de dupliquer les constructeurs de B1 et B2 pour que D puisse les invoquer, mais c'est tout. D1 et D2 sont des classes abstraites, alors elles n'ont PAS BESOIN de dupliquer les autres fonctions ou opérateurs de B1 et B2, comme les opérateurs d'affectation.

À présent, nous pouvons simplement écrire :

class D : public D1, public D2 {
public:
int ReadBufB1( const char* );
int ReadBufB2( const char* );
};

Les classes dérivées n'ont besoin que de savoir qu'elles ne doivent plus redéfinir ReadBuf lui-même.

III - Remerciements

Cet article est une traduction en français par l'équipe de la rubrique C++ de l'article de Herb Sutter publié sur Guru of the Week. Vous pouvez retrouver cet article dans sa version originale sur le site de Guru of the Week : Multiple Inheritance - Part III.

Merci à Luc Hermitte pour sa relecture technique et à _Max_ pour sa relecture orthographique.