145 votes

Quel est l'intérêt d'une fonction virtuelle pure privée?

Je suis tombé sur le code suivant dans un fichier d'en-tête:

 class Engine
{
public:
    void SetState( int var, bool val );
    {   SetStateBool( int var, bool val ); }

    void SetState( int var, int val );
    {   SetStateInt( int var, int val ); }
private:
    virtual void SetStateBool(int var, bool val ) = 0;    
    virtual void SetStateInt(int var, int val ) = 0;    
};
 

Pour moi, cela implique que soit la classe Engine , soit une classe dérivée de celle-ci, doit fournir l'implémentation de ces fonctions virtuelles pures. Mais je ne pensais pas que les classes dérivées pourraient avoir accès à ces fonctions privées afin de les réimplémenter - alors pourquoi les rendre virtuelles?

211voto

Maciej Hehl Points 4760

La question est dans le sujet suggèrent une jolie commune de la confusion. La confusion est assez commun, que C++ FAQ préconisé contre l'utilisation privée virtuals, pour une longue période, en raison de la confusion qui semblait être une mauvaise chose.

Donc, pour se débarrasser de la confusion d'abord: Oui, privés des fonctions virtuelles peut être redéfinie dans les classes dérivées. Les méthodes des classes dérivées ne peux pas les appeler des fonctions virtuelles de la classe de base, mais ils peuvent fournir leur propre mise en œuvre. Selon Herb Sutter, ayant publique non-interface virtuelle dans la classe de base et d'une salle de mise en œuvre qui peut être personnalisé dans les classes dérivées, permet une meilleure séparation de la spécification de l'interface à partir de la spécification de la mise en œuvre de personnalisation du comportement". Vous pouvez en lire plus à ce sujet dans son article "Virtualité".

Il y a cependant une chose plus 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 surcharge de non-fonctions virtuelles et les fonctions d'appels non-public, non surchargé des fonctions virtuelles. Comme d'habitude dans le C++ monde, c'est un idiome, il a un nom, et bien sûr, il est utile. Le nom est (surprise, surprise!)

"Public Surchargé Non-Virtuals Appel Protégé Non Surchargé Virtuals"

Il aide à gérer correctement la règle de masquage. Vous pouvez en lire plus à ce sujet ici, mais je vais essayer de l'expliquer en peu de temps.

Imaginez, que les fonctions virtuelles de la Engine classe sont également de son interface et c'est un ensemble de fonctions surchargées qui n'est pas virtuelle pure. Si ils étaient virtuelle pure, on pouvait encore rencontrer le même problème, comme décrit ci-dessous, mais plus bas dans la hiérarchie de classe.

class Engine
{
public:
    virtual void SetState( int var, bool val ) {/*some implementation*/}
    virtual void SetState( int var, int val )  {/*some implementation*/}
};

Maintenant, supposons que vous voulez créer une classe dérivée, et vous devez fournir un nouveau seulement la mise en œuvre de la méthode, qui prend deux entiers en tant qu'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 l'aide de la déclaration dans la classe dérivée (ou de redéfinir la seconde surcharge), vous pourriez avoir de la difficulté dans le scénario ci-dessous.

MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);

Si vous n'avez pas d'empêcher la dissimulation de l' Engine des membres, la déclaration:

myV8->SetState(5, true);

appellerait void SetState( int var, int val ) de la classe dérivée, convertir true de int.

Si l'interface n'est pas du virtuel et du virtuel, de la mise en œuvre est non-public, 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*/}
};

43voto

Kiril Kirov Points 19081

Privée virtuelle pure fonction est la base de la Non-interface virtuelle idiome (OK, ce n'est pas absolument toujours pur virtuel, mais encore virtuel). Bien sûr, ce est utilisé pour d'autres choses aussi, mais je trouve cela pour le plus utile (: En deux mots: dans une fonction publique, vous pouvez mettre quelques choses en commun (comme l'exploitation forestière, les statistiques, etc...) au début et à la fin de la fonction, puis, "au milieu" à l'appel de ce privé virtuel de la fonction, qui sera différent pour la classe dérivée. Quelque chose comme:

class Base
{
    // ..
public:
    void f();
private:
    virtual void DerivedClassSpecific() = 0;
   // ..
};
void Base::f()
{
    //.. Do some common stuff
    DerivedClassSpecific();
    //.. Some other common stuff
}
// ..

class Derived: public Base
{
    // ..
private:
    virtual void DerivedClassSpecific();
    //..
};
void Derived::DerivedClassSpecific()
{
    // ..
}

Virtuelle Pure - juste oblige les classes dérivées pour la mettre en œuvre.

EDIT: Plus à ce sujet: Wikipédia::TC-idiome

17voto

Michael Goldshteyn Points 24679

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.

4voto

Void Points 2583

EDIT: Précision des déclarations à propos de la capacité de remplacer et de capacité d'accès/invoke.

Il sera en mesure de remplacer ces fonctions privées. Par exemple, le inventée suivant l'exemple des œuvres (EDIT: fait méthode de la classe dérivée privé, et de la baisse de la méthode de la classe dérivée invocation en main() de mieux démontrer l'intention de la conception du motif en cours d'utilisation.):

#include <iostream>

class Engine
{
public:
  void SetState( int var, bool val )
  {
    SetStateBool( var, val );
  }

  void SetState( int var, int val )
  {
    SetStateInt( var, val );
  }

private:

    virtual void SetStateBool(int var, bool val ) = 0;
    virtual void SetStateInt(int var, int val ) = 0;

};

class DerivedEngine : public Engine
{
private:
  virtual void SetStateBool(int var, bool val )
  {
    std::cout << "DerivedEngine::SetStateBool() called" << std::endl;
  }

  virtual void SetStateInt(int var, int val )
  {
    std::cout << "DerivedEngine::SetStateInt() called" << std::endl;
  }
};


int main()
{
  DerivedEngine e;
  Engine * be = &e;

  be->SetState(4, true);
  be->SetState(2, 1000);
}

Private virtual méthodes dans une classe de base comme ceux de votre code sont généralement utilisés pour mettre en œuvre la Méthode de Modèle de modèle de conception. Que le design pattern permet de changer le comportement de l'algorithme dans la classe de base sans changer le code dans la classe de base. Le code ci-dessus où la classe de base des méthodes appelées par le biais d'une base de pointeur de classe est un exemple simple de la Méthode de Modèle de modèle.

2voto

Buhake Sindi Points 38654

Privé virtuel méthode est utilisée pour limiter le nombre de classes dérivées qui peut remplacer la fonction donnée. Les classes dérivées qui a remplacer le privé virtuel méthode devra être un ami de la classe de base.

Une brève explication peut être trouvée d' DevX.com.


EDIT privé virtuel méthode est utilisée de manière efficace dans la Méthode de Modèle de Modèle. Les classes dérivées peuvent remplacer le privé virtuel méthode, mais les classes dérivées ne peut pas appeler ça de la classe de base privé virtuel méthode (dans votre exemple, SetStateBool et SetStateInt). Seule la classe de base peut effectivement appeler sa méthode virtuelle (Seulement si les classes dérivées ont besoin d'invoquer la base de la mise en œuvre d'une fonction virtuelle, faire de la fonction virtuelle protégée).

Un intéressant article peut être trouvé sur la Virtualité.

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