Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Addresses, reinterpret_cast and multiple inheritance

Can anybody explain the behaviour of the following code?

  1. Why do we have b = 3 in the first case, i.e. b2 == &d is true?
  2. Why is it ok in Case 2? I have printed the addresses of b2 and d, and they are different.
#include <iostream>

using namespace std;

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;
    B *b2 = &d;

    cout << &d << endl;
    cout << b2 << endl;

    const int b = (b2 == &d) ? 3 : 4; ///Case1: b = 3;
    const int c = (reinterpret_cast<char*>(b2) == reinterpret_cast<char*>(&d)) ? 3 : 4; //Case 2:  c = 4;

    std::cout  << b << c << std::endl;

    return 0;
}
like image 205
Alex Hoppus Avatar asked Sep 20 '12 11:09

Alex Hoppus


2 Answers

d is of type C. When you convert a pointer to C to a pointer to B, it is adjusted so that it points to the B subobject of C (such ajustement is needed in general with multiple inheritence, if none was needed for B, there would be one for A as C inherit from both A and B). Thus at the assignation and comparison time, the adjustment is done.

At the two other times, &d is converted to either void* (implicitly) or char* (with a reinterpret_cast) and no adjustment is done (you asked explicitly for no adjustment with the reinterpret_cast and there is no reason to do an adjustment when converting to void*, it would just complicate the round trip for no good reason, you'd again have an similar result for A) so the representation is different.

BTW, if you had used reinterpret_cast<B*>(&d), no adjustment would have been made again, but using the result as a B* would have lead rapidly to problems.

like image 134
AProgrammer Avatar answered Sep 17 '22 21:09

AProgrammer


In case 1, the comparison automatically casts the C pointer to a B pointer. In this case, this means that the actual address changes, since you use multiple inheritance and B is second in your list of base-classes. To be more specific, the pointer has to be offset by (at least) sizeof(A). In the second case, however, no such automatic conversion is performed, so the "A prefix" makes the two pointers unequal.

like image 35
ltjax Avatar answered Sep 19 '22 21:09

ltjax