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.