La herencia múltiple permite que una clase herede la interfaz y la implementación de más de una clase base. Esta es una poderosa característica de C++, que se ha utilizado ampliamente desde los primeros días del lenguaje para implementar arquitecturas complejas.
Historia del tema: La herencia múltiple se agregó a C++ como un medio para crear componentes reutilizables y combinar diferentes roles en una sola clase (por ejemplo, cuando un objeto es simultáneamente un hilo y una cola).
Problema: Las principales dificultades de la herencia múltiple son el 'diamond problem' (problema del diamante), la ambigüedad al acceder a miembros de las clases base y la no obviedad del orden de llamada a constructores/destructores.
Solución: Para evitar los problemas mencionados, C++ proporciona la herencia virtual. Esto garantiza que el ancestro común se creará exactamente una vez, incluso si hay varias cadenas que conducen a él en la jerarquía, y asegura el orden correcto de inicialización/destrucción.
Ejemplo de código:
class A { public: int value; A() : value(1) {} }; class B : virtual public A {}; class C : virtual public A {}; class D : public B, public C {}; int main() { D d; d.value = 10; // OK, solo un A return 0; }
Características clave:
Si la clase base se hereda dos veces (por la izquierda y por la derecha), ¿cuántas copias de esa clase habrá en la memoria del objeto?
Por defecto, dos, si no se utiliza herencia virtual. Solo con herencia virtual habrá exactamente una copia.
¿Es posible especificar explícitamente a qué clase base pertenece la referencia a un miembro cuando hay ambigüedad?
Sí, utilizando calificaciones:
d.B::value = 5; d.C::value = 6;
¿Cómo se determina el orden de llamada a constructores y destructores en caso de herencia múltiple?
El orden de llamada a los constructores corresponde al orden de declaración de las clases base en la lista de herencia (de izquierda a derecha), y luego a la clase derivada misma. Para los destructores, es al revés.
Un programador implementa un sistema de registro y colas a través de herencia múltiple, sin sospechar del problema del diamante. Como resultado, el registrador común se inicializa dos veces, lo que provoca un conflicto al liberar recursos.
Ventajas:
Desventajas:
Se utiliza herencia virtual para el registrador común, y los miembros de la clase se inicializan explícitamente en el constructor.
Ventajas:
Desventajas: