使用reintepret_cast解释对象地址

时间:2013-05-26 21:43:46

标签: c++ casting

以下代码将输出显示为136.但我无法理解前两个地址比较是如何相等的。感谢任何帮助以理解这一点。谢谢。

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

3 个答案:

答案 0 :(得分:1)

当您在示例中使用多重继承时,第一个基类和派生类共享相同的基址。您继承的其他类按顺序排列,基于所有前面类的大小。比较结果为真,因为db1的基址相同。

在您的情况下,如果A的大小为4个字节,则B将从A + 4个字节的基址开始。执行B *b2 = &d;时,编译器会计算偏移量并相应地调整指针值。

当您执行b2 == &d时,在完成比较之前,会在d上执行从类型'C'到类型'B'的隐式转换。此转换调整指针值的偏移量,就像在赋值中一样。

答案 1 :(得分:0)

对于派生类(如C这里)来说,在内存中布局是非常典型的,所以它从它的两个基类(AB)开始,所以地址类型C的实例与其第一个基类(即A)的实例的地址相同。

答案 2 :(得分:0)

在这种继承中(当不涉及virtual时)C的每个实例都将具有以下布局:

  • 首先,会有A的所有成员(只是m_i,一个4字节的整数)
  • 第二个将是B的所有成员(仅m_d,一个8字节的双倍)
  • 最后一位将是C本身的所有成员,这只是一个字符(1个字节,m_c

当您将C的实例转换为A时,由于A是第一个父级,因此不会进行地址调整,并且两个指针的数值将会是相同的。这就是第一次比较评估为true的原因。 (注意,对指针执行reinterpret_cast<char *>()永远不会导致调整,因此它总是给出指针的数值。转换为void *会产生相同的效果,并且可能比较安全。)

将指向C的实例的指针转换为B 导致指针调整(4个字节),这意味着b2的数值将等于&d。但是,当您直接比较b2&d时,编译器会自动为&d生成一个转换为B *,这会将数值调整为4个字节。这就是第二次比较也评估为true的原因。

第三个比较返回false,因为如前所述,将CAB的实例的指针投射会有不同的结果(转换为转换为A *时,B *不进行调整。)