5

以下代码给出的输出为 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;
}
4

3 回答 3

1

当您在示例中使用多重继承时,第一个基类和派生类共享相同的基地址。您继承的其他类根据所有先前类的大小按偏移量排列。比较结果为真,因为 和 的基地址d相同b1

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

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

于 2013-05-26T22:11:50.027 回答
0

C派生类(如这里)布置在内存中是非常典型的,因此它从它的两个基类(AB)开始,因此类型实例C的地址将与其第一个基类的实例的地址相同(即A)。

于 2013-05-26T22:15:51.903 回答
0

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

  • 首先,将有A(也就是m_i,一个 4 字节整数)的所有成员
  • 第二个将是所有成员B(这只是m_d一个 8 字节双精度)
  • 最后将是C它自己的所有成员,这只是一个字符(1个字节,m_c

当你将指针转换为 to 的实例时CA因为A是第一个父级,所以不会发生地址调整,并且两个指针的数值将相同。这就是第一个比较结果为 的原因true。(请注意,在reinterpret_cast<char *>()指针上执行 a 永远不会导致调整,因此它总是给出指针的数值。转换为void *将具有相同的效果,并且可能比较安全。)

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

第三个比较返回false,因为如前所述,将指针转换为CtoA或 to的实例B将产生不同的结果(转换为A *不做调整,而转换为B *做。)

于 2013-05-26T22:34:18.030 回答