我试图解决一个c ++测试,看到了这个问题。
#include <iostream>
class A
{
public:
A() : m_i(0) { }
protected:
int m_i;
};
class B
{
public:
B() : m_d(0.0) { }
protected:
double m_d;
};
class C
: public A
, public B
{
public:
C() : m_c('a') { }
private:
char m_c;
};
int main()
{
C c;
A *pa = &c;
B *pb = &c;
const int x = (pa == &c) ? 1 : 2;
const int y = (pb == &c) ? 3 : 4;
const int z = (reinterpret_cast<char*>(pa) == reinterpret_cast<char*>(pb)) ? 5 : 6;
std::cout << x << y << z << std::endl;
return 0;
}
136
任何人都可以解释它的输出吗?我认为基指针指向基本部分的一部分,所以它不是对象的真实地址。
感谢。
答案 0 :(得分:3)
pa
指向A
的{{1}}子对象。 c
指向pb
的{{1}}子对象。显然,它们指向内存中的不同位置(因此输出中为B
)。
但是当它们与c
进行比较时,6
又分别转换为&c
和&c
,从而指向相同的A*
和{{ 1}}子对象。
以下是内存中B*
的可能布局:
A
答案 1 :(得分:2)
<强>背景强>
对象C在内存中看起来像这样
----------- <----- Start of the object
| A |
|---------| <----- Beginning of B implementation
| B |
|---------|
| C |
|_________| <----- End of the object
当您从派生类中获取指向基类的指针(例如A * pa =&amp; c)时,指针指向该对象的该类实现的开头。
所以这意味着A *将指向A的开头(恰好是对象的开头)而B *将指向B的开头。注意C *不会指向C的开头,因为它知道C是从A和B派生的。它将指向对象的开头。
<强>为什么吗
因为当你调用pb-&gt; someFunction()时,它实际上将指针指向B并添加一些预先计算的偏移并执行。如果pb指向A的开头,那么它将在A内部结束。预先计算的偏移是必要的,因为你不知道pb实际指向的是什么(是C,它是“D”,还是只是普通的老B?)。这种方法使我们始终可以依靠偏移来找到函数。
以下是您的代码正在做的事情
((A*)pa == (A*)&c) // Obviously true, since we defined it as such above.
((B*)pb == (B*)&c) // Obviously true, since we defined it as such above.
(reinterpret_cast<char*>(pa) == reinterpret_cast<char*>(pb)) // We know pa and pb point to different places in memory. If we cast them both to char*, they will obviously not be equivalent.
尝试一个有趣的事情是
if (pa == pb)
这会给你一个编译错误,因为你需要将两个指针都转换为一个普通类型。