Problème d'héritage multiple

cs_Aquarian Messages postés 9 Date d'inscription lundi 10 mai 2004 Statut Membre Dernière intervention 20 avril 2006 - 19 avril 2006 à 22:35
cs_Aquarian Messages postés 9 Date d'inscription lundi 10 mai 2004 Statut Membre Dernière intervention 20 avril 2006 - 20 avril 2006 à 10:43
Bonjour,

Voici un morceau de code sur lequel j'ai un problème, en fait il se compile bien sous Visual Studio .NET 2003 ou sous Dev-cpp, mais il ne fait pas vraiment ce que je souhaiterai.

#include
using namespace std;

class A {
public:
A(int a) :_a(a) {}
void write() {cout << " A : " << _a << endl; }

protected:
int _a;
};

class BInterface {
public:
void writeB() {cout << " B : " << _valeurB << endl; }
protected:
BInterface() : _valeurB(1){}
private :
int _valeurB;
};

class B : public A, public BInterface {
public:
B(int a): A(a), BInterface() {}
};

class CInterface {
public:
void writeC() {cout << " C : " << _valeurC << endl; }
protected:
CInterface() : _valeurC(2) {}
private :
int _valeurC;
};

class C : public A, public CInterface {
public:
C(int a) : A(a), CInterface() {}
};

class D : public A, public BInterface, public CInterface {
public:
D(int a) : A(a), BInterface(), CInterface() {}
};

int main(int argc, char* argv[])
{
A* ptr = new D(8);

ptr -> write();
((B*)ptr) -> writeB();
((C*)ptr) -> writeC();

cin.get();
}

>> SORTIE DU PROGRAMME :
A : 8
B : 1
C : 1 // ??? Tiens donc ???

Donc ce système marche (compile) mais n'est pas correct, j'ai l'impression (je me trompe peut-être) que les instructions
((B*)ptr) -> writeB();

((C*)ptr) -> writeC();

se font très mal, elles se baseraient sur l'organisation mémoire des classes B et C (normal vu le cast) et non sur celle de D.

J'aimerai obtenir le schéma d'héritage suivant :

A

/ \ En fait je sais qu'il faudrait déclarer class B : public virtual A mais dans ce cas,

/ \ je ne peux pas convertir directement un pointeur de A en un pointeur vers B

B C ou C sauf en utilisant un dynamic_cast. Or dans ma fonction, je connais le

\ / le type du pointeur sur A, je sais que c'est un pointeur sur B ou D. Ca me

\ / ça me semble donc contraignant d'utiliser un dynamic cast qui va faire le

D branchement sur la bonne fonction durant l'exécution...


En gros mon entête de fonction est le suivant :

void maFonction (A* ptr) {
// Ici je sais que lorsque j'ai appelé cette fonction A est un pointeur sur un B ou un D
((B*)ptr) -> writeB(); // Ligne qui ne marche pas si j'ai un héritage virtuel
}

Mon essai précédent était pour essayer de palier au problème de classes de bases virtuelles mais du coup je me retrouve coincé au niveau de ma fonction de traitement...

Est-ce que quelqu'un pourrait m'aider et me donner une piste pour que je puisse réorganiser l'ensemble de mes fonctions? Et au pire dois-je absoluement faire un dynamic_cast ?

_________

Aquarian

1 réponse

cs_Aquarian Messages postés 9 Date d'inscription lundi 10 mai 2004 Statut Membre Dernière intervention 20 avril 2006
20 avril 2006 à 10:43
Bonjour à tous,

Finalement j'ai résolu mon problème non sans évité pas mal de warning à la compilation mais qui est une solution propre à mon problème. Voici le code :

class A {
public:
A(int a) :_a(a) {}
void write() {cout << " A : " << _a << endl; }
virtual void writeB() {}
virtual void writeC() {}

protected:
int _a;
};

class B : public virtual A {
public:
B(int a) : A(a), _valeurB(1) {}
void writeB() {cout << " B : " << _valeurB << endl; }

protected:
B() : _valeurB(1);
private :
int _valeurB;
};

class C : public virtual A {
public:
C(int a) : A(a), _valeurC(2) {}

void writeC() {cout << " C : " << _valeurC << endl; }
protected:
C() : _valeurC(2) {}
private :
int _valeurC;
};

class D : public A, public B {
public:
D(int a) : A(a), B(), C() {}
};

int main(int argc, char* argv[])
{
A* ptr = new D(8);

ptr -> write(); // En fait pas besoin de cast pour
ptr -> writeB(); // faire ces différents appels c'est pour
ptr -> writeC(); // ça que je me suis planté, je voulais
// faire un cast avant de lancer la fonction
cin.get();
}

Ce code, comme je le disais plus haut provoque pas mal de warning (surtout si writeB et writeC prennent des paramètres, on a des avertissements comme quoi les variables passées en paramètre ne sont pas utilisées). Les warning en plus sont sur le changement de fonction appelée suivant la classe (rien de vraiment problématique, mais je ne sais pas si on peut les éviter).

Il me reste tout de même une question :
Dans le livre de Stroustrup (chap. 15.2.5.1), on peut mettre les deux fonctions writeB et writeC en virtuelles pures or cela ne peut marcher si on ne définit pas les deux fonctions dans chacune des classes héritantes ? Ou je me trompe et j'ai encore des erreurs dans mon code ? J'ai essayé mais à chaque fois il me dit que je n'ai pas le droit d'instancier la classe B ou la classe C car la classe est virtuelle....

_________

Aquarian
0
Rejoignez-nous