Нельзя опустить, потому что класс не полиморфен?

Возможно ли иметь наследование без виртуальных методов? Компилятор говорит, что следующий код не является полиморфным.

Пример:

class A {
public:
    int a;
    int getA(){return a;};
}


class B : public A {
public:
    int b;
    int getB(){return b;};
}

В другом классе мы пытаемся преобразовать объект A в объект B:

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

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

 cannot dynamic_cast ... (source type is not polymorphic)

person wfbarksdale    schedule 12.12.2011    source источник
comment
В дополнение к принятому ответу вы можете проверить этот вопрос: когда следует использовать static_cast, dynamic_cast и reinterpret_cast? (stackoverflow.com/questions/332030/)   -  person yasouser    schedule 12.12.2011


Ответы (5)


Несмотря на синтаксические ошибки, вы не можете dynamic_cast неполиморфный тип. static_cast — это приведение, которое вы бы использовали в этом случае, если знаете, что это на самом деле объект целевого типа.

Причина, по которой: static_cast в основном компилятор выполняет проверку во время компиляции "Может ли ввод быть преобразован в вывод?" Это можно использовать в случаях, когда вы выполняете приведение вверх или вниз по иерархии наследования указателей (или ссылок). Но проверка производится только во время компиляции, и компилятор предполагает, что вы знаете, что делаете.

dynamic_cast можно использовать только в случае приведения указателя или ссылки, и в дополнение к проверке во время компиляции он выполняет дополнительную проверку во время выполнения, что приведение допустимо. Для этого требуется, чтобы рассматриваемый класс имел хотя бы 1 виртуальный метод, что позволяет компилятору (если он поддерживает RTTI) выполнить эту дополнительную проверку. Однако если рассматриваемый тип не имеет виртуальных методов, то его нельзя использовать.

Самый простой случай и, вероятно, целесообразный, если вы передаете указатели таким образом, — рассмотреть возможность сделать деструктор базового класса виртуальным. Помимо возможности использовать динамическое приведение, он также позволяет вызывать соответствующие деструкторы при удалении указателя базового класса.

person Dave S    schedule 12.12.2011

Вам нужен хотя бы один виртуальный метод в классе для run-time type information (RTTI), чтобы успешно применить оператор dynamic_cast.

person tenorsax    schedule 12.12.2011

просто сделайте деструктор виртуальным (всегда делайте для любого класса только для безопасности).

person user993954    schedule 28.06.2013
comment
не для любого класса, а для класса, который должен быть базовым классом - person ParokshaX; 24.03.2014
comment
не будет ли это небезопасно, потому что вместо родительского деструктора будет вызываться дочерний деструктор? Программист может забыть вызвать BaseClass::~BaseClass() и будет облажаться, потому что родительская часть не будет уничтожена. - person Kari; 24.06.2018
comment
@Kari, родительский (базовый) деструктор автоматически вызывается после дочернего деструктора. Нет необходимости явно вызывать этот деструктор. - person m7913d; 18.03.2021

да, dynamic_cast для неполиморфных типов не допускается. Базовый класс должен иметь как минимум один виртуальный метод. Только тогда этот класс можно назвать полиморфным.

В этой статье объясняется аналогичный пример: http://www.cplusplus.com/doc/tutorial/typecasting/

person Murali Krishna    schedule 12.12.2011

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

Здесь a — объект, b — указатель.

На самом деле, в C++ разрешены как повышение, так и понижение. Но при использовании даункастинга следует обратить внимание на 2 вещи:

  1. Суперкласс должен иметь хотя бы один виртуальный метод.
  2. Поскольку суперкласс меньше подкласса, следует осторожно использовать объект памяти.
person tyger    schedule 12.12.2011