web-dev-qa-db-fra.com

Les destructeurs virtuels sont-ils hérités?

Si j'ai une classe de base avec un destructeur virtuel. A une classe dérivée pour déclarer un destructeur virtuel aussi?

class base {
public:
    virtual ~base () {}
};

class derived : base {
public:
    virtual ~derived () {} // 1)
    ~derived () {}  // 2)
};

Questions concrètes:

  1. Est-ce que 1) et 2) sont les mêmes? 2) est-il automatiquement virtuel à cause de sa base ou "arrête-t-il" la virtualité?
  2. Le destructeur dérivé peut-il être omis s'il n'a rien à voir?
  3. Quelle est la meilleure pratique pour déclarer le destructeur dérivé? Le déclarer virtuel, non virtuel ou l'omettre si possible?
75
cairol
  1. Oui, ils sont pareils. La classe dérivée ne déclarant pas quelque chose de virtuel ne l'empêche pas d'être virtuelle. Il n'y a en fait aucun moyen d'empêcher une méthode (destructeur inclus) d'être virtuelle dans une classe dérivée si elle était virtuelle dans une classe de base. Dans> = C++ 11, vous pouvez utiliser final pour l'empêcher d'être écrasé dans les classes dérivées, mais cela ne l'empêche pas d'être virtuel.
  2. Oui, un destructeur dans une classe dérivée peut être omis s'il n'a rien à faire. Et peu importe que ce soit virtuel ou non.
  3. Je l'omettre si possible. Et j'utilise toujours le mot clé virtual pour les fonctions virtuelles dans les classes dérivées pour des raisons de clarté. Les gens ne devraient pas avoir à remonter la hiérarchie d'héritage pour comprendre qu'une fonction est virtuelle. De plus, si votre classe est copiable ou déplaçable sans avoir à déclarer vos propres constructeurs de copie ou de déplacement, déclarer un destructeur de tout type (même si vous le définissez comme default) vous obligera à déclarer les constructeurs de copie et de déplacement et les opérateurs d'affectation si vous les voulez car le compilateur ne les mettra plus pour vous.

Comme petit point pour le point 3. Il a été souligné dans les commentaires que si un destructeur n'est pas déclaré, le compilateur en génère un par défaut (qui est toujours virtuel). Et celle par défaut est une fonction en ligne.

Les fonctions en ligne exposent potentiellement une plus grande partie de votre programme à des modifications dans d'autres parties de votre programme et rendent la compatibilité binaire pour les bibliothèques partagées délicate. De plus, le couplage accru peut entraîner beaucoup de recompilation face à certains types de changements. Par exemple, si vous décidez que vous voulez vraiment une implémentation pour votre destructeur virtuel, alors chaque morceau de code qui l'a appelé devra être recompilé. Alors que si vous l'aviez déclaré dans le corps de la classe, puis l'aviez défini vide dans un .cpp fichier vous seriez bien de le changer sans recompiler.

Mon choix personnel serait toujours de l'omettre lorsque cela est possible. À mon avis, cela encombre le code et le compilateur peut parfois faire des choses légèrement plus efficaces avec une implémentation par défaut par rapport à une implémentation vide. Mais vous pouvez être soumis à des contraintes qui en font un mauvais choix.

90
Omnifarious

Une fonction membre virtuelle rendra implicitement toute surcharge de cette fonction virtuelle.

Ainsi, le virtuel en 1) est "facultatif", le destructeur de classe de base étant virtuel rend également tous les destructeurs enfants virtuels.

1
Klaim
  1. Le destructeur est automatiquement virtuel, comme pour toutes les méthodes. Vous ne pouvez pas empêcher une méthode d'être virtuelle en C++ (si elle a déjà été déclarée virtuelle, c'est-à-dire qu'il n'y a pas d'équivalent de `` final '' en Java)
  2. Oui, cela peut être omis.
  3. Je déclarerais un destructeur virtuel si j'ai l'intention que cette classe soit sous-classée, peu importe si elle sous-classe une autre classe ou non, je préfère également continuer à déclarer des méthodes virtuelles, même si ce n'est pas nécessaire. Cela gardera les sous-classes fonctionnelles si vous décidez de supprimer l'héritage. Mais je suppose que c'est juste une question de style.
1
falstro

1/Oui 2/Oui, il sera généré par le compilateur 3/Le choix entre le déclarer virtuel ou non devrait suivre votre convention pour les membres virtuels remplacés - à mon humble avis, il y a de bons arguments dans les deux sens, choisissez-en un et suivez-le.

Je l'oublierais si possible, mais il y a une chose qui peut vous inciter à le déclarer: si vous utilisez celui généré par le compilateur, il est implicitement en ligne. Il y a du temps où vous voulez éviter les membres en ligne (bibliothèques dynamiques par exemple).

0
AProgrammer