C'est encore plus important pour une interface. Tout utilisateur de votre classe tiendra probablement un pointeur vers l'interface, pas un pointeur vers l'implémentation concrète. Quand ils viendront à le supprimer, si le destructeur n'est pas virtuel, ils appelleront le destructeur de l'interface (ou la valeur par défaut fournie par le compilateur, si vous n'en avez pas spécifié un), pas le destructeur de la classe dérivée. Fuite de mémoire instantanée.
Par exemple
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
delete p
invoque un comportement non défini. Il n'est pas garanti d'appelerInterface::~Interface
.[expr.delete]/
:... if the static type of the object to be deleted is different from its dynamic type, ... the static type shall have a virtual destructor or the behavior is undefined. ...
. Il ne serait toujours pas défini si Derived utilisait un destructeur généré implicitement.La réponse à votre question est souvent, mais pas toujours. Si votre classe abstraite interdit aux clients d'appeler delete sur un pointeur vers elle (ou si elle le dit dans sa documentation), vous êtes libre de ne pas déclarer de destructeur virtuel.
Vous pouvez interdire aux clients d'appeler delete sur un pointeur vers lui en protégeant son destructeur. En travaillant comme ça, il est parfaitement sûr et raisonnable d'omettre un destructeur virtuel.
Vous finirez par vous retrouver sans table de méthode virtuelle, et vous finirez par signaler à vos clients votre intention de la rendre non supprimable via un pointeur vers elle, vous avez donc en effet des raisons de ne pas la déclarer virtuelle dans ces cas.
[Voir le point 4 de cet article: http://www.gotw.ca/publications/mill18.htm ]
la source
J'ai décidé de faire quelques recherches et d'essayer de résumer vos réponses. Les questions suivantes vous aideront à décider du type de destructeur dont vous avez besoin:
J'espère que ça aide.
* Il est important de noter qu'il n'y a aucun moyen en C ++ de marquer une classe comme finale (c'est-à-dire non sous-classable), donc dans le cas où vous décidez de déclarer votre destructeur non virtuel et public, n'oubliez pas d'avertir explicitement vos collègues programmeurs contre dérivant de votre classe.
Références:
la source
Oui, c'est toujours important. Les classes dérivées peuvent allouer de la mémoire ou contenir des références à d'autres ressources qui devront être nettoyées lorsque l'objet est détruit. Si vous ne donnez pas à vos interfaces / classes abstraites de destructeurs virtuels, alors chaque fois que vous supprimez une instance de classe dérivée via un handle de classe de base, votre destructeur de classe dérivée ne sera pas appelé.
Par conséquent, vous ouvrez le potentiel de fuites de mémoire
la source
Ce n'est pas toujours obligatoire, mais je trouve que c'est une bonne pratique. Ce qu'il fait, c'est qu'il permet à un objet dérivé d'être supprimé en toute sécurité via un pointeur d'un type de base.
Donc par exemple:
est mal formé s'il
Base
n'a pas de destructeur virtuel, car il tentera de supprimer l'objet comme s'il s'agissait d'un fichierBase *
.la source
shared_ptr
ci, qui tentera de supprimer l'objet comme s'il s'agissait d'unBase *
- il se souvient du type de chose avec lequel vous l'avez créé. Voir le lien référencé, en particulier le bit qui dit "Le destructeur appellera delete avec le même pointeur, complet avec son type d'origine, même lorsque T n'a pas de destructeur virtuel, ou est nul."Ce n'est pas seulement une bonne pratique. C'est la règle n ° 1 pour toute hiérarchie de classes.
Maintenant pour le pourquoi. Prenez la hiérarchie animale typique. Les destructeurs virtuels passent par la répartition virtuelle comme tout autre appel de méthode. Prenons l'exemple suivant.
Supposons que Animal est une classe abstraite. Le seul moyen pour C ++ de connaître le destructeur approprié à appeler est via la répartition de méthode virtuelle. Si le destructeur n'est pas virtuel, il appellera simplement le destructeur d'Animal et ne détruira aucun objet dans les classes dérivées.
La raison pour laquelle le destructeur est virtuel dans la classe de base est qu'il supprime simplement le choix des classes dérivées. Leur destructeur devient virtuel par défaut.
la source
La réponse est simple, vous avez besoin qu'elle soit virtuelle sinon la classe de base ne serait pas une classe polymorphe complète.
Vous préférez la suppression ci-dessus, mais si le destructeur de la classe de base n'est pas virtuel, seul le destructeur de la classe de base sera appelé et toutes les données de la classe dérivée resteront non supprimées.
la source