Quel est l'avantage de rendre une méthode privée virtuelle en C ++?
J'ai remarqué cela dans un projet C ++ open source:
class HTMLDocument : public Document, public CachedResourceClient {
private:
virtual bool childAllowed(Node*);
virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};
c++
polymorphism
access-specifier
Silverburgh
la source
la source
Réponses:
Herb Sutter l'a très bien expliqué ici .
Ligne directrice n ° 2: préférez rendre les fonctions virtuelles privées.
Cela permet aux classes dérivées de remplacer la fonction pour personnaliser le comportement selon les besoins, sans exposer davantage les fonctions virtuelles directement en les rendant appelables par des classes dérivées (comme cela serait possible si les fonctions étaient simplement protégées). Le fait est que les fonctions virtuelles existent pour permettre la personnalisation; à moins qu'ils ne doivent également être appelés directement à partir du code des classes dérivées, il n'est pas nécessaire de les rendre autre chose que privés
la source
Si la méthode est virtuelle, elle peut être remplacée par des classes dérivées, même si elle est privée. Lorsque la méthode virtuelle est appelée, la version remplacée sera appelée.
(Opposé à Herb Sutter cité par Prasoon Saurav dans sa réponse, la FAQ C ++ Lite déconseille les virtuels privés , principalement parce que cela déroute souvent les gens.)
la source
Malgré tous les appels à déclarer un membre virtuel privé, l'argument ne tient tout simplement pas la route. Souvent, le remplacement d'une fonction virtuelle par une classe dérivée devra appeler la version de la classe de base. Il ne peut pas s'il est déclaré
private
:Vous devez déclarer la méthode de classe de base
protected
.Ensuite, vous devez prendre le vilain expédient d'indiquer via un commentaire que la méthode doit être surchargée mais pas appelée.
Ainsi la ligne directrice n ° 3 de Herb Sutter ... Mais le cheval est de toute façon hors de la grange.
Lorsque vous déclarez quelque chose,
protected
vous faites implicitement confiance à l'écrivain de toute classe dérivée pour comprendre et utiliser correctement les composants internes protégés, tout comme unefriend
déclaration implique une confiance plus profonde pour lesprivate
membres.Les utilisateurs qui ont un mauvais comportement en violant cette confiance (par exemple étiquetés «ignorants» en ne prenant pas la peine de lire votre documentation) n'ont qu'à eux-mêmes à blâmer.
Mise à jour : j'ai eu quelques retours qui prétendent que vous pouvez "enchaîner" les implémentations de fonctions virtuelles de cette façon en utilisant des fonctions virtuelles privées. Si tel est le cas, j'aimerais bien le voir.
Les compilateurs C ++ que j'utilise ne laisseront certainement pas une implémentation de classe dérivée appeler une implémentation de classe de base privée.
Si le comité C ++ relâchait "privé" pour permettre cet accès spécifique, je serais tout pour les fonctions virtuelles privées. Dans l'état actuel des choses, on nous conseille toujours de verrouiller la porte de la grange après le vol du cheval.
la source
set_data
. Instructionsm_data = ndata;
etcleanup();
pourrait donc être considéré comme un invariant qui doit être valable pour toutes les implémentations. Rendez donccleanup()
non virtuel et privé. Ajoutez un appel à une autre méthode privée qui est virtuelle et le point d'extension de votre classe. Désormais, vos classes dérivées n'ont plus besoin d'appeler les basescleanup()
, votre code reste propre et votre interface est difficile à utiliser de manière incorrecte.cleanup()
s de la chaîne, l'argument s'effondre. Ou recommandez-vous une fonction virtuelle supplémentaire pour chaque descendant de la chaîne? Ick. Même Herb Sutter a autorisé les fonctions virtuelles protégées comme une faille dans sa directive n ° 3. Quoi qu'il en soit, sans un code réel, vous ne me convaincrez jamais.Je suis tombé sur ce concept pour la première fois en lisant «Effective C ++» de Scott Meyers, Item 35: Considérez des alternatives aux fonctions virtuelles. Je voulais citer Scott Mayers pour d'autres qui pourraient être intéressés.
Cela fait partie du modèle de méthode de modèle via l'idiome de l'interface non virtuelle : les méthodes destinées au public ne sont pas virtuelles; ils encapsulent plutôt les appels de méthode virtuelle qui sont privés. La classe de base peut alors exécuter la logique avant et après l'appel de fonction virtuelle privée:
Je pense que c'est un modèle de conception très intéressant et je suis sûr que vous pouvez voir à quel point le contrôle ajouté est utile.
private
? La meilleure raison est que nous avons déjà fourni unepublic
méthode de mise en face.protected
sorte que je puisse utiliser la méthode pour d'autres choses intéressantes? Je suppose que cela dépendra toujours de votre conception et de la façon dont vous pensez que la classe de base s'intègre. Je dirais que le créateur de classe dérivée devrait se concentrer sur l'implémentation de la logique requise; tout le reste est déjà pris en charge. Il y a aussi la question de l'encapsulation.D'un point de vue C ++, il est tout à fait légitime de remplacer une méthode virtuelle privée même si vous ne pourrez pas l'appeler depuis votre classe. Cela prend en charge la conception décrite ci-dessus.
la source
Je les utilise pour permettre aux classes dérivées de "remplir les blancs" pour une classe de base sans exposer un tel trou aux utilisateurs finaux. Par exemple, j'ai des objets hautement avec état dérivant d'une base commune, qui ne peuvent implémenter que 2/3 de la machine à états globale (les classes dérivées fournissent le 1/3 restant en fonction d'un argument de modèle, et la base ne peut pas être un modèle pour autres raisons).
J'AI BESOIN d'avoir la classe de base commune pour que de nombreuses API publiques fonctionnent correctement (j'utilise des modèles variadiques), mais je ne peux pas laisser cet objet dans la nature. Pire encore, si je laisse les cratères dans la machine à états - sous la forme de fonctions virtuelles pures - n'importe où mais en "Privé", je permets à un utilisateur intelligent ou désemparé dérivant d'une de ses classes enfants de remplacer les méthodes que les utilisateurs ne devraient jamais toucher. Donc, j'ai mis la machine à états «cerveaux» dans les fonctions virtuelles PRIVÉES. Ensuite, les enfants immédiats de la classe de base remplissent les espaces sur leurs remplacements NON virtuels, et les utilisateurs peuvent utiliser en toute sécurité les objets résultants ou créer leurs propres classes dérivées supplémentaires sans se soucier de gâcher la machine à états.
Quant à l'argument selon lequel vous ne devriez pas AVOIR de méthodes virtuelles publiques, je dis BS. Les utilisateurs peuvent mal remplacer les virtuels privés tout aussi facilement que les publics - ils définissent de nouvelles classes après tout. Si le public ne doit pas modifier une API donnée, ne la rendez pas virtuelle DU TOUT dans les objets accessibles au public.
la source