以下代码将输出显示为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;
}
答案 0 :(得分:1)
当您在示例中使用多重继承时,第一个基类和派生类共享相同的基址。您继承的其他类按顺序排列,基于所有前面类的大小。比较结果为真,因为d
和b1
的基址相同。
在您的情况下,如果A
的大小为4个字节,则B
将从A
+ 4个字节的基址开始。执行B *b2 = &d;
时,编译器会计算偏移量并相应地调整指针值。
当您执行b2 == &d
时,在完成比较之前,会在d
上执行从类型'C'到类型'B'的隐式转换。此转换调整指针值的偏移量,就像在赋值中一样。
答案 1 :(得分:0)
对于派生类(如C
这里)来说,在内存中布局是非常典型的,所以它从它的两个基类(A
和B
)开始,所以地址类型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
,因为如前所述,将C
到A
或B
的实例的指针投射会有不同的结果(转换为转换为A *
时,B *
不进行调整。)