csharp-polimorfismo

Cómo usar polimorfismo en C#

El polimorfismo es uno de los principios fundamentales de la programación orientada a objetos (POO), que permite que los objetos puedan ser tratados como instancias de su clase base, mientras que conservan su propio comportamiento específico.

En C# esto se logra a través de:

  • Métodos virtuales
  • Métodos abstractos
  • Interfaces

Si quieres aprender más sobre programación orientada a objetos, de dejo el enlace al Curso de Programación orientada a objetos.

Métodos virtuales y sobreescritura

Un método virtual es aquel que se declara en una clase base y que puede ser sobrescrito en una clase derivada para modificar o extender su comportamiento.

En la clase base, el método se marca con la palabra clave virtual, mientras que en la clase derivada se utiliza override para especificar que ese método ha sido modificado.

public class Animal
{
    public virtual void HacerSonido()
    {
        Console.WriteLine("El animal hace un sonido.");
    }
}

public class Perro : Animal
{
    public override void HacerSonido()
    {
        Console.WriteLine("El perro ladra.");
    }
}

public class Gato : Animal
{
    public override void HacerSonido()
    {
        Console.WriteLine("El gato maúlla.");
    }
}

En el ejemplo anterior, HacerSonido es un método virtual en la clase base Animal.

Tanto Perro como Gato sobrescriben este método para especificar un sonido diferente, logrando así que cada subclase defina su comportamiento específico.

Animal miAnimal = new Perro();
miAnimal.HacerSonido(); // Salida: El perro ladra.

miAnimal = new Gato();
miAnimal.HacerSonido(); // Salida: El gato maúlla.

A pesar de que la variable miAnimal es del tipo Animal, ejecuta el método sobrescrito en la clase específica (Perro o Gato).

Esto es el polimorfismo en acción: permite que el método HacerSonido se comporte de acuerdo con el tipo concreto del objeto en tiempo de ejecución.

Ocultación de métodos

En C# existe otra forma de redefinir el comportamiento de un método heredado usando la palabra clave new. Este enfoque se denomina ocultación de métodos y permite que una clase derivada defina una nueva versión de un método de la clase base.

Al utilizar new en lugar de override, el método de la clase derivada oculta el de la clase base. Esto significa que cuando se llama al método desde una referencia de tipo de clase base, el método original se ejecuta, y no el de la clase derivada.

public class Animal
{
    public virtual void HacerSonido()
    {
        Console.WriteLine("El animal hace un sonido.");
    }
}

public class Loro : Animal
{
    public new void HacerSonido()
    {
        Console.WriteLine("El loro imita sonidos.");
    }
}

En este ejemplo, la clase Loro define una nueva versión de HacerSonido utilizando new, en lugar de override. Esto hace que el método de Loro esté presente solo cuando el objeto es accedido directamente como tipo Loro.

La palabra clave new es útil cuando se necesita definir un método en una subclase con el mismo nombre que el de la clase base, pero que no debe modificar su comportamiento polimórfico.


Aunque new es menos común que override, puede ser una buena elección si se quiere dar un comportamiento alternativo sin cambiar la estructura de la jerarquía de clases base.

Polimorfismo con interfaces

Otra forma de implementar el polimorfismo en C# es mediante el uso de interfaces. Las interfaces definen contratos que las clases deben implementar, permitiendo trabajar con diferentes clases que implementen la misma interfaz de una manera uniforme.

public interface ISonido
{
    void HacerSonido();
}

public class Perro : ISonido
{
    public void HacerSonido()
    {
        Console.WriteLine("El perro ladra.");
    }
}

public class Gato : ISonido
{
    public void HacerSonido()
    {
        Console.WriteLine("El gato maúlla.");
    }
}

En este caso, las clases Perro y Gato implementan la interfaz ISonido, lo que significa que ambas deben definir el método HacerSonido. Esto permite tratar a Perro y Gato de forma polimórfica.

ISonido miSonido = new Perro();
miSonido.HacerSonido(); // Salida: El perro ladra.

miSonido = new Gato();
miSonido.HacerSonido(); // Salida: El gato maúlla.

El uso de interfaces facilita el manejo de diferentes tipos de objetos de una manera estandarizada y extensible. Podemos introducir nuevas clases que implementen ISonido sin alterar el código que utiliza esta interfaz, permitiendo una gran flexibilidad.