在多重继承的情况下,C ++编译器如何处理成员变量内存偏移?

时间:2017-02-26 11:28:01

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

假设我们有基类:

class CommonClass {
  ...
  int common_value;
}

class ParentOfA {
  ...
  int some_int;
  int some_int_2;
}

class ParentOfB {
  ...
  int some_int_3;
}

我们继承了类:

class ClassA : ParentOfA, CommonClass
class ClassB : ParentOfB, CommonClass

然后ClassAClassB的结构如下所示:

ClassA:
  ParentOfA:
    int some_int;
    int some_int_2;
    int common_value;

ClassB:
  ParentOfB:
    int some_int_3;
    int common_value;

因此,对于相同的common_value成员变量,在ClassA中它距离ClassA的指针只有8个字节,而在ClassB中它只有4个字节。

然后在下面的例子中(假设它已经在如此编译的.cpp文件中):

int GetCommonValue(CommonClass* ptr) {
  return ptr->common_value;
}

编译器如何提前知道处理->common_value时要查找的偏移量? ClassAClassB都可以作为指针传入。

2 个答案:

答案 0 :(得分:0)

将调用者的正确地址传递给函数是调用者的工作。指向类的指针始终指向同一个类的对象的开头 - 以便成员偏移可以工作。

对于单继承,基础和派生对象从相同的地址开始(换句话说,基础部分位于派生对象的开头)。

对于所有基类,多重继承都是不可能的 - 只有一个基类与派生对象在同一地址开始。这意味着拥有类型为ClassA的对象和三个指针 - 类型为CommonClass,ParentOfA和ClassA,在比较CommonClass和ParentOfA指针时,其中一个将指向与ClassA指针相同的地址。另一个将指向不同的地址 - 基类部分的开头,与指针的类型相同。

哪个指针指向对象内存位置的开头,取决于派生对象中基本部分的顺序。此订单是实现定义的。

答案 1 :(得分:0)

您的结构图实际上如下所示:

ClassA:
  ParentOfA:
    int some_int;
    int some_int_2;
  CommonClass:
    int common_value;

ClassB:
  ParentOfB:
    int some_int_3;
  CommonClass:
    int common_value;

(您省略了CommonClass:前缀)。

希望很明显,在给定common_value的情况下找到CommonClass *的偏移量是没有问题的。

也许您忽略了如果将ClassB *转换为CommonClass *,它会指向内存中的其他位置?编译器知道CommonClassClassB的偏移量,就像它知道任何成员变量的偏移量一样。