1

After learnt from : Why can't static_cast be used to down-cast when virtual inheritance is involved?

I'm expecting following code give me the result that shows the static_cast is wrong and dynamic_cast is right.

#include <stdio.h>
class A {
 public:
  virtual ~A() {}
  int a;
};

class B : public virtual A {
  int b;
};

class C : public virtual A {
  int c;
};

class D : public B, public C {
  int d;
};

int main() {
  D obj;
  A* a1 = &obj;
  A* a2 = (A*)&obj;
  A* a3 = dynamic_cast<A*>(&obj);
  A* a4 = static_cast<A*>(&obj);

  C* c = &obj;
  A* a5 = c;
  A* a6 = (A*)(c);
  A* a7 = dynamic_cast<A*>(c);
  A* a8 = static_cast<A*>(c);

  B* b = &obj;
  A* a9 = b;
  A* a10 = (A*)b;
  A* a11 = dynamic_cast<A*>(b);
  A* a12 = static_cast<A*>(b);

  printf("D: %llx %llx %llx %llx %llx\n", &obj, a1, a2, a3, a4);
  printf("C: %llx %llx %llx %llx %llx\n", c, a5, a6, a7, a8);
  printf("B: %llx %llx %llx %llx %llx\n", b, a9, a10, a11, a12);
}

However, gcc 8/9 gives me following reuslt, showing both static cast and dynamic cast is correct:

D: 7ffddb098a80 7ffddb098aa0 7ffddb098aa0 7ffddb098aa0 7ffddb098aa0
C: 7ffddb098a90 7ffddb098aa0 7ffddb098aa0 7ffddb098aa0 7ffddb098aa0
B: 7ffddb098a80 7ffddb098aa0 7ffddb098aa0 7ffddb098aa0 7ffddb098aa0

So what's the magic involved here? How can I make a case that reproduce the static_cast problem?

Note: gcc8 with -fdump-lang-class gives me following output:

Class D
   size=48 align=8
   base size=32 base align=8
D (0x0x7f0756155000) 0
    vptridx=0 vptr=((& D::_ZTV1D) + 24)
  B (0x0x7f0755f834e0) 0
      primary-for D (0x0x7f0756155000)
      subvttidx=8
    A (0x0x7f075614c0c0) 32 virtual
        vptridx=40 vbaseoffset=-24 vptr=((& D::_ZTV1D) + 104)
  C (0x0x7f0755f83548) 16
      subvttidx=24 vptridx=48 vptr=((& D::_ZTV1D) + 64)
    A (0x0x7f075614c0c0) alternative-path
6
  • 4
    Upcasting and downcasting are two different things Commented Jul 22, 2022 at 8:16
  • 2
    the question is unclear. Title states that downcast is problematic, then you have some code with upcast, then ask how to reproduce the problems. DId you expect to see the same issue with up- as with downcast? Commented Jul 22, 2022 at 8:17
  • are you asking why upcast is fine while downcast may be not ? Commented Jul 22, 2022 at 8:17
  • 1
    When upcasting the compete definitions of all base classes is available at compile time and the compiler can therefore check the validity of any static_cast. When down casting the compiler does not know and cannot check at compile time that the cast to the derived object is valid thus we need dynamic_cast which includes a runtime check. Commented Jul 22, 2022 at 8:34
  • So can I conclude that, in any situations, static cast is reliable for virtual inheritance? It seems conflict from what I learnt from stackoverflow.com/a/44466962/376698, which says: "So, if I give you just a pointer to Right you do not know at compile time if it is a standalone object, or a part of something bigger (e.g. Bottom). You need to check the run-time information to properly cast from Right to Base. " Commented Jul 22, 2022 at 9:08

2 Answers 2

2

Not sure, but it seems like you confuse upcasting with downcasting. In your code there are only upcasts, and those are fine. You get the expected compiler error for example with this:

  D obj;
  A* a4 = static_cast<A*>(&obj);
  D* d = static_cast<D*>(a4);

gcc reports:

<source>: In function 'int main()':
<source>:26:28: error: cannot convert from pointer to base class 'A' to pointer to derived class 'D' because the base is virtual
   26 |   D* d = static_cast<D*>(a4);
      |                            ^

If you remove the virtual inheritance in your example the static_cast would fail as well, because then the cast is ambiguous.

Sign up to request clarification or add additional context in comments.

Comments

1

static_cast can correctly upcast to a virtual base class because the standard requires it to. In fact, this conversion can even be done implicitly, and static_cast can perform all implicit conversions as well as certain other kinds of conversions.

When compiling a static_cast (or an implicit conversion) to a virtual base class, the compiler must generate code that consults the vtable in order to determine how to find the virtual base class, unless it can determine the dynamic type of the argument in which case the conversion can be "devirtualized", i.e., the statically known offset can be used.

A misconception is that static_cast is "static" in the sense that it never needs to consult a vtable. Evidently, this is not the case, but we are stuck with the name.

Another misconception is that conversion to a virtual base class requires "RTTI" and thus requires dynamic_cast. It does not---just like how calling a virtual function does not require RTTI and can still be done even when RTTI has been disabled.

1 Comment

The way virtual bases is implemented can vary a lot more than the rest of the inheritance and virtual functions stuff which in practice is always done pretty much the same way (I can't stand ppl saying "the vtable is just one possible implementation for virtual functions" when it's the one and only implementation used in practice). Not all compilers go through the vtable for access to virtual bases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.