destructeurs virtuels et héritage

Le
Edrusb
Bonjour,

j'ai une question toute bête :

Pour simplifier j'ai trois classes qui dérivent les unes des autres (A
-> B -> C) les objets de chaque classe peuvent être manipulés (alloués,
détruits) par des pointeurs des classes parents, j'ai donc besoin de
destructeur virtuels.

Est-ce que chaque classe doit définir un destructeur virtuel ou est-ce
que définir un destructeur virtuel pour la classe A implique que les
destructeurs implicites ou explicites des classes héritées sont virtuels
aussi:

Soit à dire est-ce que ces déclarations :

class A
{
public:
virtuel ~A() {};
};

class B : public A
{
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};

class C : public B
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};


suffisent pour utiliser le code suivant sans risque de fuite mémoire:

B *ptr1;
B *ptr2;

ptr1 = new B;
ptr2 = new C;



delete ptr1;
delete ptr2;

ou bien dois-je obligatoirement déclarer les classes B et C comme ceci:

class B : public A
{
public:
virtual ~B(){/* implémentation éventuelle */};
};

class C : public B
public:
virtual ~C(){/* implémentation éventuelle */};
};

Merci d'avance pour toute réponse.

--
Edrusb
edrusba@free.fr (supprimer le 'a')
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Alp Mestan
Le #309201
Edrusb wrote:
Bonjour,

j'ai une question toute bête :

Pour simplifier j'ai trois classes qui dérivent les unes des autres (A
-> B -> C) les objets de chaque classe peuvent être manipulés (alloués,
détruits) par des pointeurs des classes parents, j'ai donc besoin de
destructeur virtuels.

Est-ce que chaque classe doit définir un destructeur virtuel ou est-ce
que définir un destructeur virtuel pour la classe A implique que les
destructeurs implicites ou explicites des classes héritées sont virtuels
aussi:

Soit à dire est-ce que ces déclarations :

class A
{
public:
virtuel ~A() {};
};

class B : public A
{
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};

class C : public B
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};


suffisent pour utiliser le code suivant sans risque de fuite mémoire:

B *ptr1;
B *ptr2;

ptr1 = new B;
ptr2 = new C;

...

delete ptr1;
delete ptr2;

ou bien dois-je obligatoirement déclarer les classes B et C comme ceci:

class B : public A
{
public:
virtual ~B(){/* implémentation éventuelle */};
};

class C : public B
public:
virtual ~C(){/* implémentation éventuelle */};
};

Merci d'avance pour toute réponse.



Il est nécessaire que toute classe dont une autre va dériver possède un
destructeur virtuel. Seule la classe tout en bas de la hiérarchie, dont
aucune autre va dériver, peut ne pas avoir de destructeur virtuel.
Le destructeur virtuel _DOIT_ être implémenté pour toute classe mère,
afin de ne pas avoir de fuite lors de l'utilisation du polymorphisme par
le biais d'une classe de base.

Alp

James Kanze
Le #309161
On Jul 22, 10:30 am, Edrusb
j'ai une question toute bête :

Pour simplifier j'ai trois classes qui dérivent les unes des autres (A
-> B -> C) les objets de chaque classe peuvent être manipulés (allou és,
détruits) par des pointeurs des classes parents, j'ai donc besoin de
destructeur virtuels.

Est-ce que chaque classe doit définir un destructeur virtuel ou est-ce
que définir un destructeur virtuel pour la classe A implique que les
destructeurs implicites ou explicites des classes héritées sont virtu els
aussi:


La virtualité d'une fonction s'hérite. Si le destructeur de
n'importe quelle classe de base est déclaré virtuel, le
destructeur de la classe en question est aussi virtuel, même
s'il n'est pas déclaré tel, et même s'il est généré
implicitement par le compilateur.

Soit à dire est-ce que ces déclarations :

class A
{
public:
virtuel ~A() {};
};

class B : public A
{
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};

class C : public B
{
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};

suffisent pour utiliser le code suivant sans risque de fuite mémoire:

B *ptr1;
B *ptr2;

ptr1 = new B;
ptr2 = new C;

...

delete ptr1;
delete ptr2;


Tout à fait. Sauf que la risque n'est pas une fuite de mémoire,
mais plutôt un comportement indéfini.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Alp Mestan
Le #309160
James Kanze wrote:
On Jul 22, 10:30 am, Edrusb
j'ai une question toute bête :

Pour simplifier j'ai trois classes qui dérivent les unes des autres (A
-> B -> C) les objets de chaque classe peuvent être manipulés (alloués,
détruits) par des pointeurs des classes parents, j'ai donc besoin de
destructeur virtuels.

Est-ce que chaque classe doit définir un destructeur virtuel ou est-ce
que définir un destructeur virtuel pour la classe A implique que les
destructeurs implicites ou explicites des classes héritées sont virtuels
aussi:


La virtualité d'une fonction s'hérite. Si le destructeur de
n'importe quelle classe de base est déclaré virtuel, le
destructeur de la classe en question est aussi virtuel, même
s'il n'est pas déclaré tel, et même s'il est généré
implicitement par le compilateur.


Ah j'aurais pensé qu'il y aurait exception ici.
Cependant pour échapper à des comportements indéfinis, il vaut mieux
redéfinir un destructeur (virtuel si la classe sera dérivée à son tour).



