c++ - vtable:底层算法

标签 c++ compiler-construction multiple-inheritance vtable vptr

我对 vtables 的理解是,如果我有一个带有虚函数 speak() 的类 Cat,它有子类 Lion 和 HouseCat,则有一个 vtable 将 speak() 映射到每个子类的正确实现。于是打个电话

cat.speak()

编译为

cat.vtable[0]()

即在vtable位置0进行一次查找,并调用该位置的函数指针。

我的问题是:多重继承会怎样?

让我们添加一个类 Pet。 Pet 有虚函数 speak() 和 eat()。 HouseCat 扩展了 Pet,而 Lion 没有。现在,我需要确保

pet.eat()

编译为

pet.vtable[1]()

即vtable[0]需要speak()。 Pet.eat 需要位于 slot 1。那是因为 cat.speak() 需要访问 vtable 中的 slot 0,如果对于 HouseCat,slot 0 恰好是 eat,这将是非常错误的。

编译器如何确保 vtable 索引适合在一起?

最佳答案

规范没有设置任何内容,但通常编译器会为每个直接的非虚拟基类生成一个虚表,再加上派生类的虚表——然后是第一个基类的虚表和派生类的虚表类将被合并。

更具体地说,编译器在构造类时生成的内容:

  • [vptr | Cat fields]
     [0]: speak()
    
  • 宠物

    [vptr | Pet fields]
     [0]: eat()
    
  • 狮子

    [vptr | Cat fields | Lion fields]
     [0]: speak()
    
  • 家猫

    [vptr | Cat fields | vptr | Pet fields | HouseCat fields]
     [0]: speak()        [0]: eat()
    

编译器在调用/转换时生成的内容(变量名是静态类型名):

  • cat.speak()
    • obj[0][0]() - 对 Cat、Lion 和 HouseCat 的“Cat”部分有效
  • pet.eat()
    • obj[0][0]() - 对 Pet 和 HouseCat 的“Pet”部分有效
  • lion.speak()
    • obj[0][0]() - 对 Lion 有效
  • houseCat.speak()
    • obj[0][0]() - 对 HouseCat 的“猫”部分有效
  • houseCat.eat()
    • obj[Cat size][0]() - 对 HouseCat 的“宠物”部分有效
  • (猫)houseCat
    • 对象
  • (宠物)houseCat
    • obj + Cat 大小

所以我猜让您感到困惑的关键是 (1) 多个 vtable 是可能的,并且 (2) upcasts 实际上可能返回不同的地址。

关于c++ - vtable:底层算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43450179/

相关文章:

c++ - GDALOpen 在 GEOTiff 文件上返回 null

python - cythoning 类时出现空声明符错误?

linux - 如何告诉 "gmake"使用另一个版本的 GCC? (Linux)

c++ - 多重继承 : size of class for virtual pointers?

java - 派生类中的变量可能尚未初始化(使用构造函数)

c++ - OpenGL : Is There Any Way To Use glMaterialfv( ) to Create a Transparent/Translucent Object?

c++ - 简单的 C++ 地址/指针说明

c++ - 复制静态 union 成员的地址会给出不正确的地址

windows - 查看第 3 方 DLL 中的可用消息字符串(来自 mc.exe)

c++ - 被多重继承隐藏的嵌套类