Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

destructeurs virtuels et héritage

14 réponses
Avatar
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')

10 réponses

1 2
Avatar
Alp Mestan
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

Avatar
James Kanze
On Jul 22, 10:30 am, Edrusb wrote:
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

Avatar
Alp Mestan
James Kanze wrote:
On Jul 22, 10:30 am, Edrusb wrote:
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




Avatar
Edrusb
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')


Avatar
James Kanze
On Jul 22, 11:22 am, Alp Mestan wrote:
James Kanze wrote:
On Jul 22, 10:30 am, Edrusb wrote:
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



Avatar
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 ?

Avatar
James Kanze
On Jul 22, 8:02 pm, Fabien LE LEZ wrote:
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


Avatar
Alp Mestan
James Kanze wrote:
On Jul 22, 8:02 pm, Fabien LE LEZ wrote:
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.



Avatar
hibakusha
... ...
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 ?

Avatar
Fabien LE LEZ
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.

1 2