Bonjour tout le monde !
J'ouvre cette discussion pour vous informer d'un problème que j'ai en C++.
En fait, j'ai écrit une application en JAVA qui tourne super et j'ai voulu la retranscrire en C++.
Normalement, un simple copier-coller avec les modifications qui s'imposent fonctionne.
Mais, c'est lorsque un cycle de trois headers s'includent mutuellement. Il faut que je fasse de la déclaration préventive mais j'ai toujours eu du mal avec ce concept vu qu'en JAVA, il ne faut rien inclure, avec le système de package, ça se fait automatiquement.
Et c'est là que se situe le problème à mon humble avis.
Je vais d'abord vous donner la version JAVA du programme qui fonctionne parfaitement et puis la version C++ rigoureusement identique qui foire complètement.
Le programme a été simplifié au maximum pour éviter tout effet de bord (le programme initial comptait au moins 50 classes), ce que je fais pourrait vous paraitre complètement stupide, mais c'est comme ça, il faut que ça fonctionne ainsi.
Les codes JAVA:
Code:package tests; public abstract class T { protected final int t; protected T(int t) { this.t=t; } }Code:package tests; public interface O { public abstract N getN(); }Code:package tests; public abstract class C extends T implements O { protected C(int t) { super(t); } protected abstract int get(); }Code:package tests; public class N extends C { private N(int t) { super(t); } public static N getInstance(int t) { return new N(t); } @Override public final N getN() { System.out.println("N.getN()"); return this; } @Override public final int get() { return t; } }Code:package tests; public abstract class S extends C { protected S(int t) { super(t); } @Override public final N getN() { System.out.println("S.getN()"); return N.getInstance(get()); } }Et la fonction main qui teste le tout:Code:package tests; public class P extends S { private P() { super(42); } public static P getInstance() { return new P(); } @Override public final int get() { return t; } }
La sortie du programme est:Code:package tests; public class Main { public static void main(String[] args) { T t=P.getInstance(); System.out.println("t "+t.getClass().getName()+" adress="+t); O o=(O)t; System.out.println("o "+o.getClass().getName()+" adress="+o); System.out.println("Call o.getN()"); N n=o.getN(); //affiche S.getN() System.out.println("End call o.getN()"); System.out.println("n "+n.getClass().getName()+" adress="+n); System.out.println("Call n.get()"); int i=n.get(); System.out.println("End call n.get()"); System.out.println("i = "+i+" (should be 42)"); } }
(les adresses varient évidemment d'une exécution à l'autre, les deux premières doivent cependant être identiques)Code:t tests.P adress=tests.P@308f5944 o tests.P adress=tests.P@308f5944 Call o.getN() S.getN() End call o.getN() n tests.N adress=tests.N@6dc98c1b Call n.get() End call n.get() i = 42 (should be 42)
C'est beau c'est propre, on fait la fête tellement ça fonctionne bien!
Attaquons la partie C++ maintenant, je sens qu'on va se marrer...
Les headers:
Code:#ifndef T_H #define T_H class T { protected: const int t; protected: T(int t); public: virtual ~T(); }; #endif // T_HCode:#ifndef O_H #define O_H class N; class O { public: virtual N *getN() const=0; protected: O() {} virtual ~O() {} }; #endif // O_HCode:#ifndef C_H #define C_H #include "T.h" #include "O.h" class C : public T, public O //AAAAAAAAAAAAAHHHHHHHHHHHHHHHH, ça fait mal :( { protected: C(int t); virtual ~C(); protected: virtual int get() const=0; }; #endif // C_HCode:#ifndef N_H #define N_H #include "C.h" class N : public C { private: N(int t); public: virtual ~N(); public: static N *getInstance(int t); public: virtual N *getN() const; virtual int get() const; }; #endif // N_HCode:#ifndef S_H #define S_H #include "C.h" #include "N.h" class S : public C { protected: S(int t); virtual ~S(); public: virtual N *getN() const; }; #endif // S_HLes sources:Code:#ifndef P_H #define P_H #include "S.h" class P : public S { private: P(); virtual ~P(); public: static P *getInstance(); public: virtual int get() const; }; #endif // P_H
Code:#include "T.h" T::T(int t) : t(t) { } T::~T() { }Code:#include "O.h" #include <iostream> using namespace std; #include "N.h" N *O::getN() const //=0 je sais mais au cas où { cout << "O::getN()=0" << endl; return NULL; }Code:#include "C.h" C::C(int t) : T(t) { } C::~C() { }Code:#include "N.h" #include <iostream> using namespace std; N::N(int t) : C(t) { } N::~N() { } N *N::getInstance(int t) { return new N(t); } N *N::getN() const { cout << "N::getN()" << endl; return const_cast<N *>(this); } int N::get() const { return t; }Code:#include "S.h" #include <iostream> using namespace std; S::S(int t) : C(t) { } S::~S() { } N *S::getN() const { cout << "S::getN()" << endl; return N::getInstance(get()); }Et la fonction main:Code:#include "P.h" P::P() : S(42) { } P::~P() { } P *P::getInstance() { return new P(); } int P::get() const { return t; }
Voilà la sortie du programme:Code:#include <iostream> using namespace std; #include <typeinfo> #include "T.h" #include "O.h" #include "P.h" int main() { T *t=P::getInstance(); cout << "t " << typeid(t).name() << " adress=" << t << endl; O *o=(O *)t; cout << "o " << typeid(o).name() << " adress=" << o << endl; cout << "Call o->getN()" << endl; N *n=o->getN(); //devrait afficher S::getN() mais n'affiche rien du tout cout << "End call o->getN()" << endl; cout << "n " << typeid(n).name() << " adress=" << n << endl; cout << "Call n->get()" << endl; int i=n->get(); //plante royalement cout << "End call n->get()" << endl; cout << "i = " << i << " (should be 42)" << endl; delete n; delete t; return 0; }
Et là le programme plante méchamment.Code:t P1T adress=0x10c1468 o P1O adress=0x10c1468 Call o->getN() End call o->getN() n P1N adress=0x4042e8 Call n->get()
D'abord, lors de l'appel de o->getN(), il n'appelle rien du tout, même pas la fonction virtuelle pure dont j'ai défini un corps (juste pour tester), donc, n pointe sur un zone mémoire aléatoire et donc lors de l'appel de n->get(), ben, le programme il ne sait plus où aller et il me dit merde.
Voilà tout le problème.
Si une âme sensible pouvait trouver miraculeusement la solution, je lui en serai infiniment reconnaissant.
Ah oui, une dernière chose, pour compiler en C++, j'utilise Code::Blocks avec MinGW, peut-être que ça entre en compte, je ne sais pas!
En vous remerciant d'avance,
Aenonis
-----