为何地址不同的基类指针与派生类指针比较结果相等?
多继承下指针比较为何不会触发断言失败?
C++标准在[expr.eq#3]中对指针比较的定义如下:
否则,若两个指针均为空、均指向同一函数,或均表示同一地址,则它们比较相等。
关于“表示同一地址”,[basic.compound#def:represents_the_address]中的定义为:
指向对象或对象末尾之后的指针类型的值,分别表示该对象占用内存的第一个字节([intro.memory])或该对象占用存储之后内存的第一个字节。34
既然指针比较本质基于地址,那为何如下代码不会断言失败?技术上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);// 按说应该失败,因为d_ptr和b_ptr指向的对象地址不同!
这是因为C++标准对不同类型指针的比较做了隐式调整。当比较D*和B1*类型的指针时,编译器会先将d_ptr隐式转换为B1*类型(与b_ptr同类型),再进行地址比较。
具体来说,d_ptr指向完整的D对象,当它被转换为B1*时,会自动调整指针值,指向D对象中B1子对象的起始地址——这个地址和b_ptr的地址完全一致。所以转换后的d_ptr和b_ptr表示的是同一个地址,比较结果自然为true,断言不会触发。
你可能误以为是直接比较原始D*和B1*的地址值,但实际上C++的指针相等比较规则要求,当比较不同类型的对象指针时,会先将其中一方转换为另一方的类型(遵循指针转换规则),再基于转换后的指针所表示的地址进行比较。
内容的提问来源于stack exchange,提问作者minex
相关产品推荐
相关产品推荐

