views:

224

answers:

6

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
+7  A: 

As far as I know, you need to use dynamic_cast because the inheritance is virtual and you're downcasting.

Jon Purdy
+3  A: 

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 use dynamic_cast.

ybungalobill
+3  A: 

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.

Nico
or adding at least one virtual method.
Liton
+2  A: 

According standard docs,

Section 5.2.9 - 9, for Static Cast,

An rvalue of type “pointer to cv1 B,” where B is a class type, can be converted to an rvalue of type “pointer to cv2 D,” where D is a class derived (clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is neither a virtual base class of D nor a base class of a virtual base class of D.

Hence, it is not possible and you should use dynamic_cast...

liaK
+1  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 from A then the B object will in fact contain a A subobject alongside its own attributes.

With this model, up-casting 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 with virtual inheritance all subclasses share a same instance of the subobject. In order to do that, B will have a pointer to a A, instead of a A proper, and the A base class object will be instantiated outside of B.

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:

  • compile-time cast: static_cast
  • run-time 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.

Matthieu M.
+1  A: 

$5.2.9/2- "An expression e can be explicitly converted to a type T using a static_cast of the form static_cast(e) if the declaration “T t(e);” is well-formed, for some invented temporary variable t (8.5)."

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.

Chubsdad