héritage multiple .. pour ou contre ?

héritage multiple .. pour ou contre ? - C++ - Programmation

Marsh Posté le 06-04-2008 à 17:32:38    

Bonjour,
J'aimerai savoir ce que vous pensez de l'héritage multiple en c++, êtes vous plutôt pour ou contre ? J'ai l'impression que beaucoup de langages oo ne le permettent pas ou plus, alors je me demande si c'est quelque chose qui doit être pratiqué ou évité en c++ ?
 
merci d'avance


Message édité par in_your_phion le 06-04-2008 à 17:33:00
Reply

Marsh Posté le 06-04-2008 à 17:32:38   

Reply

Marsh Posté le 06-04-2008 à 17:47:13    

en général, tu peut t'en passer.
Perso, j'essaye de coller au modèle de java : 1 classe peut héritée d'une classe mère et de X interfaces. En C++, suffit de te dire que classe abstraie = interface ;)

Message cité 1 fois
Message édité par Joel F le 06-04-2008 à 17:47:23
Reply

Marsh Posté le 06-04-2008 à 18:01:13    

Joel F a écrit :

en général, tu peut t'en passer.
Perso, j'essaye de coller au modèle de java : 1 classe peut héritée d'une classe mère et de X interfaces. En C++, suffit de te dire que classe abstraie = interface ;)


 
d'accord, merci. Alors en c++ il n'y a pas de différence entre interface et classe abstraite ? Et quand on parle d'"implémentation" ce sont les classes non abstraites ?
 
merci

Reply

Marsh Posté le 06-04-2008 à 18:10:47    

C'est pas ça.
 
Y a pas de notion d'interface au sens propre en C++.
Juste que leur comportement corresponds à celle des classes abstraites

Reply

Marsh Posté le 06-04-2008 à 18:30:36    

Joel F a écrit :

C'est pas ça.
 
Y a pas de notion d'interface au sens propre en C++.
Juste que leur comportement corresponds à celle des classes abstraites


 
ok, et pour ce qu'on appelle l'"implémentation" ?

Reply

Marsh Posté le 06-04-2008 à 19:16:01    

et bien moi je suis pour, pour et encore pour.
D'ailleurs l'absence d'héritage multiple est un des reproches que je fais au langage D.
 
Déjà à propos des interfaces : ça implique de rendre les méthodes virtuelles alors que c'est rarement utile dans ce cas.
Oui je sais la perte de perf est faible tout ça, mais en C++ il y a un principe important : "Ne paye pas pour ce que tu n'utilise pas". Or imposer des appels virtuels pour contourner l'héritage multiple ne respecte pas ce principe.
 
Joel F parle du Java et je suis d'accord sur ce point, le Java fonctionne différement et est conçu pour faire des appels systématiquement virtuels (même si on peut les désactiver avec static, c'est rarement utilisé). Il est architecturé autour du principe des Interfaces, donc c'est correct de s'en serivir tant que possible.
 
Mais Java et C++ sont différents, et plus que ce que certains croient. J'utilise aussi certains paradigmes du Java qd je code en C++ (les accessors sans surcharge et les méthodes de conversions que je préfère aux opérateurs cast par exemple) mais uniquement qd ça respecte les principes de base du C++.
 
Quand tu veux faire une classe CamionPoubelle en C++, tu peux te contenter de dériver de Camion et de Poubelle. Pas besoin d'une interface ICamion et d'une IPoubelle remplie de méthodes virtuelles pures (appellée méthodes abstraites en java) que tu seras obligé de redéfinir même si t'en as pas besoin.
 
Je ne vois pas le problème à hériter de deux classes en même temps. Certes il y a des cas pourris comme l'héritage en losange (1) et l'héritatge virtuel mais j'ai beaucoup codé en C++ et je ne me souviens pas en avoir eu besoin. Dans des condisions réelles, les deux classes dont on héritent ne rentre jamais en conflit entre elles. Il faut le faire exprès pour avoir des méthodes qui ont le même nom par exemple.
Tant qu'on utilise pas de méthodes venus de certains design pattern comme Visit() ou serialize() il n'y a vraiment aucun problème.
 

