fl****@gmail.com wrote:
#include <iostream>
using namespace std;
class Base
{
public:
Base() {}
~Base() {}
};
class Derived : virtual public Base
{
public:
Derived() {}
~Derived() {}
};
int main()
{
Base *b = new Derived();
Derived *d = (Derived*)b; //line 22. The problem line!
return 0;
}
For the code above, I got the following error message:
downcast.cc: In function `int main()':
downcast.cc:22: error: cannot convert from base `Base' to derived type `
Derived' via virtual base `Base'
That means it is illegal to explicit convert a VIRTUAL base point to the
derived point. (non-virtual is ok) Can somebody explain it? ( The coding
style is bad, please just ignore it. ^_^)
The compiler is correct - the conversion is illegal. Equivalently (and
more specifically), you cannot downcast a virtual base class pointer to
a derived class pointer using static_cast. This is because the case may
involve some pointer adjustment that depends on the dynamic type of the
object pointed to. e.g.
class Base
{
char i;
};
class Derived : virtual public Base
{
int j
};
class Derived2 : virtual public Base
{
int k;
};
class DiamondBottom: public Derived, public Derived2
{
int l;
};
int main()
{
Base *b = new DiamondBottom();
Derived *d = static_b; //line 22. The problem line!
return 0;
}
Now, in a DiamondBottom object, the Derived2 subobject is likely to be
placed after the Derived subobject, which means that the pointer
adjustment required for a conversion from a Base* to a Derived2* depends
on whether the Derived2 is part of a larger DiamondBottom object or not.
E.g. a Derived2 object looks like this (vtable pointers left out):
i
k
while a DiamondBotton object might look like this (vtable pointers left
out):
i
j
k
l
so that i and k are in different relative positions depending on the
dynamic type of the object.
The solution is to use dynamic_cast, which performs the correct
conversion by checking the real type of the object.
Tom