Подтвердить что ты не робот

Можете ли вы юридически dynamic_cast использовать неполиморфный базовый класс полиморфного класса

В этом ответе появился следующий сценарий:

#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
}

В g++ 4.8.4 (Ubuntu) это компилируется и утверждение переходит. Мой вопрос в том, что это действительно законно? Я чувствую, что вы не должны иметь возможность dynamic_cast для не-полиморфного класса вообще, но я свободно признаю, что я не эксперт в том, что происходит здесь.

Когда я пробовал в противоположном направлении:

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

он не компилируется, заявив, что "тип источника не является полиморфным". Я чувствую, что это ключ, но все же кажется, что найти неполиморфный базовый класс, принадлежащий классу, который является текущим указателем (это предложение имело смысл?).

4b9b3361

Ответ 1

Да, вы можете.

Как показывает стандарт С++ в §5.2.7/5 о выражении dynamic_cast<T>(v):

Если T является "указателем на cv1 B" и v имеет тип "указатель на cv2 D", так что B является базовым классом D, результатом является указатель на уникальный Bподобъектом объекта D, на который указывает v.

Приведен пример:

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

Как вы можете видеть, полиморфные классы явно не являются единственным вариантом использования dynamic_cast, разрешенным стандартом.

Кстати, cppreference.com объясняет это на менее стандартном языке:

Если new_type является указателем или ссылкой на Base, а тип выражение является указателем или ссылкой на Derived, где Base является уникальный, доступный базовый класс Derived, результатом является указатель или ссылка на подобъект класса Base в производном объекте указывается или идентифицируется выражением. (Примечание: неявные литые и static_cast также может выполнять это преобразование.)