Search code examples
c++pointersmultiple-inheritancereinterpret-cast

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;
}

Solution

  • 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.