替代虚拟机制实现?

Alo*_*ave 48 c++ virtual-functions vtable vptr

C++支持通过虚拟机制进行动态绑定.但据我所知,虚拟机制是编译器的实现细节,标准只是指定了在特定场景下应该发生的行为.大多数编译器通过虚拟表和虚拟指针实现虚拟机制.是的,我知道这是如何工作的,所以我的问题不是关于虚拟指针和表的实现细节.我的问题是:

  1. 是否有任何编译器以虚拟指针和虚拟表机制以外的任何其他方式实现虚拟机制?据我所见,最多(阅读g ++,Microsoft visual studio)通过虚拟表,指针机制实现它.那么实际上还有其他任何编译器实现吗?
  2. sizeof只有一个虚函数的任何类的将是一个指针(vptr的内部尺寸this)上编译,所以考虑到虚拟PTR和TBL机制本身是编译器实现,将这个说法我在上面做永远是真的吗?

Ytt*_*ill 21

对象中的vtable指针始终是最有效的.我的编译器用于另一种语言,用于使用对象内指针,原因类似但不再使用:相反,它使用一个单独的数据结构,将对象地址映射到所需的元数据:在我的系统中,这恰好是形状信息供使用由垃圾收集器.

此实现成本单个简单对象更多的位存储,是用于与许多个碱基复杂对象更有效,而且它是极大地用于阵列更有效的,因为只有一个条目在映射表所需的阵列中的所有对象.我的特定实现还可以找到给定指向对象内部任何点的指针的元数据.

实际查找非常快,存储要求非常适度,因为我使用的是地球上最好的数据结构:Judy数组.

我也知道没有使用除vtable指针之外的任何C++编译器,但它不是唯一的方法.事实上,具有基础的类的初始化语义使任何实现都变得混乱.这是因为完整类型必须在构造对象时进行跷跷板.作为这些语义的结果,复杂的mixin对象导致生成大量的vtable,大对象和慢对象初始化.这可能不是vtable技术的结果,而是需要盲目地遵循子对象的运行时类型始终是正确的要求.实际上在构造过程中没有充分的理由,因为构造函数不是方法,也不能合理地使用虚拟调度:由于析构函数是真正的方法,因此我不太清楚破坏.

  • @kotlinski:不是只涉及参考语义的语言...... (6认同)
  • "对数组来说效率更高"为什么你想首先用虚拟对象创建一个数组呢?它似乎真的没用,被认为阵列是同质的.(至少在C++中) (3认同)
  • 在最后一段:在建造和销毁期间,同样的原因是为了跟踪混凝土类型.虽然构造函数和析构函数都不是真正的成员函数,但它们可以调用其他成员函数,包括虚拟成员函数.不同的语言以不同的方式处理问题,C++跟踪每个阶段的对象类型,Java考虑到对象始终是最派生的类型.这两种方法都不完美,但这是一项必须采取的设计决策. (3认同)

Jan*_*ray 7

据我所知,所有的C++实现都使用vtable指针,尽管在对象中保留一个小的类型索引(1-2 B)并且很容易(并且可能没有你认为给定的缓存那么糟糕)随后通过小表查找获取vtable和类型信息.

另一个有趣的方法可能是BIBOP(http://foldoc.org/BIBOP) - 大量的页面 - 虽然它会有C++的问题.想法:在页面上放置相同类型的对象.通过简单地"关闭"对象指针的不太重要的位来获取指向页面顶部的类型描述符/ vtable的指针.(当然,对堆栈中的对象不起作用!)

另一种方法是在对象指针本身中编码某些类型标签/索引.例如,如果通过构造将所有对象都对齐为16字节,则可以使用4个LSB在其中放置4位类型标记.(还不够.)或者(特别是对于嵌入式系统)如果你保证地址中未使用的更高有效位,你可以在那里放置更多的标记位,并使用移位和掩码恢复它们.

虽然这两种方案对于其他语言实现都很有趣(有时也会使用),但它们对于C++来说是个问题.某些C++语义,例如在(基类)对象构造和销毁期间调用哪些基类虚函数覆盖,会将您带到一个模型,在该模型中,当您输入基类ctors/dtors时,对象中存在某些状态.

您可能会发现我对Microsoft C++对象模型实现的旧教程很有趣. http://www.openrce.org/articles/files/jangrayhood.pdf

快乐的黑客!


Joh*_*ski 5

  1. 我不认为有任何现代编译器使用除vptr/vtable之外的方法.实际上,很难找出其他不仅仅是效率低下的东西.

    但是,在该方法中,设计权衡仍有相当大的空间.特别是关于如何处理虚拟继承.因此,定义此实现是有意义的.

    如果您对这类内容感兴趣,我强烈建议您阅读C++对象模型内部.

  2. sizeof class取决于编译器.如果您想要可移植代码,请不要做任何假设.

  • @Als:例如......如果我们在一个应用程序中有最多256个类,编译器+链接器*可以*在char中打包一个typeid并在查找表中找到vptr.然后我们有sizeof(T)== 1. (6认同)

Che*_*Alf 5

是否有任何编译器以虚拟指针和虚拟表机制以外的任何其他方式实现虚拟机制?据我所见,最多(阅读g ++,Microsoft visual studio)通过虚拟表,指针机制实现它.那么实际上还有其他任何编译器实现吗?

我所知道的所有当前编译器都使用vtable机制.

这是一种可能的优化,因为C++是静态类型检查的.

在一些更动态的语言中,有一个动态搜索基类链,搜索虚拟调用的成员函数的实现,从对象的最派生类开始.例如,这就是它在原始Smalltalk中的工作方式.并且C++标准描述了虚拟调用的效果,就像使用了这样的搜索一样.

在Borland/Turbo Pascal中,在1990年代,这种动态搜索用于查找Windows API"窗口消息"的处理程序.我认为Borland C++可能也是如此.它是普通vtable机制的补充,仅用于消息处理程序.

如果它在Borland/Turbo C++中使用 - 我不记得了 - 那么它支持一种语言扩展,允许你将消息id与消息处理函数相关联.

只有一个虚函数的任何类的sizeof将是该编译器上指针的大小(在此内部的vptr),因此假设虚拟ptr和tbl机制本身是编译器实现,我上面的这个语句是否总是正确的?

形式上没有(即使假设vtable机制),它取决于编译器.由于标准不需要vtable机制,因此它没有说明在每个对象中放置vtable指针.其他规则允许编译器在最后自由添加填充,未使用的字节.

但也许在实践中.;-)

然而,这不是你应该依赖的东西,或者你需要依赖的东西.但在另一个方向,您可以要求这样做,例如,如果您正在定义ABI.然后任何没有的编译器根本不符合您的要求.

干杯&hth.,