Teoria

E aí, aqui é o Juan do Responde Aí, e agora vamos falar de mais um pilar da orientação a objetos, o Polimorfismo.

O que é polimorfismo?

Polimorfismo é um desses conceitos que são mais difíceis de explicar do que de fazer.

Polimorfismo significa “muitas formas”, e é exatamente isso que ele significa em C++. O polimorfismo é a capacidade de um objeto ou método assumir formas diferentes.

Mas o que isso quer dizer? Quando fazemos uma classe filha ela herda os métodos de uma classe mãe. Mas as vezes, um método herdado não é adequado, ou deveria agir de outra forma para uma certa classe filha específica.

A solução é usar os polimorfismos para escrever um novo método, porém usando o mesmo nome do método herdado. O usuário ainda pode usar o mesmo método, porém, sem saber que por baixo dos panos, o comportamento do método é diferente!

Ou seja, de maneira prática, o polimorfismo em C++ é a capacidade de reescrever um método que foi herdado.

Mas qual a vantagem do polimorfismo? A vantagem é que podemos escrever uma classe mãe com um método genérico bem simples que funcione com a maioria das classes filhas. E pras classes filhas que tiverem algo de especial, podemos usar polimorfismos para adaptar o conteúdo da classe mãe.

O polimorfismo é parecido com a sobrecarga que já estudamos. Mas existe uma diferença essencial: enquanto a sobrecarga representa variações de um método, o polimorfismo é a substituição de um método herdado, por um novo método com mesmo nome.

Métodos virtuais

Antes de a gente falar dos polimorfismos, a gente precisa conhecer mais uma palavra-chave do C++ o v i r t u a l . Essa palavra-chave deve ser escrita nos membros da classe mãe que vão sofrer polimorfismo:

v i r t u a l   t i p o   n o m e D o M e t o d o (   )

Usar a palavra v i r t u a l não é obrigatório. Porém, é aconselhável utiliza-lo em todos os métodos em que você pretende aplicar polimorfismo

O v i r t u a l deixa o código mais fácil de ler e entender, e facilita o uso dos ponteiros com classes que usam polimorfismo, e em situações em que um método faz chamada para um outro método que sofre polimorfismo. Usar a palavra-chave v i r t u a l deixa claro pro programador e pro compilador que esse método sofrerá polimorfismo e será reescrito em classes filhas.

Usando polimorfismo

Para executar um polimorfismo é só escrever dentro da classe filha um método com o nome igual ao do método que está sendo substituído. Vamos fazer um exemplo bem simples.

O primeiro passo é criar uma classe mãe que tem um método virtual. No exemplo, criamos a C l a s s e M a e que tem o método virtual F a z e r C o i s a (   ) , esse vai ser o método que sofrerá polimorfismo.

Dentro da C l a s s e F i l h a vamos executar um polimorfismo. Para isso, é só a gente escrever um novo método com o mesmo nome F a z e r C o i s a (   ) e pronto! O polimorfismo está feito.

É como eu falei, fazer polimorfismo é mais fácil do que explicar polimorfismo. E pra usar as classes é só criar objetos e utilizar os métodos normalmente:

Viu só. A classe mãe e a classe filha possuem um método com o mesmo nome mas que efetuam atividades diferente!

Classes abstratas

Uma coisa interessante dos métodos virtuais é que eles podem ser completamente vazios. São os métodos virtuais puros, que são declarados colocando um “ = 0 ” na declaração do método:

v i r t u a l   t i p o   n o m e M e t o d o   = 0 ;

Classes que possuem pelo menos um método virtual puro são chamadas de classes abstratas. E se todos os métodos da classe forem virtuais puros, então temos um interface.

Duas coisas vão acontecer quando você criar uma classe abstrata:

  1. Você não pode instanciar um objeto de uma classe abstrata. Isso gera um erro!
  2. Uma classe herdeira de uma classe abstrata deve ter todos os métodos virtuais sobrescritos através de polimorfismo.

