Leo*_*ldo 2 c++ inheritance casting reinterpret-cast
在做一些 c++ 练习时,我发现了一个与多继承和强制转换相关的有趣例子。
我不明白为什么
reinterpret_cast<char*>(b1) is not equal reinterpret_cast<char*>(b2)。
这是一个简单的程序,我在上面提到过:
#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 d;
A *b1 = &d;
B *b2 = &d;
const int a = (reinterpret_cast<char*>(b1) == reinterpret_cast<char*>(&d)) ? 1 : 2;
const int b = (b2 == &d) ? 3 : 4;
const int c = (reinterpret_cast<char*>(b1) == reinterpret_cast<char*>(b2)) ? 5 : 6;
std::cout << a << b << c << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当 reinterpret_cast(b1) 等于 reinterpret_cast(&d) 时,您能否对此主题提供任何评论以帮助我弄清楚为什么 reinterpret_cast(b1) 不等于 reinterpret_cast(b2)?
基类子对象必须以某种方式排列在最派生对象内的内存中。在您的情况下,编译器似乎是这样做的:
C---------------+
|A---+ B---+ |
||m_i| |m_d| m_c|
|+---+ +---+ |
+---------------+
Run Code Online (Sandbox Code Playgroud)
这意味着A子对象从与整个C对象相同的地址开始,但B子对象的大小A(即 an 的大小int)发生了偏移。
B *b2 = &d;
Run Code Online (Sandbox Code Playgroud)
因为b2是指向 的指针B,所以它指向B子对象,因此它指向的物理地址是移位后的地址。
至于为什么b2 == &d成立 - 永远无法比较指向不同类型的指针是否相等。但是指向派生类的指针可以隐式转换为指向基类的指针。Sob2 == &d实际上转换为b2 == static_cast<B*>(&d),它成立。请注意,隐式转换自然会应用移位,并且它与您b2最初用来获得的相同。
您可以尝试重新组织继承顺序或删除/添加一些数据成员以查看它如何影响布局。