vtable和多态 - 函数的偏移量

时间:2014-09-24 16:32:41

标签: c++ polymorphism multiple-inheritance virtual-functions vtable

如果我理解正确,类定义会在vtable中强加虚函数的某个顺序,因此已知给定函数与表的开头有一定的偏移量。但是,我不明白它是如何与多态性一起工作的。

class B1 {
  virtual void funcB1();
};

class B2 {
  virtual void funcB2() {}
};

class D : public B1, public B2 {
  virtual void funcB1() {}
  virtual void funcB2() {}
};

void main(...) {
  B1 *b1 = new D();
  B2 *b2 = new D();
  B1 *realB1 = new B1();
  B2 *realB2 = new B2();

  b1->funcB1();
  b2->funcB2();
  realB1->funcB1();
  realB2->funcB2();
}

生成的代码如何知道如何在不同的偏移量下访问funcB2?

2 个答案:

答案 0 :(得分:1)

通常D对象将有两个 vtable指针,每个基类一个。它确实无法避免,因为它必须包含每个基类的相同二进制布局。无论何时从一种类型转换为另一种类型,编译器都会插入指针修正 - 如果在转换为每个基类后打印指针地址,您将看到它们是不同的。

答案 1 :(得分:1)

当您从两个基类组成一个类时,每个部分都由一个功能完备的块在结果类中表示,并带有自己的指向vtable的指针。这就是生成的代码如何知道要调用的函数:将D的指针强制转换为B1B2会产生不同的指针,因此生成的代码可以使用相同的偏移量进入虚拟表

D *d = new D();
B1 *b1 = dynamic_cast<B1*>(d);
B2 *b2 = dynamic_cast<B2*>(d);
printf("%p %p %p", (void*)d, (void*)b1, (void*)b2);

produces the following output on ideone

0x91c7008 0x91c7008 0x91c700c

请注意D*B1*如何打印相同的值,而B2*打印不同的值。当您致电b2->funcB2()时,指针b2已经指向D对象的不同部分,该部分指向不同的vtable(布局为B2的vtable ),因此生成的代码不需要对您的示例中的b2 vs realB2执行任何不同的操作。