static_cast
can perform only those casts where memory layout between the classes is known at compile-time. dynamic_cast
can check information at run-time, which allows to more accurately check for cast correctness, as well as read run-time information regarding the memory layout.
Virtual inheritance puts a run-time information into each object which specifies what is the memory layout between the Base
and Derived
. Is one right after another or is there an additional gap? Because static_cast
cannot access such information, the compiler will act conservatively and just give a compiler error.
In more detail:
Consider a complex inheritance structure, where - due to multiple inheritance - there are multiple copies of Base
. The most typical scenario is a diamond inheritance:
class Base {...};
class Left : public Base {...};
class Right : public Base {...};
class Bottom : public Left, public Right {...};
In this scenario Bottom
consists of Left
and Right
, where each has its own copy of Base
. The memory structure of all the above classes is known at compile time and static_cast
can be used without a problem.
Let us now consider the similar structure but with virtual inheritance of Base
:
class Base {...};
class Left : public virtual Base {...};
class Right : public virtual Base {...};
class Bottom : public Left, public Right {...};
Using the virtual inheritance ensures that when Bottom
is created, it contains only one copy of Base
that is shared between object parts Left
and Right
. The layout of Bottom
object can be for example:
Base part
Left part
Right part
Bottom part
Now, consider that you cast Bottom
to Right
(that is a valid cast). You obtain a Right
pointer to an object that is in two pieces: Base
and Right
have a memory gap in between, containing the (now-irrelevant) Left
part. The information about this gap is stored at run-time in a hidden field of Right
(typically referred to as vbase_offset
). You can read the details for example here.
However, the gap would not exist if you would just create a standalone Right
object.
So, if I give you just a pointer to Right
you do not know at compile time if it is a standalone object, or a part of something bigger (e.g. Bottom
). You need to check the run-time information to properly cast from Right
to Base
. That is why static_cast
will fail and dynamic_cast
will not.
Note on dynamic_cast:
While static_cast
does not use run-time information about the object, dynamic_cast
uses and requires it to exist! Thus, the latter cast can be used only on those classes which contain at least one virtual function (e.g. a virtual destructor)