Une méthode virtuelle appelée depuis un destructeur n'est pas héritée!? [Résolu]

Messages postés
663
Date d'inscription
samedi 8 juin 2002
Statut
Membre
Dernière intervention
6 avril 2010
- - Dernière réponse : cs_Forman
Messages postés
663
Date d'inscription
samedi 8 juin 2002
Statut
Membre
Dernière intervention
6 avril 2010
- 16 juin 2007 à 10:52
Bonjour(soir) à tous,

je viens de me mettre au C++ et à GLUT et je bute sur un problème que je n'arrive pas à m'expliquer. D'abord, voilà le code en question (qui permettra de clarifier mes explications par la suite je l'espère):
template<class THANDLE=int,unsigned int INVALID_HANDLE=0> class Handled{
protected:
THANDLE Handle;

Handled(){
Handle=INVALID_HANDLE;
}

~Handled(){
if (handleAllocated())
deleteHandle();
}

void handleNeeded(){
if (!handleAllocated())
createHandle();
};

virtual void createHandle()=0;
virtual void deleteHandle()=0;
public:
int handleAllocated(){
return Handle!=INVALID_HANDLE;
};

THANDLE getHandle(){
handleNeeded();
return Handle;
};

void recreateHandle(){
if (handleAllocated()){
deleteHandle();
Handle=INVALID_HANDLE;
handleNeeded();
}
};
};

class Window: public Handled{
protected:
char *Name;
Window *Parent;
int X,Y,Width,Height;

void call(){
glutSetWindow(getHandle());
};

void createHandle();
void deleteHandle();
public:
Window(char *name,int x=100,int y=100,int width=320,int height=240):Name(name),Parent(NULL),X(x),Y(y),Width(width),Height(height){
handleNeeded();
};

Window(char *name,Window *parent,int x=80,int y=60,int width=160,int height=120):Name(NULL),Parent(parent),X(x),Y(y),Width(width),Height(height){
handleNeeded();
};
}

void Window::createHandle(){
/* Code qui crée une fenêtre avec GLUT et stocke l'index retourné dans Handle */
};

void Window::deleteHandle(){
/* Code qui crée une fenêtre avec GLUT et stocke l'index retourné dans Handle */
};

Donc voilà j'ai une classe de base qui sert à dériver des sous-classes encapsulant des objets systèmes auxquels on accède via une série d'API et un "Handle" qui est typiquement un entier. Le template avec THANDLE et INVALID_HANDLE sert à faire la distinction entre les objets systèmes qui sont liés à un entier signé (fenêtres GLUT par exemple) et ceux qui sont liés à un entier non signé (identifiants de texture OpenGl par exemple).

Les appels aux API servant à allouer/libérer les Handle systèmes en question sont définis dans la classes descendante en surchargeant les méthodes virtuelles pures createHandle et deleteHandle. Tout se passe bien dans les constructeurs qui appellent (directement ou indirectement) createHandle, la méthode descendante est appelée et mon objet système est bien créé.

Mais, et ça je n'arrive pas à l'expliquer, lorsqu'une instance de la classe descendante est détruite, ce n'est pas le cas : c'est la méthode de base deleteHandle qui est appelée... générant bien évidemment une exception "pure virtual function call". J'ai naïvement essayé de rendre le destructeur virtuel, voire de passer par un pointeur sur l'instance en espérant court-circuiter le typage à la compilation (car c'est de ça qu'il s'agit je suppose) rien n'y fait.

Est-ce une spécification du C++ (toute la doc que j'ai lue jusque-là n'en faisait pas mention en tout cas)? Est-ce que ça vient de ce que ma classe est une template?

Merci d'avance de votre aide.
Afficher la suite 

3 réponses

Meilleure réponse
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
2
3
Merci
Salut,

Au moment de l'appel du destructeur de ta classe de base, le
destructeur de ta classe derivée à déja été appelé, et comme un appel
virtuel peut utiliser les données de ta classe derivée, il est interdit
ici.

Même raisonnement pour le constructeur, si tu appeles une fonction
virtuelle depuis le constructeur de ta classe de base, ca signifierait
qu'une methode de ta classe derivée peut etre appelée avant que le
constructeur de cette meme classe ai été appelé, ce qui est dangereux
puisque les données de ta classe derivée n'ont pas encore été
initialisées.

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 198 internautes nous ont dit merci ce mois-ci

Commenter la réponse de cs_aardman
Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
4
0
Merci
Window * pWindow = new Window();
Handled * pHandled = pWindow;
delete pHandled;

Si ton destructeur n'est pas virtuel, c'est le destructeur de pHandled qui sera appelé dans ce cas.

delete pWindow <= ici le destructeur de Window.

Donc ca coute rien de toujours mettre le destructeur virtuel:
virtual ~Handled();

Mais ya aucun pb. Sauf que toi il semble que tu l'ais mis virtuel pure, ce qui n'a évidemment aucun sens ici, mais c'est faisable dans certain cas.
Commenter la réponse de luhtor
Messages postés
663
Date d'inscription
samedi 8 juin 2002
Statut
Membre
Dernière intervention
6 avril 2010
1
0
Merci
Bonjour,

Merci d'avoir pris la peine de répondre.

@luthor: en fait je n'ai guère besoin de faire un destructeur virtuel, sachant que ma classe Handled est seulement là pour m'éviter d'avoir à retaper 10 lignes à chaque nouvelle classe encapsulante. Mais j'y penserai, c'est plus prudent.

@aardman: merci, effectivement l'argument est imparable.
Commenter la réponse de cs_Forman