C ++多重继承内存寻址问题

时间:2012-04-07 17:44:29

标签: c++ inheritance mingw32

如果正确完成,请忽略#include部分。这也可能是特定于实现的(但是vtable的概念也是如此)但我很好奇,因为它增强了我对多重继承的可视化。 (顺便说一句,我使用的是MinGW 4.4.0)

初始代码:

class A {
public:
   A() : a(0) {}
   int a;
};

//Edit: adding this definition instead
void f(void* ptrA) {
   std::cout<<((A*)ptrA)->a;
}
//end of editing of original posted code

#if 0
//this was originally posted. Edited and replaced by the above f() definition
void f(A* ptrA) {
   std::cout<<ptrA->a;
}
#endif

编译并生成对象代码。

在我使用的其他一些编译单元中(在包含上述代码的头文件之后):

class C : public B , public A {
public:
   int c;
}objC;

f(&objC); // ################## Label 1

objC的内存模型:

//<1> stuff from B
//<2> stuff from B
//<3> stuff from A : int a
//<4> stuff from C : int c

&objC将包含起始地址&lt; 1&gt;在上面假设的记忆模型中 编译器如何/何时将其转换为&lt; 3&gt;?是否在检查Label 1的电话时发生了什么?

修改::

因为Lable 1似乎是一个赠品,只是让它对编译器来说更加模糊。请参阅上面的编辑代码。现在编译器什么时候做?在哪里?

2 个答案:

答案 0 :(得分:1)

简短回答:如果编译器知道基类和派生类之间的关系,它将在转换操作期间调整指针值。

假设您的C类对象实例的地址位于地址100.并且假设sizeof(C)== 4. sizeof(B)和sizeof(A)。

当演员阵容发生时如下:

C c;
A* pA = &c;  // implicit cast, preferred for upcasting
A* pA = (A*)&c; // explicit cast old style
A* pA = static_cast<A*>(&c); // static-cast, even better

pA的指针值将是c的存储器地址加上“A”从C开始的偏移量。在这种情况下,假设sizeof(B)也是4,pA将引用存储器地址104.

所有这一切都适用于将派生类指针传递到期望基类指针的函数中。隐式转换将与指针偏移调整一样发生。

同样,对于向下转型:

C* pC = (C*)(&a);

编译器将负责在分配期间调整指针值。

所有这一切的“问题”是在没有完整声明的情况下向前声明一个类:

 // foo.h
 class A;  // same as above, base class for C
 class C;  // same as above, derived class from A and B

 inline void foo(C* pC)
 {
      A* pA = (A*)pC; // oops, compiler doesn't know that C derives from A.  It won't adjust the pointer value during assigment
      SomeOtherFunction(pA); // bug! Function expecting A* parameter is getting garbage
 }

这是一个真正的错误!

我的一般规则。使用static_cast运算符避免使用旧的“C风格”强制转换,或者只依靠隐式强制转换而不使用运算符来执行正确的操作(对于upcast)。如果转换无效,编译器将发出错误。

答案 1 :(得分:1)

是的,你是完全正确的。

要完全理解这种情况,你必须知道编译器在两点上知道什么:

  1. 在标签1处(正如您已经确定的那样)
  2. 内部函数f()

    (1)编译器知道C和A的确切二进制布局以及如何从C *转换为A *,并且将在调用站点(标签1)执行此操作

    (2)但是,在函数f()内部,编译器只需要(需要)知道A *,因此将自身限制为A的成员(在本例中为int a),不能混淆是否特定实例是其他任何内容的一部分。