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

Why virtual inheritance cause pointer offset?

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

但是我想不通为什么虚继承也会造成这种效果?我只知道虚拟继承是为了防止相同的多个实例 class.

下面是我的代码。

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;
}

如下代码

#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);
}

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

Base offset: 16
a offset: 16
Derived offset: 0
b offset: 8

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

+------+------+------+
| vptr |  b   |  a   |
+------+------+------+

              | Base |

|      Derived       |

如您所见,编译器尚未将 vptr 分配给 class Base。这是标准所要求的,因为 Base 是一种没有任何虚拟特征的 POD(普通旧数据)类型。 Derived class 必须包含一个 vptr 因为它有一个虚拟基础。因此,编译器不可能将 vptr-less Base 子对象放在 Derived 对象的最开头,因为它需要放置一个 vptr 在内存中的那个位置.