Herencia múltiple en C++


Herencia múltiple común

C++ nos permite derivar una clase a más de una superclase. La siguiente figura es la representación del diagrama UML de la herencia múltiple.

Imagen pendiente

Para declarar la herencia múltiple, tan solo hay que separar las clases base como se muestra en el siguiente ejemplo:

class Clase : public Clase-A, public Clase-B

class Hidroavion : public Avion, public Barco
class Sofacama : public Cama, public Sofa

Este es el código completo

#include <cstdio>
#include <cstdlib>
#include <iostream>

using namespace std;

class Cama
{
public:

    Cama()
    {
        cout << "Creando una Cama" << endl;
    }

    ~Cama()
    {
        cout << "Destruyendo la Cama" << endl;
    }
};

class Sofa
{
public:

    Sofa()
    {
        cout << "Creando un Sofa" << endl;
    }

    ~Sofa()
    {
        cout << "Destruyendo el Sofa" << endl;
    }
};

class Sofacama : public Cama, public Sofa
{
public:

    Sofacama()
    {
        cout << "Ahora tenemos un Sofacama" << endl;
    }

    ~Sofacama()
    {
        cout << "Destruyendo el Sofacama" << endl;
    }
};

int main()
{
    Sofacama ss;
    return 0;
}

Compilamos y ejecutamos el programa.

$ g++ Herencia.cxx -o Herencia
$ ./Herencia
Creando Cama
Creando Sofa
Ahora tenemos un Sofacama
Destruyendo Sofacama
Destruyendo Sofa
Destruyendo Cama

Herencia virtual

Es posible que la clase Cama y la clase Sofa hereden de una misma clase llamada Mueble. ¿Porqué?, hay que recordar que la herencia establece la relación es un, una Cama es un Mueble y un Sofa es un Mueble. Al agregar la clase Mueble nuestro código quedaría así:

#include <cstdio>
#include <cstdlib>
#include <iostream>

using namespace std;

class Mueble
{
public:

    Mueble()
    {
        cout << "Creando un Mueble" << endl;
    }

    ~Mueble()
    {
        cout << "Destruyendo en Mueble" << endl;
    }
};

class Cama : public Mueble
{
public:

    Cama()
    {
        cout << "Creando una Cama" << endl;
    }

    ~Cama()
    {
        cout << "Destruyendo la Cama" << endl;
    }
};

class Sofa : public Mueble
{
public:

    Sofa()
    {
        cout << "Creando un Sofa" << endl;
    }

    ~Sofa()
    {
        cout << "Destruyendo el Sofa" << endl;
    }
};

class Sofacama : public Cama, public Sofa
{
public:

    Sofacama()
    {
        cout << "Ahora tenemos un Sofacama" << endl;
    }

    ~Sofacama()
    {
        cout << "Destruyendo el Sofacama" << endl;
    }
};

int main()
{
    Sofacama ss;
    return 0;
}

Compilamos y Ejecutamos el programa. Pero en este caso observamos que se crearon dos clases Mueble o dos instancias, lo cual es un problema ya que solo deseamos crear un solo “mueble”, en este caso un Sofacama.

$ g++ Herencia.cxx -o Herencia
$ ./Herencia
Creando un Mueble
Creando una Cama
Creando un Mueble
Creando un Sofa
Ahora tenemos un Sofacama
Destruyendo el Sofacama
Destruyendo el Sofa
Destruyendo en Mueble
Destruyendo la Cama
Destruyendo en Mueble

Este ejemplo se representa con el diagrama UMl de la izquierda.

Imagen pendiente

Para evitar este problema debemos implementar el diagrama UML de la derecha. De este modo estamos creando una herencia de una clase base compartida, también llamada herencia virtual y así solo se crea una instancia de la clase compartida y no se crean dos objectos o muebles y generamos solo un Sofacama.

Para lograr esto tan solo hay que agregar la palabra virtual en todos los métodos de la clase, su destructor y al heredar la clase como se muestra en el siguiente código:

#include <cstdio>
#include <cstdlib>
#include <iostream>

using namespace std;

class Mueble
{
public:

    Mueble()
    {
        cout << "Creando un Mueble" << endl;
    }

    virtual void metodo() { /*  */ }

    virtual ~Mueble()
    {
        cout << "Destruyendo en Mueble" << endl;
    }
};

class Cama : public virtual Mueble
{
public:

    Cama()
    {
        cout << "Creando una Cama" << endl;
    }

    ~Cama()
    {
        cout << "Destruyendo la Cama" << endl;
    }
};

class Sofa : public virtual Mueble
{
public:

    Sofa()
    {
        cout << "Creando un Sofa" << endl;
    }

    ~Sofa()
    {
        cout << "Destruyendo el Sofa" << endl;
    }
};

class Sofacama : public Cama, public Sofa
{
public:

    Sofacama()
    {
        cout << "Ahora tenemos un Sofacama" << endl;
    }

    ~Sofacama()
    {
        cout << "Destruyendo el Sofacama" << endl;
    }
};

int main()
{
    Sofacama ss;
    return 0;
}

Y al Compilar y Ejecutar el programa observamos que solo se ha creado un solo objeto o mueble. El método que declaramos es solo representativo.

$ g++ Herencia.cxx -o Herencia
$ ./Herencia
Creando un Mueble
Creando una Cama
Creando un Sofa
Ahora tenemos un Sofacama
Destruyendo el Sofacama
Destruyendo el Sofa
Destruyendo la Cama
Destruyendo en Mueble

Recuerda que debemos utilizar la herencia virtual cuando las clases derivadas deban tener solo una instancia de la clase base compartida.

Problemas con la Herencia Múltiple

El problema con la herencia múltiple se debe a la Herencia de diamante ya que aumenta la complejidad. Hay quienes dices que se puede implementar de forma simple como la Herencia múltiple común sin la necesidad de recurrir al problema de diamante.

Por ejemplo, en el contexto del desarrollo de software GUI, una clase Botón puede heredar de las clases Rectángulo (para la apariencia) y Ratón (para los eventos de ratón), y las clases Rectángulo y Botón heredar a su vez de la clase Objeto. Si ahora el método EsIgualA es llamado para un objeto Botón y ese método no está definido en la clase Botón pero sí para Rectángulo y también para Ratón, ¿cuál de los dos métodos debería ser finalmente llamado?

Este ejemplo lo obtuve del artículo: Problema del diamante.

Java, C# y Objective-C no permiten herencia múltiple como C++. Sin embargo, permiten heredar múltiples interfaces.

Posted in

Leave a Reply