C ++:指针在传递后包含不同的地址

时间:2015-03-10 22:11:34

标签: c++ pointers visual-studio-2013 multiple-inheritance memory-address

所以我有一些像这样的代码:

#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;
}

但这是我在使用Visual Studio 2013编译后获得的输出:

  

这是B.我在地址0045F0B8

     

这是A. B位于地址0045F0B9

     

按任意键继续。 。

有人可以解释为什么地址不同吗?

2 个答案:

答案 0 :(得分:9)

0x0045F0B8是完整B对象的地址。 0x0045F0B9Base2对象的B子对象的地址。

通常,完整对象的地址可能与基类子对象的地址不同。在您的情况下,B对象可能如下所示:

+---+-------+
|   | Base1 | <-- 0x0045F0B8
| B |-------+
|   | Base2 | <-- 0x0045F0B9
+---+-------+

每个基类占用一个字节,Base1之前列出Base2。指向完整B的指针指向开头,位于0x0045F0B8,但指向Base2的指针指向完整B对象内的地址, Base2子对象启动,即0x0045F0B9

然而,当我使用g ++ 4.8在我的系统上编译程序时,我得到两行中打印的相同地址。这可能是因为允许实现为空基类(所谓的空基类优化)和两个基类子对象{{分配根本没有空间 1}}和Base1都位于Base2对象的最开头,没有空格,并与B共享其地址。

答案 1 :(得分:5)

B派生自Base1Base2,因此它包含Base1Base2包含的所有数据,以及BB::bar()包含的所有数据{1}}添加了它们。

Base2正在将一个指向A::for()部分的指针传递给B,而不是B::bar()部分。 B正在打印A::foo()部分的根地址,而Base2正在打印B部分的根地址。您传递的是同一个对象,但它们是该对象中的不同地址:

image

如果B未添加任何新数据,则其基本地址可能与其最近祖先的根地址相同(由于empty base optimization):

enter image description here

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

image2

始终将各个部分视为独立部分(因为它们逻辑上是)。仅仅因为Base2派生自B*并不能保证指向同一对象的Base2*指针和Base2*指针都指向相同的内存地址。 / p>

如果您有B指针且需要访问其dynamic_cast数据,请使用static_cast(或B,如果您确定对象是{{1} }})以确保正确的B*指针。您可以从B*转发Base2*而不进行投射(这就是B::bar()能够将this - B* - 传递给A::foo()的原因它期待Base2*作为输入)。给定B*指针,您始终可以直接访问其Base2数据。