Question

I was reading about static and dynamic casts along with the differences between them. It states that

static_cast cannot cast through virtual inheritance however dynamic cast can.

I would appreciate it if someone could clarify what this means presumably with a simple example. Thanks

Was it helpful?

Solution

class A {virtual ~A {}}
class B {virtual ~B {}}
class C : A, B {}

C o;
// Now, some implicit conversions:
A& a = c;
B& b = c;
// static casts back:
C& ca = static_cast<C>(a);
C& cb = static_cast<C>(b);
// dynamic casts over the type:
A& ab = dynamic_cast<A>(b);
B& ba = dynamic_cast<B>(a);

The dynamic cast can cast accross the hierarchy (or checked to derived types), while the static casts can only cast up and down the hierarchy, where statically proovable sound, aside from the object actually being of the target type.

Where possible, compilers reduce a dynamic cast to a static one for efficiency.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top