Code :
  1. class Camion
  2. {
  3. public :
  4.     Camion( int powerCv );
  5.     void run();
  6.     void stop();
  7. private :
  8.     int m_powerCv;
  9. }
  10. class Poubelle
  11. {
  12. public :
  13.     Poubelle( int capacitySquareMeter );
  14.     void flush();
  15.     void compact();
  16. private :
  17.     int m_capacitySquareMeter;
  18. }
  19. class CamionPoubelle : public Camion, public Poubelle
  20. {
  21. public :
  22.     CamionPoubelle( int power, int capacity ) // je donne un exemple d'apppel des  
  23.     : Camion( power ), Poubelle( capacity  ) {} // constructeurs parents, rien de compliqué
  24. }
  25. // Je veux un Camion-poubelle de 1000cv et 10m² :
  26. CamionPoubelle cp( 1000, 10 );
  27. cp.run(); // avance
  28. cp.stop(); // arrete-toi
  29. cp.compact(); // compacte tes ordures
  30. cp.flush(); // et vidange-les


 
Il est où le problème, elle est où la difficulté ?
En vrai l'héritage multiple c'est surtout chiant à gérer quand on écrit un compilo (les conversions de pointeurs provoquent des décalages...) mais pour le programmeur c'est très utile.
 
Pour répondre à la question de départ, il n'y a aucune fonctionnalité du C++ qui ne doit être éviter, sinon cette fonction ne serait pas dans le langage. C++ n'est pas un langage commercial comme le Java ou Delphi, donc qd il mette une fonctionnalité c'est qu'elle est utile, c'est pas juste pour faire plaisir à leurs actionnaires (2). Et en plus l'héritatge multiple n'entraine aucune perte de perf, contrairement au RTTI ou aux exceptions qu'on peut voiloir éviter dans une optique d'optimisation.
 
Et historiquement je me souviens qu'il y a qlq années on reprochait au C++ d'avoir les templates, soit disant ça servait à rien, c'était compliqué et Java s'en passait bien. Maintenant les templates sont de + en plus utilisés en C++ et le Java a fini par s'en dotter, sous une forme plus simple il est vrai (la généricité). Donc chercher à niveler vers le bas ça ne tient pas longtemps. On finit toujours par avoir besoin de fonctionnalités de + en + avancées.
 
(1) souvent mal traduit par "diamant" (venant de diamond en anglais, qui signifie diamant et losange)
(2) ouais c'est un gros troll contre Sun désolé, par contre pas contre Borland, on ne tire pas sur les ambulances :D

Reply

Marsh Posté le 06-04-2008 à 19:18:33    

merde j'ai oublié les points-virgules derrière les def de classes :D

Reply

Marsh Posté le 06-04-2008 à 19:41:51    

J'ai jamais prophétisé l'abolition de l'héritage multiple.
Moi, perso le camion poubelle, il hérite de camion car C'EST un camion et il implémente IPoubelle car il se COMPORTE COMME une poubelle.

 

après chacun sa sauce :)

 
Citation :


Il faut le faire exprès pour avoir des méthodes qui ont le même nom par exemple.


Dans certains cas de CRTP, ça arrive aussi :s

Message cité 1 fois
Message édité par Joel F le 06-04-2008 à 19:42:43
Reply

Marsh Posté le 06-04-2008 à 19:50:07    

CRTP : skoi cet acronyme ?, ça me dit rien.
 
Avec l'héritage multiple du C++ tu n'as justement pas besoin de te demander si c' "est-une" poubelle ou si ça "implémente" (se comporte comme) une poubelle, puisque les deux reviennent au même niveau code.
 
Par contre dans un contexte Java, même avec l'héritage multiple possible, j'approuverais ton utilisation d'une interface pour Poubelle. Ca serait + élégant et pas plus couteux en perfs.
 
