简体   繁体   English

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

[英]C++: Pointer contains different address after being passed

So i have some code like this: 所以我有一些像这样的代码:

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

But this is the output i get after compiling with Visual Studio 2013: 但这是我在使用Visual Studio 2013编译后获得的输出:

This is B. I am at the address 0045F0B8 这是B.我在地址0045F0B8

This is A. B is at the address 0045F0B9 这是A. B位于地址0045F0B9

Press any key to continue . 按任意键继续 。 . .

Can somebody please explain why the addresses are different? 有人可以解释为什么地址不同?

0x0045F0B8 is the address of the complete B object. 0x0045F0B8是完整B对象的地址。 0x0045F0B9 is the address of the Base2 subobject of the B object. 0x0045F0B9B对象的Base2子对象的地址。

In general the address of the complete object might not be the same as the address of a base class subobject. 通常,完整对象的地址可能与基类子对象的地址不同。 In your case the B object is probably laid out as follows: 在您的情况下, B对象可能如下布局:

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

Each base class occupies one byte and Base1 is laid out before Base2 . 每个基类占用一个字节, Base1Base2之前布局。 The pointer to the complete B points to the beginning, which is at 0x0045F0B8 , but the pointer to the Base2 points to the address inside the complete B object at which the Base2 subobject starts, which is 0x0045F0B9 . 指向完整B的指针指向开头,位于0x0045F0B8 ,但指向Base2的指针指向Base2子对象启动的完整B对象内的地址,即0x0045F0B9

However when I compile your program on my system using g++ 4.8, I get the same address printed in both lines. 但是当我使用g ++ 4.8在我的系统上编译你的程序时,我得到了两行中打印的相同地址。 This is presumably because the implementation is allowed to allocate no space at all for empty base classes (the so-called empty base class optimization ) and the two base class subobjects Base1 and Base2 are both located at the very beginning of the B object, taking no space, and sharing their address with B . 这可能是因为允许实现为空基类(所谓的空基类优化根本不分配空间,并且两个基类子对象Base1Base2都位于B对象的最开头,没有空间,并与B分享他们的地址。

B derives from Base1 and Base2 , so it consists of all the data that Base1 and Base2 contain, and all of the data that B adds on top of them. B派生自Base1Base2 ,因此它包含Base1Base2包含的所有数据,以及B在其上添加的所有数据。

B::bar() is passing a pointer to the Base2 portion of itself to A::for() , not the B portion of itself. B::bar()将指向其自身的Base2部分的指针传递给A::for() ,而不是它自身的B部分。 B::bar() is printing the root address of the B portion, whereas A::foo() is printing the root address of the Base2 portion instead. B::bar()正在打印B部分的根地址,而A::foo()正在打印Base2部分的根地址。 You are passing around the same object, but they are different addresses within that object: 您传递的是同一个对象,但它们是该对象中的不同地址:

图片

If B does not add any new data, its base address might be the same as the root address of its nearest ancestor (due to empty base optimization ): 如果B不添加任何新数据,则其基址可能与其最近祖先的根地址相同(由于空基优化 ):

在此输入图像描述

Don't rely on that. 不要依赖于此。 A compiler might add padding between the classes, for instance: 编译器可能会在类之间添加填充,例如:

图像2

Always treat the various sections as independent (because they logically are). 始终将各个部分视为独立的(因为它们在逻辑上是)。 Just because B derives from Base2 does not guarantee that a B* pointer and a Base2* pointer, both pointing at the same object, will point at the same memory address. 仅仅因为B派生自Base2并不能保证指向同一对象的B*指针和Base2*指针都指向同一个内存地址。

If you have a Base2* pointer and need to access its B data, use dynamic_cast (or static_cast if you know for sure the object is a B ) to ensure a proper B* pointer. 如果您有Base2*指针并需要访问其B数据,请使用dynamic_cast (如果您确定该对象是B ,则使用static_cast )以确保正确的B*指针。 You can downcast from B* to Base2* without casting (which is why B::bar() is able to pass this - a B* - to A::foo() when it is expecting a Base2* as input). 您可以从B*向下转换为Base2*而不进行转换(这就是为什么B::bar()能够将this - B* - 传递给A::foo()当它期望Base2*作为输入时)。 Given a B* pointer, you can always access its Base2 data directly. 给定B*指针,您可以始终直接访问其Base2数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM