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 */};
};
... ... 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 ?
déclaration (de variables) polymorphes ou appels polymorphes ? dans le premier cas, un destructeur virtuel est nécessaire, sinon...
B* toto = new B(); delete toto; ... ...
mais
A* toto = new B(); delete toto;
ne marchera pas.
Ce sont bien les destructeurs de B puis de A qui seront executés ? pas de polymorphisme ici donc pas besoin de destructeurs virtuels ?
certes mais définit-on un bon usage sur un seul exemple bati exprès pour?
Sylvain.
hibakusha
En réponse à Fabien et Sylvain : je suis entierement d'accord avec vous. Je comprends et j'approuve que l'on qualifie systématiquement un destructeur de virtuel pour les raisons qu'évoque Fabien. Et bien entendu l'exemple pour l'exemple ne dicte pas la bonne pratique.
Je ne pratique pas assez en C++ pour ne pas avoir de doute sur ce genre de point, je voulais donc être certain d'avoir compris un point "théorique". J'ai par contre suffisament d'expériences en C pour comprendre l'importance d'un bonne pratique tel que celle enoncée par Fabien.
Merci à vous deux.
En réponse à Fabien et Sylvain : je suis entierement d'accord avec vous.
Je comprends et j'approuve que l'on qualifie systématiquement un
destructeur de virtuel pour les raisons qu'évoque Fabien. Et bien
entendu l'exemple pour l'exemple ne dicte pas la bonne pratique.
Je ne pratique pas assez en C++ pour ne pas avoir de doute sur ce genre
de point, je voulais donc être certain d'avoir compris un point
"théorique". J'ai par contre suffisament d'expériences en C pour
comprendre l'importance d'un bonne pratique tel que celle enoncée par
Fabien.
En réponse à Fabien et Sylvain : je suis entierement d'accord avec vous. Je comprends et j'approuve que l'on qualifie systématiquement un destructeur de virtuel pour les raisons qu'évoque Fabien. Et bien entendu l'exemple pour l'exemple ne dicte pas la bonne pratique.
Je ne pratique pas assez en C++ pour ne pas avoir de doute sur ce genre de point, je voulais donc être certain d'avoir compris un point "théorique". J'ai par contre suffisament d'expériences en C pour comprendre l'importance d'un bonne pratique tel que celle enoncée par Fabien.
Merci à vous deux.
James Kanze
On Jul 25, 6:50 pm, Fabien LE LEZ wrote:
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.
Tu pourrais espérer qu'il utilise la classe à bonne échéance. Sinon, ce n'est pas en faisant le destructeur virtuel que le code va marcher.
La règle générale aujourd'hui est, je crois : si la classe doit servir de base, le destructeur doit être soit virtuel, soit protégé (afin qu'on ne peut pas faire delete à un pointeur à la classe de base). N'empèche que std::iterator a bien un destructeur public, tout le monde en dérive, et je n'ai jamais, jamais entendu parler d'un problème à cet égard. La sémantique de la classe est telle qu'il ne vient même pas à l'esprit d'en vouloir un pointeur à elle.
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.
Si l'objet est polymorphique, oui, et il y a même des compilateurs qui avertit si la classe a une fonction virtuelle, mais que le destructeur n'est pas virtuel. Si la classe est conçue pour servir de base pour des raisons autres que le polymorphisme, comme c'est le cas de std::iterator, tout dépend. (Dans le cas de std::iterator, moi, je lui aurais donné un destructeur protégé. Mais dans la pratique, le fait que le destructeur soit public ne me paraît pas être un gros problème non plus.)
-- 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
On Jul 25, 6:50 pm, Fabien LE LEZ <grams...@gramster.com> wrote:
On Wed, 25 Jul 2007 18:34:02 +0200, hibakusha
<bradypefuri...@free.fr>:
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.
Tu pourrais espérer qu'il utilise la classe à bonne échéance.
Sinon, ce n'est pas en faisant le destructeur virtuel que le
code va marcher.
La règle générale aujourd'hui est, je crois : si la classe doit
servir de base, le destructeur doit être soit virtuel, soit
protégé (afin qu'on ne peut pas faire delete à un pointeur à la
classe de base). N'empèche que std::iterator a bien un
destructeur public, tout le monde en dérive, et je n'ai jamais,
jamais entendu parler d'un problème à cet égard. La sémantique
de la classe est telle qu'il ne vient même pas à l'esprit d'en
vouloir un pointeur à elle.
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.
Si l'objet est polymorphique, oui, et il y a même des
compilateurs qui avertit si la classe a une fonction virtuelle,
mais que le destructeur n'est pas virtuel. Si la classe est
conçue pour servir de base pour des raisons autres que le
polymorphisme, comme c'est le cas de std::iterator, tout dépend.
(Dans le cas de std::iterator, moi, je lui aurais donné un
destructeur protégé. Mais dans la pratique, le fait que le
destructeur soit public ne me paraît pas être un gros problème
non plus.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
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
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.
Tu pourrais espérer qu'il utilise la classe à bonne échéance. Sinon, ce n'est pas en faisant le destructeur virtuel que le code va marcher.
La règle générale aujourd'hui est, je crois : si la classe doit servir de base, le destructeur doit être soit virtuel, soit protégé (afin qu'on ne peut pas faire delete à un pointeur à la classe de base). N'empèche que std::iterator a bien un destructeur public, tout le monde en dérive, et je n'ai jamais, jamais entendu parler d'un problème à cet égard. La sémantique de la classe est telle qu'il ne vient même pas à l'esprit d'en vouloir un pointeur à elle.
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.
Si l'objet est polymorphique, oui, et il y a même des compilateurs qui avertit si la classe a une fonction virtuelle, mais que le destructeur n'est pas virtuel. Si la classe est conçue pour servir de base pour des raisons autres que le polymorphisme, comme c'est le cas de std::iterator, tout dépend. (Dans le cas de std::iterator, moi, je lui aurais donné un destructeur protégé. Mais dans la pratique, le fait que le destructeur soit public ne me paraît pas être un gros problème non plus.)
-- 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
On Thu, 26 Jul 2007 07:09:39 -0700, James Kanze :
N'empèche que std::iterator a bien un destructeur public
Le standard suit des règles différentes : le programmeur est censé connaître le standard, et savoir comment on utilise ses classes. Par contre, on n'est pas censé connaître sur le bout des doigts les règles d'utilisation d'une classe issue d'une autre bibliothèque.
On Thu, 26 Jul 2007 07:09:39 -0700, James Kanze
<james.kanze@gmail.com>:
N'empèche que std::iterator a bien un destructeur public
Le standard suit des règles différentes : le programmeur est censé
connaître le standard, et savoir comment on utilise ses classes. Par
contre, on n'est pas censé connaître sur le bout des doigts les règles
d'utilisation d'une classe issue d'une autre bibliothèque.
N'empèche que std::iterator a bien un destructeur public
Le standard suit des règles différentes : le programmeur est censé connaître le standard, et savoir comment on utilise ses classes. Par contre, on n'est pas censé connaître sur le bout des doigts les règles d'utilisation d'une classe issue d'une autre bibliothèque.