[英]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. 0x0045F0B9
是B
对象的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
. 每个基类占用一个字节, Base1
在Base2
之前布局。 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
. 这可能是因为允许实现为空基类(所谓的空基类优化 ) 根本不分配空间,并且两个基类子对象Base1
和Base2
都位于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
派生自Base1
和Base2
,因此它包含Base1
和Base2
包含的所有数据,以及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: 编译器可能会在类之间添加填充,例如:
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.