En C ++, una clase puede heredar (directa o indirectamente) de más de una clase, lo que se conoce como
herencia múltiple .
C # y Java, sin embargo, limitan las clases a una herencia única que cada clase hereda de una única clase principal.
La herencia múltiple es una forma útil de crear clases que combinan aspectos de dos jerarquías de clases dispares, algo que ocurre a menudo cuando se utilizan diferentes marcos de clase dentro de una sola aplicación.
Si dos marcos definen sus propias clases base para las excepciones, por ejemplo, puede usar herencia múltiple para crear clases de excepción que se pueden usar con cualquiera de los marcos.
El problema de la herencia múltiple es que puede generar ambigüedad. El ejemplo clásico es cuando una clase hereda de otras dos clases, cada una de las cuales hereda de la misma clase:
class A {
protected:
bool flag;
};
class B : public A {};
class C : public A {};
class D : public B, public C {
public:
void setFlag( bool nflag ){
flag = nflag; // ambiguous
}
};
En este ejemplo, el flag
miembro de datos está definido por class A
. Pero class D
desciende de class B
y class C
, que ambos derivan de A
, por lo que, en esencia, dos copias de flag
están disponibles debido a dos instancias de A
están en D
la jerarquía de clases 's. ¿Cuál quieres configurar? El compilador se quejará de que la referencia a flag
en D
es ambigua . Una solución es eliminar la ambigüedad explícita de la referencia:
B::flag = nflag;
Otra solución es declarar B y C como virtual base classes
, lo que significa que solo puede existir una copia de A en la jerarquía, eliminando cualquier ambigüedad.
Existen otras complejidades con la herencia múltiple, como el orden en el que se inicializan las clases base cuando se construye un objeto derivado, o la forma en que los miembros pueden ocultarse inadvertidamente de las clases derivadas. Para evitar estas complejidades, algunos lenguajes se limitan al modelo de herencia única más simple.
Aunque esto simplifica considerablemente la herencia, también limita su utilidad porque solo las clases con un ancestro común pueden compartir comportamientos. Las interfaces mitigan un poco esta restricción al permitir que las clases en diferentes jerarquías expongan interfaces comunes incluso si no están implementadas compartiendo código.