static_cast
, when applied on pointer or a reference allows you to treat an address differently. That works ok for single inheritance but not for multiple inheritance (whether virtual or not).
Let's create a simple multiple inheritance without virtual inheritance.
class A1 {virtual ~A1 {}}
class A2 {virtual ~A2 {}}
class B : public A1, public A2 {virtual ~B {}}
An object of type B
could be laid out in memory like this:
+----------------------+
| A1 memory footprint |
+----------------------+
| A2 memory footprint |
+----------------------+
| B memory footprint |
+----------------------+
Let's create an object of type B and some pointers to it.
B b;
B* bPtr = &b;
A1* a1Ptr = bPtr;
A1* a2Ptr = bPtr;
bPtr
and a1Ptr
points to the start of entire B
object. a2Ptr
points to the A2
part of the object.
bPtr
a1Ptr -> +----------------------+
| A1 memory footprint |
a2Ptr -> +----------------------+
| A2 memory footprint |
+----------------------+
| B memory footprint |
+----------------------+
Now, if you decide to use static_cast
to get a B*
from a1Ptr
, like:
B* bPtr2 = static_cast<B*>(a1Ptr);
Then, bPtr2
points to the start of entire B
object, which is fine but only by coincidence.
bPtr2 -> +----------------------+
| A1 memory footprint |
+----------------------+
| A2 memory footprint |
+----------------------+
| B memory footprint |
+----------------------+
However, if you decide to use static_cast
to get a B*
from a2Ptr
, it will point to the start of the A2
part of the object, which is wrong.
B* bPtr3 = static_cast<B*>(a2Ptr); // Points to the wrong block of memory.
+----------------------+
| A1 memory footprint |
bPtr3 -> +----------------------+
| A2 memory footprint |
+----------------------+
| B memory footprint |
+----------------------+
The layouts of objects for multiple but virtual inheritance are slightly different.
Say you have:
class L1 {virtual ~L1();};
class L2 : public virtual L1 {virtual ~L2();};
class L3 : public virtual L1 {virtual ~L3();};
class L4 : public L2, public L3 {virtual ~L4();};
The layout of an object of type L4
will look something like:
+----------------------+
| L1 memory footprint |
+----------------------+
| L2 memory footprint |
+----------------------+
| L3 memory footprint |
+----------------------+
| L4 memory footprint |
+----------------------+
You will most likely run into the same type of problems if you try to perform a static_cast
on L2*
or L3*
to L4*
.
dynamic_cast
avoids the problems of static_cast
by using RTTI at run time and returns you the right address.