Question:
Why is casting prohibited in the following code?
class Base
{
};
class Derived : virtual public Base
{
};
int main()
{
Base *p = new Derived;
static_cast<Derived *>(p);
return 0;
}
Answer:
The compiler cannot cast Base*
to Derived*
, because it does not do a full analysis of the code, which means it does not know exactly how the types are located relative to each other.
If there are only Base
and Derived
types, then when casting Base*
in Derived*
you need to add an offset of 0 bytes, since Derived
and Base
addresses are the same.
However, the compiler assumes that other types may exist, for example
struct Derived2 : virtual Base { char x[1024]; };
struct MostDerived : virtual Derived2, Derived {};
And Base* p
can point to an object of that type. Then MostDerived
looks like this in memory:
смещение | что находится
0 | MostDerived
0 | Base
0 | Derived2
0 | char Derived2::x[1024]
1024 | Derived
The virtual base class Base
, is in Derived2
, the very first base class MostDerived
. Because Base
is an empty base class and does not take up any memory space. After Derived2
, Derived
will be located, already without Base
. Therefore, in this case, when casting Base*
in Derived*
you need to add an offset of 1024 bytes.
Because the compiler does not know which offset to use, it cannot make such a static_cast
.
Therefore, only dynamic_cast
supported for virtual base types, and then only for types that have virtual functions.