CSharp

Tutorial CSharp: Polimorfismo

CSharp polimorfismo: técnicas y ejemplos. Aprende técnicas de polimorfismo en CSharp con ejemplos prácticos y detallados.

El polimorfismo es un concepto fundamental de la programación orientada a objetos. En C#, este concepto permite a las clases derivadas compartir comportamientos con las clases base. En resumen, el polimorfismo permite tratar objetos de una clase derivada como si fueran objetos de su clase base. Este concepto es muy útil cuando se necesita trabajar con grupos de objetos relacionados de manera genérica.

El polimorfismo en C# se logra de dos maneras:

  1. A través de la herencia, donde una clase derivada puede heredar miembros de la clase base.
  2. A través de las interfaces, que permiten que las clases no relacionadas tengan comportamientos comunes.

Ejemplo de Polimorfismo en C# a través de la Herencia

Un ejemplo clásico para ilustrar el polimorfismo es una clase base Animal y dos clases derivadas Perro y Gato.

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 este ejemplo, la clase Animal tiene un método HacerSonido(). Las clases Perro y Gato heredan de la clase Animal y sobrescriben el método HacerSonido(). Para ello, el método en la clase padre debe ser declarado como virtual, que indica que puede ser sobreescrito, y entonces el método en la clase hija ser marcado como override, para sobreescribirlo.

Ahora, se puede referir a un objeto Perro o Gato como si fuera un objeto Animal y llamar al método HacerSonido(). C# determinará en tiempo de ejecución qué versión del método debe ser llamada, dependiendo del tipo real del objeto.

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

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

Específicamente, cuando se llama a un método desde alguna clase y hay varias clases derivadas, la búsqueda de la declaración del método sigue una secuencia específica. Se realiza una búsqueda en profundidad primero (depth-first search) a través de la jerarquía de herencia. El orden de búsqueda se puede entender de la siguiente manera:

  1. Búsqueda en la clase actual: Primero, se busca el método en la clase desde la cual se realiza la llamada. Si el método se encuentra en esta clase, la búsqueda se detiene y se utiliza esta definición.

  2. Búsqueda en la clase base: Si el método no se encuentra en la clase actual, la búsqueda continúa en la clase base. Esto se repite de manera recursiva si tampoco se encuentra en la clase base, buscando en cada clase inmediatamente superior hasta que se encuentra el método o hasta que se hayan revisado todas las clases relacionadas y no se encuentre, lanzando un error en tiempo de compilación.

Ejemplo de Polimorfismo en C# a través de Interfaces

Las interfaces proporcionan una manera de lograr el polimorfismo entre clases que no están relacionadas a través de la herencia.

A continuación, se define una interfaz IVolador con un método Volar(). Dos clases, Pajaro y Avion, implementan esta interfaz.

public interface IVolador
{
    void Volar();
}

public class Pajaro : IVolador
{
    public void Volar()
    {
        Console.WriteLine("El pájaro vuela");
    }
}

public class Avion : IVolador
{
    public void Volar()
    {
        Console.WriteLine("El avión vuela");
    }
}

Aunque Pajaro y Avion no están relacionados por herencia, ambos implementan la interfaz IVolador. Esto significa que pueden ser tratados de manera genérica como objetos IVolador.

IVolador miVolador = new Pajaro();
miVolador.Volar();  // Output: "El pájaro vuela"

miVolador = new Avion();
miVolador.Volar();  // Output: "El avión vuela"

En ambos casos, C# utiliza el polimorfismo para determinar en tiempo de ejecución qué versión del método Volar() debe ser llamada.

Polimorfirsmo Estático y Dinámico

En el contexto de la programación orientada a objetos, el polimorfismo se divide en dos categorías principales: el polimorfismo estático (también conocido como polimorfismo en tiempo de compilación) y el polimorfismo dinámico (también conocido como polimorfismo en tiempo de ejecución).

Polimorfismo Estático

El polimorfismo estático, también conocido como sobrecarga de métodos, ocurre en tiempo de compilación. En este caso, el polimorfismo se logra mediante la creación de varios métodos con el mismo nombre pero con diferentes firmas (es decir, diferentes tipos de parámetros o número de parámetros) en la misma clase. Cuando se llama a un método, el compilador determina el método específico a utilizar a través de la coincidencia de los argumentos con las firmas de los métodos.

public class Calculadora
{
    public int Sumar(int a, int b)
    {
        return a + b;
    }

    public float Sumar(float a, float b)
    {
        return a + b;
    }

    public double Sumar(double a, double b)
    {
        return a + b;
    }
}

En este ejemplo, el método Sumar está sobrecargado con diferentes firmas de método: Sumar(int, int), Sumar(float, float) y Sumar(double, double). El compilador determinará cuál de estos métodos llamar en función de los tipos de argumentos utilizados.

Polimorfismo Dinámico

El polimorfismo dinámico, también conocido como anulación de métodos, ocurre en tiempo de ejecución. En este caso, el polimorfismo se logra mediante la creación de un método en la clase base y la redefinición de este mismo método en la clase derivada. Cuando se llama a un método, la versión específica del método a utilizar se determina en tiempo de ejecución, basándose en el objeto que realiza la llamada.

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 este ejemplo, el método HacerSonido se declara en la clase base Animal y luego se redefinido en las clases derivadas Perro y Gato. En tiempo de ejecución, C# determinará cuál versión del método HacerSonido debe llamarse basándose en si el objeto es de tipo Perro o Gato.

Por tanto, el polimorfismo estático y el polimorfismo dinámico son dos caras de la misma moneda. Ambos son esenciales para lograr la flexibilidad y la reutilización en la programación orientada a objetos.

En resumen, el polimorfismo es una poderosa herramienta en C# y la programación orientada a objetos en general, ya que permite tratar objetos de diferentes clases de una manera genérica, al tiempo que se mantiene la capacidad de invocar comportamientos específicos de la clase.

Certifícate en CSharp con CertiDevs PLUS

Ejercicios de esta lección Polimorfismo

Evalúa tus conocimientos de esta lección Polimorfismo con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de CSharp

Accede a todas las lecciones de CSharp y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el concepto de polimorfismo en C# y su importancia en la programación orientada a objetos.
  2. Aprender a implementar el polimorfismo a través de la herencia, permitiendo que las clases derivadas sobrescriban métodos de la clase base.
  3. Conocer cómo implementar el polimorfismo mediante el uso de interfaces, permitiendo que clases no relacionadas tengan comportamientos comunes.
  4. Familiarizarse con los conceptos de polimorfismo estático y dinámico, y cómo se logran en C# mediante la sobrecarga de métodos y la anulación de métodos, respectivamente.
  5. Entender cómo el polimorfismo mejora la flexibilidad y la reutilización de código en la programación orientada a objetos.