C++ – more c++ multiple inheritance fun


Possible Duplicate:
C++ pointer multi-inheritance fun.

(Follow up on: C++ pointer multi-inheritance fun )

I'm writing some code involving inheritance from a basic ref-counting pointer class; and some intricacies of C++ popped up. I've reduced it as follows:

Suppose I have:

class A{int x, y;};
class B{int xx, yy;};
class C: public A, public B {int z;};

C c;
C* pc = &c;
B* pb = &c;
A* pa = &c;

// does pa point to a valid A object?
// does pb point to a valid B object?

// does pa == pb ?

Furthermore, does:

// pc == (C*) pa ?
// pc == (C*) pb ?


Here, "==" means points at the same value.

Best Solution

  • Yes
  • Yes
  • No
  • Yes
  • No*

But you need to know how C++ organises memory. The layout of a class, CClass, is as follows:

0                              First base class in list of base classes
sizeof first base class        Next base class
sizeof first N-1 base classes  Nth base class
sizeof all base classes        CClass

OK, it's a bit more complex than that if there is an inheritance tree, but you should get the basic idea. Assuming an int is four bytes then class C is laid out like:

0             A::x
4             A::y
8             B::xx
12            B::yy
16            C:z

But the an object of type C is all of the above, so a pointer to a C is pointing to offset 0. However, C++ allows implicit downcasting, so a pointer to a C can be converted to a pointer to an A or a pointer to a B. But if you look at the above, a pointer to a B is at offset 8 rather than 0 (a pointer to a C) and that a pointer to an A is at offset 0. So, casting a pointer to a C to a pointer to a B adds 8 to the pointer value. This is because the methods of B assume the 'this' pointer points to B's first member (B::xx), but a pointer to a C if reinterpreted as a pointer to a B (i.e. the value is the same) would be pointer to an address eight bytes before where B actually is, so that all of B's methods would be using, in this instance, A's members.

Upcasting (the final two conversions) is different kettle of fish. Going from a pointer to a B to a pointer to a C is really hard because you don't know if the pointer to a B is just pointing to an instance of B or at an instance of C plus eight. This is where RTTI and the dynamic cast comes in. With RTTI (Run Time Type Information) enabled, the pointer to B contains additional information that describes what B really is - a simple B or a B as part of a C. This does have additional cost, both execution time and memory usage.

Finally, this does highlight the ambiguity of the C style cast. You really should use the C++ style casts (static_cast <>, etc) as this clarifies the way the conversion should be done.

*This could also be a yes, I guess it depends on the compiler and if RTTI is on or off. You would need to get into the details of the standard and the compiler implementation to say for sure.