#include <iostream>
using namespace std;
class Pessoa {
public:
virtual void falar() { cout << "Sou uma pessoa." << endl; }
};
class Estudante : public Pessoa {
public:
void falar() override { cout << "Sou um estudante." << endl; }
};
int main() {
Pessoa* p = new Estudante();
p->falar();
}
O que será impresso?
#include <iostream>
using namespace std;
class Pessoa {
public:
virtual void falar() { cout << "Sou uma pessoa." << endl; }
};
class Estudante : public Pessoa {
public:
void falar() override { cout << "Sou um estudante." << endl; }
};
int main() {
Pessoa* p = new Estudante();
p->falar();
}
Passo 1
O enunciado pede: “O que será impresso?” e nos dá o código C++ abaixo. Informações relevantes extraídas do enunciado:
- Há uma classe
Pessoacom método públicovirtual void falar()que fazcout << "Sou uma pessoa." << endl;. - Há uma classe
Estudanteque herdapublic Pessoae que implementavoid falar() overridefazendocout << "Sou um estudante." << endl;. - No
mainé criada uma variávelPessoa* p = new Estudante();— ou seja, um ponteiro paraPessoaque aponta para um objetoEstudante. - Em seguida é chamada
p->falar();.
A pergunta é: qual linha aparecerá na saída quando o programa for executado?
Passo 2
Entender o que vai acontecer exige saber o que significa que o método em
Pessoa é virtual e que Estudante override esse método. Vou explicar isso devagar, passo a passo, como se fosse um truque de mágica que o compilador faz por trás das cortinas.- Quando um método é marcado como
virtualem C++, o compilador cria para cada objeto (na prática, para cada tipo com métodos virtuais) uma tabela interna de funções (chamada de vtable) e coloca no objeto um ponteiro para essa tabela (vptr). Essa tabela diz “se alguém chamar este método virtual neste objeto, chame esta função concreta”. - O importante: a ligação entre a chamada do método e a função concreta que será executada é feita em tempo de execução (runtime), não apenas em tempo de compilação. Isso é chamado de ligação dinâmica (dynamic dispatch) ou polimorfismo.
- A palavra-chave
overrideemEstudantesó serve para garantir ao compilador que você está realmente substituindo (overriding) um método virtual da base; se houver erro de assinatura, o compilador avisa. Mas o comportamento de chamada em tempo de execução vem dovirtualna classe base.
Passo 3
Agora apliquei isso ao código concreto:
Pessoa* p = new Estudante();cria um objeto cujo tipo real (dinâmico) éEstudante, mas a variável que o referencia tem tipo estáticoPessoa*.- Quando fazemos
p->falar();, por causa defalar()servirtualna classe base, o mecanismo de tempo de execução olha na vtable do objeto real (que é umEstudante) e chama a implementação correspondente doEstudante. - Se
falar()não tivesse sidovirtualemPessoa, então a chamadap->falar()usaria ligação estática e chamariaPessoa::falar(). Mas como évirtual, o método do objeto derivado é chamado.
Passo 4
O método que será executado é, portanto, o de
Estudante:Estudante::falar()executacout << "Sou um estudante." << endl;.endltermina a linha e esvazia o buffer de saída, então a saída que aparece no terminal é exatamente a linhaSou um estudante.seguida de quebra de linha.
Passo 5
Resumo prático e dica para prova (estou torcendo por você!): quando tiver uma variável de tipo base apontando para um objeto derivado e o método for
virtual na base, a chamada vai para a versão do derivado. É o comportamento de polimorfismo que vale na hora da prova. Se quiser praticar rápido: remova virtual e veja que a saída muda para a versão da classe base — é uma diferença simples de testar para fixar a ideia.Resposta
Sou um estudante.