Las interfaces COM son bastante parecidas a las interfaces JAVA de una manera: no tienen miembros de datos. Esto significa que la herencia de interfaz es diferente a la herencia de clase cuando se usa herencia múltiple.
Para empezar, la herencia considerar no virtual con patrones de herencia en forma de diamante ...
- B hereda una
- C hereda una
- D hereda B y C
Una instancia de D contiene dos instancias separadas de los miembros de datos de A. Eso significa que cuando un apuntador a A apunta a una instancia de D, necesita identificar qué instancia de A dentro de D significa - la punta r es diferente en cada caso, y los lanzamientos de puntero no son simples relés del tipo - la dirección también cambia.
Considere ahora el mismo diamante con herencia virtual. Las instancias de B, C y D contienen una única instancia de A. Si considera que B y C tienen un diseño fijo (incluida la instancia A), esto es un problema. Si el diseño de Bs es [A, x] y el diseño de Cs es [A, y], entonces [B, C, z] no es válido para D - contendría dos instancias de A. Lo que tiene que usar es algo así como [ A, B ', C', z] donde B 'es todo desde B excepto el A heredado, etc.
Esto significa que si tiene un puntero-a-B, no tiene un solo esquema para desreferenciar los miembros heredados de A. Encontrar esos miembros es diferente dependiendo de si el puntero apunta a un B puro o un B dentro de D o un B dentro de algo diferente. El compilador necesita alguna pista en tiempo de ejecución (tablas virtuales) para encontrar los miembros heredados de A. Terminas necesitando varios punteros a varias tablas virtuales en la instancia D, ya que hay un vtable para el B heredado y para el C heredado, etc., lo que implica un poco de sobrecarga de memoria.
La herencia simple no tiene estos problemas. El diseño de la memoria de las instancias se mantiene simple, y las tablas virtuales son más simples también. Es por eso que Java no permite herencia múltiple para las clases. En la herencia de la interfaz no hay miembros de datos, así que de nuevo estos problemas simplemente no surgen, no hay problema, que heredaron A-con-D, ni de diferentes maneras de encontrar A dentro de B, dependiendo de qué B particular pasa a estar dentro. Tanto COM como Java pueden permitir herencia múltiple de interfaces sin tener que manejar estas complicaciones.
EDITAR
me olvidaba decir - sin miembros de datos, no hay ninguna diferencia real entre la herencia virtual y no virtual. Sin embargo, con Visual C++, el diseño es probablemente diferente, incluso si no hay miembros de datos, utilizando las mismas reglas para cada estilo de herencia consistentemente independientemente de si hay miembros de datos presentes o no.
Además, el diseño de la memoria COM coincide con el diseño de Visual-C++ (para los tipos de herencia soportados) porque fue diseñado para hacer eso. No hay ninguna razón por la que COM no se haya diseñado para admitir herencia múltiple y virtual de "interfaces" con miembros de datos. Microsoft podría haber diseñado COM para admitir el mismo modelo de herencia que C++, pero optó por no hacerlo, y no hay ninguna razón por la que deberían haber hecho lo contrario.
El código COM antiguo a menudo se escribía en C, es decir, distribuciones de estructuras manuscritas que tenían que coincidir exactamente con el diseño de Visual-C++ para funcionar. Diseños para la herencia múltiple y virtual: bueno, no me ofrecería voluntariamente para hacerlo manualmente. Además, COM siempre fue lo suyo, con la intención de vincular el código escrito en muchos idiomas diferentes. Nunca se pretendió vincularlo a C++.
AÚN MÁS DE EDICIÓN
me di cuenta de que me perdí un punto clave.
En COM, el único problema de diseño que importa es la tabla virtual, que solo debe gestionar el envío de métodos. Existen diferencias significativas en el diseño, dependiendo de si se toma el enfoque virtual o no virtual, similar a la disposición de el objeto con miembros de datos ...
- Para no virtual, el VTAB D contiene una A- dentro de B vtab y A-within-C vtab.
- Para virtual, el A solo aparece una vez dentro de Ds vtable, pero el objeto contiene varios vtables y los modelos de puntero necesitan cambios de dirección.
Con interfaz de la herencia, esto es básicamente detalle de implementación - sólo hay una serie de implementaciones de métodos de A.
En el caso no virtual, las dos copias de la tabla virtual Un serían idénticos (llevando a las mismas implementaciones de método). Es una tabla virtual un poco más grande, pero la sobrecarga por objeto es menor y los lanzamientos del puntero son simplemente re-etiquetados (sin cambio de dirección). Es una implementación más simple y más eficiente.
COM no puede detectar el caso virtual porque no hay indicador en el objeto o vtable. Además, no tiene sentido apoyar ambas convenciones cuando no hay miembros de datos. Simplemente es compatible con la única convención simple.
Me resulta muy incómodo obtener la aceptación de esta respuesta. ¿Cómo hago para que me la quiten? - Respondí detenidamente, editado para continuar, y hay algo aquí que probablemente explique un aspecto clave de por qué sucedió esto en los primeros días del COM, pero solo tengo una comprensión muy limitada y anticuada del COM, y esto responder simplemente no es exacto. En DCOM, simplemente no puede ser correcto, e incluso en días de "cuándo-era-simplemente-el-OLE2-back-end", una implementación de QueryInterface probablemente podría hacer lo que quiera en principio. – Steve314
"_Single inheritance no tiene estos problemas." Obviamente, con single hay solo un vptr y vtable compartidos. "_En la herencia de interfaz no hay miembros de datos, por lo que nuevamente estos problemas simplemente no surgen_" si "estos problemas" se refieren a su descripción anterior de "Usted necesita varios punteros a varias tablas virtuales en la instancia D" y "implica un poco de memoria ", entonces esto obviamente está mal: el MI de las interfaces implica tantos vptr y vtables como interfaces heredadas, en C++ o en Java, si desea mantener la eficiencia del tiempo de ejecución de las llamadas a funciones virtuales de C++. – curiousguy
"_ Olvidé decir que, sin miembros de datos, no existe una diferencia real entre la herencia virtual y no virtual._" Absolutamente no es correcto. Me temo que simplemente no entiendes la herencia en C++. "_Sin embargo, con Visual C++, el diseño es probablemente diferente, incluso si no hay miembros de datos_", el diseño ciertamente no es el mismo para 'struct D: B' y para' struct D: virtual B'.No veo cómo podrían tener un diseño similar, sin ser muy ineficientes. – curiousguy