En C++ par convention le "is-a" est utilisé comme premier héritage, et le "implements" comme héritage secondaire. Ca permet aussi de pouvoir convertir en dur un pointeur de CamionPoubelle en Camion, mais pas en Poubelle. Mais c'est juste une convention.

Reply

Marsh Posté le 06-04-2008 à 19:57:29    

jesus_christ a écrit :

CRTP : skoi cet acronyme ?, ça me dit rien.


Curiously Recursive Template Pattern
 

jesus_christ a écrit :


Avec l'héritage multiple du C++ tu n'as justement pas besoin de te demander si c' "est-une" poubelle ou si ça "implémente" (se comporte comme) une poubelle, puisque les deux reviennent au même niveau code.
Par contre dans un contexte Java, même avec l'héritage multiple possible, j'approuverais ton utilisation d'une interface pour Poubelle. Ca serait + élégant et pas plus couteux en perfs.
 
En C++ par convention le "is-a" est utilisé comme premier héritage, et le "implements" comme héritage secondaire. Ca permet aussi de pouvoir convertir en dur un pointeur de CamionPoubelle en Camion, mais pas en Poubelle. Mais c'est juste une convention.


 
Disons que j'aime bien faire ce distingo, ca aide à garder séparer les classes qui ont tendances à êtres concretes et les autres.
Encore une fois, ca n'engage que moi.

Reply

Marsh Posté le 06-04-2008 à 19:57:29   

Reply

Marsh Posté le 06-04-2008 à 20:00:11    

"Ca permet aussi de pouvoir convertir en dur un pointeur de CamionPoubelle en Camion, mais pas en Poubelle."
 
Je trouve ça un peu con :/
 
Moi qui croyait que justement l'héritage multiple permettait de faire ça...
Du coup je préfère les interfaces au moins on peut instancier un objet selon l'interface désirée, sans ce soucier de qui fait quoi à la base dans l'héritage.
A moins que j'aie mal compris la phrase ?


Message édité par MagicBuzz le 06-04-2008 à 20:02:29
Reply

Marsh Posté le 06-04-2008 à 20:02:45    

Curiously Recursive Template Pattern
 
Je connais ça, mais pas l'acronyme ;)
Ca arriverait donc si les deux classes dont on hérite utilisent ce CRTP ? Oui en effet, c'est une forme d'héritage de noms en losange.

Reply

Marsh Posté le 06-04-2008 à 20:05:49    

jesus_christ a écrit :


Ca arriverait donc si les deux classes dont on hérite utilisent ce CRTP ? Oui en effet, c'est une forme d'héritage de noms en losange.


 
ouais mais bon, pour en faire comme pas possible, ca a du m'arriver 2 fois quoi  [:absolutelykaveh]

Reply

Marsh Posté le 06-04-2008 à 20:09:14    

qd je parle de "en dur" c'est du genre :
 

Code :
  1. CamionPoubelle cp;
  2. void* ptr = &cp;
  3. ...
  4. Camion* c = (Camion*)ptr; // ça marche
  5. Poubelle* p = (Poubelle*)ptr; // ça marche pas
  6. Poubelle* p2 = &cp; // ça marche, et c'est surement ça que tu veux faire.


 
