Appel de fonctions virtuelles à l'intérieur des fonctions membres
-
23-09-2019 - |
Question
Je lis Penser en C ++ par Bruce Eckel. Dans le chapitre 15 (Volume 1) sous la rubrique " Comportement des fonctions virtuelles à l'intérieur constructeur ", il va
Qu'est-ce qui se passe si vous êtes dans un constructeur et que vous appelez un virtuel une fonction? A l'intérieur d'un membre ordinaire fonction, vous pouvez imaginer ce qui va arriver - l'appel virtuel est résolu à l'exécution parce que l'objet ne peut pas savoir si elle appartient à la classe la fonction de membre est, ou quelque classe dérivée de celle-ci. Pour la cohérence, vous pourriez penser que c'est ce qui devrait se produire à l'intérieur constructeurs.
Ici, Bruce essayant d'expliquer que lorsque vous appelez une fonction virtuelle à l'intérieur du constructeur d'un objet, le polymorphisme n'est pas exposé à savoir la fonction classe actuelle ne sera appelé et il ne sera pas une autre version classe dérivée de cette fonction. Ceci est valable et je peux le comprendre, puisque le constructeur d'une classe ne saura pas à l'avance si elle est en cours d'exécution pour elle ou pour la création de someother objet dervied. De plus, si elle le fait, ce sera l'appel de fonctions sur un objet partiellement créé, ce qui est désastreux.
Alors que ma confusion se soudainement à cause de la première phrase où il dit à propos de la fonction membre ordinaire, où il dit l'appel virtuel sera résolu @ l'exécution. Mais attendez, à l'intérieur une fonction membre d'une classe, lorsque vous appelez une autre fonction (que ce soit virtuel ou non virtuel) sa propre version de classe ne sera appelée, non? Par exemple.
class A
{
virtual void add() { subadd(); }
virtual subadd() { std::cout << "A::subadd()\n"; }
};
class B : public A
{
void add() { subadd(); }
void subadd() { std::cout << "B::subadd()\n"; }
};
Dans le code ci-dessus, A::add()
lorsqu'un appel à subadd()
est fait, il va toujours A::subadd()
d'appel et même pour B
aussi bien, non? Alors, qu'est-ce qu'il veut dire par « l'appel virtuel est résolu lors de l'exécution parce que l'objet ne peut pas savoir si elle appartient à la classe la fonction membre est, ou une classe dérivée de celle-ci »?
est-il l'expliquer par rapport à un appel via un pointeur de classe de base ? (Je pense vraiment si) Dans ce cas, il ne doit pas être écrit « A l'intérieur d'une fonction de membre ordinaire »; de ma compréhension à ce jour, tout appel d'une fonction membre à l'intérieur une autre fonction membre de la même classe n'est pas polymorphes, s'il vous plaît me corriger si je suis se tromper.
La solution
Vous avez tort - une autre classe dérivée pourrait remplacer certaines des fonctions virtuelles, ce qui signifie qu'un appel statique serait erroné. Donc, pour prolonger votre exemple:
class C : public B
{
public:
// Not overriding B::add.
void subadd() { std::cout << "C::subadd\n"; }
};
A *a = new C;
a->add();
Cette dynamique appelle B::add
, qui appelle à son tour dynamiquement C::subadd
. Un appel statique B::subadd
serait erroné, car le type dynamique est C
et C
remplace la fonction.
Dans votre exemple, la duplication des A::add
comme B::add
est inutile -. Toutes les deux appelleront subadd
polymorphically quel que soit le type dynamique de l'objet
Autres conseils
lorsque vous appelez une autre fonction (que ce soit virtuel ou non virtuel) sa propre version de classe ne sera appelée, non?
Sorry, wrong. Le constructeur est l'exception. Dans le cas contraire, vous avez affaire à un objet entièrement construit pour lequel le polymorphisme complet est en place. Dans votre exemple plus tard (si B hérite de A), ce qu'on appelle le B::subadd()
(il suffit de prendre le code pour un essai routier: qui est vraiment la meilleure façon d'apprendre comment fonctionne le langage de programmation).
Le subadd();
d'appel dans vos exemples est vraiment le this->subadd();
d'appel. Dans A::add()
, le type de this
est A*
, mais this
peut pointer vers un objet C
(en supposant que C dérive d'un trop). Lors de la compilation A::add()
, le compilateur ne peut pas savoir quelles fonctions virtuelles sont remplacées dans class C
. Le this->subadd();
d'appel dans A::add()
peut réellement appeler C::subadd()
. Ainsi, le compilateur n'a pas d'autre choix que de mettre dans un appel virtuel, à résoudre lors de l'exécution quand il sait où les points de this->
à.