Ou seja, você não consegue usar uma classe abstrata diretamente, porque o propósito das classes abstratas é servir de protótipos para criar classes filhas concretas. As classes abstratas servem de régua pra criar classes derivadas que sigam um determinado padrão.

Por outro lado, uma classe concreta é uma classe que é útil diretamente. Todas as classes que nós já fizemos até aqui eram classes concretas.

Exemplo de polimorfismo

Vamos ver agora um exemplo mais complexo de um programa de cadastro de funcionários.

A gente criou uma classe mãe F u n c i o n a r i o , que tem os atributos n o m e , s a l a r i o e s e t o r e o método   r e c e b e r _ s a l a r i o (   ) , e criamos três classes filhas E n g e n h e r i o , V e n d e d o r e G e r e n t e :

O método r e c e b e r _ s a l a r i o simplesmente utiliza o atributo s a l a r i o , o que funciona sem problemas nas classes E n g e n h e i r o e G e r e n t e .

Porém, a remuneração do vendedor é composta de duas coisas: o salário mensal fixo mais uma comissão sobre o valor vendido. A solução é usar polimorfismo na classe filha V e n d e d o r .

Primeiro vamos fazer um código simples para a classe mãe F u n c i o n a r i o . Repara no detalhe: a função r e c e b e _ s a l a r i o vai sofrer polimorfismo. Então, r e c e b e _ s a l a r i o deve ser uma função virtual. A primeira etapa é utilizar o v i r t u a l nos métodos que sofrerão polimorfismos.

Em seguida, vamos desenvolver a classe V e n d e d o r que herda os membros de F u n c i o n a r i o . Para efetuar uma herança a gente usa o operador : e escreve p u b l i c   n o m e C l a s s e M a e

Em seguida, dentro da classe V e n d e d o r vamos adicionar o atributo v a l o r V e n d i d o :

E adicionar o método e f e t u a r _ v e n d a (   ) que recebe um parâmetro que corresponde ao valor vendido, atualiza o atributo v a l o r V e n d i d o e exibe uma mensagem pro usuário.

Ok! Até aqui tudo que fizemos foi herdar uma classe e adicionar novos membros na classe filha. Agora, vamos executar o polimorfismo! Executar o polimorfismo é só a gente reescrever o método virtual dentro da classe filha.

O novo método r e c e b e _ s a l a r i o vai primeiro calcular uma comissão de 10 % para o vendedor. E depois vai imprimir o salário e o também a comissão!

E pronto! É só isso! A gente executou o polimorfismo!

Se aprofundando nos detalhes do Polimorfismo.

  1. O uso de métodos virtuais é recomendado, mas não é obrigatório!
  2. É perfeitamente possível aplicar polimorfismo em um método comum, ou seja, em um método que não tem a palavra v i r t u a l . Porém, usar métodos virtuais facilita o trabalho com os ponteiros e em casos que um método da classe mãe executa um método com polimorfismo.

  3. Métodos virtuais geram herdeiros virtuais.
  4. Um outro ponto é que quando um método virtual é herdado, todos os polimorfismos deste método serão considerados virtuais (mesmo sem usar a palavra chave v i r t u a l ).

    Isso quer dizer que um método virtual permanecerá virtual em todas as classes herdeiras e descendentes.

  5. Criar um destrutor virtual é uma boa prática quando fazemos alocação dinâmica.

E é isso pessoal! Agora é só fazer uns exercícios de fixação.

Métodos virtuais

Usando polimorfismo

Classes abstratas

Exemplo de polimorfismo

Se aprofundando nos detalhes do Polimorfismo.

Exercícios Resolvidos

Exercício Resolvido #1

O que é polimorfismo? Como executamos um polimorfismo em C++?

Passo 1

O polimorfismo é a capacidade de um objeto ou método assumir formas diferentes. Isso é, quando um mesmo nome pode ser usado para coisas diferentes, dependendo do contexto.