Soit à dire est-ce que ces déclarations :

class A
{
public:
virtuel ~A() {};
};

class B : public A
{
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};

class C : public B
{
public:
// pas de destructeur explicite
// ou destructeur explicite sans mot clef "virtuel"
};

suffisent pour utiliser le code suivant sans risque de fuite mémoire:

B *ptr1;
B *ptr2;

ptr1 = new B;
ptr2 = new C;

...

delete ptr1;
delete ptr2;


Tout à fait. Sauf que la risque n'est pas une fuite de mémoire,
mais plutôt un comportement indéfini.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Edrusb
Le #309158
James Kanze wrote:
[...]

Tout à fait. Sauf que la risque n'est pas une fuite de mémoire,
mais plutôt un comportement indéfini.




Merci à tous les deux pour vos réponses.


--
Edrusb
(supprimer le 'a')


James Kanze
Le #309156
On Jul 22, 11:22 am, Alp Mestan
James Kanze wrote:
On Jul 22, 10:30 am, Edrusb
j'ai une question toute bête :

Pour simplifier j'ai trois classes qui dérivent les unes des autres (A
-> B -> C) les objets de chaque classe peuvent être manipulés (all oués,
détruits) par des pointeurs des classes parents, j'ai donc besoin de
destructeur virtuels.

Est-ce que chaque classe doit définir un destructeur virtuel ou est- ce
que définir un destructeur virtuel pour la classe A implique que les
destructeurs implicites ou explicites des classes héritées sont vi rtuels
aussi:


La virtualité d'une fonction s'hérite. Si le destructeur de
n'importe quelle classe de base est déclaré virtuel, le
destructeur de la classe en question est aussi virtuel, même
s'il n'est pas déclaré tel, et même s'il est généré
implicitement par le compilateur.


Ah j'aurais pensé qu'il y aurait exception ici.


Pourquoi ?

Cependant pour échapper à des comportements indéfinis, il vaut mieux
redéfinir un destructeur (virtuel si la classe sera dérivée à son tour).


Encore, pourquoi ? La seule raison que je vois, c'est
l'habituelle, qu'on définit toujours un destructeur, même vide,
afin d'éviter qu'il soit inline.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Fabien LE LEZ
Le #309155
On Sun, 22 Jul 2007 17:34:14 -0000, James Kanze

La seule raison que je vois, c'est
l'habituelle, qu'on définit toujours un destructeur, même vide,
afin d'éviter qu'il soit inline.


Pour des raisons de temps de compilation, si on décide après coup que
le destructeur doit contenir quelque chose ?

James Kanze
Le #309109
On Jul 22, 8:02 pm, Fabien LE LEZ
On Sun, 22 Jul 2007 17:34:14 -0000, James Kanze

La seule raison que je vois, c'est
l'habituelle, qu'on définit toujours un destructeur, même vide,
afin d'éviter qu'il soit inline.


Pour des raisons de temps de compilation, si on décide après coup que
le destructeur doit contenir quelque chose ?


C'est pour ça, principalement, qu'on ne veut pas qu'ils soient
inline.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Alp Mestan
Le #309105
James Kanze wrote:
On Jul 22, 8:02 pm, Fabien LE LEZ
On Sun, 22 Jul 2007 17:34:14 -0000, James Kanze

La seule raison que je vois, c'est
l'habituelle, qu'on définit toujours un destructeur, même vide,
afin d'éviter qu'il soit inline.


Pour des raisons de temps de compilation, si on décide après coup que
le destructeur doit contenir quelque chose ?


C'est pour ça, principalement, qu'on ne veut pas qu'ils soient
inline.


Oui oui c'est principalement pour ça.
Pour le destructeur, je n'y avais jamais pensé en fait qu'il héritait de
la virtualité comme toute autre fonction. Je n'ai jamais eu à m'en
soucier en réalité ; je ne me suis jamais retrouvé devant un cas où j'ai
du m'en rendre compte. Merci de l'information.



hibakusha
Le #309778
... ...
Il est nécessaire que toute classe dont une autre va dériver possède un
destructeur virtuel. ... ... ...


Nécessaire ? je pensais que le destructeur ne devait être virtuel que
lorsque l'on jouait ensuite avec le polymorphisme ?

Si j'ai B qui derive de A, sans qualifier les destructeurs de virtuel,
et que je fait :
... ...
B* toto = new B();
//jouer avec toto
delete toto;
... ...

Ce sont bien les destructeurs de B puis de A qui seront executés ? pas
de polymorphisme ici donc pas besoin de destructeurs virtuels ?

Je suis à coté de la plaque ou pas ?

Fabien LE LEZ
Le #309777
On Wed, 25 Jul 2007 18:34:02 +0200, hibakusha

Nécessaire ? je pensais que le destructeur ne devait être virtuel que
lorsque l'on jouait ensuite avec le polymorphisme ?


Oui. Mais en tant qu'auteur de la classe, tu ne peux pas être sûr de
ce que l'utilisateur fera avec.
Même si tu as les deux casquettes, tu finiras peut-être, au bout de
quelques transformations de code, par détruire un objet de la classe
de façon polymorphique, ayant oublié que tu n'as pas le droit de le
faire.

Publicité
Poster une réponse
Anonyme