Consider the following code:
struct Base {}; struct Derived : public virtual Base {}; void f() { Base* b = new Derived; Derived* d = static_cast<Derived*>(b); }
This is prohibited by the standard ([n3290: 5.2.9/2]
) so the code does not compile, because Derived
virtually inherits from Base
. Removing the virtual
from the inheritance makes the code valid.
What's the technical reason for this rule to exist?
The static_cast is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coercion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. This can cast related type classes.
Static casting is done by the compiler: it treats the result as the target type, no matter what. You do this when you're absolutely sure about the argument being of the target type. Dynamic casting is done at runtime, and thus requires runtime type information.
static_cast can't throw exception since static_cast is not runtime cast, if some cannot be casted, code will not compiles. But if it compiles and cast is bad - result is undefined.
If, in your code, you know you do not need a result somewhere, you can use the static_cast<void> method to mark the result as discarded – but the compiler will consider the variable used then and no longer create a warning or error.
The technical problem is that there's no way to work out from a Base*
what the offset is between the start of the Base
sub-object and the start of the Derived
object.
In your example it appears OK, because there's only one class in sight with a Base
base, and so it appears irrelevant that the inheritance is virtual. But the compiler doesn't know whether someone defined another class Derived2 : public virtual Base, public Derived {}
, and is casting a Base*
pointing at the Base
subobject of that. In general[*], the offset between the Base
subobject and the Derived
subobject within Derived2
might not be the same as the offset between the Base
subobject and the complete Derived
object of an object whose most-derived type is Derived
, precisely because Base
is virtually inherited.
So there's no way to know the dynamic type of the complete object, and different offsets between the pointer you've given the cast, and the required result, depending what that dynamic type is. Hence the cast is impossible.
Your Base
has no virtual functions and hence no RTTI, so there certainly is no way to tell the type of the complete object. The cast is still banned even if Base
does have RTTI (I don't immediately know why), but I guess without checking that a dynamic_cast
is possible in that case.
[*] by which I mean, if this example doesn't prove the point then keep adding more virtual inheritance until you find a case where the offsets are different ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With