Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1328 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  problème d'héritage

 



 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

problème d'héritage

n°2014433
in_your_ph​ion
Posté le 05-08-2010 à 12:31:16  profilanswer
 

bonjour,  
 
j'ai une problème  :whistle: en fait:  
 
- j'ai deux classes A B  
 
-  B hérite de A
 
-  une classe C qui hérite de A
 
-  une classe D qui hérite de C
 
schématiquement:
 
A <--- B
|
|
C <--- D
 
Or, je voudrais faire hériter D de B, soit :
 
A <--- B
|        |
|        |
C <--- D
 
le problème, c'est que D hérite de C qui contient donc A, et comme B contient A, ben si D hérite de B il contient potentiellement A deux fois...  :pt1cable:  :pt1cable:  :pt1cable:  
 
comment faire ??
 
merci par avance!
 

mood
Publicité
Posté le 05-08-2010 à 12:31:16  profilanswer
 

n°2014448
Un Program​meur
Posté le 05-08-2010 à 13:18:39  profilanswer
 

Renseigne-toi sur l'heritage virtuel (si B&C heritent virtuellement de A, il n'y en aura qu'un dans D).


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2014462
in_your_ph​ion
Posté le 05-08-2010 à 13:48:34  profilanswer
 

Un Programmeur a écrit :

Renseigne-toi sur l'heritage virtuel (si B&C heritent virtuellement de A, il n'y en aura qu'un dans D).


 
merci!!  :)

n°2014778
in_your_ph​ion
Posté le 06-08-2010 à 11:37:34  profilanswer
 

up

 

ne fait j'aurais encore une question ...

 

comment je fais si A, B et C prennent des paramètres en entrée ??

 

par exemple A(const char * buffer)

 

et :  B(const char *buffer, int toto) C(const char *buffer, int toto)

 

buffer c'est la même chose pour tous.

 

une fois que j'initialise D, je dois initialisée deux fois ??

 
Code :
  1. D(const char * buffer, int toto)
  2. : A(buffer)
  3. , B(buffer,toto)
  4. , C(buffer,toto)
  5. { ; }
 


c'est comme ça ? dans ce cas je passe buffer 3 fois pour des constructeurs qui utilisent le même paramètre ...

 

merki par avance


Message édité par in_your_phion le 06-08-2010 à 11:37:52
n°2014780
Un Program​meur
Posté le 06-08-2010 à 11:40:55  profilanswer
 

Oui: le constructeur de A sera appele une fois, et les parametres seront ceux donne par le constructeur de la classe la plus derivee (D ici).  C'est piegeux si A a un constructeur par defaut mais qu'il ne faut pas l'utiliser, si il n'y a pas d'appel a un constructeur de A dans la classe la plus derivee, c'est le constructeur par defaut qui sera appele.


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2015094
in_your_ph​ion
Posté le 07-08-2010 à 14:03:12  profilanswer
 

ok merci!!

 

Y'a t-il un moyen d'éviter l'héritage virtuel ? je trouve ça vraiment complexe à mettre en œuvre et piegeux comme tu le dis ;)

 

Que faut t'il faire dans ce genre de situation ?

 
Code :
  1. A_1 <-------- A_2
  2.   |            |
  3.   |            |
  4.   |            |
  5. B_1 <-------- B_2
  6.   |            |
  7.   |            |
  8.   |            |
  9. C_1 <-------- C_2
  10.   .            .
  11.   .            .
  12.   .            .
 

i.e :  

 

- C_1 dérive de B_1 qui dérive de A_1 - etc
- C_2 dérive de B_2 qui dérive de A_2 - etc

 

chaque classe A_1,B_1, ... a besoin d'hériter d'une classe correspondante A_2, B_2, ...

 

j'ai l'impression que ce genre de situation peut arriver souvent .... Par exemple :

 

A_1 est une voiture traban qui 'hérite' d'une classe A_2 qui implémente un moteur de base (à pédales  :D )

 

