El polimorfismo es uno de los pilares de la programación orientada a objetos que te permite que un mismo método se comporte de forma distinta según la clase que lo use. Si ya entiendes herencia y abstracción, este concepto te va a encajar rápido y vas a poder escribir código más flexible en C#.
Qué diferencia hay entre herencia, abstracción y polimorfismo
Antes de ver el código, conviene aclarar cómo se relacionan estos tres conceptos, porque suelen confundirse.
Con la herencia, una clase hija recibe los métodos del padre y los ejecuta igual. Si el padre tiene un método que imprime salvar el mundo, la hija hará exactamente lo mismo sin escribir nada extra.
Con la abstracción, el padre declara el método pero no lo implementa. La clase hija está obligada a darle un cuerpo, y si no lo hace, el código no compila.
Con el polimorfismo, el padre sí tiene una implementación, pero la hija puede sobrescribirla cuando le convenga. El mismo nombre, los mismos parámetros, el mismo tipo de retorno, pero comportamientos distintos.
¿Qué es el polimorfismo en POO? Es la capacidad de que un método heredado tenga una implementación diferente en la clase hija, conservando la misma firma. En C# se logra con las palabras clave virtual y override.
Cómo se implementa polimorfismo en C# con virtual y override
En el proyecto de superhéroes tenemos una clase Heroe que es el padre y una clase Superheroe que hereda de ella. Dentro de Heroe existen dos métodos: salvarElMundo, que está marcado como abstracto, y salvarLaTierra, que ya tiene su lógica escrita.
Mientras salvarElMundo obliga a Superheroe a implementarlo (eso es abstracción), salvarLaTierra se hereda tal cual. Para abrir la puerta al polimorfismo, basta con marcar el método del padre con la keyword virtual.
csharp
public virtual string salvarLaTierra()
{
return nombre + " ha salvado la Tierra";
}
El detalle clave: a diferencia de abstract, virtual no obliga a la hija a sobrescribir el método. Es opcional. Si Superheroe no hace nada, hereda el comportamiento del padre sin error de compilación.
Cuándo usar virtual en lugar de abstract
Usa virtual cuando el padre tenga una implementación útil por defecto, pero quieras dejar abierta la posibilidad de que algunas hijas la cambien. Usa abstract cuando no exista un comportamiento por defecto razonable y cada hija deba definir el suyo.
Cómo sobrescribir el método en la clase hija
En Superheroe aplicamos override para reescribir la lógica. Visual Studio incluso te sugiere de qué método quieres hacer override:
csharp
public override string salvarLaTierra()
{
return nombre + " " + identidadSecreta + " ha salvado la Tierra";
}
Aquí pasa algo interesante. Como Superheroe tiene una propiedad identidadSecreta que el Heroe común no posee, podemos enriquecer la respuesta concatenando ambos datos. Un héroe normal solo devolvería su nombre; un superhéroe devuelve nombre más identidad secreta.
Cómo reutilizar la lógica del padre con la palabra clave base
Cuando haces override, Visual Studio escribe automáticamente una llamada con base. Esa cláusula te da dos caminos.
- Reutilizar el comportamiento del padre y agregarle algo encima usando
base.salvarLaTierra().
- Ignorar por completo la implementación del padre y escribir una totalmente nueva.
En el ejemplo decidimos descartar la lógica del padre porque no servía para superhéroes. Pero pudimos haber escrito algo como return base.salvarLaTierra() + " con su identidad secreta " + identidadSecreta; para combinar ambas.
¿Para qué sirve la palabra clave base en C#? Permite invocar la implementación original del método del padre desde la clase hija. Es útil cuando quieres extender la lógica heredada sin reescribirla por completo.
Al ejecutar el código, el resultado muestra Superman, Clark Kent ha salvado la Tierra, evidenciando que la clase hija ejecutó su propia versión del método y no la del padre.
Por qué el polimorfismo importa para escribir mejor código
El polimorfismo te da flexibilidad real. En lugar de duplicar métodos con nombres distintos para cada variante, mantienes una misma firma y dejas que cada clase decida cómo responder. Eso simplifica el diseño y prepara el terreno para aplicar patrones de diseño más adelante.
Un buen ejercicio para afianzar el concepto: aplica polimorfismo al método usarSuperpoderes que también vive en la clase Superheroe. Define una versión virtual en el padre y experimenta con distintas implementaciones en la hija, usando o ignorando base según el caso.
¿Ya tienes claro cuándo usarías virtual en tu propio código? Cuéntame en los comentarios qué método de tu proyecto actual podría beneficiarse de polimorfismo.