No contexto de herança, o polimorfismo é a capacidade de uma classe filha substituir um método herdado da classe mãe, por um novo método com comportamento diferente e mesmo nome. Ou seja, o polimorfismo é a substituição de um método herdado, por um novo método com mesmo nome.

No C++ a gente executa um polimorfismo simplesmente escrevendo um novo método dentro da classe filha que tenha o mesmo nome de um método já existente na classe mãe. Para executar um polimorfismo é só escrever dentro da classe filha um método com o nome igual ao do método que está sendo substituído

Uma característica interessante do C++ são os métodos virtuais, que são métodos que desde o começo são pensados para sofrer polimorfismo. Para criar um método virtual é só usar a palavra chave v i r t u a l

Resposta

Ei, a resposta está no passo a passo :)

Exercício Resolvido #2

O que é um método virtual? Qual a diferença entre uma classe concreta, classe abstrata e interface.

Passo 1

Um método virtual é um método que foi pensado desde o começo para sofrer polimorfismo. Para criar um método virtual basta utilizar a palavra-chave v i r t u a l no momento de declarar o método. Usando métodos virtuais nós facilitamos a leitura do código, e facilita o uso de ponteiros com classes derivadas.

Um método virtual funciona como um método comum, recebe parâmetros, efetua operações e pode retornar um resultado.

Porém, é possível criar métodos virtuais completamente vazios. Esses são os métodos virtuais puros. Os métodos virtuais puros não efetuam nenhuma atividade, e servem simplesmente para “guardar espaço” numa classe mãe. Esse método deve obrigatoriamente sofrer polimorfismo.

Uma classe que possui ao menos um método virtual puro é chamada de classe abstrata. Classes abstratas não podem gerar objetos. Se todos os métodos de um classe forem virtuais puros, então é chamado de interface. As classes abstratas e interfaces são desde o começo pensadas para funcionar como classes bases para gerar classes filhas que serão utilizáveis.

Caso uma classe não possua nenhum método virtual puro, então ela é chamada de classe concreta. Essas são as classes que podem ser utilizadas diretamente gerando novos objetos.

Resposta

Ei, a resposta está no passo a passo :)

Exercício Resolvido #3

Observe a classe V e t o r 2 D abaixo. Use herança e polimorfismo para criar a classe V e t o r 3 D

A classe acima utiliza o cabeçalho < c m a t h >

Passo 1

Vamos nessa, pessoal.

A questão já foi bacana com a gente e entregou a classe mãe prontinha! Então tudo que temos que fazer é criar a classe filha.

A classe mãe representar um vetor de duas dimensões, e já possui as coordenadas x e y e o método para calcular o módulo desse vetor.

Para criar uma classe para vetores de três dimensões a gente pode herdar a classe V e t o r 2 D e ganhamos sem esforço algum os atributos x e y , e a gente só vai precisar adicionar o atributo z .

Já o método m o d u l o terá de sofrer polimorfismo. Afinal de contas, na classe mãe tanto a mensagem exibida quanto o cálculo só funcionam para vetores de duas dimensões. Então vamos usar polimorfismo para substituir esse método para uma versão tridimensional.

Mas primeiro, vamos escrever o cabeçalho da questão, que vai precisar incluir o < c m a t h >

E também já vamos copiar o código da classe mãe pra dentro do nosso código:

Passo 2

Certo. Vamos agora desenvolver a nossa classe.

Primeiro, vamos declarar a classe V e t o r 3 D que herda a classe V e t o r 2 D . Lembre-se para criar uma classe com herança é assim:

c l a s s   N o m e F i l h a   : p u b l i c   N o m e M a e

Beleza! Agora nós temos os atributos x e y e o método m o d u l o ( ) a nossa disposição. O próximo passo é adicionar o atributo z :

Show! Agora, a gente tem que lembrar que o método m o d u l o ( ) não é adequado para vetores de três dimensões. Então vamos executar polimorfismo para adaptar o método.

Para executar polimorfismo não tem segredo. É só a gente escrever um novo método com nome m o d u l o ( ) dentro da nossa classe filha!

