que-es-un-metodo-virtual-en-programacion

Qué es y cómo usar los métodos virtuales y finales

Hemos visto la importancia del override de métodos como una de las bases de la programación orientada a objetos, y la Herencia y Polimorfismo.

Los métodos virtuales son aquellos métodos definidos en una clase base que pueden ser sobrescritos por las clases derivadas. Así de sencillo.

Al marcar un método como virtual en la clase base, se indica que este método puede ser reemplazado por una implementación diferente en las clases derivadas (proporcionando su propia implementación)

En contraposición llamaremos un método final a aquel que no puede ser sobreescrito por las clases derivadas (si intentamos sobre escribirlos, el compilador o el IDE nos marcará un error).

En este punto en particular, los distintos lenguajes de programación tienen distintas formas de aplicar estos conceptos. No todos los lenguajes siguen los mismos criterios, aunque los conceptos básicos sean los mismos.

En algunos lenguajes, es obligatorio marcas explícitamente como virtual los métodos que pueden ser sobreescritos (por ejemplo anteponiéndoles una palabra clave como virtual).

Otros lenguajes no diferencian los métodos virtuales de los que no. De esta forma, todos los métodos de estos lenguajes son implícitamente virtuales.

Finalmente, unos pocos lenguajes consideran que por defecto los métodos son virtuales, y aquellos que no quieres que puedan ser sobreescritos deben indicarse con una palabra reservada como final o sealed.

Ejemplos en distintos lenguajes

Vamos a verlo con algunos ejemplos reales en distintos lenguajes de programación.

En C#, los métodos virtuales se definen utilizando la palabra clave virtual en la clase base y se sobrescriben en las clases derivadas con la palabra clave override.

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

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

public class Gato : Animal
{
    public override void HacerSonido()
    {
        Console.WriteLine("Miau");
    }
}

// Uso
Animal perro = new Perro();
Animal gato = new Gato();

perro.HacerSonido(); // Salida: Guau
gato.HacerSonido(); // Salida: Miau

En C++, los métodos virtuales se definen en la clase base utilizando la palabra clave virtual y se sobrescriben en las clases derivadas.

#include <iostream>

class Animal {
public:
    virtual void HacerSonido() const {
        std::cout << "El animal hace un sonido" << std::endl;
    }
};

class Perro : public Animal {
public:
    void HacerSonido() const override {
        std::cout << "Guau" << std::endl;
    }
};

class Gato : public Animal {
public:
    void HacerSonido() const override {
        std::cout << "Miau" << std::endl;
    }
};

// Uso
int main() {
    Animal* perro = new Perro();
    Animal* gato = new Gato();

    perro->HacerSonido(); // Salida: Guau
    gato->HacerSonido(); // Salida: Miau

    delete perro;
    delete gato;

    return 0;
}

En JavaScript, no existe una sintaxis específica para métodos virtuales como en otros lenguajes, todos los métodos son virtuales.

class Animal {
    hacerSonido() {
        console.log("El animal hace un sonido");
    }
}

class Perro extends Animal {
    hacerSonido() {
        console.log("Guau");
    }
}

class Gato extends Animal {
    hacerSonido() {
        console.log("Miau");
    }
}

// Uso
let animal1 = new Perro();
let animal2 = new Gato();

animal1.hacerSonido(); // Salida: Guau
animal2.hacerSonido(); // Salida: Miau

En TypeScript, al igual que JavaScript, todos los métodos son virtuales.

class Animal {
    hacerSonido(): void {
        console.log("El animal hace un sonido");
    }
}

class Perro extends Animal {
    hacerSonido(): void {
        console.log("Guau");
    }
}

class Gato extends Animal {
    hacerSonido(): void {
        console.log("Miau");
    }
}

// Uso
const perro: Animal = new Perro();
const gato: Animal = new Gato();

perro.hacerSonido(); // Salida: Guau
gato.hacerSonido(); // Salida: Miau

En Python, nuevamente todos los métodos son virtuales por defecto.

class Animal:
    def hacer_sonido(self):
        print("El animal hace un sonido")

class Perro(Animal):
    def hacer_sonido(self):
        print("Guau")

class Gato(Animal):
    def hacer_sonido(self):
        print("Miau")

# Uso
perro = Perro()
gato = Gato()

perro.hacer_sonido() # Salida: Guau
gato.hacer_sonido() # Salida: Miau