4

After reading C++: Comparing pointers of base and derived classes, I thought for sure this wouldn't work.

When I executed this, the printed addresses for c_as_b and &c were different, so why does this print "seems safe to compare pointers in same hierarchy"? What is being compared besides the printed addresses that could result in true?

Can you give a similar small example where the == results in false?

#include <iostream>
using namespace std;

struct A { std::string s; };
struct B { int i; };
struct C : A, B { double d; };

int main() {
    C c;
    B* c_as_b = &c;
    A* c_as_a = &c;
    cout << "c_as_a: " << c_as_a << endl
         << "c_as_b: " << c_as_b << endl
         << "&c:     " << &c << endl;
    cout << (c_as_b == &c ? "seems safe to compare pointers in same hierarchy" : "definately not safe") << endl;
    return 0;
}

Sample output:

c_as_a: 0xbfb98f10
c_as_b: 0xbfb98f14
&c:     0xbfb98f10
seems safe to compare pointers in same hierarchy
Community
  • 1
  • 1
JDiMatteo
  • 12,022
  • 5
  • 54
  • 65

3 Answers3

5

The pointer equality comparison c_as_b == &c will do an implicit pointer conversion. From [expr.eq]:

If at least one of the operands is a pointer, pointer conversions (4.10), function pointer conversions (4.12), and qualification conversions (4.4) are performed on both operands to bring them to their composite pointer type (Clause 5).

Basically, &c will be converted to a B* so that the comparison can happen. At which point, it is exactly the same as c_as_b (since that's how you got that pointer to begin with), so they compare equal.

Barry
  • 286,269
  • 29
  • 621
  • 977
1

In this example, c is statically upcast to B, and then compared with c_as_b yielding true.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
-1

To answer the part of the question that nobody touched on: Can you give a similar small example where the == results in false?

Here is a similar example where the == results in false, using dynamic_cast<void*> makes the same comparison true, and commented out is a way that == results in a compile time error:

#include <iostream>
using namespace std;

struct A { virtual ~A() {} };
struct B : A { };
struct C : A { };
struct D : B, C { };

int main() {
    D d;
    C* c = &d;
    B* b = &d;
    A* a_through_b = b; // &d results in error: 'A' is an ambiguous base of 'D'
    A* a_through_c = c;
    cout << "&d:           " << &d << endl
         << "c :           " << c << endl
         << "b :           " << b << endl
         << "a_through_b : " << a_through_b << endl
         << "a_through_c : " << a_through_c << endl;
    cout << (a_through_b == a_through_c ? "a_through_b == a_through_c" : "a_through_b != a_through_c") << endl;
    cout << (dynamic_cast<void*>(a_through_b) == dynamic_cast<void*>(a_through_c) ? "dynamic_cast<void*>(a_through_b) == dynamic_cast<void*>(a_through_c)" : "dynamic_cast<void*>(a_through_b) != dynamic_cast<void*>(a_through_c)") << endl;
    //cout << (a_through_c == &d) << endl; // error: 'A' is an ambiguous base of 'D'
    cout << (dynamic_cast<void*>(a_through_c) == dynamic_cast<void*>(&d) ? "dynamic_cast<void*>(a_through_c) == dynamic_cast<void*>(&d)" : "dynamic_cast<void*>(a_through_c) != dynamic_cast<void*>(&d)") << endl;
    return 0;
}

Sample output:

&d:           0xbff6d558
c :           0xbff6d55c
b :           0xbff6d558
a_through_b : 0xbff6d558
a_through_c : 0xbff6d55c
a_through_b != a_through_c
dynamic_cast<void*>(a_through_b) == dynamic_cast<void*>(a_through_c)
dynamic_cast<void*>(a_through_c) == dynamic_cast<void*>(&d)
JDiMatteo
  • 12,022
  • 5
  • 54
  • 65