Então, dentro de V e t o r 3 d vamos escrever a classe m o d u l o ( ) . Nesse método “polimorfado” a gente vai imprimir uma mensagem utilizando os três atributos x , y e z . E em seguida, vamos escrever uma equação que calcule o módulo de um vetor tridimensional.

m o d u l o 3 D = x 2 + y 2 + z 2

E prontinho! A classe filha e o polimorfismos estão feitos.

Passo 3

Agora é só a gente testar pra ver se deu tudo certo:

Pra testar, é só a gente criar um objeto de cada classe.

Vamos preencher os atributos do vetor bidimensional e executar o método módulo:

E fazer a mesma coisa com o vetor 3D:

E prontinho! Rodando o código vemos que deu tudo certo:

Resposta

Exercício Resolvido #4

Observe a classe P a c i e n t e

Crie uma classe derivada de P a c i e n t e chamada A s s e g u r a d o que possui os atributos s t r i n g   S e g u r a d o r a e i n t   N u m S e g u r o . Na classe A s s e g u r a d o   crie um construtor para a classe e métodos getters para os atributos, implemente o método P r i n t   que mostre os valores de todos os atributos.

Passo 1

E aí, beleza?! Vamos resolver esse exercício!

A questão entregou pra gente uma classe e pede pra gente criar uma filha. A nova classe terá novos métodos e atributos.

Mas a chave da questão é que a classe filha vai ter um novo método chamado P r i n t (   ) , ou seja, vamos executar polimorfismo neste método.

Mas antes de começar, vamos escrever a classe da questão dentro do nosso código:

Vamos analisar esse código antes de prosseguir. A classe possui um atributo protegido e dois métodos públicos.

O atributo é chamado N o m e que, podemos presumir, vai armazenar o nome do paciente.

O primeiro método é simplesmente um getter que apenas retorna o valor do atributo N o m e .

E o segundo método é o P r i n t (   ) que imprime um texto com os dados do paciente, nesse caso, apenas o atributo nome. Note que esse é um método virtual, isso quer dizer que ele foi pensado desde o começo para sofrer polimorfismo.

Passo 2

Vamos começar criando a classe A s s e g u r a d o herdando a classe base P a c i e n t e . Lembre-se, a gente executa uma herança assim:

c l a s s   N o m e F i l h a   : p u b l i c   N o m e M a e

No código fica assim:

Agora os atributos e métodos da classe mãe foram copiados para a classe filha.

Em seguida, vamos adicionar na classe filha os seus novos atributos: uma string S e g u r a d o r a que armazena o nome da seguradora e o inteiro N u m S e g u r o que armazena o número do seguro.

Agora vamos desenvolver os métodos. Primeiro, precisamos inicializar os atributos da classe, e pra isso vamos usar um construtor.

Note que a classe mãe não possui um construtor. Isso quer dizer que a gente não precisa chamar o construtor da classe mãe. Então, vamos simplesmente fazer um construtor simples para a classe filha.

Outro detalhe é que o atributo N o m e é protegido. E isso quer dizer que a classe filha tem acesso direto a esse atributo, então podemos modifica-lo sem problemas.

Para desenvolver o construtor, é só você lembrar que construtores são funções sem tipo que têm o mesmo nome da classe:

O próximo passo é criar os métodos getters para que seja possível acessar os novos atributos privados:

Belezinha, a classe está quase pronta. Só falta desenvolver o método P r i n t (   )

Passo 3

Ainda dentro da nossa classe, vamos dar desenvolver o método P r i n t   .

A classe A s s e g u r a d o já têm um método chamado P r i n t   que foi herdado da classe mãe. Porém, a versão que foi herdada imprime apenas o atributo N o m e .

A solução é executar um polimorfismo! Nós vamos reescrever uma nova função com o nome P r i n t   .

Primeiro a gente declarou o método na linha 34, perceba que não é preciso escrever a palavra chave v i r t u a l .

