指针值是不同的,但他们比较相等。 为什么?
一个简短的例子输出一个奇怪的结果!
#include <iostream> using namespace std; struct A { int a; }; struct B { int b; }; struct C : A, B { int c; }; int main() { C* c = new C; B* b = c; cout << "The address of b is 0x" << hex << b << endl; cout << "The address of c is 0x" << hex << c << endl; if (b == c) { cout << "b is equal to c" << endl; } else { cout << "b is not equal to c" << endl; } }
我非常惊讶的是输出结果如下:
The address of b is 0x003E9A9C The address of c is 0x003E9A98 b is equal to c
我想知道的是:
0x003E9A9C不等于0x003E9A98,但输出是“b等于c”
一个C
对象包含两个typesA
和B
子对象。 显然,这些地址必须有不同的地址,因为两个单独的对象不能有相同的地址。 所以最多只能有一个与C
对象相同的地址。 这就是为什么打印指针给出不同的值。
比较指针不会简单地比较它们的数值。 只有同一types的指针可以比较,所以第一个指针必须转换为匹配另一个指针。 在这种情况下, c
被转换为B*
。 这与用于初始化b
转换完全相同:它调整指针值,使其指向B
子对象而不是C
对象,现在两个指针比较相等。
C
types对象的内存布局将如下所示:
| <---- C ----> | |-A: a-|-B: b-|- c -| 0 4 8 12
我从对象的地址(在像你的sizeof(int)= 4)的平台中添加了字节偏移量。
在你的主体中,你有两个指针,为了清晰起见,我将它们重命名为pb
和pc
。 pc
指向整个C对象的开始,而pb
指向B子对象的开始:
| <---- C ----> | |-A: a-|-B: b-|- c -| 0 4 8 12 pc-^ pb-^
这就是他们的价值观不同的原因。 3E9A98 + 4是3E9A9C,以hex表示。
如果现在比较这两个指针,编译器会看到一个B*
和C*
之间的比较,它们是不同的types。 所以它必须应用隐式转换,如果有的话。 pb
不能被转换成C*
,但反过来也是可能的 – 它将pc
转换成B*
。 这个转换会给出一个指针,指向pc
指向的B子对象 – 当你定义B* pb = pc;
时,它是相同的隐式转换B* pb = pc;
。 结果等于pb
,显然是:
| <---- C ----> | |-A: a-|-B: b-|- c -| 0 4 8 12 pc-^ pb-^ (B*)pc-^
所以比较这两个指针时,编译器实际上比较了转换的指针,它们是相等的。
我知道有一个答案,但也许这将是一个例子更直接和备份。
if (b == c)
在c
操作数中有一个从C*
到B*
的隐式转换,
如果你使用这个代码:
#include <iostream> using namespace std; struct A { int a; }; struct B { int b; }; struct C : A, B { int c; }; int main() { C* c = new C; B* b = c; cout << "The address of b is 0x" << hex << b << endl; cout << "The address of c is 0x" << hex << c << endl; cout << "The address of (B*)c is 0x" << hex << (B*)c << endl; if (b == c) { cout << "b is equal to c" << endl; } else { cout << "b is not equal to c" << endl; } }
你得到:
The address of b is 0x0x88f900c The address of c is 0x0x88f9008 The address of (B*)c is 0x0x88f900c b is equal to c
所以c
转换成B*
types的地址与b
相同。 正如所料。
如果我可以加上Mike的优秀答案,如果你把他们视为void*
那么你会得到你预期的行为:
if ((void*)(b) == (void*)(c)) ^^^^^^^ ^^^^^^^
版画
b is not equal to c
在C(语言)上做类似的事情实际上使得编译器感到恼火,因为比较了不同types的指针。
我有:
warning: comparison of distinct pointer types lacks a cast [enabled by default]
在计算(或者说,我们应该在math中说)可以有许多平等的概念。 任何对称,自反和传递的关系都可以用作平等。
在你的程序中,你正在检查两个有点不同的概念:按位实现的标识(两个指向完全相同的地址)与基于对象标识的另一种相等,它允许通过不同的引用静态types,要正确地视为引用同一个对象。
这些不同types的视图使用不具有相同地址值的指针,因为它们locking在对象的不同部分。 编译器知道这一点,所以它会为考虑到这个偏移量的相等比较生成正确的代码。
这是由inheritance带来的对象结构,这使得有必要有这些抵消。 当有多个基地(由于多重inheritance),只有一个基地可以在对象的低地址,以便指向基地部分的指针是相同的指向派生的对象。 其他基地部分是在对象的其他地方。
所以,根据对象的面向对象视图,指针的按位比较不会产生正确的结果。
这里有一些很好的答案,但有一个简短的版本。 “两个对象是相同的”并不意味着他们有相同的地址。 这意味着将数据放入其中并从中取出数据是等同的。