web-dev-qa-db-fra.com

Chaque classe devrait-elle avoir un destructeur virtuel?

Java et C # prennent en charge la notion de classes qui ne peuvent pas être utilisées comme classes de base avec les mots clés final et sealed. En C++ cependant, il n'y a pas de bon moyen d'empêcher qu'une classe en dérive laisse à l'auteur de la classe un dilemme, chaque classe devrait-elle avoir un destructeur virtuel ou non?


Edit: Puisque C++ 11 ce n'est plus vrai, vous pouvez spécifier qu'une classe est final =.


D'une part, donner à un objet un destructeur virtuel signifie qu'il aura un vtable et donc consommera 4 (ou 8 sur les machines 64 bits) octets supplémentaires par objet pour le vptr.

D'un autre côté, si quelqu'un dérive plus tard de cette classe et supprime une classe dérivée via un pointeur vers la classe de base, le programme sera mal défini (en raison de l'absence d'un destructeur virtuel), et franchement l'optimisation d'un pointeur par objet est ridicule.

Sur le main de préhension avoir un destructeur virtuel (sans doute) annonce que ce type est destiné à être utilisé de manière polymorphe.

Certaines personnes pensent que vous avez besoin d'une raison explicite pour ne pas utiliser un destructeur virtuel (comme c'est le sous-texte de cette question ) et d'autres disent que vous ne devriez les utiliser que lorsque vous avez des raisons de croire que votre classe est de être dérivé de quoi pensez vous?

49
Motti

La question est vraiment, voulez-vous appliquer des règles sur la façon dont vos classes doivent être utilisées? Pourquoi? Si une classe n'a pas de destructeur virtuel, toute personne utilisant la classe sait qu'elle n'est pas destinée à être dérivée, et quelles limitations s'appliquent si vous l'essayez quand même. N'est-ce pas assez bon?

Ou avez-vous besoin du compilateur pour lancer une erreur matérielle si quelqu'un ose pour faire quelque chose que vous n'aviez pas prévu?

Donnez à la classe un destructeur virtuel si vous voulez que les gens en dérivent. Sinon, ne le faites pas et supposez que toute personne utilisant votre code est suffisamment intelligente pour utiliser correctement votre code.

28
jalf

Chaque classe abstraite doit avoir un,

  • destructeur protégé, ou
  • destructeur virtuel.

Si vous avez un destructeur public non virtuel, ce n'est pas bon, car il permet aux utilisateurs de supprimer via ce pointeur un objet dérivé. Comme nous le savons tous, c'est un comportement indéfini.

Pour une classe qui n'est pas destinée à être supprimée via un pointeur vers celle-ci, il n'y a aucune raison d'avoir un destructeur virtuel. Non seulement cela gaspillerait des ressources, mais surtout, cela donnerait aux utilisateurs un mauvais indice. Réfléchissez à ce que ce sens de merde donnerait à std::iterator un destructeur virtuel.

54

Non! Les destructeurs virtuels sont utilisés uniquement lorsqu'un objet d'une classe dérivée est supprimé via un pointeur de classe de base. Si votre classe n'est pas destinée à servir de base dans ce scénario, ne rendez pas le destructeur virtuel - vous enverriez un mauvais message.

8
Nemanja Trifunovic

Vérifiez cet article de Herb Sutter :

Directive n ° 4: Un destructeur de classe de base doit être soit public et virtuel, soit protégé et non virtuel.

4
Paolo Tedesco

Je voudrais "non" à la question générale. Pas chaque classe en a besoin d'un. Si vous pouvez savoir que la classe ne doit jamais être héritée, il n'est pas nécessaire d'engager des frais généraux mineurs. Mais s'il y a une chance, soyez prudent et mettez-en un dedans.

2
Evan Teran

La classe de base devient une classe abstraite, lorsqu'elle contient au moins une fonction virtuelle pure. Si Base n'a pas de destructeur virtuel et Derived (dérivé de Base), vous pouvez détruire en toute sécurité un objet Derived via un pointeur d'objet Derived mais pas via un pointeur d'objet Base.

1
shurli pataka

J'ajouterai qu'il y a eu des moments où je me suis gratté la tête pendant un certain temps sur les destructeurs qui ne se faisaient pas appeler lorsque j'avais oublié un virtuel dans la classe parent ou enfant. Je suppose que je sais chercher ça maintenant. :)

Quelqu'un pourrait dire qu'il y a des moments où la classe parent fait quelque chose dans son destructeur qu'un enfant ne devrait pas faire ... mais c'est probablement un indicateur de quelque chose qui ne va pas avec votre structure d'héritage de toute façon.

0
Patrick Hogan