У меня есть следующий код:
using namespace std;
class BaseOk
{
public:
virtual void ImplementMe()
{
};
};
class DerivedOk : public BaseOk
{
public:
void ImplementMe()
{
}
};
class CBase { };
class CDerived: public CBase { };int main()
{
CBase b; CBase* pb;
CDerived d; CDerived* pd;
pb = dynamic_cast<CBase*>(&d); // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b); // wrong: base-to-derived -> this doesn't compile
// Polymorphic case
BaseOk b2; BaseOk* pb2;
DerivedOk d2; DerivedOk* pd2;
pb2 = dynamic_cast<BaseOk*>(&d2); // ok: derived-to-base
pd2 = dynamic_cast<DerivedOk*>(&b2); // wrong: base-to-derived -> this returns a NULL pointer
}
Строка с указателем «pd» выполняет downcast, и я согласен с тем, что она должна завершиться неудачей, потому что результатом является совершенно другой объект.
Мой вопрос: почему dynamic_cast в этой строке не компилируется вообще, а просто возвращает нулевой указатель?
Я использую компилятор MSVC2012
Почему не
dynamic_cast
в этой строке компилировать вообще вместо
просто возвращает нулевой указатель?
Рассматривайте это как особенность / возможность, а не как ограничение.
dynamic_cast
это механизм, в котором мы бы нашли RTTI (информацию о типе времени выполнения) объекта на основе указателя / ссылки.
Теперь предположим, что если класс совсем не полиморфен (т.е. не содержит virtual
метод), то определенно dynamic_cast
будут всегда терпеть неудачу.
Это означает, что вам не нужно использовать dynamic_cast
где есть вероятность прохождения 0. Почему вы должны тратить машинные циклы на то, что известно во время компиляции? Вот почему компилятор предоставляет вам средства сразу.
Есть еще одно скрытое преимущество этого. Предположим, вы используете dynamic_cast
со ссылками, если это не удается, то генерируется исключение. Кто-нибудь захочет обработать исключение для чего-то, что уже известно во время компиляции!
С помощью dynamic_cast
указатель на неполиморфный тип является ошибкой. Это диагностируемое правило, поэтому вы должны получить ошибку во время компиляции.
Использование его для указателя на полиморфный тип, который не может быть преобразован в целевой тип, не является ошибкой и, в любом случае, обычно не обнаруживается при компиляции. Он имеет четко определенное поведение, давая нулевой указатель.