Pourquoi j'utilise un void* ?
Dans le cas d'une utilisation d'un langage externe (perso j'utilise souvent du LUA) pour lequel la donnée est un pointeur abstrait, le void* est inévitable. C'est pareil pour du code API Win32 :
 

Code :
  1. HWND CreateWindowEx(          DWORD dwExStyle,
  2.     LPCTSTR lpClassName,
  3.     LPCTSTR lpWindowName,
  4.     DWORD dwStyle,
  5.     int x,
  6.     int y,
  7.     int nWidth,
  8.     int nHeight,
  9.     HWND hWndParent,
  10.     HMENU hMenu,
  11.     HINSTANCE hInstance,
  12.     LPVOID lpParam // <- attention si hériatage multiple
  13. );


 
edit : je précise qu'avec une Interface, ça ne marche pas mieux qd on utilise un void*, ça a même tendance à être pire.


Message édité par jesus_christ le 06-04-2008 à 20:17:27
Reply

Marsh Posté le 06-04-2008 à 21:37:16    

Ah ok, me voilà rassuré, sur le coup j'ai eu peur ;)

Reply

Marsh Posté le 06-04-2008 à 23:28:06    

Joel F a écrit :

J'ai jamais prophétisé l'abolition de l'héritage multiple.
Moi, perso le camion poubelle, il hérite de camion car C'EST un camion et il implémente IPoubelle car il se COMPORTE COMME une poubelle.  


En même temps, y'a des voitures qui sont des poubelles, mais c'est une autre histoire. :o


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 07-04-2008 à 00:15:11    

Salut,
merci beaucoup pour toutes ces explications très poussées .... :) Je viens de m'entrainer sur un exo d'héritage en losange, c'est mal ? (Je vais poster mon exo dans un autre thread, ce sera mieux)
 
@Jesus :
 

Code :
  1. CamionPoubelle cp;
  2. void* ptr = &cp;
  3. ...
  4. Camion* c = (Camion*)ptr; // ça marche
  5. Poubelle* p = (Poubelle*)ptr; // ça marche pas
  6. Poubelle* p2 = &cp; // ça marche, et c'est surement ça que tu veux faire.


 
pourrais tu m'expliquer pourquoi  Poubelle* p = (Poubelle*)ptr; ne marche pas ? est-ce par rapport au fait que dans l'héritage il y a d'abord "public Camion" et ensuite "public Poubelle" ?
 
merci encore

Reply

Marsh Posté le 07-04-2008 à 08:17:04    

oui.
 
Dans CamionPoubelle, la partie Camion se trouve au début, donc l'adresse de la partie Camion de la structure est la même que celle de CamionPoubelle.
Par contre la partie Poubelle se trouve + loin, et si on prend l'adresse de la partie poubelle de la structure, il faut décaler le pointeur.
 


addr CamionPoubelle  
|
+-------------------+
|   CamionPoubelle  |
+-------------------+
 
est en interne :
 
+--------+----------+
| Camion | Poubelle |
+--------+----------+
|        |
addr     addr
Camion   Poubelle

Message cité 1 fois
Message édité par jesus_christ le 07-04-2008 à 08:17:15
Reply

Marsh Posté le 07-04-2008 à 09:03:27    

el muchacho a écrit :


En même temps, y'a des voitures qui sont des poubelles, mais c'est une autre histoire. :o


 
lol ^^ en effet  [:spyer]

Reply

Marsh Posté le 07-04-2008 à 10:37:47    

Bon au risque de me faire fusillé, j'ai développé un moteur de calcul qui utilise de l'héritage multiple et des losanges. Mes collègues bien plus forts que moi en C++ ne m'ont pas trop crié dessus, donc je vais expliquer quel était le problème de départ et ensuite si vous avez des idées pour faire mieux je suis évidemment preneur.  
Mon problème est le suivant, je veux créer un produit qui a des caractéristique, et si c'est possible j'aimerai créer son type au moment de la compilation, on va dire que les caractéristiques sont Call,Barrière,Swap,Constant, etc... Ensuite j'ai plein de produit qui peuvent combiner une ou plusieurs de ses caractéristiques voire même plusieurs barrières, qui plus est une notion d'ordre est nécessaire parce que lorsque je dit "combiner" en fait je parle de composition (en terme de fonction). Ensuite les propriétés peuvent dériver entre elles, genre Putable dérive de Callable. Donc j'ai un beau merdier, et je suis hyper fainéant je veux éviter de réécrire plein de classes dérivées genre DoubleBarrière dérivant de Barrière. Le seul avantage c'est que mes propriétés partage le même squelette de base et ne comporte que très peu de méthodes. Donc j'ai pensé (out of the box) au type de structure suivant:
 
