Eu tenho minha resposta em forma de conversa para uma melhor leitura:
Por que precisamos de funções virtuais?
Por causa do polimorfismo.
O que é polimorfismo?
O fato de um ponteiro base também poder apontar para objetos de tipo derivado.
Como essa definição de polimorfismo leva à necessidade de funções virtuais?
Bem, através da ligação inicial .
O que é ligação antecipada?
A ligação antecipada (ligação em tempo de compilação) no C ++ significa que uma chamada de função é corrigida antes da execução do programa.
Assim...?
Portanto, se você usar um tipo base como parâmetro de uma função, o compilador reconhecerá apenas a interface base e, se você chamar essa função com argumentos de classes derivadas, ela será cortada, o que não é o que você deseja que aconteça.
Se não é o que queremos que aconteça, por que isso é permitido?
Porque precisamos de polimorfismo!
Qual é o benefício do polimorfismo, então?
Você pode usar um ponteiro de tipo base como parâmetro de uma única função e, no tempo de execução do seu programa, pode acessar cada uma das interfaces de tipo derivadas (por exemplo, suas funções de membro) sem problemas, usando a desreferenciação dessa única ponteiro base.
Ainda não sei para que servem as funções virtuais ...! E essa foi minha primeira pergunta!
bem, isso é porque você fez sua pergunta muito cedo!
Por que precisamos de funções virtuais?
Suponha que você chamou uma função com um ponteiro base, que tinha o endereço de um objeto de uma de suas classes derivadas. Como falamos sobre isso acima, no tempo de execução, esse ponteiro é desreferenciado, até agora tudo bem, no entanto, esperamos que um método (== uma função de membro) "de nossa classe derivada" seja executado! No entanto, um mesmo método (aquele que tem o mesmo cabeçalho) já está definido na classe base, então por que seu programa deveria se preocupar em escolher o outro método? Em outras palavras, quero dizer, como você pode diferenciar esse cenário do que costumávamos ver normalmente acontecer antes?
A resposta breve é "uma função membro virtual na base" e uma resposta um pouco mais longa é que "nesta etapa, se o programa vir uma função virtual na classe base, ele saberá (perceberá) que você está tentando usar polimorfismo "e, portanto, vai para as classes derivadas (usando v-table , uma forma de ligação tardia) para encontrar esse outro método com o mesmo cabeçalho, mas com - inesperadamente - uma implementação diferente.
Por que uma implementação diferente?
Sua cabeça de junta! Vá ler um bom livro !
OK, espere, espere, espere, por que alguém se incomodaria em usar ponteiros base, quando ele / ela poderia simplesmente usar ponteiros de tipo derivado? Você é o juiz, toda essa dor de cabeça vale a pena? Veja estes dois trechos:
// 1:
Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();
// 2:
Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();
OK, embora eu pense que 1 ainda seja melhor que 2 , você pode escrever 1 como este:
// 1:
Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();
além disso, você deve estar ciente de que esse é apenas um uso artificial de todas as coisas que eu expliquei até agora. Em vez disso, assuma, por exemplo, uma situação em que você tinha uma função em seu programa que usava os métodos de cada uma das classes derivadas respectivamente (getMonthBenefit ()):
double totalMonthBenefit = 0;
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
totalMonthBenefit += x -> getMonthBenefit();
}
Agora, tente reescrever isso, sem dores de cabeça!
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();
E, na verdade, esse também pode ser um exemplo artificial!