and*_*927 3 c++ pointers multiple-inheritance memory-address visual-studio-2013
所以我有一些像这样的代码:
#include <iostream>
using namespace std;
class Base1 {};
class Base2 {};
class A
{
public:
A() {}
void foo(Base2* ptr) { cout << "This is A. B is at the address " << ptr << endl; }
};
A *global_a;
class B : public Base1, public Base2
{
public:
B() {}
void bar()
{
cout << "This is B. I am at the address " << this << endl;
global_a->foo(this);
}
};
int main()
{
global_a = new A();
B *b = new B();
b->bar();
system("pause");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但这是我在使用Visual Studio 2013编译后获得的输出:
这是B.我在地址0045F0B8
这是A. B位于地址0045F0B9
按任意键继续 ...
有人可以解释为什么地址不同?
0x0045F0B8是完整B对象的地址.0x0045F0B9是Base2对象的子对象的地址B.
通常,完整对象的地址可能与基类子对象的地址不同.在您的情况下,B对象可能布局如下:
+---+-------+
| | Base1 | <-- 0x0045F0B8
| B |-------+
| | Base2 | <-- 0x0045F0B9
+---+-------+
Run Code Online (Sandbox Code Playgroud)
每个基类占用一个字节并Base1在之前布局Base2.指向完整B点的指针指向开头,0x0045F0B8指向,但指向指向子对象开始Base2的完整B对象内的地址的指针Base2,即0x0045F0B9.
但是当我使用g ++ 4.8在我的系统上编译你的程序时,我得到了两行中打印的相同地址.这可能是因为允许实现根本没有为空基类(所谓的空基类优化)和两个基类子对象分配空间,Base1并且Base2它们都位于对象的最开头B,没有空间,和他们分享他们的地址B.
B派生自Base1和Base2,因此它包含所有包含的数据,Base1以及在它们之上添加的Base2所有数据B.
B::bar()将指针传递给Base2自身A::for()的B一部分,而不是自身的一部分. B::bar()正在打印B部分A::foo()的根地址,Base2而是打印部分的根地址.您传递的是同一个对象,但它们是该对象中的不同地址:

如果B不添加任何新数据,则其基址可能与其最近祖先的根地址相同(由于空基优化):

不要依赖于此.编译器可能会在类之间添加填充,例如:

始终将各个部分视为独立的(因为它们在逻辑上是).仅仅因为B派生Base2不能保证指向同一对象的B*指针和Base2*指针都指向同一个内存地址.
如果您有一个Base2*指针并需要访问其B数据,请使用dynamic_cast(或者static_cast如果您确定该对象是a B),以确保正确的B*指针.你可以向下转换B*到Base2*没有转换(这就是为什么B::bar()能够传递this- 到B*- A::foo()当它期望Base2*作为输入时).给定B*指针,您始终可以Base2直接访问其数据.