Toutes mes propriétes (que j'appelle module) dérivent d'une seule classe de base et comporte 2-3 méthodes, là je peux dériver entre elles et j'ai toute une famille à ma disposition. En plus je les définit avec un argument template <int> dummy pour pouvoir combiner par la suite les même modules (je sais c'est pas beaux mais ca a aussi des côtés intéressants).
Enfin je décide de créer une class qui hérite virtuellement de deux modules pour les mélanger, là je décrit les relations d'ordres (qui on va créer en premier), et la composition fonctionelle, la classe ressemble à ca:
 

Code :
  1. template<class X, class Y>
  2. class PDEMix : virtual public X, virtual public Y, public with_type_traits<PDEMix<X,Y> >
  3. {
  4. public:
  5. using with_type_traits<PDEMix<X,Y> >::sp;
  6. using with_type_traits<PDEMix<X,Y> >::const_sp;
  7. using X::Calc;
  8. using X::setDim;
  9. using X::setPDEParameters;
  10. PDEMix(int BucketedGreeks=0, int NumStocks=1, int bOneCurve=1,CalibrationSet * calibraSet=NULL) : X(BucketedGreeks,NumStocks, bOneCurve, calibraSet),
  11.  Y(BucketedGreeks,NumStocks, bOneCurve, calibraSet)
  12. {}
  13. virtual ~PDEMix()
  14. {}
  15. /// Creates the Properties.
  16. inline std::vector<EQPDEProperty_Base::sp> createProperties()
  17. {
  18.  std::vector<EQPDEProperty_Base::sp> vect_X = X::createProperties();
  19.  std::vector<EQPDEProperty_Base::sp> vect_Y = Y::createProperties();
  20.  std::copy(vect_Y.begin(),vect_Y.end(),back_inserter(vect_X));
  21.  m_vspProperties.assign(vect_X.begin(), vect_X.end());
  22.  return m_vspProperties;
  23. }
  24. /// CalcValue.
  25. inline virtual double CalcValue()
  26. {
  27.  return PDESolve<typename PDEMix<X,Y> >();
  28. }
  29. /// PDESolve.
  30. template<class Module> double PDESolve()
  31. {
  32.            ...
  33. }
  34. private:
  35. };


 
Bon ensuite pour donner un exemple lorsque je veux créer un produit qui correspond à une Bairrière sur un Call je fait:

Code :
  1. PDEMix<PDECallPut<0>,PDEBarrier<0> > monProduit;


Lorsque je veux créer deux barrières sur un call:

Code :
  1. PDEMix<PDEMix<PDECallPut<0>,PDEBarrier<0> >, PDEBarrier<1> > monProduit;


etc... J'ai une récurrence vachement flexible pour prototyper des produits, j'aime bien c'est cool, m'enfin ca reste du losange... Sinon lorsque j'ai une famille de propriétés qui vont partager des variables similaires et bien je peux les définir statique par famille, genre une famille de Callable 0 et 1 i.e. Callable<0> et Callable<1>. Jusqu'à présent l'expérience nous montre que malgré un design alambiqué le prototypage de produit est devenu très rapide (je suis dans un environnement ou quelques heures peuvent faire la différence), et c'est assez efficaces en terme de temps de calcul. Ensuite c'est une solution à mon problème particulier, et je suis sûr que l'on peut faire mieux (d'ailleurs j'attends les suggestions).
 

Reply

Marsh Posté le 07-04-2008 à 10:47:05    

Encore une fois : j'ai rien contre l'héritage multiple, juste que si je peut m'en passer, je m'en passe. ^^
 
@ElDesdichado : ton truc c'est purement 'industriel' ou y a des papiers dessus ? Je cherche des exemples de ce types d'idiomes de prog hors HPC.

Reply

Marsh Posté le 07-04-2008 à 10:54:32    

