在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保存在那个内存布局中(如果它们完全保存的话)?
答案 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
(实际上以任何顺序排列,但通常会保留源代码顺序)。
第一个类是主要基类:在D
中B1
的vptr指向D
的完整vtable,vtable包含{{1}的所有虚函数}。来自非主要基类的每个vptr指向D
的辅助vtable:只包含此辅助基类中的虚函数的vtable。
D
的构造函数必须初始化类实例的每个vptr以指向D
的相应vtable。