J'ai ma réponse sous forme de conversation pour une meilleure lecture:
Pourquoi avons-nous besoin de fonctions virtuelles?
À cause du polymorphisme.
Qu'est-ce que le polymorphisme?
Le fait qu'un pointeur de base puisse également pointer vers des objets de type dérivé.
Comment cette définition du polymorphisme conduit-elle au besoin de fonctions virtuelles?
Eh bien, grâce à une liaison anticipée .
Qu'est-ce qu'une liaison anticipée?
La liaison anticipée (liaison au moment de la compilation) en C ++ signifie qu'un appel de fonction est fixé avant l'exécution du programme.
Donc...?
Donc, si vous utilisez un type de base comme paramètre d'une fonction, le compilateur ne reconnaît que l'interface de base, et si vous appelez cette fonction avec des arguments de classes dérivées, elle est coupée, ce qui n'est pas ce que vous voulez.
Si ce n'est pas ce que nous voulons faire, pourquoi est-ce autorisé?
Parce que nous avons besoin de polymorphisme!
Quel est l'avantage du polymorphisme alors?
Vous pouvez utiliser un pointeur de type de base comme paramètre d'une seule fonction, puis au cours de l'exécution de votre programme, vous pouvez accéder à chacune des interfaces de type dérivé (par exemple, leurs fonctions membres) sans aucun problème, en utilisant le déréférencement de cette seule pointeur de base.
Je ne sais toujours pas à quoi servent les fonctions virtuelles ...! Et c'était ma première question!
eh bien, c'est parce que vous avez posé votre question trop tôt!
Pourquoi avons-nous besoin de fonctions virtuelles?
Supposons que vous ayez appelé une fonction avec un pointeur de base, qui avait l'adresse d'un objet de l'une de ses classes dérivées. Comme nous en avons parlé ci-dessus, lors de l'exécution, ce pointeur est déréférencé, jusqu'ici tout va bien, cependant, nous nous attendons à ce qu'une méthode (== une fonction membre) "de notre classe dérivée" soit exécutée! Cependant, une même méthode (une qui a le même en-tête) est déjà définie dans la classe de base, alors pourquoi votre programme devrait-il prendre la peine de choisir l'autre méthode? En d'autres termes, je veux dire, comment pouvez-vous distinguer ce scénario de ce que nous avions l'habitude de voir se produire auparavant?
La réponse brève est "une fonction membre virtuelle dans la base", et une réponse un peu plus longue est que, "à cette étape, si le programme voit une fonction virtuelle dans la classe de base, il sait (se rend compte) que vous essayez d'utiliser polymorphisme "et va donc aux classes dérivées (en utilisant v-table , une forme de liaison tardive) pour trouver qu'une autre méthode avec le même en-tête, mais avec -pourvu - une implémentation différente.
Pourquoi une implémentation différente?
T'es la tête de l'articulation! Allez lire un bon livre !
OK, attendez, attendez, pourquoi se donner la peine d'utiliser des pointeurs de base, alors qu'il / elle pourrait simplement utiliser des pointeurs de type dérivé? Vous êtes le juge, tout ce mal de tête en vaut-il la peine? Regardez ces deux extraits:
//1:
Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();
// 2:
Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();
OK, bien que je pense que 1 est toujours meilleur que 2 , vous pouvez écrire 1 comme ceci:
//1:
Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();
et de plus, sachez que ce n'est encore qu'une utilisation artificielle de tout ce que je vous ai expliqué jusqu'à présent. Au lieu de cela, supposons par exemple une situation dans laquelle vous aviez une fonction dans votre programme qui utilisait respectivement les méthodes de chacune des classes dérivées (getMonthBenefit ()):
double totalMonthBenefit = 0;
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
totalMonthBenefit += x -> getMonthBenefit();
}
Maintenant, essayez de réécrire ceci, sans maux de tête!
double totalMonthBenefit=0;
Shop1* branch1 = &shop1;
Shop2* branch2 = &shop2;
Shop3* branch3 = &shop3;
Shop4* branch4 = &shop4;
Shop5* branch5 = &shop5;
Shop6* branch6 = &shop6;
totalMonthBenefit += branch1 -> getMonthBenefit();
totalMonthBenefit += branch2 -> getMonthBenefit();
totalMonthBenefit += branch3 -> getMonthBenefit();
totalMonthBenefit += branch4 -> getMonthBenefit();
totalMonthBenefit += branch5 -> getMonthBenefit();
totalMonthBenefit += branch6 -> getMonthBenefit();
Et en fait, cela pourrait être un exemple artificiel non plus!