为什么我们不能使用“虚拟继承”在COM? [英] Why can't we use "virtual inheritance" in COM?

查看:110
本文介绍了为什么我们不能使用“虚拟继承”在COM?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读过一些含糊的陈述,说明 虚拟继承 不提供内存结构需要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内部的东西。编译器需要一些运行时线索(虚拟表)来查找继承自A成员。你最终需要几个指针到D实例中的几个虚拟表,作为继承B和继承C等的vtable,意味着一些内存开销。



单继承没有这些问题。实例的内存布局保持简单,虚拟表也更简单。这就是为什么Java不允许类的多重继承。在接口继承中没有数据成员,所以再次这些问题根本不会出现 - 没有什么 - 继承A与D的问题,也没有不同的方式来找到A在B之内取决于什么特定的B恰好在内。 COM和Java都可以允许多个接口继承,而不必处理这些复杂情况。



EDIT



我忘了说 - 没有数据成员,虚拟和非虚拟继承之间没有真正的区别。但是,使用Visual C ++,即使没有数据成员,布局也可能不同 - 无论是否存在任何数据成员,对每个继承类型使用相同的规则。



此外,COM内存布局匹配Visual-C ++布局(对于支持的继承类型),因为它被设计为这样做。没有理由为什么COM不能被设计为支持与数据成员的接口的多重和虚拟继承。 Microsoft可以设计COM以支持与C ++相同的继承模型,但是选择不 - 并且没有理由为什么他们应该这样做。



早期的COM代码经常用C编写,意味着手工编写的结构布局必须精确匹配Visual-C ++布局工作。布局多个和虚拟继承 - 好吧,我不会自愿做手动。此外,COM总是它自己的东西,意味着链接用许多不同的语言编写的代码。



更多编辑

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



在COM中,唯一重要的布局问题是虚拟表,只需要处理方法分派。布局取决于你是否采用虚拟或非虚拟方法,类似于具有数据成员的on对象的布局有显着的区别...




  • 对于非虚拟,D vtab包含A-within-B vtab和A-within-C vtab。

  • 对于虚拟,A仅在Ds内出现一次vtable,但是该对象包含多个vtables和指针转换需要地址更改。



接口继承,这基本上是实现细节 - 只有一组方法实现A。



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



COM无法检测虚拟案例,因为对象或vtable中没有指示符。此外,当没有数据成员时,没有必要支持两个约定。它只是支持一个简单的约定。


I have read some vague statement that virtual inheritance doesn't provide the memory structure required by COM, so we have to use the normal inheritance. Virtual inheritance is invented to handle the diamond problem.

Could someone show me an illustration of the difference of memory structure details between this two inherit approaches? And the key reason why virtual inheritance is not suitable for COM. A picture would be best.

Many thanks.

解决方案

COM interfaces are rather like JAVA interfaces in a way - they don't have data members. This means that interface inheritance is different to class inheritance when multiple inheritance is used.

To start with, consider non-virtual inheritance with diamond-shaped inheritance patterns...

  • B inherits A
  • C inherits A
  • D inherits B and C

An instance of D contains two separate instances of the data members of A. That means that when a pointer-to-A points into an instance of D, it needs to identify which instance of A within D it means - the pointer is different in each case, and pointer casts are not simple relabellings of the type - the address changes too.

Now consider the same diamond with virtual inheritance. Instances of B, C and D all contain a single instance of A. If you think of B and C having a fixed layout (including the A instance) this is a problem. If Bs layout is [A, x] and Cs layout is [A, y], then [B, C, z] is not valid for D - it would contain two instances of A. What you have to use is something like [A, B', C', z] where B' is everything from B except the inherited A etc.

This means that if you have a pointer-to-B, you don't have a single scheme for dereferencing the members inherited from A. Finding those members is different depending on whether the pointer points to a pure-B or a B-within-D or a B-within-something-else. The compiler needs some run-time clue (virtual tables) to find the inherited-from-A members. You end up needing several pointers to several virtual tables in the D instance, as theres a vtable for the inherited B and for the inherited C etc, implying some memory overhead.

Single inheritance doesn't have these issues. Memory layout of instances is kept simple, and virtual tables are simpler too. That's why Java disallows multiple inheritance for classes. In interface inheritance there are no data members, so again these problems simply don't arise - there's no issue of which-inherited-A-with-D, nor of different ways to find A-within-B depending on what that particular B happens to be within. Both COM and Java can allow multiple inheritance of interfaces without having to handle these complications.

EDIT

I forgot to say - without data members, there is no real difference between virtual and non-virtual inheritance. However, with Visual C++, the layout is probably different even if there are no data members - using the same rules for each inheritance style consistently irrespective of whether any data members are present or not.

Also, the COM memory-layout matches the Visual-C++ layout (for supported inheritance types) because it was designed to do that. There's no reason why COM couldn't have been designed to support multiple and virtual inheritance of "interfaces" with data members. Microsoft could have designed COM to support the same inheritance model as C++, but chose not to - and there's no reason why they should have done otherwise.

Early COM code was often written in C, meaning hand-written struct layouts that had to precisely match the Visual-C++ layout to work. Layouts for multiple and virtual inheritance - well, I wouldn't volunteer to do it manually. Besides, COM was always its own thing, meant to link code written in many different languages. It was never intended to be tied to C++.

YET MORE EDITING

I realised I missed a key point.

In COM, the only layout issue that matters is the virtual table, which only has to handle method dispatch. There are significant differences in layout depending on whether you take the virtual or non-virtual approach, similar to the layout of on object with data members...

  • For non-virtual, the D vtab contains an A-within-B vtab and an A-within-C vtab.
  • For virtual, the A only occurs once within Ds vtable, but the object contains multiple vtables and pointer casts need address changes.

With interface-inheritance, this is basically implementation detail - there's only one set of method implementations for A.

In the non-virtual case, the two copies of the A virtual table would be identical (leading to the same method implementations). Its a slightly larger virtual table, but the per-object overhead is less and the pointer casts are just type-relabelling (no address change). It's simpler and more efficient implementation.

COM can't detect the virtual case because there's no indicator in the object or vtable. Also, there's no point supporting both conventions when there's no data members. It just supports the one simple convention.

这篇关于为什么我们不能使用“虚拟继承”在COM?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