0

Consider this simple example:

struct Base1 {};

struct Base2 {};

struct Derived : public Base1, public Base2 {};

int main()
{
   Derived foo;
   Base1* foo1 = &foo;
   Base2* foo2 =  static_cast<Base2*>(foo1); 
}

I get:

Error: static_cast from 'Base1 *' to 'Base2 *', which are not related by inheritance, is not allowed

The compiler should have enough information to figure out that Base2 can be reached from Derived without RTTI (dynamic_cast) and having me to do:

Derived* foo3 = static_cast<Derived*>(foo1);
Base2* foo2 = foo3;

Why isn't this allowed? (One could argue that the compiler doesn't know if foo1 is of Derived type, but static_cast doesn't check the type anyway even when converting from Base1 to Derived for example)

Note: This question is similiar to mine, but it's not quite the same because here we are cross-casting base classes, not derived ones

yggdrasil
  • 737
  • 5
  • 14
  • 1
    It's totally not a good idea to cast from Base1 to Base2 IMHO. why would you like to do this? don't waste time. – Brent81 Jan 06 '20 at 07:49
  • Imagine you're a compiler, how would you fulfill the request "convert `0x123456`, a `Base1 *`, to a `Base2 *`. What's the resulting address and how did you work it out? – M.M Jan 06 '20 at 08:09
  • In a different file you might have `struct Derived2 : public Base2, public Base1 {};` so the compiler cannot do any assumption based on `Derived` alone. – Johannes Schaub - litb Jan 06 '20 at 08:09
  • The `Derived` memory layout is known to the compiler, so it could cast `Base1` to `Base2` without problems. (Assuming `Base1` is actually `Derived` of course). I think what Johannes said is probably the real reason it doesn't make this assumption. (And the reason why `Base1` and `Base2` are treated as not related) – yggdrasil Jan 06 '20 at 08:13
  • Why assume Base1 is actually Derived? There might be various other classes that have Base1 and Base2 as bases in different layouts. – M.M Jan 06 '20 at 08:16
  • Yes, that's pretty much what Johannes said. I got it now thanks :) – yggdrasil Jan 06 '20 at 08:19

1 Answers1

3

A static_cast will fail since, informally speaking, Base1 and Base2 are not related.

However a dynamic_cast will work if your classes are polymorphic: which you can achieve by adding virtual destructors:

struct Base1 {virtual ~Base1() = default;};

struct Base2 {virtual ~Base2() = default;};

struct Derived : Base1, Base2 {};

int main()
{
   Derived foo;
   Base1* foo1 = &foo;
   Base2* foo2 =  dynamic_cast<Base2*>(foo1); 
}

This casting from Base1 to Base2 is idiomatic when working with composition (i.e. interfaces).

Bathsheba
  • 231,907
  • 34
  • 361
  • 483