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

C++ 为什么虚拟继承会导致指针偏移?,c++,pointers,casting,virtual-inheritance,C++,Pointers,Casting,Virtual Inheritance,我知道,由于内存布局的原因,在将派生类指针强制转换为基类指针时,多个继承和虚拟函数会导致指针偏移 然而,我不明白为什么虚拟继承也会造成这种影响?关于虚拟继承,我只知道防止同一类的多个实例 下面是我的代码 class X { public: int i; }; class Y :virtual public X { int j; public: void vf(){}; }; int main() { Y* py = new Y; X* px =

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

然而,我不明白为什么虚拟继承也会造成这种影响?关于虚拟继承,我只知道防止同一类的多个实例

下面是我的代码

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;
}
X类
{
公众:
int i;
};
Y类:虚拟公共X
{
int j;
公众:
void vf(){};
};
int main()
{
Y*py=新的Y;
X*px=(X*)py;
cout以下代码

#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);
}
因此,对象的布局如下所示:

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

              | Base |

|      Derived       |

如您所见,编译器没有将
vptr
分配给类
Base
。这是标准所要求的,因为
Base
是POD(普通旧数据)键入时不带任何虚拟功能。
派生的
类必须包含一个
vptr
,因为它有一个虚拟基。因此,编译器不可能将
vptr
-less
子对象放在
派生的
对象的最开头,因为它需要在内存中的该位置

请不要添加不相关的标记。这显然不是C代码。px的值与py的值不同“也可能导致此问题?”:这不是问题,是吗?请解释为什么在这种情况下,您认为指针偏移是一个问题。这是一件事,表明存在(有效的)问题在a
Y
中只有一个
X
,另外一个建议
X
Y
应该在同一个地址。想象一下,如果存在多个
Y
X1
X2
等虚拟基,会发生什么情况-你真的建议a
Y
的地址应该是相等的吗l到所有
X1
X2
等的地址,以获得更多信息:同时打印对象内两个变量的地址(或相对偏移量)。间隙将显示vtable指针的位置。vptr(如果存在)不必先来。它必须在<代码>派生对象中有固定的偏移量,以便编译器能够找到它。在旧的日子里,VPTR的位置是不同的。当微软引入COM时,是COM要求VPTR在前面,而C++编译器没有做过,所以它们会工作。使用COM时。@PeteBecker我记得在(经典)Mac OS(68000或第一代PowerPC)上,Metrowerks CodeWarrior在对象的一端有vptr,在另一端有Symantec“THINK C”/C++(但我不记得哪个是哪个)@curiousguy-Borland的编译器最初将vtable放在基类数据的末尾。当我们添加COM支持时,它移到了前面。
+------+------+------+
| vptr |  b   |  a   |
+------+------+------+

              | Base |

|      Derived       |