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.