Primordial vs Virtuel
Quel est le but de l'utilisation du mot réservé virtuel en face de fonctions? Si je veux un enfant de la classe pour remplacer une fonction parent, je viens de déclarer la même fonction comme void draw(){}
.
class Parent {
public:
void say() {
std::cout << "1";
}
};
class Child : public Parent {
public:
void say()
{
std::cout << "2";
}
};
int main()
{
Child* a = new Child();
a->say();
return 0;
}
La sortie est de 2.
Donc encore une fois, pourquoi le mot réservé virtual
être nécessaire dans l'en-tête de say()
?
Merci beaucoup.
Vous devez vous connecter pour publier un commentaire.
C'est la question classique de la façon dont le polymorphisme fonctionne, je pense. L'idée principale est que vous voulez résumé le type spécifique de chacun des objets. En d'autres termes: Vous voulez être en mesure d'appeler l'Enfant des cas, sans savoir qu'il est un enfant!
Voici un exemple:
En supposant que vous avez la classe "Enfant" et de classe "Enfant2" et "Enfant3" vous voulez être en mesure de se référer à eux par le biais de leur classe de base (le Parent).
Comme vous pouvez l'imaginer, c'est très puissant. Il vous permet d'étendre le Parent autant de fois que vous le souhaitez et des fonctions qui prennent un Parent pointeur fonctionne toujours. Pour que cela fonctionne, comme d'autres parlent de vous avez besoin de déclarer la méthode virtuelle.
Si la fonction a été virtuel, alors vous pourriez le faire et encore obtenir la sortie "2":
Cela fonctionne parce qu'un
virtual
fonction utilise la réelle type alors qu'une fonction non virtuelle utilise le déclaré type. Lire sur le polymorphisme pour une meilleure discussion de pourquoi vous voulez le faire.Parent
est, disons,Shape
, et l'enfant est un type spécifique de la forme (comme unSquare
). Puis remplacersay
avec, par exemple,draw
. Voyez-vous, pourquoi ce serait utile? C'est exactement le même exemple que dans le cas des OP question, juste avec des mots différents.Essayer avec:
Sans
virtual
, à la fois avec l'impression '1'. Ajouter virtuel, et l'enfant va agir comme un Enfant, même s'il est visé par l'intermédiaire d'un pointeur vers unParent
.Si vous n'utilisez pas le
virtual
mot-clé, vous n'êtes pas primordial, mais rahter définir une autre méthode dans la classe dérivée qui permet de masquer la méthode de classe de base. C'est, sans levirtual
,Base::say
etDerived::say
sont sans rapport entre eux, outre le nom de la coïncidence.Lorsque vous utilisez le mot-clé virtuel (requis dans la base, facultatif dans la classe dérivée), vous pouvez dire au compilateur que les classes qui dérivent de cette base sera en mesure de remplacer la méthode. Dans ce cas,
Base::say
etDerived::say
sont considérés comme des remplacements de la même méthode.Lorsque vous utilisez une référence ou un pointeur vers une classe de base pour appeler une méthode virtuelle, le compilateur va ajouter le code approprié afin que la final overrider est appelé (le remplacer dans la plupart des dérivés de la classe qui définit la méthode de la hiérarchie du béton instance en cours d'utilisation). Notez que si vous n'utilisez pas de référence/pointeur mais les variables locales, le compilateur ne peut résoudre à l'appeler et il n'a pas besoin d'utiliser le virtual expédition mécanisme.
Bien je l'ai testé moi-même, parce qu'il y a beaucoup de choses que nous pouvons penser:
de sortie:
Je pense que une bonne, simple et bref, la réponse pourrait ressembler à ça (parce que je pense que les gens qui peuvent comprendre plus peut mémoriser moins donc besoin pour faire court et simple explication):
Méthodes virtuelles vérifie les DONNÉES de l'instance sur laquelle pointe le pointeur, alors que les méthodes classiques ne sont pas ainsi, l'appel de la méthode procès correspondant au type spécifié.
Le point de cette fonction est la suivante: supposons que vous disposez d'un tableau de de. Le tableau peut contenir de B, de C, (ou même les types dérivés.). si vous souhaitez de manière séquentielle appel à la même méthode de tous les cas, vous devez appeler chacun vous surchargé.
Je trouve cela assez difficile à comprendre, et évidemment toute C++ cours devrait expliqué comment cela est réalisé, car la plupart du temps vous êtes simplement appris à propos des fonctions virtuelles, vous les utilisez, mais jusqu'à ce que vous comprenez comment le compilateur de les comprendre et comment l'exécutable sera de gérer les appels, vous êtes dans l'obscurité.
La chose à propos de VFtables est que je n'ai jamais été expliqué quel genre de code, il ajoute, et c'est évidemment là où C++ nécessite beaucoup plus d'expérience que C, et ce pourrait être la raison principale de C++ a été étiqueté comme "lent" dans ses premiers jours: en fait, c'est puissant, mais comme tout, il est puissant, si vous savez comment l'utiliser, ou bien vous venez de "coup l'ensemble de votre jambe off".
Lorsque vous utilisez le mot-clé virtuelle, une fonction virtuelle table est créée pour localiser les bonnes méthodes dans une instance. Alors, même si le dérivé de l'instance est indiqué par une classe de base pointeur, il faudra encore trouver la bonne mise en œuvre de la méthode.
C'est un aspect très important de la programmation en c++-- presque à chaque interview que j'ai été, je me pose cette question.
Qu'advient-il si vous changez vos principales de:
Aussi, il vaut la peine de comprendre ce qu'est une vtable est.