Question

During doing some c++ excercises I found an interesting example related to multi inheritance and casting.

I cannot figure out why reinterpret_cast<char*>(b1) is not equal reinterpret_cast<char*>(b2).

Here is a simple program, I mentioned above:

#include <iostream>

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

    const int a = (reinterpret_cast<char*>(b1) == reinterpret_cast<char*>(&d)) ? 1 : 2;
    const int b = (b2 == &d) ? 3 : 4;
    const int c = (reinterpret_cast<char*>(b1) == reinterpret_cast<char*>(b2)) ? 5 : 6;

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

    return 0;
}

Could you provide any comments to this topis to help me to figure out why reinterpret_cast(b1) is not equal reinterpret_cast(b2), when reinterpret_cast(b1) equals reinterpret_cast(&d)?

Was it helpful?

Solution

Base class subobjects have to be somehow arranged in memory inside the most derived object. In your case, it seems the compiler did this:

C---------------+
|A---+ B---+    |
||m_i| |m_d| m_c|
|+---+ +---+    |
+---------------+

Which means the A subobject starts at the same address as the entire C object, but the B subobject is shifted by the size of A (i.e. the size of an int).

B *b2 = &d;

Because b2 is a pointer to B, it points to the B subobject, thus the physical address it points to is the shifted one.

As for why b2 == &d holds - pointers to different types can never be compared for equality. But a pointer to derived class can be implicitly converted to a pointer to base class. So b2 == &d is actually converted to b2 == static_cast<B*>(&d), which holds. Note that the implicit conversion naturally applies the shift, and it's the same one you used to obtain b2 in the first place.

You can experiment with reorganising the inheritance order or removing/adding some data members to see how it affects layout.

OTHER TIPS

Why should the addresses be equal? *b1 is an object of type A, and *b2 is an object of type B. They are different objects (albeit not complete ones) and neither one is a subobject of the other, so it's perfectly expected for them to have different addresses -- in fact, they only way they could have the same address is if at least one of their types was empty (which isn't the case in your code).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top