La question du sujet suggère une confusion assez courante. La confusion est assez courante, que la FAQ C ++ a prôné pendant longtemps l'utilisation de virtuels privés, car la confusion semblait être une mauvaise chose.
Donc, pour se débarrasser de la confusion en premier: Oui, les fonctions virtuelles privées peuvent être remplacées dans les classes dérivées. Les méthodes des classes dérivées ne peuvent pas appeler des fonctions virtuelles à partir de la classe de base, mais elles peuvent leur fournir leur propre implémentation. Selon Herb Sutter, avoir une interface publique non virtuelle dans la classe de base et une implémentation privée qui peut être personnalisée dans les classes dérivées, permet une meilleure «séparation de la spécification de l'interface de la spécification du comportement personnalisable de l'implémentation». Vous pouvez en savoir plus à ce sujet dans son article "Virtuality" .
Il y a cependant une autre chose intéressante dans le code que vous avez présenté, qui mérite un peu plus d'attention, à mon avis. L'interface publique se compose d'un ensemble de fonctions non virtuelles surchargées et ces fonctions appellent des fonctions virtuelles non publiques et non surchargées. Comme d'habitude dans le monde C ++, c'est un idiome, il a un nom et bien sûr c'est utile. Le nom est (surprise, surprise!)
«Public surchargé non-virtuels virtuels protégés contre les appels non surchargés»
Cela aide à gérer correctement la règle de masquage . Vous pouvez en savoir plus ici , mais je vais essayer de l'expliquer sous peu.
Imaginez que les fonctions virtuelles de la Engine
classe sont aussi son interface et que c'est un ensemble de fonctions surchargées qui ne sont pas purement virtuelles. S'ils étaient purement virtuels, on pourrait toujours rencontrer le même problème, comme décrit ci-dessous, mais plus bas dans la hiérarchie des classes.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Supposons maintenant que vous souhaitiez créer une classe dérivée et que vous deviez fournir une nouvelle implémentation uniquement pour la méthode, qui prend deux entiers comme arguments.
class MyTurbochargedV8 : public Engine
{
public:
// To prevent SetState( int var, bool val ) from the base class,
// from being hidden by the new implementation of the other overload (below),
// you have to put using declaration in the derived class
using Engine::SetState;
void SetState( int var, int val ) {/*new implementation*/}
};
Si vous avez oublié de mettre la déclaration using dans la classe dérivée (ou de redéfinir la deuxième surcharge), vous pourriez avoir des problèmes dans le scénario ci-dessous.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Si vous n'avez pas empêché la dissimulation des Engine
membres, la déclaration:
myV8->SetState(5, true);
appellerait à void SetState( int var, int val )
partir de la classe dérivée, convertissant true
en int
.
Si l'interface n'est pas virtuelle et que l'implémentation virtuelle n'est pas publique, comme dans votre exemple, l'auteur de la classe dérivée a un problème de moins à penser et peut simplement écrire
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};
La fonction virtuelle pure privée est la base de l' idiome d' interface non virtuelle (OK, ce n'est pas absolument toujours pur virtuel, mais toujours virtuel là-bas). Bien sûr, cela est également utilisé pour d'autres choses, mais je trouve cela pour le plus utile (: En deux mots: dans une fonction publique, vous pouvez mettre des choses courantes (telles que la journalisation, les statistiques, etc.) au début et à la fin de la fonction et ensuite, "au milieu" pour appeler cette fonction virtuelle privée, ce sera différent pour la classe dérivée spécifique. Quelque chose comme:
Pure virtual - oblige simplement les classes dérivées à l'implémenter.
EDIT : Plus à ce sujet: Wikipedia :: NVI-idiom
la source
Eh bien, d'une part, cela permettrait à une classe dérivée d'implémenter une fonction que la classe de base (contenant la déclaration de fonction virtuelle pure) peut appeler.
la source
EDIT: des déclarations clarifiées sur la capacité de passer outre et la capacité d'accéder / invoquer.
Il pourra remplacer ces fonctions privées. Par exemple, l'exemple artificiel suivant fonctionne ( EDIT: rend la méthode de classe dérivée privée et supprime l'invocation de la méthode de classe dérivée
main()
pour mieux démontrer l'intention du modèle de conception utilisé. ):Private
virtual
Les méthodes d'une classe de base comme celles de votre code sont généralement utilisées pour implémenter le modèle de conception de méthode modèle . Ce modèle de conception permet de changer le comportement d'un algorithme dans la classe de base sans changer le code de la classe de base. Le code ci-dessus où les méthodes de classe de base sont appelées via un pointeur de classe de base est un exemple simple du modèle de méthode modèle.la source
Engine
etDerivedEngine
n'a rien à voir avec ce quiDerivedEngine
peut ou ne peut pas remplacer (ou accéder, d'ailleurs).La méthode virtuelle privée est utilisée pour limiter le nombre de classes dérivées qui peuvent remplacer la fonction donnée. Les classes dérivées qui doivent remplacer la méthode virtuelle privée devront être un ami de la classe de base.
Une brève explication peut être trouvée sur DevX.com .
EDIT Une méthode virtuelle privée est effectivement utilisée dans Template Method Pattern . Les classes dérivées peuvent remplacer la méthode virtuelle privée mais les classes dérivées ne peuvent pas appeler sa méthode virtuelle privée de classe de base (dans votre exemple,
SetStateBool
etSetStateInt
). Seule la classe de base peut effectivement appeler sa méthode virtuelle privée ( uniquement si les classes dérivées doivent appeler l'implémentation de base d'une fonction virtuelle, protégez la fonction virtuelle ).Un article intéressant peut être trouvé sur la virtualité .
la source
friend
de la classe de base. Qt a adopté la même approche lors de la mise en œuvre de son modèle de document XML DOM.TL; DR réponse:
Vous pouvez le traiter comme un autre niveau d'encapsulation - quelque part entre protégé et privé : vous ne pouvez pas l'appeler à partir d'une classe enfant, mais vous pouvez le remplacer.
Il est utile lors de l'implémentation du modèle de conception de méthode modèle. Vous pouvez utiliser protégé , mais privé avec virtuel peut être considéré comme un meilleur choix, en raison d'une meilleure encapsulation.
la source