这是我的代码。我只想看看虚拟继承的内存布局。

#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个字节,因为还有一个额外的指针可以访问虚拟基类。

08-16 20:31