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 technical problem is that there’s no way to work out from a
Base*what the offset is between the start of theBasesub-object and the start of theDerivedobject.In your example it appears OK, because there’s only one class in sight with a
Basebase, and so it appears irrelevant that the inheritance is virtual. But the compiler doesn’t know whether someone defined anotherclass Derived2 : public virtual Base, public Derived {}, and is casting aBase*pointing at theBasesubobject of that. In general[*], the offset between theBasesubobject and theDerivedsubobject withinDerived2might not be the same as the offset between theBasesubobject and the completeDerivedobject of an object whose most-derived type isDerived, precisely becauseBaseis 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
Basehas 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 ifBasedoes have RTTI (I don’t immediately know why), but I guess without checking that adynamic_castis 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 😉