B_1 est une voiture hummer qui 'hérite' d'une classe B_2 qui implémente un moteur à réaction

 

ne reste t-il que l'héritage virtuel et tout le hardcore qui va avec ?  [:tinostar]

 

merci par avance ...    


Message édité par in_your_phion le 07-08-2010 à 14:10:45
n°2015140
theshockwa​ve
I work at a firm named Koslow
Posté le 07-08-2010 à 20:22:21  profilanswer
 

J'ai tendance à penser que l'héritage virtuel, ca arrive plutôt rarement. Regarde si tu ne peux pas découper ton objet en des entités plus simples, essaye de séparer en terme de responsabilités. Est-ce que ta voiture doit nécessairement savoir exactement quel type de moteur elle embarque ? Ou est-ce qu'au contraire, il lui suffit d'avoir une interface basique sur comment l'utiliser et ne pas se soucier de son type exact ?


---------------
last.fm
n°2015152
Un Program​meur
Posté le 07-08-2010 à 21:57:59  profilanswer
 

Une voiture qui hérite (virtuellement ou non) d'un moteur, ça m'inquiète.
 
L'héritage virtuel arrive naturellement pour les classes qui ont la fonction des interfaces de Java.


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2015156
Joel F
Real men use unique_ptr
Posté le 07-08-2010 à 22:12:56  profilanswer
 

fichtre, oui composition/aggrégation et non héritage ici

n°2015191
in_your_ph​ion
Posté le 08-08-2010 à 12:58:59  profilanswer
 

Un Programmeur a écrit :

Une voiture qui hérite (virtuellement ou non) d'un moteur, ça m'inquiète.


 
hello
oui l'exemple est peut être mal choisi, mais c'était pour illustrer.
 
mon probleme est que ma classe A_1 de base hérite d'un encodeur, qui permet d'encoder certaines données de base (type entier, flottant, etc)
 
ma classe B_1, qui hérite de A_1, aurait besoin d'un encodeur un peu plus sophistiqué, qui pemet d'encoder des données plus haut niveau. Donc mon encodeur sophistiqué est un type d'encodeur qui a quelques fonctions en plus (encoder un prix, un produit, etc)
 
Si je fais de l'agregation ou de la composition pour moi ça reviens au même: on a toujours duplication des données, ou alors je suis obligé de faire un static_cast dans ma classe B_1 mais là je perds l'intéret de l'héritage :
 

Code :
  1. class A_1 {
  2. ...
  3. private:
  4. Encoder * e;
  5. };
  6. class B_1 : public A_1 {
  7. ...
  8. private:
  9. EncoderSophistique * e;
  10. };


 
C'est peut être mieux au niveau de la sémantique, ok, mais bon ..
 
Du coup je ne vois pas du tout comment découper autrement  :??: La seule solution 'mauvaise' que je trouve, c'est de faire un encodeur énorme avec tout dedans, et chaque classe est responsable de ce qu'elle fait avec. Je vois pas d'autre option...


Message édité par in_your_phion le 08-08-2010 à 13:00:27
mood
Publicité
Posté le 08-08-2010 à 12:58:59  profilanswer
 

n°2015467
Paulp
~, sweet ~
Posté le 09-08-2010 à 15:49:47  profilanswer
 

Tu peux regarder du coté du design pattern "decorator", c'est une solution pour éviter l'héritage multiple.

n°2015602
in_your_ph​ion
Posté le 09-08-2010 à 23:44:50  profilanswer
 

Paulp a écrit :

Tu peux regarder du coté du design pattern "decorator", c'est une solution pour éviter l'héritage multiple.


 
hello,
merci! mais je ne crois pas que ce soit adapté pour ce que je veux faire.
 
En fait, je crois que j'ai trouvé, il faut que j'utilise la covariance des types de retour avec des pointeurs dans mes classes. Du style :
 
mon problème :
 

