17

In this answer, the following scenario came up:

#include <cassert>

struct A {};

struct B { virtual ~B(){} };

struct AA{};
template <class T>
struct C : A, T {};

int main()
{
  B * b = new C<B>;
  AA * aa = new C<AA>;
  assert(dynamic_cast<A*>(b));
  assert(dynamic_cast<A*>(aa)); //this line doesn't compile, as expected
}

On g++ 4.8.4 (Ubuntu), this compiles and the assert passes. My question is, is that really legal? I feel like you shouldn't be able to dynamic_cast to a non-polymorphic class at all, but I freely admit that I'm not an expert in what's happening here.

When I tried the opposite direction:

dynamic_cast<B*>((A*)(new C<B>));

it fails to compile, stating that "source type is not polymorphic". I feel like that's a clue, but it still seems a stretch to find the non-polymorphic base class that belongs to a class that the current pointer is a base of (did that sentence make sense?).

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
SirGuy
  • 10,660
  • 2
  • 36
  • 66

1 Answers1

14

Yes, you can.

As the C++ standard says in §5.2.7/5 about the expression dynamic_cast<T>(v):

If T is “pointer to cv1 B” and v has type “pointer to cv2 D” such that B is a base class of D, the result is a pointer to the unique B subobject of the D object pointed to by v.

An example is given, too:

struct B { };
struct D : B { };
void foo(D* dp) {
  B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
}

As you can see, polymorphic classes are clearly not the only use case of dynamic_cast permitted by the standard.

By the way, cppreference explains it in less standardese language:

If new_type is a pointer or reference to Base, and the type of expression is a pointer or reference to Derived, where Base is a unique, accessible base class of Derived, the result is a pointer or reference to the Base class subobject within the Derived object pointed or identified by expression. (Note: an implicit cast and static_cast can perform this conversion as well.)

SirGuy
  • 10,660
  • 2
  • 36
  • 66
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • There's no reason this _wouldn't_ work, as by definition, any compiler that knows the source type must know that it has the destination type as a base. – underscore_d Jun 02 '17 at 14:58
  • 1
    @underscore_d: Of course. Nevertheless, seeing `dynamic_cast` used for this should raise an eyebrow and *might* indicate a logical error in the code. – Christian Hackl Jun 02 '17 at 15:02
  • In my example, `dynamic_cast` is given a pointer to `B` and then has to find the derived class `C` and then finds _its_ base class `A` for the `dynamic_cast` to work. – SirGuy Jun 02 '17 at 15:37
  • Looking at a draft of the standard, §5.2.7/8.1 seems to be the passage that I'm looking for, not /5. The difference is that since the input is polymorphic, the most derived type is considered (`C` in my example) and its base classes are scanned for a match. – SirGuy Jun 02 '17 at 17:08