42 votes

Quand votre destructeur doit-il être virtuel ?

Duplicata possible :
Quand utiliser des destructeurs virtuels ?

Quand le destructeur de votre objet C++ doit-il être virtual ?

53voto

stefanB Points 27796
  1. Vous avez besoin d'un destructeur virtuel lorsqu'à au moins une des méthodes de la classe est virtuelle.

En effet, la raison d'être de la méthode virtuelle est que vous voulez utiliser le polymorphisme. Cela signifie que vous allez appeler une méthode sur le pointeur de la classe de base et que vous voulez la mise en œuvre la plus dérivée - c'est tout l'intérêt du polymorphisme.

Maintenant, si vous n'avez pas de destructeur virtuel et que vous appelez le destructeur par le biais du pointeur vers la classe de base, vous finissez par appeler le destructeur de la classe de base. Dans ce cas, vous voulez que le polymorphisme fonctionne également sur votre destructeur, par exemple, en appelant le destructeur de votre classe de base, vous voulez finir par appeler le destructeur de votre classe la plus dérivée et non de votre classe de base.

class A
{
   virtual void f() {}
   ~A() {}
}

class B : public A
{
   void f() {}
   ~B() {}
}

A * thing = new B();
thing->f(); // calls B's f()
delete thing; // calls ~A(), not what you wanted, you wanted ~B()

avoir ~A() virtuel active le polymorphisme

virtual ~A() {}

Donc quand vous appelez maintenant

delete thing;

~B() sera appelé.

Vous déclarez des destructeurs virtuels lorsque vous concevez une classe comme une interface, par exemple lorsque vous vous attendez à ce qu'elle soit étendue ou implémentée. Une bonne pratique dans ce cas est d'avoir une classe d'interface (au sens des interfaces Java) avec des méthodes virtuelles et un destructeur virtuel, puis des classes d'implémentation concrètes.

Vous pouvez voir que les classes STL n'ont pas de destructeurs virtuels et ne sont donc pas censées être étendues (par exemple std::vector, std::string ...). Si vous étendez std::vector et que vous appelez le destructeur de la classe de base via un pointeur ou une référence, vous n'appellerez certainement pas le destructeur de votre classe spécialisée, ce qui peut entraîner des fuites de mémoire.

33voto

luke Points 16255

De FAQ sur le style et la technique C++ de Stroustrup :

Alors quand dois-je déclarer un destructeur virtuel ? Dès que la classe a au moins une au moins une fonction virtuelle. Le fait d'avoir fonctions virtuelles indiquent qu'une classe est destinée à servir d'interface pour les classes dérivées, et quand c'est le cas, un objet d'une classe dérivée peut être détruit par le biais d'un pointeur vers la base.

Beaucoup d'informations supplémentaires sur quand votre destructeur doit être virtuel sur la FAQ C++. . (merci Stobor)

Qu'est-ce qu'un membre virtuel ? Depuis le FAQ C++ :

[20.1] Qu'est-ce qu'une "fonction membre virtuelle" ?

D'un point de vue OO, c'est le caractéristique la plus importante de C++ : [6.9], [6.10].

Une fonction virtuelle permet aux dérivés dérivées de remplacer l'implémentation fournie par la classe de base. Le compilateur compilateur s'assure que le remplacement est toujours appelé lorsque l'objet en question en question est effectivement de la classe dérivée dérivée, même si l'objet est accédé par un pointeur de base plutôt que par un pointeur dérivé. Cela permet algorithmes de la classe de base d'être remplacés dans la classe dérivée, même si utilisateurs ne connaissent pas la classe dérivée.

La classe dérivée peut soit entièrement remplacer ("override") la fonction membre de la classe de base de la classe de base, soit la classe dérivée peut remplacer partiellement ("augmenter") la fonction membre de la fonction membre de la classe de base. Dans ce dernier cas est réalisée en faisant en sorte que la fonction membre de la appelle la fonction membre de la classe de base de la classe de base, si on le souhaite.

5voto

Pukku Points 5571

J'en suis venu récemment à conclure que la réponse entièrement correcte est la suivante :

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

Et bien sûr Herb Sutter donne le raisonnement à sa demande. Notez qu'il va au-delà des réponses habituelles "quand quelqu'un supprimera un objet de classe dérivée via un pointeur de classe de base" et "rendez votre destructeur virtuel si votre classe a des fonctions virtuelles".

3voto

Michael Kohne Points 8233

Si vous avez l'intention (ou même la possibilité) de détruire des objets d'une classe dérivée par le biais d'un pointeur de classe de base, vous avez besoin d'un destructeur virtuel.

Je considère que si je dois dériver d'une classe, celle-ci doit avoir un destructeur virtuel. Il n'y a effectivement aucun cas dans le code que j'écris où les implications en termes de performances d'un destructeur virtuel ont de l'importance, et même s'il n'est pas réellement nécessaire aujourd'hui, il pourrait en avoir besoin à l'avenir lorsque la classe sera modifiée.

En gros : Mettez du virtuel sur tous les destructeurs des classes de base, sauf si vous avez une bonne raison bien pensée de ne pas le faire.

Ce n'est qu'une autre règle empirique, mais c'est une règle qui vous évite de commettre des erreurs ultérieures.

0voto

Jared Oberhaus Points 8877

Toujours.

A moins que je ne sois vraiment concerné par le stockage et les performances d'une table virtuelle, je la rend toujours virtuelle. A moins que vous n'ayez un outil d'analyse statique pour vérifier que votre destructeur est virtuel dans les bons cas, cela ne vaut pas la peine de faire une erreur et de ne pas faire un destructeur virtuel quand c'est nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X