Depois, nas linhas 35 a 39 a gente escreveu novas instruções para o método P r i n t   !

Polimorfismo é super tranquilo de fazer. É só sobrescrever o método antigo com um novo método usando o mesmo nome. 😊

E pronto! A classe está concluída.

Passo 4

Show! Agora vamos testar pra ver se deu tudo certo.

Vamos criar um objeto da classe A s s e g u r a d o , e usando o construtor vamos preencher os valores dos atributos. Em seguida vamos executar o método P r i n t :

E o resultado é esse:

Resposta

Exercício Resolvido #5

Observe a classe P a c i e n t e

Crie uma classe derivada de P a c i e n t e chamada N a o A s s e g u r a d o que possui os atributos f l o a t   C o n s u l t a , i n t   B a n c o , i n t   C h e q u e . Na classe N a o A s s e g u r a d o   crie um construtor para a classe e métodos getters para os atributos, e implemente o método P r i n t   que mostre os valores de todos os atributos.

Passo 1

Vamos que vamos, pessoal!

Essa questão já deu pra gente a classe mãe e pediu pra criar uma classe filha. O detalhe da questão é que ela pede pra gente criar um método P r i n t ( ) dentro da classe filha: isso é um polimorfismo!

Vamos escrevendo a classe da questão dentro do nosso código:

Essa classe possui um atributo protegido e dois métodos públicos. O atributo N o m e que deve armazenar o nome do paciente, o método G e t N o m e que retorna o valor do atributo N o m e e o método virtual P r i n t (   ) que imprime um texto com os dados do paciente.

O método P r i n t ( ) é virtual, isso quer dizer que desde o começo ele foi pensado para sofrer polimorfismo.

Passo 2

Vamos recordar como se cria uma herança:

c l a s s   N o m e F i l h a   : p u b l i c   N o m e M a e

Agora, vamos criar uma classe N a o A s s e g u r a d o herdando a classe base P a c i e n t e :

Agora os atributos e métodos da classe mãe foram copiados para a classe filha. O próximo passo é adicionar os novos atributos que são exclusivos da classe filha:

Para inicializar os atributos da classe vamos desenvolver um construtor. Lembre-se que construtores são funções sem tipo que têm o mesmo nome da classe.

Fique atento a dois detalhes: o atributo N o m e é protegido e por isso podemos acessá-lo sem dificuldades, e o segundo é que a classe mãe não possui um construtor e por isso a gente não precisa chamar o construtor da classe mãe.

O próximo passo é criar os métodos getters para que seja possível acessar os novos atributos privados:

Belezinha, a classe está quase pronta. Só falta desenvolver o método P r i n t (   )

Passo 3

A classe N a o A s s e g u r a d o herdou o método P r i n t   da classe mãe. Mas da forma como foi herdado, esse método não consegue utilizar todos os atributos da classe N a o A s s e g u r a d o

A melhor solução é executar um polimorfismo que consiste em reescrever o método P r i n t   .

A vantagem de usar um polimorfismo é que a classe filha vai continuar com uma estrutura semelhante a da classe mãe. O que pode ser super útil quando a gente utiliza ponteiros, ou quando existem outros métodos que fazem chamada ao método “polimorfado”.

Para executar o polimorfismo, é só declarar o método P r i n t (   ) novamente, e nem é preciso usar a palavra chave v i r t u a l . Depois é só escrever o código que a gente quiser dentro do método “polimorfado”

Nesse caso, a gente vai adicionar vários c o u t para imprimir cada um dos atributos.

Só pra esclarecer “polimorfado” não é uma palavra de verdade 😂😂! Então não vai escrever isso na sua prova não 🤣🤣🤣

Passo 4

Show! Agora vamos testar pra ver se deu tudo certo.

Vamos criar um objeto da classe N a o A s s e g u r a d o , e usando o construtor vamos preencher os valores dos atributos. Em seguida vamos executar o método P r i n t :

E o resultado é esse:

