Weird C++ casting problem

Started by
6 comments, last by smitty1276 13 years, 6 months ago
Can anyone shed any light on this? Here is an approximation of what I have:

class A {};class B : public A {};class Meh {};class C : public B, Meh {};Foo::Foo(A* a){  m_pAObject = a;  m_pCObject = reinterpret_cast<C*>(a);}void C::SomeMethod(){  this->DoStuff(); // <-- "this" and m_pCObject above don't match}


C::C is only invoked once, but when I examine these guys in debugger the pointer assigned to m_pCObject and the this pointer when tracing in C are two different things--specifically, m_pCObject is 64 greater than the this pointer inside of C methods. The objects methods are only invoked as an instance of C from other places, so it hasn't been an issue. I added some methods to C so that Foo could notify it of some state change, and it is behaving as though it is pointing to a different, uninitialized instance.

Is there some behavior around the casting here that I'm not aware of? (I'm not able to use dynamic_cast, but I know that the A object will always be a C object.)
Advertisement
Unfortunately, you can't easily do reinterpret_cast or () casts with multiple inheritance. That is because of how the compiler organizes multiple-inheritance internally.

In single inheritance, if a class C inherits A, internally, you'll have A's members, followed by C's members. That way, you can cast A to C and the other way around and it's always the same pointer.

In multiple inheritance, it doesn't work that way. If a class C inherits A and B, the internal representation of C will be A's members followed by B and C. (Or B, A and C) If you cast C to A, it still works, but if you cast it to B, then the resulting pointer to B is different then the original C pointer because B's data starts after A.
OK, this is what I was afraid of. So, without RTTI/dynamic_cast, this isn't something that is possible?
Also, I just realized that the classes that are inherited (in my example, A, B, and Meh... and a third one I didn't use in my example) are all pure virtual interfaces. They have no data defined at all. Shouldn't it work in that case?
These FAQs should shed some light on what's going on here.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I'd add this as well. Explains that stuff, with graphics and illustrations.

Basically, it shouldn't work even with interfaces because you need the vtable for the interface. Try to see if it works if you have non-virtual methods in your interface.
Generally speaking using reinterpret_cast and multiple inheritance is a recipe for disaster as reinterpret_cast simply changes the static type of the pointer without making the required adjustments to the pointer value - adjustments that are automatically taken care of by the compiler behind the scene when static_cast or dynamic_cast is used. Moreover, you cannot downcast a virtual base class pointer to a derived class pointer using static_cast. This is because the case may involve some pointer adjustment that depends on the dynamic type of the object pointed to. The solution is to use dynamic_cast, which performs the correct conversion by checking the real type of the object.

So long story short, with non-virtual multiple inheritance you can use static_cast to walk the tree, while with virtual inheritance, dynamic_cast is the only way. If you want to avoid dynamic_cast, stay away from virtual inheritance.
OK, this makes sense. Bearhugger, that was a good link.

Thanks for the help, everyone.

This topic is closed to new replies.

Advertisement