Hay una serie de problemas con la herencia múltiple cuando se usa con clases completas, pero todas giran en torno a la ambigüedad .
La ambigüedad se muestra de diferentes maneras:
- Si tiene dos clases base con el mismo campo
x
, y el tipo derivado pregunta x
, ¿qué obtiene?
- Si las dos
x
variables tienen tipos incongruentes, podría inferirlo.
- Si son del mismo tipo, podría intentar fusionarlos en la misma variable.
- Siempre puedes exponerlos como nombres raros y totalmente calificados.
- Si tiene dos clases base con la misma función
f
con firmas idénticas y alguien llama f
, ¿a quién se llama?
- ¿Qué pasa si las dos clases base comparten otro ancestro virtual común (el problema del diamante)?
- ¿Qué pasa si la función tiene firmas diferentes pero compatibles?
- Cuando construyes una clase con dos clases base, ¿cuál de los constructores de las clases base se llama primero? Cuando destruyes el objeto, ¿cuál es asesinado?
- Cuando coloca el objeto en la memoria, ¿cómo lo hace de manera consistente?
- ¿Cómo manejas todos estos casos con 3 clases base? 10?
Y eso ignora cosas como el despacho dinámico, la inferencia de tipos, la coincidencia de patrones y otras cosas sobre las que sé menos y que se vuelven más desafiantes cuando el lenguaje admite la herencia múltiple de clases completas.
Los rasgos o Mix-ins (o interfaces, o ...) son construcciones que limitan específicamente las capacidades de un tipo para que no haya ambigüedad. Raramente poseen algo ellos mismos. Esto permite que la composición de los tipos sea más suave porque no hay dos variables o dos funciones ... hay una variable y una referencia; una función y una firma. El compilador sabe qué hacer.
El otro enfoque común adoptado es obligar al usuario a "construir" (o mezclar) su tipo de uno en uno. En lugar de que las clases base sean socios iguales en el nuevo tipo, agrega un tipo a otro, anulando todo lo que estaba allí (generalmente con sintaxis opcional para renombrar y / o volver a exponer los bits anulados).
¿Hay algo que no es posible con mixins / rasgos pero posible con herencia múltiple estilo C ++?
Dependiendo del idioma, generalmente se vuelve problemático o imposible combinar implementaciones de funciones y almacenamiento para variables de múltiples clases base y exponerlas en el tipo derivado.
¿Es posible encontrarse con un problema de diamantes con ellos?
Ocasionalmente, aparecerán variaciones menos severas en función de su idioma, pero generalmente no. El punto completo de los rasgos es romper ese tipo de ambigüedad.