为什么指向具有不同地址的基类的指针与派生类指针相比等于

min*_*nex 5 c++ pointers object language-lawyer

标准定义的指针比较基本上来自 [expr.eq#3]

否则,如果指针都为空,都指向同一个函数,或者都表示相同的地址,则它们比较相等。

表示相同的地址意味着来自 [basic.compound#def:represents_the_address]

指向或超过对象末尾的指针类型的值表示object34占用的内存中第一个字节([intro.memory])的地址或存储结束后的内存中第一个字节的地址分别被物体占据

所以这实际上与地址有关,但如果是这样,那么为什么这段代码不会失败,因为技术上d_ptrb_ptr指向具有不同地址的对象?这看起来像是关于对象,而不是地址,因为编译器可以找出 d_ptr 和 b_ptr 最后指向同一个完整对象!

struct B { int a;};
struct B1 { int b; };
struct D : B, B1 {};
struct A {};
....
D obj;
D *d_ptr = &obj;
B1 *b_ptr = d_ptr;
assert(d_ptr == b_ptr);//should have failed as d_ptr and b_ptr point to objects with diffrent addresses!
Run Code Online (Sandbox Code Playgroud)

n. *_* m. 10

你错过了这段

如果至少其中一个操作数是指针,则对这两个操作数执行指针转换、函数指针转换和限定转换,以将它们转换为复合指针类型。

指针转换可以更改指针表示的地址,这正是您的情况所发生的情况。


Cli*_*ord 6

在表达式中,d_ptr == b_ptr有一个隐式转换为d_ptr-B1*公共基类。当发生这种情况时,地址是相等的,因此标准并没有“错误” - 标准中也定义了转换。

例如,通过显式转换(在第二行中):

std::cout << static_cast<void*>(b_ptr) << " != " << static_cast<void*>(d_ptr) << '\n' ;
std::cout << static_cast<void*>(b_ptr) << " == " << static_cast<void*>(static_cast<B1*>(d_ptr)) << '\n' ;
Run Code Online (Sandbox Code Playgroud)

输出(在我的测试中):

std::cout << static_cast<void*>(b_ptr) << " != " << static_cast<void*>(d_ptr) << '\n' ;
std::cout << static_cast<void*>(b_ptr) << " == " << static_cast<void*>(static_cast<B1*>(d_ptr)) << '\n' ;
Run Code Online (Sandbox Code Playgroud)

第二个显示显式转换修改了地址。隐式转换也不例外。

反过来:

0x7ffdefb36204 != 0x7ffdefb36200
0x7ffdefb36204 == 0x7ffdefb36204
Run Code Online (Sandbox Code Playgroud)

结果是:

void* b_addr = b_ptr ;
void* d_addr = d_ptr ;
assert( d_addr == b_addr ) ;
Run Code Online (Sandbox Code Playgroud)

正如您所期望的那样,没有转换为公共基数的直接地址比较会失败。同样,没有中间指针:

a.out: main.cpp:24: int main(): Assertion `d_addr == b_addr' failed.
Run Code Online (Sandbox Code Playgroud)

也会失败。