Часто задаваемые вопросы: почему dynamic_cast работает, только если в классе есть хотя бы 1 виртуальный метод? - PullRequest
15 голосов
/ 19 ноября 2010

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

class A
{
};

class B : public A
{
};

...

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

Ответы [ 3 ]

27 голосов
/ 19 ноября 2010

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

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

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

и вуаля!

Сноска

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

9 голосов
/ 19 ноября 2010

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

Так почему же в стандарте так сказано?

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

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

8 голосов
/ 19 ноября 2010

Начиная с 5.2.7 (динамическое приведение):

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

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

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

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

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

...