C++ Polimorfismo con ejemplo

โšก Resumen inteligente

Polimorfismo en C++ Permite que una รบnica funciรณn miembro adopte mรบltiples formas, comportรกndose de manera diferente segรบn el objeto que la invoca. Se basa en la herencia y se presenta en dos variantes, que se resuelven en tiempo de compilaciรณn o en tiempo de ejecuciรณn.

  • ๐Ÿ”ท Definiciรณn: El polimorfismo significa "muchas formas", lo que permite que una funciรณn miembro se comporte de manera diferente segรบn el objeto que la llama.
  • ๐Ÿงญ Dos tipos: C++ Proporciona polimorfismo en tiempo de compilaciรณn (estรกtico) y polimorfismo en tiempo de ejecuciรณn (dinรกmico).
  • ๐Ÿงฉ Tiempo de compilaciรณn: La sobrecarga de funciones y la sobrecarga de operadores seleccionan la funciรณn correcta durante la compilaciรณn.
  • ๐Ÿ” Tiempo de ejecuciรณn: La sobreescritura de funciones y las funciones virtuales resuelven la llamada mientras el programa se ejecuta.
  • โš™๏ธ Funciones virtuales: La palabra clave virtual en una clase base permite la vinculaciรณn tardรญa a travรฉs de un puntero de clase base.
  • ๐Ÿค– Asistencia de IA: GitHub Copilot y asistentes similares generan funciones sobrecargadas, anuladas y virtuales a partir de un breve comentario.

C++ Polimorfismo

ยฟQuรฉ es el polimorfismo en C++?

In C++El polimorfismo hace que una funciรณn miembro se comporte de manera diferente segรบn el objeto que la llama/invoca. Polimorfismo es una palabra griega que significa tener muchas formas. Ocurre cuando tienes una jerarquรญa de privadas emparentados por herencia.

Por ejemplo, supongamos que tenemos la funciรณn makeSound(). Cuando un gato llama a esta funciรณn, producirรก un maullido. Cuando una vaca invoca la misma funciรณn, emitirรก el sonido de un maullido.

Polimorfismo en C++ Ejemplo de makeSound

Aunque tenemos una funciรณn, se comporta de manera diferente en diferentes circunstancias. La funciรณn tiene muchas formas; por tanto, hemos logrado el polimorfismo.

Con la idea central ya establecida, C++ Organiza este comportamiento en dos categorรญas distintas.

Tipos de polimorfismo

C++ admite dos tipos de polimorfismo:

  • Polimorfismo en tiempo de compilaciรณn y
  • Polimorfismo en tiempo de ejecuciรณn.

Tipos de polimorfismo en C++

La primera categorรญa resuelve todas las llamadas a funciones antes de que se ejecute el programa.

Compilar polimorfismo de tiempo

Se invocan las funciones sobrecargadas haciendo coincidir el nรบmero y el tipo de argumentos. La informaciรณn estรก presente durante el tiempo de compilaciรณn. Esto significa que C++ El compilador seleccionarรก la funciรณn correcta en el momento de la compilaciรณn.

El polimorfismo en tiempo de compilaciรณn se logra mediante la sobrecarga de funciones y la sobrecarga de operadores.

Sobrecarga de funciones

La sobrecarga de funciones ocurre cuando tenemos muchas funciones con nombres similares pero argumentos diferentes. Los argumentos pueden diferir en tรฉrminos de nรบmero o tipo.

Ejemplo

#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;
}

Salida:

C++ Ejemplo de sobrecarga de funciones 1 salida

Aquรญ hay una captura de pantalla del cรณdigo:

C++ Ejemplo de sobrecarga de funciones (cรณdigo 1)

