Polimorfismo de C++ con ejemplo

¿Qué es el polimorfismo en C++?

En 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 clases relacionadas mediante 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 ++

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.

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

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 el compilador de C++ 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 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;
}

Salida:

Sobrecarga de funciones

Aquí hay una captura de pantalla del código:

Sobrecarga de funciones

Explicación del código:

  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.

Sobrecarga del operador

En Sobrecarga de operadores, definimos un nuevo significado para un operador de C++. También cambia la forma de trabajar del operador. Por ejemplo, podemos definir el operador + para concatenar dos cadenas. Lo conocemos como el operador de suma para sumar valores numéricos. Después de nuestra definición, cuando se coloca entre números enteros, los sumará. Cuando se coloca entre cadenas, las concatenará.

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

Salida:

Sobrecarga del operador

Aquí hay una captura de pantalla del código:

Sobrecarga del operador

Sobrecarga del operador

Explicación del código:

  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 ComplexNúm. 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 del 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. Crear el resultado del tipo de datos de tipo ComplexNum.
  13. Utilice el operador + con complex números. Esta línea sumará la parte real de un número a la parte real de otro número.
  14. Utilice el operador + con complex números. 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, sobrecarga.
  17. Llame al método print().
  18. Imprime el nuevo complex número después de agregarlo en la consola.
  19. Fin del cuerpo de la función print().
  20. Fin del cuerpo de ComplexClase numérica.
  21. Llame a la función principal().
  22. Pase los valores de real y com.plex piezas que se van a agregar. 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. Realice una operación utilizando el operador + sobrecargado y almacenando 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().

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:

Anulación de funciones

Aquí hay una captura de pantalla del código:

Anulación de funciones

Explicación del código:

  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().

Función virtual C++

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:

Función virtual C++

Aquí hay una captura de pantalla del código:

Función virtual C++

Explicación del código:

  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(). endl es una palabra clave de C++, 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().

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 llama unión temprana o polimorfismo estático. También se llama 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 de métodos se realiza durante el tiempo de compilación. Ejecución más lenta ya que el descubrimiento de métodos se realiza durante el tiempo de ejecución.
Se proporciona menos flexibilidad para la resolución de problemas ya que todo se sabe durante el tiempo de compilación. Se proporciona mucha flexibilidad para resolver complex problemas ya que los métodos se descubren durante el tiempo de ejecución.

Resumen

  • Polimorfismo significa tener muchas formas.
  • Ocurre cuando existe una jerarquía de clases relacionadas mediante herencia.
  • Con el polimorfismo, una función puede comportarse de manera diferente según el objeto que la invoca/llama.
  • En el polimorfismo en tiempo de compilación, la función que se invocará se establece durante el tiempo de compilación.
  • En el polimorfismo en tiempo de ejecución, la función que se invocará se establece durante el tiempo de ejecución.
  • El polimorfismo en tiempo de compilación se determina mediante la sobrecarga de funciones y la sobrecarga de operadores.
  • En la sobrecarga de funciones, hay muchas funciones con nombres similares pero argumentos diferentes.
  • Los parámetros pueden diferir en número o tipo.
  • En la sobrecarga de operadores, se define un nuevo significado para Operadores C++.
  • El polimorfismo en tiempo de ejecución se logra mediante la anulación de funciones.
  • En la anulación de funciones, una clase derivada proporciona una nueva definición a una función definida en la clase base.