cpp-herencia

Qué es y cómo usar la herencia en C++

En C++ la herencia se utiliza para establecer una relación entre una clase base (o clase padre) y una clase derivada (o clase hija).

La clase derivada cuenta con todas las características públicas y protegidas de la clase base, además de las suyas propias. Esto le que permite extender o modificar el comportamiento de la clase base.

Implementación de la Herencia en C++

La herencia en C++ se define utilizando la sintaxis de dos puntos (:) seguida del tipo de herencia (public, protected, o private) y el nombre de la clase base.

class ClaseBase
{
    // Miembros de la clase base
};

class ClaseDerivada : public ClaseBase
{
    // Miembros adicionales de la clase derivada
};

Vamos a crear un ejemplo simple donde una clase Animal es la clase base y una clase Perro es la clase derivada:

#include <iostream>

class Animal
{
public:
    void Comer()
    {
        std::cout << "El animal está comiendo." << std::endl;
    }
};

class Perro : public Animal
{
public:
    void Ladrar()
    {
        std::cout << "El perro está ladrando." << std::endl;
    }
};

int main()
{
    Perro miPerro;
    miPerro.Comer();  // Heredado de Animal
    miPerro.Ladrar(); // Método definido en Perro

    return 0;
}

En este ejemplo,

  • La clase Perro hereda de Animal
  • Esto lo que significa que Perro tiene acceso al método Comer de Animal
  • Además de su propio método Ladrar.

Acceso a miembros clase padre

Puedes acceder a los miembros de la clase base directamente usando el nombre de la clase base seguido del operador de resolución de ámbito (::).

#include <iostream>

class Animal
{
public:
    std::string Nombre;

    Animal(const std::string& nombre) : Nombre(nombre) {}

    virtual void HacerSonido()
    {
        std::cout << "El animal hace un sonido." << std::endl;
    }
};

class Perro : public Animal
{
public:
    Perro(const std::string& nombre) : Animal(nombre) {}

    void HacerSonido() override
    {
        Animal::HacerSonido(); // Llama al método de la clase base
        std::cout << "El perro ladra." << std::endl;
    }
};

int main()
{
    Perro miPerro("Rex");
    miPerro.HacerSonido(); // Salida: El animal hace un sonido. El perro ladra.

    return 0;
}

Sobrescritura de Métodos

Las clases derivadas pueden sobrescribir métodos de la clase base para proporcionar una implementación específica.

Para hacerlo, el método en la clase base debe ser declarado con la palabra clave virtual, y el método en la clase derivada debe usar la palabra clave override.

#include <iostream>

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

class Perro : public Animal
{
public:
    void HacerSonido() override
    {
        std::cout << "El perro ladra." << std::endl;
    }
};

int main()
{
    Animal* miAnimal = new Perro();
    miAnimal->HacerSonido(); // Llama al método sobrescrito en Perro

    delete miAnimal;
    return 0;
}

En este ejemplo,

  • Perro sobrescribe el método HacerSonido de Animal.
  • Cuando llamamos a HacerSonido a través de un puntero a Animal, se ejecuta la versión sobrescrita en Perro.

Constructores en clases derivadas

Cuando se crea una instancia de una clase derivada, el constructor de la clase base se llama automáticamente antes del constructor de la clase derivada.

Puedes especificar qué constructor de la clase base se debe llamar utilizando el inicializador de lista de la clase derivada.

#include <iostream>

class Animal
{
public:
    std::string Nombre;

    Animal(const std::string& nombre) : Nombre(nombre) {}

    void MostrarNombre()
    {
        std::cout << "Nombre: " << Nombre << std::endl;
    }
};

class Perro : public Animal
{
public:
    std::string Raza;

    Perro(const std::string& nombre, const std::string& raza)
        : Animal(nombre), Raza(raza) {}

    void MostrarInfo()
    {
        MostrarNombre();
        std::cout << "Raza: " << Raza << std::endl;
    }
};

int main()
{
    Perro miPerro("Rex", "Labrador");
    miPerro.MostrarInfo(); // Salida: Nombre: Rex Raza: Labrador

    return 0;
}

En este ejemplo, el constructor de Perro llama al constructor de Animal para inicializar el campo Nombre.