Non purement industriel (enfin adaptés à nos besoin). M'enfin je dirai plutôt purement amateur, dans la mesure où c'est de bibi i.e. avec mes mimines et mes idées foireuses, donc si il y a des articles je suis preneur. Pour ce qui est du code en entier, je peux pas vraiment le poster, ils me versent un salaire donc... Quant à savoir si c'est bien fait ou d'un quelconque intérêt je précise que je suis mathématicien et pas un expert du C++ (heureusement j'ai un collègues qui s'y connaît pas mal). Quoiqu'il en soit on l'utilise en production pour chiffrer autre chose que des boîtes à savon ;)
 

Reply

Marsh Posté le 07-04-2008 à 11:09:26    

c'était exactement ce genre d'infos que je voulais (les boites à savons ;) )

Reply

Marsh Posté le 07-04-2008 à 11:18:52    

M'enfin il était pas difficile de deviner de quelles boîtes à savon je parle. De toute manière je t'ai PM.

Reply

Marsh Posté le 07-04-2008 à 13:48:10    

jesus_christ a écrit :

oui.
 
Dans CamionPoubelle, la partie Camion se trouve au début, donc l'adresse de la partie Camion de la structure est la même que celle de CamionPoubelle.
Par contre la partie Poubelle se trouve + loin, et si on prend l'adresse de la partie poubelle de la structure, il faut décaler le pointeur.
 


addr CamionPoubelle  
|
+-------------------+
|   CamionPoubelle  |
+-------------------+
 
est en interne :
 
+--------+----------+
| Camion | Poubelle |
+--------+----------+
|        |
addr     addr
Camion   Poubelle



 
d'accord ! c'est vrai que c'est logique en fait!
 
merci :)

Reply

Marsh Posté le 23-04-2008 à 16:19:26    

in_your_phion a écrit :


@Jesus :
 

Code :
  1. CamionPoubelle cp;
  2. void* ptr = &cp;
  3. ...
  4. Camion* c = (Camion*)ptr; // ça marche
  5. Poubelle* p = (Poubelle*)ptr; // ça marche pas
  6. Poubelle* p2 = &cp; // ça marche, et c'est surement ça que tu veux faire.




 
up,
 
j'ai essayé ça et ça marche dans les trois cas ... kesako ??

Reply

Marsh Posté le 23-04-2008 à 20:09:57    

t'es bien passé par un void* ?
Une de tes deux classes de base n'est pas vide ?
T'as essayé de compiler, ou vraiment d'éxécuter ?
 
Parce que avec 2 classes non vides et en passant par un voird*, c'est juste pas possible que ça marche !

Reply

Marsh Posté le 24-04-2008 à 00:46:46    

de toutes façons utiliser le cast C (Type*) en C++, c'est mal :o

 

et sinon l'héritage multiple c'est très pratique et ça permet de bien mieux factoriser le code que l'interfaçage à la java :o


Message édité par Aiua le 24-04-2008 à 00:48:48

---------------
"The pen is mightier than the sword if the sword is very short, and the pen is very sharp." TP. Mes Jeux. Mes Ventes. Groupe HFR sur PlayFire.
Reply

Marsh Posté le 24-04-2008 à 08:11:40    

ou pas ! :o
et
ou pas :o !

Reply

Marsh Posté le 24-04-2008 à 14:25:06    

jesus_christ a écrit :

t'es bien passé par un void* ?
Une de tes deux classes de base n'est pas vide ?
T'as essayé de compiler, ou vraiment d'éxécuter ?

 

Parce que avec 2 classes non vides et en passant par un voird*, c'est juste pas possible que ça marche !

 

salut,

 

j'ai essayé ça mais peut être que c'est pas bon alors comme ça marche  :pt1cable: :

 
Code :
  1. class A {
  2. public:
  3.  A() { cout  << "construction de A" << endl; }
  4.  virtual ~A() { cout << "destruction de A" << endl; }
  5.  virtual void print() { cout << "A says hello" << endl; }
  6. };
  7. class B {
  8. public:
  9.  B() { cout  << "construction de B" << endl; }
  10.  virtual ~B() { cout << "destruction de B" << endl; }
  11.  virtual void print() { cout << "B says hello" << endl; }
  12. };
  13. class C : public A, public B {
  14. public:
  15.  C() { cout  << "construction de C" << endl; }
  16.  ~C() { cout << "destruction de C" << endl; }
  17.  void print() { cout << "C says hello" << endl; }
  18. };
  19. int main() {
  20. C c;
  21. void * ptr = &c;
  22. A * a = (A*)ptr; //ça devrait marcher
  23. B * b = (B*)ptr; //ça devrait pas marcher ?
  24. system("pause" );
  25. return 0;
  26. }