Code :
  1. A_1 <-------- EncodeurBasique
  2.   ^            ^
  3.   |            |
  4.   |            |
  5. B_1 <-------- EncodeurDeOuf
  6.   .            .
  7.   .            .
  8.   .            .
  9. etc ...


 
et on veut pas utiliser l'héritage virtuel car c'est trop ba-caca-pas-beau-et-un-calvaire.
 
La solution, s'il en fut :
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. struct EncodeurBasique {
  4. void dumpBasique() { cout << "encodeur basique" << endl; }
  5. };
  6. struct EncodeurDeOuf : public EncodeurBasique {
  7. void dumpDeOuf() { cout << "encodeur de ouf: tu peux pas teste" << endl; }
  8. };
  9. struct A_1 {
  10. virtual E_1* getE() { return new EncodeurBasique; }
  11. };
  12. struct B_1 : public A_1 {
  13. E_2* getE() { return new EncodeurDeOuf; }
  14. };
  15. int main() {
  16. A_2 * a2 = new A_2;
  17. a2->getE()->dumpDeOuf();
  18. return 0;
  19. }


 
comme ça chaque classe a son encodeur, et chaque encodeur de ouf dérive d'un encodeur plus basique.
 
c'est bon ça, non ?  [:tinostar]

Message cité 1 fois
Message édité par in_your_phion le 09-08-2010 à 23:51:47
n°2015605
mr simon
Posté le 10-08-2010 à 00:29:59  profilanswer
 

Pourquoi tu n'as pas de hierarchie entre les encodeurs ?

Code :
  1. class EncodeurBasique {
  2.   virtual void dump() {
  3.     cout << "encodeur de base" << endl;
  4.   }
  5. }
  6. class EncodeurComplexe : public EncodeurBasique {
  7.   void dump() {
  8.     cout << "encodeur complexe" << endl;
  9.   }
  10. }


 
Ensuite tu ajoutes un membre dans A_1 pointant vers un objet EncodeurBasique que tu initialise avec le bon encodeur suivant si tu es A, B, ... (ou alors tu le passes en parametre)
 
Tu peux aussi definir une classe abstraite pure pour definir "l'interface" des encodeurs si tu ne souhaites pas avoir de hierarchie entre tes differents encodeurs (par exemple parce qu'il n'ont rien a voir dans leur fonctionnement interne).

Message cité 1 fois
Message édité par mr simon le 10-08-2010 à 00:36:42
n°2015665
theshockwa​ve
I work at a firm named Koslow
Posté le 10-08-2010 à 10:13:48  profilanswer
 

in_your_phion a écrit :


 
hello,
merci! mais je ne crois pas que ce soit adapté pour ce que je veux faire.
 
En fait, je crois que j'ai trouvé, il faut que j'utilise la covariance des types de retour avec des pointeurs dans mes classes. Du style :
 
mon problème :
 

Code :
  1. A_1 <-------- EncodeurBasique
  2.   ^            ^
  3.   |            |
  4.   |            |
  5. B_1 <-------- EncodeurDeOuf
  6.   .            .
  7.   .            .
  8.   .            .
  9. etc ...


 
et on veut pas utiliser l'héritage virtuel car c'est trop ba-caca-pas-beau-et-un-calvaire.
 
La solution, s'il en fut :
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. struct EncodeurBasique {
  4. void dumpBasique() { cout << "encodeur basique" << endl; }
  5. };
  6. struct EncodeurDeOuf : public EncodeurBasique {
  7. void dumpDeOuf() { cout << "encodeur de ouf: tu peux pas teste" << endl; }
  8. };
  9. struct A_1 {
  10. virtual E_1* getE() { return new EncodeurBasique; }
  11. };
  12. struct B_1 : public A_1 {
  13. E_2* getE() { return new EncodeurDeOuf; }
  14. };
  15. int main() {
  16. A_2 * a2 = new A_2;
  17. a2->getE()->dumpDeOuf();
  18. return 0;
  19. }


 
comme ça chaque classe a son encodeur, et chaque encodeur de ouf dérive d'un encodeur plus basique.
 
