c – 为什么我们不能在COM中使用“虚拟继承”?

前端之家收集整理的这篇文章主要介绍了c – 为什么我们不能在COM中使用“虚拟继承”?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经读了一些含糊的陈述,virtual inheritance没有提供COM所要求的内存结构,所以我们必须使用正常的继承.发明了虚拟遗产来处理钻石问题.

有人可以向我展示这两种继承方式之间的记忆结构细节的区别吗?虚拟继承不适合COM的关键原因.一张照片将是最好的.

非常感谢.

解决方法

COM接口在某种程度上就像JAVA接口 – 它们没有数据成员.这意味着当使用多重继承时,接口继承与类继承不同.

首先,考虑使用菱形继承模式的非虚拟继承…

B继承A
> C继承A
> D继承B和C

D的一个实例包含A的数据成员的两个独立的实例.这意味着当一个指向A的指针指向D的实例时,它需要识别D内的A的哪个实例 – 指示符是不同的每个案例和指针转换都不是类型的简单的重新标注 – 地址也改变了.

现在考虑与虚拟继承相同的钻石. B,C和D的实例都包含A的单个实例.如果您认为B和C具有固定的布局(包括A实例),这是一个问题.如果Bs布局是[A,x]和Cs布局是[A,y],则[B,C,z]对于D无效 – 它将包含两个A的实例.你必须使用的是像[ A,B’,C’,z]其中B’是来自B的一切,除了继承的A等

这意味着如果您有一个指向B的指针,则您没有一个解除引用从A继承的成员的方案.根据指针是指向纯B还是B内部-D或B-else-else.编译器需要一些运行时线索(虚拟表)来查找从A继承的成员.您最终需要在D实例中的几个虚拟表的几个指针,因为继承的B和继承的C等的vtable意味着一些内存开销.

单一继承没有这些问题.实例的内存布局保持简单,虚拟表也比较简单.这就是为什么Java不允许类的多重继承.在接口继承中,没有数据成员,所以再一次这些问题根本就不会出现 – 没有问题的是哪个继承的A-D,也不是不同的方式来查找A-B内部,取决于什么特定的B恰巧在内. COM和Java都可以允许多个继承的接口,而不必处理这些并发症.

编辑

我忘了说 – 没有数据成员,虚拟和非虚拟继承之间没有真正的区别.然而,使用Visual C,布局可能不同,即使没有数据成员 – 对于每个继承样式使用相同的规则,无论是否存在任何数据成员.

此外,COM内存布局匹配Visual C布局(支持的继承类型),因为它被设计为这样做.没有理由为什么COM不能被设计为支持与数据成员的“接口”的多个虚拟继承. Microsoft可以设计COM来支持与C相同的继承模型,但是选择不使用 – 并且没有理由他们应该做到这一点.

早期的COM代码通常用C编写,这意味着手写结构布局必须精确地匹配Visual C布局才能正常工作.多重和虚拟继承的布局 – 我不会自愿手动进行.此外,COM始终是自己的东西,意在链接用许多不同语言编写的代码.它从来没有意图与C有关.

更多编辑

我意识到我错过了一个关键点.

在COM中,唯一重要的布局问题是虚拟表,只能处理方法分派.根据您是否采用虚拟或非虚拟方法,布局方面存在显着差异,类似于使用数据成员的对象的布局…

>对于非虚拟的,D vtab包含A-in-B vtab和A-in-C vtab.
>对于虚拟,A只在Ds vtable中发生一次,但该对象包含多个vtables,并且指针转换需要更改地址.

使用接口继承,这基本上是实现细节 – 只有一组方法实现为A.

在非虚拟情况下,A虚拟表的两个副本将是相同的(导致相同的方法实现).它是一个稍大的虚拟表,但每个对象的开销较少,并且指针转换只是类型重新标记(无地址更改).它更简单和更有效的实现.

COM无法检测虚拟案例,因为对象或vtable中没有指示符.另外,当没有数据成员时,没有任何意义支持这两个约定.它只是支持一个简单的约定.

猜你在找的C&C++相关文章