Часто задаваемые вопросы: Почему dynamic_cast работает только в том случае, если класс имеет не менее 1 виртуальный метод?

Это не компилируется в С++:

class A
{
};

class B : public A
{
};

...

A *a = new B();
B *b = dynamic_cast<B*>(a);

Ответы

Ответ 1

Потому что dynamic_cast может только печатать полиморфные типы, так говорит стандарт.

Вы можете сделать свой класс полиморфным, добавив деструктор virtual в базовый класс. Фактически, вы, вероятно, должны все равно (см. Сноску). Если вы попытаетесь удалить объект B с помощью указателя A, вы вызовете Undefined Поведение.

class A
{
public:
  virtual ~A() {};
};

et voila!

Сноска

Существуют исключения из "правила" о необходимости виртуального деструктора в полиморфных типах.
Одним из таких исключений является использование boost::shared_ptr, как указал Стив Джессоп в комментариях ниже. Для получения дополнительной информации о том, когда вам нужен виртуальный деструктор, прочитайте эту статью Herb Sutter.

Ответ 2

Из 5.2.7 (Динамический бросок):

Результат выражения dynamic_cast<T>(v) является результатом преобразуя выражение v в тип T.

[... несколько строк, которые относятся к другим случаям...]

В противном случае v будет указатель на или значение l полиморфный тип (10.3).

От 10.3 (Виртуальные функции):

Класс, который объявляет или наследует виртуальная функция называется полиморфный класс.

Ответ 3

Как сказано в другом: стандарт говорит так.

Итак, почему стандарт говорит так?

Потому что, если тип не является полиморфным, он может (или есть? Вопрос к стандартным гурум) быть простым типом. И для простых типов существует множество предположений, вытекающих из обратной совместимости C. Один из них состоит в том, что тип состоит только из его членов, поскольку разработчик объявил + необходимые байты выравнивания. Таким образом, не может быть никаких дополнительных (скрытых) полей. Таким образом, нет способа сохранить в памяти пространство, сохраненное A, информацией, которая на самом деле является B.

Это возможно только тогда, когда оно является полиморфным, так как тогда ему разрешено добавлять такие скрытые вещи. (В большинстве реализаций это делается через vtable).