c'est bon ça, non ?  [:tinostar]


 
Tes fonctions doivent avoir le même type de retour (donc ici, ton EncodeurBasique) et il faut que ton interface soit tout de même similaire entre tes deux encodeurs. Au sein de ta classe B_1, tu pourras peut-être supposer que ton encodeur est du type EncodeurComplexe ou je ne sais quoi et faire un static_cast pour accéder à ses méthodes spécifiques


---------------
last.fm
n°2015762
in_your_ph​ion
Posté le 10-08-2010 à 15:04:43  profilanswer
 

hello,
 

mr simon a écrit :

Pourquoi tu n'as pas de hierarchie entre les encodeurs ?


 
je ne suis pas sur de comprendre ? Normalement si car mon encodeur complexe dérive de mon encodeur basique  
 

theshockwave a écrit :


Tes fonctions doivent avoir le même type de retour (donc ici, ton EncodeurBasique) et il faut que ton interface soit tout de même similaire entre tes deux encodeurs. Au sein de ta classe B_1, tu pourras peut-être supposer que ton encodeur est du type EncodeurComplexe ou je ne sais quoi et faire un static_cast pour accéder à ses méthodes spécifiques


 
Apparement non, je ne suis pas obligé de faire de static_cast si j'utilise les types de retour covariant ... :
 
http://www.lwithers.me.uk/articles/covariant.html
 

n°2016266
in_your_ph​ion
Posté le 12-08-2010 à 09:58:34  profilanswer
 

bonjour,
j'aurais encore une question s'il vous plait :D

 

Est ce que je peux faire ça ?

 
Code :
  1. //EncodeurSophistique hérite de EncodeurDeBase
  2. class A {
  3. EncodeurDeBase * e; // initialisé à new EncodeurDeBase;
  4. };
  5. class B : public A {
  6. EncodeurSophistique * e; // initialisé à new EncodeurSophistique;
  7. };
 

est ce que ce n'est pas trop "crade" ? car pour la classe B j'initialise B::e mais du coup B hérite de A::e (en privé donc inaccessible) qui ne sera jamais utilisé ni initialisé.

 

merci par avance

Message cité 1 fois
Message édité par in_your_phion le 12-08-2010 à 10:00:25
n°2016458
Joel F
Real men use unique_ptr
Posté le 12-08-2010 à 15:08:34  profilanswer
 

B n'a pas a hérité de A,mais d'une interface de A
 
class A : public AInterface
{
  SomeType memberOfA;
};
 
classBA : public AInterface
{
  SomeOtherType memberOfB;
}
 

n°2016532
theshockwa​ve
I work at a firm named Koslow
Posté le 12-08-2010 à 17:20:55  profilanswer
 

in_your_phion a écrit :

bonjour,
j'aurais encore une question s'il vous plait :D
 
Est ce que je peux faire ça ?
 

Code :
  1. //EncodeurSophistique hérite de EncodeurDeBase
  2. class A {
  3. EncodeurDeBase * e; // initialisé à new EncodeurDeBase;
  4. };
  5. class B : public A {
  6. EncodeurSophistique * e; // initialisé à new EncodeurSophistique;
  7. };


 
est ce que ce n'est pas trop "crade" ? car pour la classe B j'initialise B::e mais du coup B hérite de A::e (en privé donc inaccessible) qui ne sera jamais utilisé ni initialisé.
 
merci par avance


 
 
non, il n'en hérite pas en privé et A::e est toujours accessible en faisant ca :

Code :
  1. B b;
  2. b.A::e->SomeFunc;


 
Qui plus est, tu n'aurais pas de moyen d'accéder au bon e depuis les fonctions que tu pourrais vouloir factoriser dans A


---------------
last.fm
n°2016586
in_your_ph​ion
Posté le 12-08-2010 à 21:10:21  profilanswer
 

theshockwave a écrit :

