J'apprends l'héritage dans C ++ 11 et j'ai constaté que si une classe dérivée a redéfini d'un nom de fonction virtuel mais avec un prototype différent, un pointeur de classe de base attribué à un pointeur à la classe dérivée ne peut accéder à la Version de la classe de base de la fonction. La fonction de version dérivée n'est pas accessible. Je me demande pourquoi cela se produit.
Dragon foo; Enemy* pe = &foo; pe->describe(); // Enemy foo.describe(1); // Dragon pe->describe(1); // no matching function, candidate is Enemy::describe()
3 Réponses :
fonctionne avec le même nom, mais des signatures différentes sont des fonctions essentiellement différentes. P>
En déclarant Vous ne pouvez pas appeler vide virtuel Décrivez (INT DUMMY) CODE> Dans votre classe CODE> DRAGON CODE>, vous avez déclaré une nouvelle fonction virtuelle, qui ne remplace pas l'original (
vide virtuel décris () code> dans
ennemi code>). Vous pouvez seulement remplacer les fonctions virtuelles avec la même signature. P>
décrivec (1) code> sur un pointeur sur
ennemi code> car C ++ appelle fonction en fonction du type d'heure de compilation de l'instance (bien qu'un tel appel puisse être expédié de manière dynamique à Appelez la méthode de remplacement réelle). P>
Mais pourquoi la fonction est-elle expédiée à l'heure de la compilation mais pas d'exécution? À partir de ma compréhension, si la fonction est expédiée pendant l'exécution, le programme devrait pouvoir trouver un décrire code> dans
SRONGRAGE code> 'S Tablevis, bien qu'il soit sans rapport avec le
Décrivez code> dans
ennemi code>. Est-ce vrai?
@LUCIDASEASE La fonction est présente dans la table de table, mais on ne peut pas accéder à partir d'un pointeur sur ennemi code>, car
ennemi code> n'a pas cette fonction de membre (il en a un avec le même nom , mais pas la même fonction de membre).
@Lucidase également, réfléchissez du point de vue du compilateur. Si vous avez un autre type, dites, soldat code> qui dérive également de
ennemi code>, qui a la méthode code> décrire code>, mais avec la signature
décrire ( ) code> (sans
int code>). Vous donnez au compilateur un pointeur à
ennemi code> et appelez
décrivez (1) code> dessus. Comment le compilateur voudrait-il savoir au compilateur s'il a
dragon code> type ou
soldat code> type? Les méthodes virtuelles sont un bon moyen de créer une interface Solid B> pour appeler des appels de fonctions, pour ne pas improviser à différents paramètres.
Mais lorsque la fonction est correctement annulée, le programme peut accéder à code> DRAGON code> S à partir d'un "code> ennemi * code> pointeur. Et d'après ce que j'ai appris, il semble que la table / expédition dynamique est exactement les mécanismes pour faire face aux situations où le type n'est pas connu pendant la compilation.
@Lucidase Ce que vous suggère est théoriquement possible (preuve: il y a dynamic_cast code> en C ++), mais ils ne sont tout simplement pas autorisés dans votre contexte.
en C ++, fonctions qui ont le même nom, mais différents paramètres sont des fonctions totalement indépendantes, C'est exactement la même chose que si vous appeliez la fonction dans la classe de base "Apple", et celle de la classe dérivée "banane". Comme il n'existe aucune fonction "banane" dans la classe de base, vous ne pouvez pas évidemment l'appeler dans la classe de base. La fonction de banane dans la classe dérivée ne remplace évidemment pas la fonction de la classe de base. P>
Je sais aussi que la redéfinition d'un nom de la fonction dans la classe dérivée
va cacher toutes les fonctions du même nom dans la classe de base. p>
blockQuote>
c'est incorrect. Il ne la cache que s'il a le même nom, mais également des paramètres identiques (et des qualificatifs, s'il n'y en a pas ou n'est pas). P>
En fait, vous avez:
class Dragon : public Enemy { public: using Enemy::describe; // Unhide Enemy::describe() virtual void describe(int dummy) { std::cout << "Dragon"; } };
Pointants / Références sur Pointants / Références sur L'envoi virtuel est effectué avec type d'exécution. p> SO P> Enemy CODE> VOIR UNIQUEMENT Voir
NOID ENNEMY :: Décrivez () CODE> P> LI>
Dragon Code> seulement Voir
Void Dragon :: Décrivez (INT) CODE> (mais pourrait avoir explicitement accès à
ennemi annulé :: décrit () code>). p> li>
ul>
Dragon foo;
Enemy* pe = &foo;
foo.describe(); // KO: Enemy::describe() not visible (1)
foo.Enemy::describe(); // OK: Enemy::describe()
foo.describe(1); // OK: Dragon::describe(int)
pe->describe(); // OK: Enemy::describe()
pe->describe(1); // KO: No Enemy::describe(int)
pe->Dragon::describe(1);// KO: Dragon is not a base class of Enemy
Mais pourquoi pe-> décrivez code> est la liaison statique (envoi) au lieu de la liaison dynamique? J'ai supposé que pendant l'exécution, lorsque le programme tente d'envoyer une méthode virtuelle, il examinera la table de fonction virtuelle de l'objet. Dans ce cas, il est
Dragon Code> S Tablevisible.
Void (C :: *) Décrivez () CODE> et
VOID (C :: *) Décrivez (int) code> sont 2 signatures différentes. Dragon Ttable aurait 2 entrées, une pour
ennemi :: décrivant (() code> (ce qu'elle ne remplace pas, alors aurait la même valeur qu'un
ennemi code>), un pour
dragon :: décrit (int) code>.
PE code> utilise l'API code> ennemi code> et la méthode d'accès ne fait pas partie de cette API.
J'ai mis à jour mon hypothèse sur ce qui se passe dans l'exemple.