这是我的代码。我只想看看虚拟继承的内存布局。
#include<iostream>
using namespace std;
class A{
private:
int a;
public:
virtual void print() const{
cout << a << endl;
}
};
class B:public virtual A{
private:
int b;
public:
void print() const{
cout << b << endl;
}
};
int main(){
A a;
B b;
return 0;
}
然后在gdb中,我使用了
p a
p b
输出是
(gdb) p a
$1 = {
_vptr.A = 0x400b40 <vtable for A+16>,
a = 0
}
(gdb) p b
$2 = {
<A> = {
_vptr.A = 0x400b18 <vtable for B+56>,
a = 4196384
},
members of B:
_vptr.B = 0x400af8 <vtable for B+24>,
b = 0
}
(gdb)
我知道_vptr.A和_vptr.B的含义,但我不了解vtable对B + 24或A + 16意味着什么。
感谢您的回答!
最佳答案
a
的 list 表明它是一个具有两个字段的类:vptr指向A的vtable内具有偏移量16的字节,而数据元素a
包含零。
第二种是相同的思路,但是由于虚拟基类而更加复杂。也就是说b由3个字段组成:A的一个实例,其字段类似于上面的字段,然后是B的两个元素,同样如上。这次,vptr指向偏移量24。
为什么vptr指向表的中间而不是表的开始?您需要更多地了解gcc内存布局的细节,而我不是。初始字节可能是RTTI(运行时类型信息),给定的偏移量是虚函数指针数组的第一个元素。还有许多其他选择。
注意in this earlier article有一些很好的信息,它表示始终有2个指针引导vtable:一个指针用于多继承顶级指针,另一个指针用于RTTI。如果您的机器和编译器是64位(您确实应该提到这一点;这很重要),则这与16个字节的指针重合。 B可以是24个字节,因为还有一个额外的指针可以访问虚拟基类。