Qui plus est, tu n'aurais pas de moyen d'accéder au bon e depuis les fonctions que tu pourrais vouloir factoriser dans A

 

hello
dans ce cas je ne vois pas la solution, comment faire ?  :pt1cable:

 

En fait, pp à l'interface: comment, quand on a une classe :

 
Code :
  1. class A {
  2. public:
  3. E * e;
  4. };
 

pourquoi on peut faire :

 
Code :
  1. A::e->SomeFunc();
 

alors que 'e' ne pointe vers aucun objet de type E alloué ???

 

je ne pige plus ... il me semblait que pour faire ça il faut avoir un objet alloué. Par exemple :

 
Code :
  1. int * p;
  2. *p = 3; //normalement ça c'est caca ?? pourquoi pas avec la classe ????

Message cité 1 fois
Message édité par in_your_phion le 12-08-2010 à 23:45:52
n°2016803
in_your_ph​ion
Posté le 13-08-2010 à 17:54:51  profilanswer
 

uuuup

n°2016816
mr simon
Posté le 13-08-2010 à 19:09:42  profilanswer
 

in_your_phion a écrit :


Code :
  1. A::e->SomeFunc();


[/cpp]


 
Ceci ne marche pas puisque "e" n'est pas statique et ce n'est ce qu'a ecris theshockwave:  

Code :
  1. B b;
  2. b.A::e->SomeFunc;

n°2017268
in_your_ph​ion
Posté le 16-08-2010 à 17:59:08  profilanswer
 

mr simon a écrit :

 

Ceci ne marche pas puisque "e" n'est pas statique et ce n'est ce qu'a ecris theshockwave:

Code :
  1. B b;
  2. b.A::e->SomeFunc;


 

effectivement, ça me parait bizarre que ça marche. En plus de toute manière la fonction est privée donc ce n'est pas possible même si 'e' est statique, non ?

 

Est ce que quelqu'un pourrait m'indiquer la solution ? :) je ne vois pas ... i.e. comment faire de la composition ou de l'agrégation en évitant les static_cast partout, es-ce possible ?

 

merci  :hello:


Message édité par in_your_phion le 16-08-2010 à 18:00:05
n°2017269
theshockwa​ve
I work at a firm named Koslow
Posté le 16-08-2010 à 18:04:51  profilanswer
 

Code :
  1. struct iEncoder
  2. {
  3.   virtual void Encode() {};
  4. };
  5. struct iEncoderUser
  6. {
  7.   virtual iEncoder* GetEncoder() = 0;
  8.   void DoSomething()
  9.   {
  10.     GetEncoder()->Encode();
  11.   }
  12. };
  13. struct SimpleEncoder : public iEncoder
  14. {
  15. };
  16. struct ComplexEncoder : public iEncoder
  17. {
  18. };
  19. struct A : public iEncoderUser
  20. {
  21.   SimpleEncoder e;
  22.   virtual iEncoder* GetEncoder() {return &e;}
  23. };
  24. struct B : public iEncoderUser
  25. {
  26.   ComplexEncoder e;
  27.   virtual iEncoder* GetEncoder() {return &e;}
  28. };


 
tout le code générique (factorisable) doit être dans iEncoderUser, qui ne peut donc pas supposer que l'encodeur est d'un type ou d'un autre (donc pas de static cast).
A et B connaissent directement le type de leur encodeur, donc pas de cast non plus


Message édité par theshockwave le 16-08-2010 à 18:06:19

---------------
last.fm
n°2017276
in_your_ph​ion
Posté le 16-08-2010 à 18:50:46  profilanswer
 

salut,
merci beaucoup pour ta réponse ...  
seulement, dans mon problème B dérive obligatoirement de A  :cry: du coup je suis obligé d'utiliser l'héritage virtuel non ?

n°2017280
theshockwa​ve
I work at a firm named Koslow
Posté le 16-08-2010 à 19:01:28  profilanswer
 

pourquoi l'interface commune ne te suffirait pas ?