Resposta

Exercício Resolvido #6

Implemente uma classe abstrata de nome F o r m a onde são declarados os métodos virtuais puros f l o a t   c a l c u l a r A r e a e f l o a t   c a l c u l a r P e r i m e t r o .

Passo 1

E aí, galera.

Antes de mais nada, a gente precisa lembrar que um método virtual puro é um tipo de método especial que é vazio. A única utilidade de um método virtual puro é “guardar o lugar” dentro da classe mãe, para que uma classe filha efetue o polimorfismo desse método.

Para criar um método virtual puro é assim:

v i r t u a l   t i p o   n o m e M e t o d o = 0 ;

Usar um método virtual puro é principalmente uma decisão de design e é útil para garantir que todas as classes irmãs tenham certos métodos em comum. Isso é útil para manter a coesão do código.

Outro conceito para lembrar é que uma classe abstrata é uma classe que possui ao menos um método virtual puro. E se a classe abstrata possuir apenas métodos virtuais puros, então ela pode ser chamada de interface.

O que a questão está pedindo de verdade é que a gente construa uma interface que vai servir de base para outras classes no futuro. Como existem dois métodos virtuais puros dentro dessa interface, isso garante que todas as classes derivadas vão ser obrigadas a implementar versões próprias de como calcular uma área e de como calcular o perímetro.

Passo 2

Sem mais delongas, vamos escrever o cabeçalho do nosso código:

E em seguida, vamos criar uma classe chamada F o r m a :

E determinamos o encapsulamento como público:

Agora vamos declarar o método c a l c u l a r A r e a   como virtual puro, assim:

v i r t u a l   f l o a t   c a l c u l a r A r e a   = 0 ;

E depois, vamos declarar o método c a l c u l a r P e r i m e t r o   como virtual puro:

v i r t u a l   f l o a t   c a l c u l a r P e r i m e t r o   = 0 ;

E aí podemos finalizar a classe!

Questão prontinha!

Resposta

Exercício Resolvido #7

Observe a classe interface F o r m a

Crie, uma classe de nome R e t a n g u l o cujas instâncias são caracterizadas pelos atributos l a d o e a l t u r a ambos do tipo f l o a t . Implemente na classe R e t a n g u l o os métodos herdados e outros que ache necessários.

Passo 1

Lets go, galerinha!

A primeira coisa que você tem que notar é que todos os métodos de F o r m a são virtuais puros. E isso é importante pois todos os métodos virtuais puros precisam sofrer polimorfismo. Para identificar um método virtual puro, olhe se ele tem a palavra chave v i r t u a l e se termina com “ = 0 ” .

A classe que vamos criar é a R e t a n g u l o que precisa de dois atributos l a d o e a l t u r a . O ideal é que esses atributos sejam privados, então vamos precisar também de um construtor para inicializar os atributos e de um par de getters para podermos visualizar os atributos.

Mas antes de tudo, vamos começar escrevendo a interface dentro do nosso código:

Passo 2

Belezinha, partimos agora pro desenvolvimento da classe filha, lembre-se que pra executar uma herança é assim:

c l a s s   N o m e F i l h a   : p u b l i c   N o m e M a e

Então criamos a classe R e t a n g u l o que herda a classe F o r m a

Os atributos l a d o e a l t u r a devem ser de acesso restrito, então vamos declarar os atributos com encapsulamento privado:

Em seguida, vamos criar um método construtor para iniciar os atributos. Os métodos construtores devem ser públicos.

Por questão de gosto pessoal, o nome dos parâmetros do método construtor vai ser igual ao dos atributos. Para evitar ambiguidades, vou usar o t h i s - > para indicar quais são as variáveis que representam os atributos da classe, e os que não tem essa indicação são os parâmetros inseridos pelo usuário.

Depois vamos criar métodos getters para os atributos:

O próximo passo é executar o polimorfismo

Passo 3

Ainda dentro da classe, vamos dar atenção aos detalhes da herança.

Foram herdados dois métodos virtuais puros. Esse tipo de método deve sempre sofrer polimorfismo!

Então vamos começar pelo método c a l c u l a r A r e a . Para aplicar o polimorfismo é só declarar um método utilizando este mesmo nome! O uso do v i r t u a l não é necessário. Depois, dentro do método, é só a gente calcular a área do retângulo e retornar o resultado

a r e a r e t a n g u l o = l a d o × a l t u r a

E depois vamos efetuar o polimorfismo no método c a l c u l a r P e r i m e t r o . Novamente, para executar um polimorfismo é só a gente escrever um novo método utilizando o mesmo nome c a l c u l a r P e r i m e t r o .

p e r i m e t r o r e t a n g u l o = 2 × ( l a d o + a l t u r a )

E a classe está prontinha!

Passo 4

Agora é só a gente testar. Vamos criar um objeto da classe retângulo e vamos imprimir o resultado da área e do perímetro:

Resposta

Exercício Resolvido #8

Os dois códigos abaixo implementam duas classes com herança e polimorfismo. A única diferença entre eles está na linha 07.

Qual o impacto dessa diferença? Escreva uma m a i n ( ) que demonstre o seu argumento.

Passo 1

Vamos lá, pessoal!

A única diferença entre os dois códigos é que na linha 07 o Código A utiliza a palavra chave v i r t u a l e o código B não utiliza

Isso quer dizer que no código A o método T e x t o (   ) é um método virtual, e no código B não.

Os métodos virtuais são uma forma de mudar o comportamento de um método que vai sofrer polimorfismo.

A mudança de comportamento acontece quando existe iterações entre a classe mãe e a classe filha de uma das duas formas:

  1. Quando um método que sofreu polimorfismo na classe filha é executando dentro de outro método da classe mãe.
  2. Quando usamos ponteiros da classe mãe para armazenar o endereço de um objeto da classe filha.

O v i r t u a l informa ao C++ que ele sempre deve olhar pra classe filha em busca de polimorfismos. Caso o virtual não esteja presente, quando a gente executar um dos dois casos acima, a versão “polimorfada” será ignorada, e a versão da classe mãe será executada.

Você pode ver que o Caso 2 acontece nos códigos do enunciado. O método T e x t o (   ) é executando dentro do método P r i n t (   ) da classe mãe, e ao mesmo tempo sofre polimorfismo dentro da classe filha. Quando o v i r t u a l não é utilizado, os métodos da classe mãe vão executar chamadas para métodos existentes na classe mãe.

De certa forma é como se quando a gente não usa o v i r t u a l o polimorfismo só tem validade dentro da classe Filha, e métodos e ponteiro da classe mãe não vão levar o polimorfismo em conta.

Para ficar mais claro. Vamos executar os códigos A e B

Passo 2

Agora vamos ver um exemplo do código A em ação.

Vamos criar um objeto da classe filha e executar os métodos T e x t o e P r i n t

Quando o objeto executa o método T e x t o ele sempre executa versão com polimorfismo, pois estamos fazendo uma chamada direta ao método.

Quando executamos o método P r i n t estamos executando um método herdado. Esse método herdado vai executar o método T e x t o , porém o método T e x t o é virtual, e logo, a o P r i n t sabe que deve conferir se o método T e x t o sofreu polimorfismo.

Passo 3

Agora vamos ver como o código B se comporta.

Vamos criar um objeto da classe filha e executar os métodos T e x t o e P r i n t

Quando o objeto executa o método T e x t o ele sempre executa versão com polimorfismo, pois estamos fazendo uma chamada direta ao método.

Quando executamos o método P r i n t estamos executando um método herdado. Esse método herdado vai executar o método T e x t o , porém o método T e x t o é não virtual, e logo, a o P r i n t simplesmente executa a versão existente na classe mãe.

Resposta

A ausência da palavra-chave v i r t u a l modifica o comportamento dos métodos da classe mãe que fazem chamadas ao método T e x t o