Message édité par in_your_phion le 24-04-2008 à 14:26:46
Reply

Marsh Posté le 24-04-2008 à 16:06:24    

Joel F a écrit :

ou pas ! :o
et
ou pas :o !


pour le premier je me sens obligé d'insister, en plus d'être illisible, ça masque totalement le type de cast effectué
 
pour le 2e, y a la composition pour contrebalancer, mais c'est chiant :o


---------------
"The pen is mightier than the sword if the sword is very short, and the pen is very sharp." TP. Mes Jeux. Mes Ventes. Groupe HFR sur PlayFire.
Reply

Marsh Posté le 24-04-2008 à 16:34:00    

pour le C-style cast, je t'accorde que un bon vieux xxx_cast<> a plus de charme. Malheureusement, dés fois, ca fait trop ce que tu veut :/

Reply

Marsh Posté le 24-04-2008 à 16:44:28    


 
Non c'est bon :o

Reply

Marsh Posté le 24-04-2008 à 16:47:00    

et sinon par rapport à ma question ... plz ....
 
 :hello:

Reply

Marsh Posté le 24-04-2008 à 23:58:34    

Joel F a écrit :


 
lol ^^ en effet  [:spyer]


D'ailleurs ne dit-on pas parfois : "fait chier, j'ai encore hérité d'une poubelle :o" ?
 
Nouvel exemple d'héritage dont on voudrait bien se passer. :o


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 25-04-2008 à 21:15:50    

Code :
  1. class A {
  2. public:
  3.  A() { cout  << "construction de A" << endl; }
  4.  virtual ~A() { cout << "destruction de A" << endl; }
  5.  virtual void print() { cout << "A says hello" << endl; }
  6. };
  7. class B {
  8. public:
  9.  B() { cout  << "construction de B" << endl; }
  10.  virtual ~B() { cout << "destruction de B" << endl; }
  11.  virtual void print() { cout << "B says hello" << endl; }
  12. };
  13. class C : public A, public B {
  14. public:
  15.  C() { cout  << "construction de C" << endl; }
  16.  ~C() { cout << "destruction de C" << endl; }
  17.  void print() { cout << "C says hello" << endl; }
  18. };
  19. int main() {
  20. C c;
  21. void * ptr = &c;
  22. A * a = (A*)ptr; //ça devrait marcher
  23. B * b = (B*)ptr; //ça devrait pas marcher ?
  24. // jusque là tout va bien...
  25. b->print(); // CRASH !!
  26. system("pause" );
  27. return 0;
  28. }

Reply

Marsh Posté le 25-04-2008 à 21:18:05    

system("pause" ); <- pas bien, pas portable et si tu veux arréter ton prog à la fin, mets un breakpoint ou passe par un .bat/.sh
 
ici avec un peu de malchance ça va pas cracher car les deux classes sont de taille vide sauf pour le vtable-pointeur. Donc si ça se trouve ça va pas planter et afficher "A says hello".

Reply

Marsh Posté le 25-04-2008 à 22:01:16    

jesus_christ a écrit :

system("pause" ); <- pas bien, pas portable et si tu veux arréter ton prog à la fin, mets un breakpoint ou passe par un .bat/.sh


cin.get() ? :whistle:  
</contribution à 2 balles>

Reply

Marsh Posté le 25-04-2008 à 22:06:29    

getchar() ou cin.get à la rigueur...
 
mais bon débugger avec des getchar() et des printf()... il y a de très bons debugger gratuits en plus.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed