usa - ¿Cómo se implementa la herencia múltiple de C++?
para que se usa implements en java (7)
La herencia individual es fácil de implementar. Por ejemplo, en C, la herencia se puede simular como:
struct Base { int a; }
struct Descendant { Base parent; int b; }
Pero con herencia múltiple, el compilador tiene que organizar varios padres dentro de la clase recién construida. ¿Cómo se hace?
El problema que veo surgir es: ¿deberían organizarse los padres en AB o BA, o tal vez de otra manera? Y luego, si hago un elenco:
SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;
El compilador debe considerar si alterar o no el puntero original. Se requieren cosas complicadas similares con los virtuales.
Y luego, si hago un elenco:
SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;
El compilador debe considerar si alterar o no el puntero original. Cosas trucos similares con virtuales.
Con la herencia no virulenta, esto es menos complicado de lo que se podría pensar: en el punto donde se compila el elenco, el compilador conoce el diseño exacto de la clase derivada (después de todo, el compilador hizo el diseño). Por lo general, todo lo que sucede es un desplazamiento fijo (que puede ser cero para una de las clases base) se agrega / resta del puntero de clase derivado.
Con la herencia virutal es tal vez un poco más complejo, puede implicar tomar una compensación de una vblbl (o similar).
El libro de Stan Lippman, "Dentro del modelo de objetos C ++" tiene muy buenas descripciones de cómo esto podría funcionar (y a menudo realmente funciona).
El siguiente documento del creador de C ++ describe una posible implementación de herencia múltiple:
Herencia múltiple para C ++ - Bjarne Stroustrup
Este es un tema interesante que realmente no es específico de C ++. Las cosas se vuelven más complejas también cuando tienes un lenguaje con despacho múltiple y herencia múltiple (por ejemplo, CLOS).
La gente ya ha notado que hay diferentes maneras de abordar el problema. Puede que le resulte interesante leer un poco acerca de los Protocolos Meta-Object (MOP) en este contexto ...
Había un artículo muy antiguo de MSDN sobre cómo se implementó en VC ++.
He realizado un experimento simple:
class BaseA { int a; };
class BaseB { int b; };
class Descendant : public BaseA, BaseB {};
int main() {
Descendant d;
BaseB * b = (BaseB*) &d;
Descendant *d2 = (Descendant *) b;
printf("Descendant: %p, casted BaseB: %p, casted back Descendant: %p/n", &d, b, d2);
}
La salida es:
Descendant: 0xbfc0e3e0, casted BaseB: 0xbfc0e3e4, casted back Descendant: 0xbfc0e3e0
Es bueno darse cuenta de que la conversión estática no siempre significa "cambiar el tipo sin tocar el contenido". (Bueno, cuando los tipos de datos no se ajustan entre sí, también habrá una interferencia en el contenido, pero es diferente la situación de la OMI).
Los padres se organizan en el orden en que se especifican:
class Derived : A, B {} // A comes first, then B
class Derived : B, A {} // B comes first, then A
Su segundo caso se maneja de una manera específica del compilador. Un método común es usar punteros que son más grandes que el tamaño del puntero de la plataforma para almacenar datos adicionales.
Todo depende del compilador de cómo se hace, pero creo que se hace generalmente a través de una estructura jerárquica de tablas.