Disons que nous avons:
Class Base
{
virtual void f(){g();};
virtual void g(){//Do some Base related code;}
};
Class Derived : public Base
{
virtual void f(){Base::f();};
virtual void g(){//Do some Derived related code};
};
int main()
{
Base *pBase = new Derived;
pBase->f();
return 0;
}
Quel g()
sera appelé à partir de Base::f()
? Base::g()
ou Derived::g()
?
Merci...
Le g de la classe dérivée sera appelé. Si vous voulez appeler la fonction dans la base, appelez
Base::g();
au lieu. Si vous souhaitez appeler la version dérivée, mais souhaitez toujours appeler la version de base, faites en sorte que la version dérivée de g appelle la version de base dans sa première instruction:
virtual void g() {
Base::g();
// some work related to derived
}
Le fait qu'une fonction de la base puisse appeler une méthode virtuelle et que le contrôle soit transféré dans la classe dérivée est utilisé dans le modèle de conception de la méthode de modèle. Pour C++, il est plus connu sous le nom de Interface non virtuelle . Il est également largement utilisé dans la bibliothèque standard C++ (les tampons de flux C++, par exemple, ont des fonctions pub...
qui appellent des fonctions virtuelles qui font le travail réel. Par exemple, pubseekoff
appelle le protected seekoff
). J’en ai écrit un exemple dans cette réponse: Comment valider l’état interne d’un objet?
C'est le Derived :: g, sauf si vous appelez g dans le constructeur de Base. Étant donné que le constructeur de base est appelé avant que l'objet dérivé soit construit, Derived :: g ne peut pas être appelé logiquement car il peut manipuler des variables qui n'ont pas encore été construites.
pBase est un pointeur sur une base . pBase = new Derived renvoie un pointeur sur une base Derived - Derived is.
Donc, pBase = new Derived est valide.
pBase fait référence à une base, donc il considérera Derived comme s'il s'agissait d'une base.
pBase-> f () appellera Derive :: f ();
Ensuite, nous voyons dans le code que:
Dériver :: f () -> Base :: f () -> g() - mais quel g ??
Eh bien, il appelle Derive :: g () car c’est le g vers lequel "pBase" pointe.
Réponse: Dériver :: g ()
Eh bien ... je ne suis pas sûr que cela devrait compiler. Le suivant,
Base *pBase = new Derived;
est invalide sauf si vous avez:
Class Derived : public Base
Est-ce que tu veux dire? Si c'était ce que tu voulais dire,
pBase->f();
Ensuite, la pile d'appels irait comme ceci:
Derived::f()
Base::f()
Derived::g()
En réalité, l’exécution de votre code montre que Derived :: g () est appelé.
Comme vous l'avez défini g() comme virtuel, le plus dérivé g() sera recherché dans la table vtable de la classe et appelé quel que soit le type de code auquel votre code est en train d'accéder. il.
Voir le C++ FAQ sur les fonctions virtuelles .
La méthode de la classe dérivée sera appelée.
Cela est dû à l'inclusion de vtables dans des classes qui ont des fonctions virtuelles et des classes qui remplacent ces fonctions. (Ceci est également appelé répartition dynamique.) Voici ce qui se passe réellement: une vtable est créée pour Base
et une vtable est créée pour Derived
, car il n'y a qu'une seule vtable par classe. Étant donné que pBase
appelle une fonction virtuelle et remplacée, un pointeur sur vtable pour Derived
est appelé. Appelez-le d_ptr
, également appelé vpointer:
int main()
{
Base *pBase = new Derived;
pBase->d_ptr->f();
return 0;
}
Maintenant, le d_ptr appelle Derived::f()
, qui appelle Base::f()
, qui examine ensuite la table vtable pour voir quelle g()
utiliser. Parce que le vpointer ne connaît que g()
dans Derived
, c'est celui que nous utilisons. Par conséquent, Derived::g()
est appelé.
Je pense que vous essayez d'inventer Modèle de méthode modèle