10

So it's impossible to downcast using static_cast with virtual inheritance, but how is it possible to do the following upcast:

class Base {...};
class Derived : public virtual Base {...};

...

Derived *d = new Derived();
Base *b = static_cast<Base*>(d);

Memory layout of the object:

[ derived part | base part ]

I know that upcasting is considered "safe", but how can the compiler know the offset to the base sub-object at compile-time, when the inheritance is virtual? Does the static_cast use the vtable?

This is especially confusing when we have something like this (note that it's not virtual):

class Third : public Derived {...};

...

Derived *d = new Third();            // non-virtual upcast, no offset will be added
Base *b = static_cast<Base*>(d);

This time I used the same static_cast line, but the offset to the Base sub-object is different!

Memory layout of the object:

[ derived part | third part | base part ]

So how can it be determined at compile time, if it depends on the actual dynamic type of the object d points to?

1 Answers1

3

When you have a pointer to a Derived in your case, it is clear which Base is to be used and you can even implicitly convert the pointer to Derived to a pointer to Base! If any address adjustment is needed the compiler will figure out how to do so using embedded pointer, a vtable, or whatever: the exact approach isn't prescribed by the C++ standard. What is done exact depends on the ABI. For example, for the Itanium C++ ABI it seems the offsets for virtual bases are store in the virtual tables.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • That's usually the case from what I know, that the offsets are stored in the vtable. However this doesn't answer the question of how it's done statically at compile-time. If you look at the two cases I provided, it raises the question of which vtable has the right offset? Which one should the compiler look at, Derived's vtable or Third's vtable? Clearly the 2 offsets in the vtables are different, and choosing the right vtable depends on d's run-time type. This is why I can't understand how it's done statically. –  Jul 28 '13 at 23:59
  • 1
    The "static" in `static_cast` doesn't mean it is done at compile time! It just means that the compiler can statically figure out where to find the information at compile-time: For example, it knows where to look up the offset in the vtable or where the embedded pointer to the base is located (depending on how virtual inheritance is implemented). It won't go looking for a match of some class in the vtable as `dynamic_cast` does. – Dietmar Kühl Jul 29 '13 at 00:07
  • So you're saying static_cast has some dynamic aspect to it, I see. By that logic, why can't static_cast do downcasting in virtual inheritance? –  Jul 29 '13 at 00:22
  • 1
    The base class doesn't know that it is used as a virtual base class, i.e., it doesn't have a virtual table pointer! However, the derived class does now that virtual inheritance is involved and it does have a virtual table pointer (and a complete object involving virtual base classes may have multiple virtual table pointers). – Dietmar Kühl Jul 29 '13 at 00:31