vtable:底层算法

Ale*_*lex 8 c++ compiler-construction multiple-inheritance vtable vptr

我对vtable的理解是,如果我有一个带有虚函数的Cat,带有子类Lion和HouseCat的函数,那么有一个vtable,它将speak()映射到每个子类的正确实现.所以一个电话

cat.speak()
Run Code Online (Sandbox Code Playgroud)

编译成

cat.vtable[0]()
Run Code Online (Sandbox Code Playgroud)

也就是说,在vtable位置0中查找并在该位置调用函数指针.

我的问题是:多重继承会发生什么?

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

pet.eat()
Run Code Online (Sandbox Code Playgroud)

编译为

pet.vtable[1]()
Run Code Online (Sandbox Code Playgroud)

那就是vtable [0]需要说话().Pet.eat需要是插槽1.这是因为cat.speak()需要访问vtable中的插槽0,如果对于HouseCat,插槽0恰好吃了,这将是非常错误的.

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

Oak*_*Oak 1

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

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

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

  • cat.speak()
    • obj[0][0]()- 适用于猫、狮子和 HouseCat 的“猫”部分
  • pet.eat()
    • obj[0][0]()- 适用于宠物和 HouseCat 的“宠物”部分
  • lion.speak()
    • obj[0][0]()- 对狮子有效
  • houseCat.speak()
    • obj[0][0]()- 适用于 HouseCat 的“Cat”部分
  • houseCat.eat()
    • obj[Cat size][0]()- 适用于 HouseCat 的“宠物”部分
  • (Cat)houseCat
    • obj
  • (Pet)houseCat
    • obj + Cat size

所以我想让你困惑的关键是(1)多个虚函数表是可能的,(2)向上转换实际上可能返回不同的地址。