I found myself in a situation where I know what type something is. The Type is one of three (or more) levels of inheritance. I call factory which returns B*
how
Just for completeness (knowing that I'm late a little, just for late readers like me...):
static_cast
can be applied, if used correctly!
At first, the simple case:
struct D1 { }; // note: no common base class B!
struct D2 { };
struct DD : D1, D2 { };
You can get from D1*
to D2*
via intermediate downcast to DD*
:
D1* d1 = new DD();
D2* d2 = static_cast- (d1);
The upcast to D2* is implicit then. This is possible even for non-virtual inheritance. But be aware that you need to be 100% sure that d1 really was created as DD
when doing the downcast, otherwise you end up in undefined behaviour!
Now the more complex case: Diamond pattern! This is what is presented in the question:
void* cptr = new DD();
B* a = (B*)cptr;
Now this cast is already is dangerous! What actually is implemented here is a reinterpret_cast:
B* a = reinterpret_cast(cptr);
What you instead want is a simple upcast. Normally, one would not need a cast at all:
B* a = new DD(); //ambigous!
Solely: DD has two inherited instances of B. It would have worked if both D1 and D2 inherited virtually from B (struct D1/2 : virtual B { };
– not to be confused with B/D1/D2 being virtual classes!).
B* b1 = static_cast(new DD());
B* b2 = static_cast(new DD());
The cast to the respective bases D1
or D2
now makes clear which of the two inherited instances of B
shall be pointed to.
You now can get back the respective other instance by downcasting to DD again; due to the diamond pattern, you need an intermediate cast again:
D2* bb1 = static_cast- (static_cast
(b1));
D1* bb2 = static_cast- (static_cast
(b2));
The very important point about all this matter is: You absolutely need to use, when down-casting, the same diamond edge you used for up-casting!!!
Conclusion: Yes, it is possible using static casts, and it is the only option if the classes involved are not virtual (note: to be differed from virtual inheritance!). But it is just too easy to fail in doing it correctly, sometimes even impossible (e. g. if having stored pointers of base type to arbitrary derived types in a std::vector
), so usually, the dynamic_cast solution as presented by Ben is the much safer one (provided virtual data types are available; if so, in the forementioned vector example, it is the only solution!).