在多重继承中保存在vtable c ++中的重写虚方法在哪里

时间:2015-09-13 10:36:48

标签: c++ multiple-inheritance vtable memory-layout vptr

在C ++中,运行时没有类表示,但我总是可以在派生类中调用重写的虚方法。哪个被覆盖的方法保存在vtable中?这是一段代码,用于演示:

struct B1 {
 virtual void f() { ... }
};
struct B2 {
 virtual void f() { ... }
 virtual void g() { ... }
};
struct D : B1, B2 {
 void f() { ... }
 virtual void h() { ... }
};

D类对象的内存布局是什么? B1 :: f和B2 :: f保存在那个内存布局中(如果它们完全保存的话)?

2 个答案:

答案 0 :(得分:0)

d的对象D将只有指向类D的{​​{3}}的指针,该指针将包含指向D :: f的指针。 由于B1:f和B2 :: f只能从D类的范围内静态调用,因此对象d不需要保留指向那些被重写方法的动态指针。

这个原因没有在标准中定义,这只是编译器的通常/逻辑实现。

事实上,图片更复杂,因为D类的VMT包含了B1和B2类的VMT。但无论如何,在创建B1类对象之前,不需要动态调用B1 :: f。

答案 1 :(得分:0)

虽然C ++标准中没有强制要求,但每个已知的C ++实现都使用相同的方法:每个至少具有虚函数的类都有一个vptr(指向vtable的指针)。

你没有提到虚拟继承,这是一种不同的,更微妙的继承关系;非虚拟继承是基类子对象和派生类之间的简单排他关系。 我将假设在这个答案中所有的继承关系都不是虚拟的。

这里我假设我们派生自至少具有虚函数的类。

在单继承的情况下,重用基类的vptr 。 (不重用它只会浪费空间和运行时间。)基类被称为" 主要基类"。

在多重继承的情况下,派生类的布局包含每个基类的布局,就像C中的结构布局包含每个成员的布局一样。 D的布局为B1,然后是B2(实际上以任何顺序排列,但通常会保留源代码顺序)。

第一个类是主要基类:在DB1的vptr指向D的完整vtable,vtable包含{{1}的所有虚函数}。来自非主要基类的每个vptr指向D的辅助vtable:只包含此辅助基类中的虚函数的vtable。

D的构造函数必须初始化类实例的每个vptr以指向D的相应vtable。