Code Explicaciรณn:

  1. Incluya el archivo de encabezado iostream en nuestro cรณdigo. Podremos utilizar sus funciones.
  2. Incluya el espacio de nombres estรกndar en nuestro cรณdigo. Podremos utilizar sus clases sin llamarlo.
  3. Cree una funciรณn llamada prueba que tome un parรกmetro entero i. El { marca el comienzo del cuerpo de la prueba de funciรณn.
  4. Declaraciรณn que se ejecutarรก si se invoca/llama la funciรณn de prueba anterior.
  5. Fin del cuerpo de la prueba de funciรณn anterior.
  6. Cree una funciรณn llamada prueba que tome un parรกmetro flotante f. El { marca el comienzo del cuerpo de la prueba de funciรณn.
  7. Declaraciรณn que se ejecutarรก si se invoca/llama la funciรณn de prueba anterior.
  8. Fin del cuerpo de la prueba de funciรณn anterior.
  9. Cree una funciรณn llamada prueba que tome un parรกmetro de carรกcter ch. El { marca el comienzo del cuerpo de la prueba de funciรณn.
  10. Declaraciรณn que se ejecutarรก si se invoca/llama la funciรณn de prueba anterior.
  11. Fin del cuerpo de la prueba de funciรณn anterior.
  12. Llame a la funciรณn principal(). El { marca el comienzo del cuerpo de la funciรณn.
  13. Llame a la funciรณn test y pรกsele 5 como valor del argumento. Esto invoca la funciรณn de prueba que acepta un argumento entero, es decir, la primera funciรณn de prueba.
  14. Llame a la funciรณn test y pรกsele 5.5 como valor del argumento. Esto invocarรก la funciรณn de prueba que acepta un argumento flotante, es decir, la segunda funciรณn de prueba.
  15. Llame a la funciรณn test y pรกsele cinco como valor del argumento. Esto invocarรก la funciรณn de prueba que acepta un argumento de carรกcter, es decir, la tercera funciรณn de prueba.
  16. El programa debe devolver un valor si se ejecuta correctamente.
  17. El final del cuerpo de la funciรณn main().

Tenemos tres funciones con el mismo nombre pero diferentes tipos de argumentos. Hemos logrado el polimorfismo.

OperaSobrecarga de Tor

In Operator Overloading, definimos un nuevo significado para un C++ operadorTambiรฉn modifica el funcionamiento del operador. Por ejemplo, podemos definir el operador + para concatenar dos cadenas. Lo conocemos como el operador de suma para aรฑadir valores numรฉricos. Tras nuestra definiciรณn, cuando se coloca entre nรบmeros enteros, los suma. Cuando se coloca entre cadenas, las concatena.

Ejemplo

#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();
}

Salida:

C++ Ejemplo 2 de sobrecarga de operadores

Aquรญ hay una captura de pantalla del cรณdigo:

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

C++ Ejemplo 2 de sobrecarga de operadores

Code Explicaciรณn:

  1. Incluya el archivo de encabezado iostream en nuestro programa para poder utilizar sus funciones.
  2. Incluya el espacio de nombres estรกndar en nuestro programa para poder usar sus clases sin llamarlo.
  3. Crea una clase llamada ComplexNum. El { marca el comienzo del cuerpo de la clase.
  4. Utilice el modificador de acceso privado para marcar las variables como privadas, lo que significa que solo se puede acceder a ellas desde dentro de la clase.
  5. Defina dos variables enteras, reales y superiores.
  6. Utilice el modificador de acceso pรบblico para marcar el constructor como pรบblico, lo que significa que serรก accesible incluso desde fuera de la clase.
  7. Crea el constructor de la clase e inicializa las variables.
  8. Inicializa el valor de la variable real.
  9. Inicialice el valor de la variable over.
  10. Fin del cuerpo del constructor.
  11. Necesitamos anular el significado del operador +.
  12. Crea el tipo de datos resultado del tipo ComplexNum.
  13. Utilice el operador + con nรบmeros complejos. Esta lรญnea sumarรก la parte real de un nรบmero con la parte real de otro nรบmero.
  14. Utilice el operador + con nรบmeros complejos. Esta lรญnea sumarรก la parte imaginaria de un nรบmero a la parte imaginaria de otro nรบmero.
  15. El programa devolverรก el valor de la variable resultado tras una ejecuciรณn exitosa.
  16. Fin de la definiciรณn del nuevo significado del operador +, es decir, la sobrecarga.
  17. Llame al mรฉtodo print().
  18. Imprima el nuevo nรบmero complejo despuรฉs de la suma en la consola.
  19. Fin del cuerpo de la funciรณn print().
  20. Fin del cuerpo de la clase ComplexNum.
  21. Llame a la funciรณn principal().
  22. Pasar los valores de las partes reales y complejas que se van a sumar. La primera parte de c1 se sumarรก a la primera parte de c2, es decir, 10+3. La segunda parte de c1 se sumarรก a la segunda parte de c, es decir, 2+7.
  23. Realizar una operaciรณn utilizando el operador + sobrecargado y almacenar el resultado en la variable c3.
  24. Imprime el valor de la variable c3 en la consola.
  25. Fin del cuerpo de la funciรณn main().

Mientras que el polimorfismo en tiempo de compilaciรณn decide pronto, la segunda categorรญa pospone la elecciรณn hasta la ejecuciรณn.

Polimorfismo en tiempo de ejecuciรณn

Esto sucede cuando el mรฉtodo de un objeto se invoca/llama durante el tiempo de ejecuciรณn en lugar de durante el tiempo de compilaciรณn. El polimorfismo en tiempo de ejecuciรณn se logra mediante la anulaciรณn de funciones. La funciรณn a llamar/invocar se establece durante el tiempo de ejecuciรณn.

Anulaciรณn de funciones

La anulaciรณn de funciones ocurre cuando a una funciรณn de la clase base se le da una nueva definiciรณn en una clase derivada. En ese momento, podemos decir que la funciรณn base ha sido anulada.

Por ejemplo:

#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;

}

Salida:

C++ funciรณn que anula la salida

Aquรญ hay una captura de pantalla del cรณdigo:

C++ cรณdigo de anulaciรณn de funciรณn

Code Explicaciรณn:

  1. Importe el archivo de encabezado iostream a nuestro programa para usar sus funciones.
  2. Incluya el espacio de nombres estรกndar en nuestro programa para poder usar sus clases sin llamarlo.
  3. Crea una clase llamada Mamรญfero. El { marca el comienzo del cuerpo de la clase.
  4. Utilice el modificador de acceso pรบblico para configurar la funciรณn que estamos a punto de crear como de acceso pรบblico. Serรก accesible desde fuera de esta clase.
  5. Crea una funciรณn pรบblica llamada comer. El { marca el comienzo del cuerpo de la funciรณn.
  6. Imprime la declaraciรณn agregada a la funciรณn cout cuando se invoca la funciรณn eat().
  7. El final del cuerpo de la funciรณn eat().
  8. Fin del cuerpo de la clase Mamรญfero.
  9. Cree una clase llamada Vaca que herede la clase Mamรญfero. Vaca es la clase derivada, mientras que Mamรญfero es la clase base. El { marca el comienzo de esta clase.
  10. Utilice el modificador de acceso pรบblico para marcar la funciรณn que estamos a punto de crear como de acceso pรบblico. Serรก accesible desde fuera de esta clase.
  11. Anule la funciรณn eat() que se definiรณ en la clase base. El { marca el comienzo del cuerpo de la funciรณn.
  12. La declaraciรณn que se imprimirรก en la consola cuando se invoque esta funciรณn.
  13. Fin del cuerpo de la funciรณn comer().
  14. Fin del cuerpo de la clase Vaca.
  15. Llame a la funciรณn principal(). El { marca el comienzo del cuerpo de esta funciรณn.
  16. Cree una instancia de la clase Cow y asรญgnele el nombre c.
  17. Llame a la funciรณn eat() definida en la clase Cow.
  18. El programa debe devolver un valor al finalizar con รฉxito.
  19. Fin de la funciรณn main().

C++ Funciรณn virtual

Una funciรณn virtual es otra forma de implementar polimorfismo en tiempo de ejecuciรณn en C++. Es una funciรณn especial definida en una clase base y redefinida en la clase derivada. Para declarar una funciรณn virtual, debe utilizar la palabra clave virtual. La palabra clave debe preceder a la declaraciรณn de la funciรณn en la clase base.

Si se hereda una clase de funciรณn virtual, la clase virtual redefine la funciรณn virtual para satisfacer sus necesidades. Por ejemplo:

#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();      
	}

Salida:

C++ Salida de funciรณn virtual

Aquรญ hay una captura de pantalla del cรณdigo:

C++ cรณdigo de funciรณn virtual

Code Explicaciรณn:

  1. Incluya el archivo de encabezado iostream en el cรณdigo para usar sus funciones.
  2. Incluya el espacio de nombres estรกndar en nuestro cรณdigo para usar sus clases sin llamarlo.
  3. Crea una clase llamada ClassA.
  4. Utilice el modificador de acceso pรบblico para marcar a un miembro de la clase como de acceso pรบblico.
  5. Cree una funciรณn virtual llamada show(). Serรก una funciรณn pรบblica.
  6. El texto que se imprimirรก cuando se invoque show(). El final es un C++ palabra clave, que significa lรญnea final. Mueve el cursor del mouse a la siguiente lรญnea.
  7. Fin del cuerpo de la funciรณn virtual show().
  8. Fin del cuerpo de la clase ClassA.
  9. Creando una nueva clase llamada ClassB que hereda la clase ClassA. ClassA se convierte en la clase base mientras que ClassB se convierte en la clase derivada.
  10. Utilice el modificador de acceso pรบblico para marcar a un miembro de la clase como de acceso pรบblico.
  11. Redefina la funciรณn virtual show() derivada en la clase base.
  12. El texto que se imprimirรก en la consola cuando se invoque la funciรณn show() definida en la clase derivada.
  13. Fin del cuerpo de la funciรณn show().
  14. Fin del cuerpo de la clase derivada, ClassB.
  15. Llame a la funciรณn principal(). La lรณgica del programa debe agregarse dentro de su cuerpo.
  16. Cree una variable de puntero denominada a. Apunta a la clase denominada ClassA.
  17. Cree una instancia de la clase denominada ClassB. La instancia recibe el nombre b.
  18. Asigne los valores almacenados en la direcciรณn b en la variable a.
  19. Invoca la funciรณn show() definida en la clase derivada. Se ha implementado la vinculaciรณn tardรญa.
  20. Fin del cuerpo de la funciรณn main().

Una vez explicados ambos mecanismos, la siguiente tabla los compara uno al lado del otro.

Polimorfismo en tiempo de compilaciรณn vs. Polimorfismo en tiempo de ejecuciรณn

Estas son las principales diferencias entre los dos:

Polimorfismo en tiempo de compilaciรณn Polimorfismo en tiempo de ejecuciรณn
Tambiรฉn se le denomina uniรณn temprana o polimorfismo estรกtico. Tambiรฉn se denomina uniรณn tardรญa/dinรกmica o polimorfismo dinรกmico.
El mรฉtodo se llama/invoca durante el tiempo de compilaciรณn. El mรฉtodo se llama/invoca durante el tiempo de ejecuciรณn.
Implementado mediante sobrecarga de funciones y sobrecarga de operadores. Implementado mediante anulaciรณn de mรฉtodos y funciones virtuales.
Ejemplo, sobrecarga de mรฉtodos. Muchos mรฉtodos pueden tener nombres similares pero diferentes nรบmeros o tipos de argumentos. Ejemplo, anulaciรณn de mรฉtodo. Muchos mรฉtodos pueden tener un nombre similar y el mismo prototipo.
Ejecuciรณn mรกs rรกpida ya que el descubrimiento del mรฉtodo se realiza durante la compilaciรณn. La ejecuciรณn es mรกs lenta, ya que el descubrimiento de mรฉtodos se realiza durante el tiempo de ejecuciรณn.
Less Se proporciona flexibilidad para la resoluciรณn de problemas ya que todo se sabe durante el tiempo de compilaciรณn. Se proporciona mucha flexibilidad para resolver problemas complejos ya que los mรฉtodos se descubren durante el tiempo de ejecuciรณn.

Preguntas Frecuentes

La sobrecarga define varias funciones con el mismo nombre pero con parรกmetros diferentes, que se resuelven en tiempo de compilaciรณn sin herencia. La anulaciรณn redefine una funciรณn heredada de la clase base con la misma firma en una clase derivada, y se resuelve en tiempo de ejecuciรณn cuando la funciรณn se declara virtual.

Una funciรณn virtual pura se declara con = 0 y no tiene cuerpo en la clase base. Cualquier clase que contenga una se convierte en una funciรณn absoluta.tracclase t, que no se puede instanciar directamente y obliga a las clases derivadas a proporcionar su propia implementaciรณn.

Cuando una clase declara funciones virtuales, el compilador crea una tabla virtual (vtable) de punteros a funciones. Cada objeto almacena un puntero oculto a la vtable de su clase, de modo que un puntero de la clase base llama a la funciรณn sobrescrita correcta en tiempo de ejecuciรณn mediante enlace tardรญo.

Sรญ. Las plantillas permiten que una funciรณn o clase opere con muchos tipos de datos, y el compilador genera cรณdigo especรญfico para cada tipo durante la compilaciรณn. Esta programaciรณn genรฉrica es una forma de polimorfismo estรกtico que complementa la sobrecarga de funciones y la sobrecarga de operadores.

Al eliminar un objeto derivado mediante un puntero a la clase base, solo un destructor virtual garantiza que el destructor derivado tambiรฉn se ejecute. Sin รฉl, la limpieza es incompleta y provoca fugas de memoria. Declarar el destructor base como virtual hace que la destrucciรณn se comporte de forma polimรณrfica.

El polimorfismo permite que una sola interfaz gestione muchos tipos de objetos, reduciendo la duplicaciรณn de cรณdigo y simplificando el mantenimiento. Admite diseรฑos flexibles y extensibles donde se incorporan nuevas clases derivadas sin modificar el cรณdigo existente, y posibilita patrones potentes basados โ€‹โ€‹en punteros y referencias de la clase base.

Sรญ. Los asistentes de codificaciรณn con IA convierten un comentario breve en funciones sobrecargadas, clases base virtuales y anulaciones derivadas. Procesan rรกpidamente el cรณdigo repetitivo, aunque conviene verificar las palabras clave virtuales, las firmas de las funciones y la seguridad de los destructores antes de compilar el cรณdigo generado.

Sรญ. Copiloto de GitHub Sugiere declaraciones de funciones virtuales, anulaciones de clases derivadas y sobrecargas de operadores a medida que escribes. Acelera la generaciรณn de cรณdigo repetitivo para jerarquรญas de herencia, aunque debes confirmar la palabra clave virtual, las firmas coincidentes y el comportamiento correcto de enlace tardรญo antes de compilar.

Resumir este post con: