C++ Polimorfismo com Exemplo

โšก Resumo Inteligente

Polimorfismo em C++ Permite que uma รบnica funรงรฃo membro assuma vรกrias formas, comportando-se de maneira diferente dependendo do objeto que a invoca. Baseia-se em heranรงa e aparece em duas variantes, resolvidas em tempo de compilaรงรฃo ou em tempo de execuรงรฃo.

  • ๐Ÿ”ท Definiรงรฃo: Polimorfismo significa "muitas formas", permitindo que uma funรงรฃo membro se comporte de maneira diferente dependendo do objeto que a chama.
  • ๐Ÿงญ Dois tipos: C++ Oferece polimorfismo em tempo de compilaรงรฃo (estรกtico) e polimorfismo em tempo de execuรงรฃo (dinรขmico).
  • ๐Ÿงฉ Tempo de compilaรงรฃo: A sobrecarga de funรงรตes e a sobrecarga de operadores selecionam a funรงรฃo correta durante a compilaรงรฃo.
  • ๐Ÿ” Tempo de execuรงรฃo: A sobrescrita de funรงรตes e as funรงรตes virtuais resolvem a chamada durante a execuรงรฃo do programa.
  • โš™๏ธ Funรงรตes virtuais: A palavra-chave `virtual` em uma classe base permite a vinculaรงรฃo tardia por meio de um ponteiro para a classe base.
  • ๐Ÿค– Assistรชncia de IA: O GitHub Copilot e assistentes semelhantes criam funรงรตes sobrecarregadas, substituรญdas e virtuais a partir de um breve comentรกrio.

C++ Polimorfismo

O que รฉ polimorfismo em C++?

In C++O polimorfismo faz com que uma funรงรฃo membro se comporte de maneira diferente dependendo do objeto que a chama/invoca. Polimorfismo รฉ uma palavra grega que significa ter muitas formas. Ele ocorre quando vocรช tem uma hierarquia de funรงรตes membro. aulas relacionados por heranรงa.

Por exemplo, suponha que temos a funรงรฃo makeSound(). Quando um gato chama esta funรงรฃo, ele produz o som de miado. Quando uma vaca invoca a mesma funรงรฃo, ela emitirรก o som moow.

Polimorfismo em C++ Exemplo makeSound

Embora tenhamos uma funรงรฃo, ela se comporta de maneira diferente em circunstรขncias diferentes. A funรงรฃo tem vรกrios formatos; portanto, alcanรงamos o polimorfismo.

Com a ideia central definida, C++ Organiza esse comportamento em duas categorias distintas.

Tipos de polimorfismo

C++ suporta dois tipos de polimorfismo:

  • Polimorfismo em tempo de compilaรงรฃo e
  • Polimorfismo de tempo de execuรงรฃo.

Tipos de polimorfismo em C++

A primeira categoria resolve todas as chamadas de funรงรฃo antes mesmo de o programa ser executado.

Polimorfismo de tempo de compilaรงรฃo

Vocรช invoca as funรงรตes sobrecarregadas combinando o nรบmero e o tipo de argumentos. A informaรงรฃo estรก presente durante o tempo de compilaรงรฃo. Isto significa o C++ o compilador selecionarรก a funรงรฃo correta em tempo de compilaรงรฃo.

O polimorfismo em tempo de compilaรงรฃo รฉ obtido por meio da sobrecarga de funรงรตes e da sobrecarga de operadores.

Sobrecarga de funรงรฃo

A sobrecarga de funรงรตes ocorre quando temos muitas funรงรตes com nomes semelhantes, mas argumentos diferentes. Os argumentos podem diferir em termos de nรบmero ou tipo.

Exemplo 1

#include <iostream> 
using namespace std;

void test(int i) {
	cout << " The int is " << i << endl;
}
void test(double  f) {
	cout << " The float is " << f << endl;
}
void test(char const *ch) {
	cout << " The char* is " << ch << endl;
}

int main() {
	test(5);
	test(5.5);
	test("five");
	return 0;
}

Saรญda:

C++ Sobrecarga de funรงรฃo Exemplo 1 saรญda

Aqui estรก uma captura de tela do cรณdigo:

C++ Sobrecarga de funรงรตes Exemplo 1 cรณdigo

Code Explicaรงรฃo:

  1. Inclua o arquivo de cabeรงalho iostream em nosso cรณdigo. Poderemos usar suas funรงรตes.
  2. Inclua o namespace std em nosso cรณdigo. Poderemos usar suas classes sem chamรก-lo.
  3. Crie uma funรงรฃo chamada test que receba um parรขmetro inteiro i. O {marca o inรญcio do corpo do teste de funรงรฃo.
  4. Instruรงรฃo a ser executada se o teste de funรงรฃo acima for invocado/chamado.
  5. Fim do corpo do teste de funรงรฃo acima.
  6. Crie uma funรงรฃo chamada test que receba um parรขmetro flutuante f. O {marca o inรญcio do corpo do teste de funรงรฃo.
  7. Instruรงรฃo a ser executada se o teste de funรงรฃo acima for invocado/chamado.
  8. Fim do corpo do teste de funรงรฃo acima.
  9. Crie uma funรงรฃo chamada test que receba um parรขmetro de caractere ch. O {marca o inรญcio do corpo do teste de funรงรฃo.
  10. Instruรงรฃo a ser executada se o teste de funรงรฃo acima for invocado/chamado.
  11. Fim do corpo do teste de funรงรฃo acima.
  12. Chame a funรงรฃo main(). O { marca o inรญcio do corpo da funรงรฃo.
  13. Chame a funรงรฃo test e passe 5 para ela como o valor do argumento. Isto invoca a funรงรฃo de teste que aceita um argumento inteiro, ou seja, a primeira funรงรฃo de teste.
  14. Chame a funรงรฃo test e passe 5.5 para ela como o valor do argumento. Isto invocarรก a funรงรฃo de teste que aceita um argumento float, ou seja, a segunda funรงรฃo de teste.
  15. Chame a funรงรฃo test e passe cinco para ela como o valor do argumento. Isto invocarรก a funรงรฃo de teste que aceita um argumento de caractere, ou seja, a terceira funรงรฃo de teste.
  16. O programa deverรก retornar um valor se for executado com sucesso.
  17. O final do corpo da funรงรฃo main().

Temos trรชs funรงรตes com o mesmo nome, mas diferentes tipos de argumentos. Alcanรงamos o polimorfismo.

Operasobrecarga

In Operator Sobrecarga, definimos um novo significado para um C++ operadorIsso tambรฉm altera o funcionamento do operador. Por exemplo, podemos definir o operador + para concatenar duas strings. Conhecemos esse operador como o operador de adiรงรฃo para somar valores numรฉricos. Apรณs nossa definiรงรฃo, quando colocado entre nรบmeros inteiros, ele os somarรก. Quando colocado entre strings, ele as concatenarรก.

Exemplo 2

#include<iostream> 
using namespace std;

class ComplexNum {
private:
	int real, over;
public:
	ComplexNum(int rl = 0, int ov = 0) {
		real = rl;   
		over = ov; 
	}

	ComplexNum operator + (ComplexNum const &obj) {
		ComplexNum result;
		result.real = real + obj.real;
		result.over = over + obj.over;
		return result;
	}
	void print() { 
		cout << real << " + i" << over << endl; 
	}
};
int main()
{
	ComplexNum c1(10, 2), c2(3, 7);
	ComplexNum c3 = c1+c2;
	c3.print();
}

Saรญda:

C++ sobrecarga de operadores Exemplo 2 saรญda

Aqui estรก uma captura de tela do cรณdigo:

C++ Sobrecarga de operadores Exemplo 2 cรณdigo

C++ sobrecarga do operador Exemplo 2 resultado

Code Explicaรงรฃo:

  1. Inclua o arquivo de cabeรงalho iostream em nosso programa para usar suas funรงรตes.
  2. Inclua o namespace std em nosso programa para usar suas classes sem chamรก-lo.
  3. Crie uma classe chamada ComplexNum. O { marca o inรญcio do corpo da classe.
  4. Use o modificador de acesso privado para marcar variรกveis โ€‹โ€‹como privadas, o que significa que elas sรณ podem ser acessadas dentro da classe.
  5. Defina duas variรกveis โ€‹โ€‹inteiras, reais e superiores.
  6. Use o modificador de acesso `public` para marcar o construtor como pรบblico, o que significa que ele serรก acessรญvel mesmo de fora da classe.
  7. Crie o construtor da classe e inicialize as variรกveis.
  8. Inicialize o valor da variรกvel real.
  9. Inicialize o valor da variรกvel.
  10. Fim do corpo do construtor.
  11. Precisamos substituir o significado do operador +.
  12. Crie o tipo de dados resultado do tipo ComplexNum.
  13. Use o operador + com nรบmeros complexos. Esta linha adicionarรก a parte real de um nรบmero ร  parte real de outro nรบmero.
  14. Use o operador + com nรบmeros complexos. Esta linha adicionarรก a parte imaginรกria de um nรบmero ร  parte imaginรกria de outro nรบmero.
  15. O programa retornarรก o valor da variรกvel resultado apรณs a execuรงรฃo bem-sucedida.
  16. Fim da definiรงรฃo do novo significado do operador +, ou seja, sobrecarga.
  17. Chame o mรฉtodo print().
  18. Imprima o novo nรบmero complexo apรณs a adiรงรฃo no console.
  19. Fim do corpo da funรงรฃo print().
  20. Fim do corpo da classe ComplexNum.
  21. Chame a funรงรฃo main().
  22. Passe os valores das partes reais e complexas a serem somadas. A primeira parte de c1 serรก somada ร  primeira parte de c2, ou seja, 10+3. A segunda parte de c1 serรก somada ร  segunda parte de c, ou seja, 2+7.
  23. Execute uma operaรงรฃo usando o operador + sobrecarregado e armazenando o resultado na variรกvel c3.
  24. Imprima o valor da variรกvel c3 no console.
  25. Fim do corpo da funรงรฃo main().

Enquanto o polimorfismo em tempo de compilaรงรฃo decide cedo, a segunda categoria adia a escolha atรฉ a execuรงรฃo.

Polimorfismo de tempo de execuรงรฃo

Isso acontece quando o mรฉtodo de um objeto รฉ invocado/chamado durante o tempo de execuรงรฃo, e nรฃo durante o tempo de compilaรงรฃo. O polimorfismo de tempo de execuรงรฃo รฉ obtido por meio da substituiรงรฃo de funรงรตes. A funรงรฃo a ser chamada/invocada รฉ estabelecida durante o tempo de execuรงรฃo.

Substituiรงรฃo de funรงรฃo

A substituiรงรฃo de funรงรฃo ocorre quando uma funรงรฃo da classe base recebe uma nova definiรงรฃo em uma classe derivada. Nesse momento, podemos dizer que a funรงรฃo base foi substituรญda.

Por exemplo:

#include <iostream>
using namespace std;
class Mammal {

public:
	void eat() {

		cout << "Mammals eat...";
	}

};

class Cow: public Mammal {

public:
	void eat() {

		cout << "Cows eat grass...";
	}
};
int main(void) {

	Cow c = Cow();

	c.eat();

	return 0;

}

Saรญda:

C++ saรญda de substituiรงรฃo de funรงรฃo

Aqui estรก uma captura de tela do cรณdigo:

C++ cรณdigo de substituiรงรฃo de funรงรฃo

Code Explicaรงรฃo:

  1. Importe o arquivo de cabeรงalho iostream para nosso programa para usar suas funรงรตes.
  2. Inclua o namespace std em nosso programa para usar suas classes sem chamรก-lo.
  3. Crie uma classe chamada Mamรญfero. O { marca o inรญcio do corpo da classe.
  4. Use o modificador de acesso pรบblico para definir a funรงรฃo que estamos prestes a criar como acessรญvel publicamente. Serรก acessรญvel de fora desta classe.
  5. Crie uma funรงรฃo pรบblica chamada comer. O { marca o inรญcio do corpo da funรงรฃo.
  6. Imprima a instruรงรฃo adicionada ร  funรงรฃo cout quando a funรงรฃo eat() รฉ invocada.
  7. O final do corpo da funรงรฃo eat().
  8. Fim do corpo da classe Mamรญfero.
  9. Crie uma classe chamada Cow que herda a classe Mammal. Cow รฉ a classe derivada, enquanto Mammal รฉ a classe base. O { marca o inรญcio desta aula.
  10. Use o modificador de acesso pรบblico para marcar a funรงรฃo que estamos prestes a criar como acessรญvel publicamente. Serรก acessรญvel de fora desta classe.
  11. Substitua a funรงรฃo eat() que foi definida na classe base. O { marca o inรญcio do corpo da funรงรฃo.
  12. A instruรงรฃo a ser impressa no console quando esta funรงรฃo รฉ invocada.
  13. Fim do corpo da funรงรฃo comer().
  14. Fim do corpo da classe Vaca.
  15. Chame a funรงรฃo main(). O { marca o inรญcio do corpo desta funรงรฃo.
  16. Crie uma instรขncia da classe Cow e dรช a ela o nome c.
  17. Chame a funรงรฃo eat() definida na classe Cow.
  18. O programa deve retornar um valor apรณs a conclusรฃo bem-sucedida.
  19. Fim da funรงรฃo main().

C++ Funรงรฃo Virtual

Uma funรงรฃo virtual รฉ outra maneira de implementar o polimorfismo em tempo de execuรงรฃo em C++. ร‰ uma funรงรฃo especial definida em uma classe base e redefinida na classe derivada. Para declarar uma funรงรฃo virtual, vocรช deve usar a palavra-chave virtual. A palavra-chave deve preceder a declaraรงรฃo da funรงรฃo na classe base.

Se uma classe de funรงรฃo virtual for herdada, a classe virtual redefine a funรงรฃo virtual para atender ร s suas necessidades. Por exemplo:

#include <iostream>  
using namespace std;
class ClassA {
		public:
		virtual void show() {
			cout << "The show() function in base class invoked..." << endl;
		}
	};
	class ClassB :public ClassA {
	public:
		void show() 	{
			cout << "The show() function in derived class invoked...";
		}
	};
	int main() {
		ClassA* a;   
		ClassB b;
		a = &b;
		a->show();      
	}

Saรญda:

C++ saรญda da funรงรฃo virtual

Aqui estรก uma captura de tela do cรณdigo:

C++ cรณdigo de funรงรฃo virtual

Code Explicaรงรฃo:

  1. Inclua o arquivo de cabeรงalho iostream no cรณdigo para usar suas funรงรตes.
  2. Inclua o namespace std em nosso cรณdigo para usar suas classes sem chamรก-lo.
  3. Crie uma classe chamada ClassA.
  4. Use o modificador de acesso pรบblico para marcar um membro da classe como acessรญvel publicamente.
  5. Crie uma funรงรฃo virtual chamada show(). Serรก uma funรงรฃo pรบblica.
  6. O texto a ser impresso quando show() invocado รฉ invocado. O final รฉ um C++ palavra-chave, que significa linha final. Move o cursor do mouse para a prรณxima linha.
  7. Fim do corpo da funรงรฃo virtual show().
  8. Fim do corpo da classe ClassA.
  9. Criando uma nova classe chamada ClassB que herda a classe ClassA. ClassA se torna a classe base enquanto ClassB se torna a classe derivada.
  10. Use o modificador de acesso pรบblico para marcar um membro da classe como acessรญvel publicamente.
  11. Redefina a funรงรฃo virtual show() derivada na classe base.
  12. O texto a ser impresso no console quando a funรงรฃo show() definida na classe derivada รฉ invocada.
  13. Fim do corpo da funรงรฃo show().
  14. Fim do corpo da classe derivada, ClassB.
  15. Chame a funรงรฃo main(). A lรณgica do programa deve ser adicionada ao seu corpo.
  16. Crie uma variรกvel de ponteiro chamada a. Ele aponta para a classe chamada ClassA.
  17. Crie uma instรขncia da classe chamada ClassB. A instรขncia recebe o nome b.
  18. Atribua os valores armazenados no endereรงo b na variรกvel a.
  19. Invoque a funรงรฃo show() definida na classe derivada. A vinculaรงรฃo tardia foi implementada.
  20. Fim do corpo da funรงรฃo main().

Com ambos os mecanismos explicados, a tabela abaixo os compara lado a lado.

Polimorfismo em tempo de compilaรงรฃo vs. Polimorfismo em tempo de execuรงรฃo

Aqui estรฃo as principais diferenรงas entre os dois:

Polimorfismo em tempo de compilaรงรฃo Polimorfismo em tempo de execuรงรฃo
Tambรฉm รฉ chamado de ligaรงรฃo precoce ou polimorfismo estรกtico. Tambรฉm รฉ chamado de ligaรงรฃo tardia/dinรขmica ou polimorfismo dinรขmico.
O mรฉtodo รฉ chamado/invocado durante o tempo de compilaรงรฃo O mรฉtodo รฉ chamado/invocado durante o tempo de execuรงรฃo
Implementado por meio de sobrecarga de funรงรฃo e sobrecarga de operador Implementado por meio de substituiรงรฃo de mรฉtodo e funรงรตes virtuais
Exemplo, sobrecarga de mรฉtodo. Muitos mรฉtodos podem ter nomes semelhantes, mas diferentes nรบmeros ou tipos de argumentos Exemplo, substituiรงรฃo de mรฉtodo. Muitos mรฉtodos podem ter um nome semelhante e o mesmo protรณtipo.
Execuรงรฃo mais rรกpida, pois a descoberta de mรฉtodos รฉ feita durante a compilaรงรฃo. Execuรงรฃo mais lenta, pois a descoberta de mรฉtodos รฉ feita em tempo de execuรงรฃo.
Less flexibilidade para resoluรงรฃo de problemas รฉ fornecida, pois tudo รฉ conhecido durante o tempo de compilaรงรฃo. Muita flexibilidade รฉ fornecida para resolver problemas complexos, uma vez que os mรฉtodos sรฃo descobertos durante o tempo de execuรงรฃo.

Perguntas Frequentes

A sobrecarga define vรกrias funรงรตes com o mesmo nome, mas parรขmetros diferentes, resolvidas em tempo de compilaรงรฃo sem heranรงa. A sobrescrita redefine uma funรงรฃo herdada da classe base com a mesma assinatura em uma classe derivada, resolvida em tempo de execuรงรฃo quando a funรงรฃo รฉ declarada como virtual.

Uma funรงรฃo virtual pura รฉ declarada com `virtual` = 0 e nรฃo possui corpo na classe base. Qualquer classe que contenha uma torna-se uma funรงรฃo absoluta.tracClasse t, que nรฃo pode ser instanciada diretamente e forรงa as classes derivadas a fornecerem sua prรณpria implementaรงรฃo.

Quando uma classe declara funรงรตes virtuais, o compilador constrรณi uma tabela virtual (vtable) de ponteiros para funรงรตes. Cada objeto armazena um ponteiro oculto para a vtable de sua classe, de modo que um ponteiro da classe base chama a funรงรฃo sobrescrita correta em tempo de execuรงรฃo por meio de vinculaรงรฃo tardia.

Sim. Os templates permitem que uma funรงรฃo ou classe opere com diversos tipos de dados, com o compilador gerando cรณdigo especรญfico para cada tipo durante a compilaรงรฃo. Essa programaรงรฃo genรฉrica รฉ uma forma de polimorfismo estรกtico que complementa a sobrecarga de funรงรตes e a sobrecarga de operadores.

Ao excluir um objeto derivado por meio de um ponteiro para a classe base, somente um destrutor virtual garante que o destrutor do objeto derivado tambรฉm seja executado. Sem ele, a limpeza fica incompleta e causa vazamentos de memรณria. Declarar o destrutor da classe base como virtual faz com que a destruiรงรฃo se comporte de forma polimรณrfica.

O polimorfismo permite que uma รบnica interface lide com vรกrios tipos de objetos, reduzindo a duplicaรงรฃo de cรณdigo e simplificando a manutenรงรฃo. Ele suporta designs flexรญveis e extensรญveis, nos quais novas classes derivadas sรฃo integradas sem alterar o cรณdigo existente, e possibilita padrรตes poderosos construรญdos com base em ponteiros e referรชncias de classes base.

Sim. Os assistentes de codificaรงรฃo com IA transformam um comentรกrio curto em funรงรตes sobrecarregadas, classes base virtuais e sobrescritas derivadas. Eles lidam rapidamente com cรณdigo repetitivo, embora vocรช ainda deva verificar palavras-chave virtuais, assinaturas de funรงรตes e a seguranรงa do destrutor antes de compilar o cรณdigo gerado.

Sim. Travas deslizantes portรกteis Copiloto do GitHub Sugere declaraรงรตes de funรงรตes virtuais, sobrescritas de classes derivadas e sobrecargas de operadores conforme vocรช digita. Isso acelera a geraรงรฃo de cรณdigo repetitivo para hierarquias de heranรงa, embora vocรช deva confirmar a palavra-chave `virtual`, as assinaturas correspondentes e o comportamento correto de vinculaรงรฃo tardia antes de compilar.

Resuma esta postagem com: