为什么虚拟继承会导致指针偏移?

问题描述

我知道,由于内存布局的原因,在将派生类指针转换为基类指针时,多重继承和虚函数会导致指针偏移。

但是我不知道为什么虚拟继承也会导致这种情况?我对虚拟继承的唯一了解是防止同一类的多个实例。

下面是我的代码

class X 
{
public:
    int i;
};

class Y :virtual  public X 
{
    int j;
public:
    void vf(){};
};

int main()
{
    Y* py = new Y;
    X* px = (X*)py;

    cout<<py<<endl;
    cout<<px<<endl;
}

解决方法

以下代码

npm start

在我的机器(Debian / g ++)上产生以下输出:

node001 gpu,compute,randomgroup
node002 compute,randomgroup

因此,对象的布局是这样:

#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>

struct Base {
  long a;
};

struct Derived : virtual public Base {
  long b;
};

int main() {
  Derived object;
  intptr_t reference = (intptr_t)&object;
  printf("Base offset: %" PRIdPTR "\n",(intptr_t)(Base*)&object - reference);
  printf("a offset: %" PRIdPTR "\n",(intptr_t)&object.a - reference);
  printf("Derived offset: %" PRIdPTR "\n",(intptr_t)(Derived*)&object - reference);
  printf("b offset: %" PRIdPTR "\n",(intptr_t)&object.b - reference);
}

如您所见,编译器尚未为类Base offset: 16 a offset: 16 Derived offset: 0 b offset: 8 分配+------+------+------+ | vptr | b | a | +------+------+------+ | Base | | Derived | 。这是标准要求的,因为vptr是POD(普通旧数据)类型,没有任何虚拟功能。 Base类必须包含Base,因为它具有虚拟基数。因此,编译器不可能将Derived少的vptr子对象放在vptr对象的最开始,因为它需要放置{{1} }在内存中的那个位置