C ++:使用继承的类的内存布局

时间:2014-08-05 11:29:26

标签: c++ inheritance multiple-inheritance memory-layout

我知道标准没有指定如何打包数据。我只是试图了解类的内存布局(尤其是dynamic_cast<void*>如何保证返回指向最派生类的开头的指针)。我想不出有关以下代码输出的任何解释:

struct A{ int a;};
struct B{ int b;};
struct C: public A, public B { int c;};
struct D:public C {int d;};


int main(){
  D* ob=new D;
  A* a = ob;
  B* b = ob;
  C* c = ob;
}

打印指针的值表明,acd始终具有相同的值,仅添加b 4个字节作为偏移量。这是偶然的吗?或者背后有一个逻辑?

修改 从概念上讲,布局应该像图像一样,但不知何故,点A,C和D合并为一个。enter image description here

3 个答案:

答案 0 :(得分:6)

首先,您的struct A

| int a |

B

| int b |

struct C继承struct Astruct B,并且还有一个成员int c。所以它可以有这样的布局:

            struct B
struct A     /
   \        /
| int a | int b | int c |
继承struct D

struct C

            struct B
struct A     /
   \        /
| int a | int b | int c | int d |
\-----------------------/
         struct C

现在想想D* ob = new D;。它会是这样的:

| int a | int b | int c | int d |
^
\
 ob

考虑A* a = ob - struct A位于struct D的偏移0处,所以它是

| int a | int b | int c | int d |
^
\
 a

等于struct c

然而,当涉及struct B时,它位于偏移4(如果sizeof(int) == 4),那么它是 -

| int a | int b | int c | int d |
        ^
        /
       b

请注意,布局未在标准中定义,并且每个实现可能不同。我向您展示了一种可能的布局。

如需高级信息,建议您阅读C++ Multiple Inheritance Memory Layout with "Empty classes"

答案 1 :(得分:0)

你的推理是正确的。但是,标准中没有定义布局,因此您不能依赖它。话虽这么说,大多数编译器会选择你在图中描绘的布局。

答案 2 :(得分:0)

  

打印指针的值表明,a,c,d始终具有相同的值,只有b被添加4个字节作为偏移量。

在D对象中,C子对象首先出现,所以它与完整的D对象具有相同的地址并不奇怪(你期望在C对象之前出现什么?为什么还有任何额外的对象? D?开头的字节数?)

在C对象中,A子对象首先出现,因此它与C对象具有相同的地址并不奇怪,因此如果C是D的子对象,它也有与完整D对象相同的地址。

  

是偶然的吗?或者背后有一个逻辑?

这不是偶然的。它由您的编译器的ABI定义。许多编译器遵循Itanium C++ ABI,它记录了必须如何布置类。