I have three classes:
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D: public B, public C {};
Attempting a static cast from A* to B* I get the below error:
cannot convert from base A to derived type B via virtual base A
In order to understand the cast system you need to dive in the object model.
The classic representation of a simple hierarchy model is containment: that if
B
derives fromA
then theB
object will in fact contain aA
subobject alongside its own attributes.With this model, downcasting is a simple pointer manipulation, by an offset known at compilation time which depends from the memory layout of
B
.This is what static_cast do: a static cast is dubbed static because the computation of what is necessary for the cast is done at compile-time, be it pointer arithmetic or conversions (*).
However, when
virtual
inheritance kicks in things tend to become a bit more difficult. The main issue is that withvirtual
inheritance all subclasses share a same instance of the subobject. In order to do that,B
will have a pointer to aA
, instead of aA
proper, and theA
base class object will be instantiated outside ofB
.Therefore, it's impossible at compilation time to be able to deduce the necessary pointer arithmetic: it depends on the runtime type of the object.
Whenever there is a runtime type dependency, you need RTTI (RunTime Type Information), and making use of RTTI for casts is the job of dynamic_cast.
In summary:
static_cast
dynamic_cast
The other two are also compile-time casts, but they are so specific that it's easy to remember what they are for... and they are smelly, so better not use them at all anyway.
(*) As noted by @curiousguy in the comments, this only holds for downcasting. A
static_cast
allows upcasting regardless of virtual or simple inheritance, though then the cast is also unnecessary.I don't know if this is "safe" but.
Assuming
B derived from A (and A pure virtual)
Since I KNOW that a pointer to B still remains a pointer to B.
this program executes and correctly return printing "hello!" and the value of the other object (in this case "2").
by the way, what I'm doing is highly unsafe (personally I give a different ID to every class and I assert after reinterpret casting that current ID is equal to other ID to be sure we are doing something with 2 equal classes) and as you see I limited myself to "const" methods. Thus this will work with "non-const" methods, but if you do something wrong catching the bug will be almost unpossible. And even with assertion there's a 1 chance out of 4 billions to succeed assertion even when it is supposed to fail (assert(ID== other->ID);)
By the way.. A good OO design should not require this kinda of stuff, but in my case I tried to refactor/re-design the code without being able to drop the usage of reinterpret casting. generally speaking you CAN avoid this kind of things.
In your code you are attempting static_cast with 'T = B*' and 'e = A*'
Now 'B* t(A*)' is not well-formed in C++ (but 'A* t(B*)' is because 'A' is a virtual unambiguous and accessible base of 'B'. Therefore the code gives error.
As far as I know, you need to use
dynamic_cast
because the inheritance isvirtual
and you're downcasting.Yes, you have to use a dynamic_cast, but you'll have to make the base class A polymorphic, e.g. by adding a virtual dtor.
You can't use
static_cast
in this situation because the compiler doesn't know the offset of B relative to A at compile time. The offset must be calculated at run-time based on the exact type of the most derived object. Therefore you must usedynamic_cast
.