Why static_cast
cannot downcast from a virtual base ?
struct A {};
struct B : public virtual A {};
struct C : public virtual A {};
struct D : public B, public C {};
int main()
{
D d;
A& a = d;
D* p = static_cast<D*>(&a); //error
}
g++ 4.5 says:
error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’
The solution is to use dynamic_cast
? but why. What is the rational ?
-- edit --
Very good answers below. No answers detail exactly how sub objects and vtables end up to be ordered though. The following article gives some good examples for gcc:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting
Because if the object was actually of type E
(derived from D), the location of A
subobject relative to D
subobject could be different than if the object is actually D
.
It actually already happens if you consider instead casting from A to C. When you allocate C, it has to contain instance of A and it lives at some specific offset. But when you allocate D, the C subobject refers to the instance of A that came with B, so it's offset is different.
The obvious answer is: because the standard says so. The
motivation behind this in the standard is that static_cast
should be close to trivial—at most, a simple addition or
subtraction of a constant to the pointer. Where s the downcast
to a virtual base would require more complicated code: perhaps
even with an additional entry in the vtable somewhere. (It
requires something more than constants, since the position of
D
relative to A
may change if there is further derivation.)
The conversion is obviously doable, since when you call
a virtual function on an A*
, and the function is implemented
in D
, the compiler must do it, but the additional overhead was
considered inappropriate for static_cast
. (Presumably, the
only reason for using static_cast
in such cases is
optimization, since dynamic_cast
is normally the preferred
solution. So when static_cast
is likely to be as expensive as
dynamic_cast
anyway, why support it.)