为什么虚继承会导致指针偏移?
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
在内存中的那个位置.
我知道在将派生 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
在内存中的那个位置.