---------------
last.fm
n°2017311
in_your_ph​ion
Posté le 16-08-2010 à 22:53:51  profilanswer
 

theshockwave a écrit :

pourquoi l'interface commune ne te suffirait pas ?

 

salut,
en fait IEncoder est une interface pour les encodeurs, et IEncodeurUser une interface pour A et B, c'est ça ?

 

dans ton exemple, B n'hérite plus de A ... mais les deux A et B héritent d'une interface commune iEncoderUser. Dans mon cas B est "une sorte de" A.

 

La seule solution que je vois, ce serait effectivement de casser l'héritage et de dire que A et B sont disctincts et héritent chacun d'un encodeur différent. Mais bon, normalement B est un bien une sorte de A  :(

 

ou alors, de faire des fonctions vides dans comme dans ton interface IEncoder, mais c'est pas terrible non ? Comme ça alors ?

 
Code :
  1. struct IEncoder {
  2.   virtual int encodeInt() {return 0;}
  3.   virtual int encodePrice() {return 0; };
  4.   //...
  5.   //toutes les fonctions mais non implémentées
  6. };
  7. struct EncoderBasic : public IEncoder {
  8.   int encodeInt() { //réimplémente un encodage d'entier }
  9. };
  10. struct EncoderComplex : public EncoderBasic {
  11.   int encodePrice() { //réimplémente un encodage de Price }
  12. };
  13. struct IUser {
  14.   virtual IEncoder* getEncoder() =0;
  15.   IEncoder *e;
  16. };
  17. struct A : public IUser {
  18.     virtual IEncoder* getEncoder() {
  19.     e = new EncoderBasic;
  20.     return e;
  21.     }
  22. };
  23. struct B : public A {
  24.     IEncoder* getEncoder() { 
  25.     e = new EncoderComplex;
  26.     return e;
  27. }
  28. };
 

.. :??:  [:tinostar]  


Message édité par in_your_phion le 16-08-2010 à 23:21:41
n°2017367
theshockwa​ve
I work at a firm named Koslow
Posté le 17-08-2010 à 10:38:54  profilanswer
 

instancier dans ton getter me semble être une grosse erreur.
 
Si tu as ta classe A et que tu peux la modifier, alors tu peux la transformer en simple interface, tu dois bien pouvoir choisir qui est instancié, non ? Je soupçonne que cette contrainte que tu mets n'en est pas vraiment une. Quoiqu'il arrive, tu ne pourras pas faire quelque chose de propre si tu veux avoir B qui dérive de A.


---------------
last.fm
n°2017406
in_your_ph​ion
Posté le 17-08-2010 à 13:24:07  profilanswer
 

salut
oui c'est clair  :o

 

finalement j'ai changé, effectivement je pourrais pas faire quelque chose de propre avec B qui dérive de A et EncodeurComplexe qui dérive de Encodeur.

 

J'ai finalement un seul encodeur qui fait les trucs vraiment de base (encodage int/string, etc), et j'ai transféré les encodages plus complexes dans les classes A et B, car les traitements sont davantage fonctionnels : il appartient donc aux classes de savoir ce qu'elles encodent, pas à l'encodeur.

 

Donc voilà, je ne sais pas si c'est la meilleur solution, mais bon, ça me simplifie les choses...

 

merci encore pour ton aide!  :)


Message édité par in_your_phion le 17-08-2010 à 13:24:35
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  problème d'héritage

 

Sujets relatifs
[resolu] Probleme d'heritage des CSSProblème d'héritage depuis une classe abstraite
Problème dozer et héritageHeritage: virtual / static probleme de design
Problème avec héritage et méthode virtuelleProblème d'héritage multiple
[merise] Probleme d'heritage, MCD et sgbd mysql..Problème héritage entre 2 classes
Heritage Fonction abstraite, Probleme conteneur Heterogene[Résolu] Problème d'héritage d'héritage + redéfinition de méthode
Plus de sujets relatifs à : problème d'héritage


Copyright © 1997-2018 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR