Ошибка: невозможно dynamic_cast ... (цель не указатель или ссылка)
Я изучаю обработку исключений в C++ и столкнулся с проблемой. Вот код:
#include<iostream>
#include<exception>
using namespace std;
class A
{
public:
virtual void f(void){}
};
class AA:public A
{
public:
void aa(void){};
};
int main(void)
{
A a;
try
{
dynamic_cast<AA>(a).aa();
}
catch(exception ex)
{
cout<<"["<<ex.what()<<"]"<<endl;
}
return 0;
}
Поэтому я подумал, что try catch позволит функции выполняться и покажет мне содержимое исключения, но мой компилятор не компилирует его. Я использую кодовый блок с GNU GCC. Пожалуйста, помогите мне и покажите, что мне нужно сделать, чтобы код работал так, как я планировал. большое спасибо.
4 ответа
dynamic_cast
может привести только к значению указателя или ссылке, что именно то, что говорит вам ошибка.
От $5.2.7/1 стандарта C++.
Результатом выражения dynamic_cast
(v) является результат преобразования выражения v в тип T. T должен быть указателем или ссылкой на полный тип класса или "указателем на cv void".
Для того чтобы dynamic_cast
Чтобы сгенерировать исключение, когда объект не может быть преобразован, вам нужно привести его к ссылке. Измените это на следующее:
dynamic_cast<AA&>(a).aa();
// ^^^ cast to reference.
Как указал Johnsyweb dynamic_cast
всегда будет бросать std::bad_cast
когда преобразование не удается. Хотя std::bad_cast
происходит от std::exception
всегда полезно использовать исключение, которое наилучшим образом соответствует ожидаемому условию сбоя. Это предотвращает непреднамеренную интерпретацию других ошибок как неудачного приведения.
Чтобы применить это к вашему примеру, это может выглядеть как код ниже.
#include <iostream>
#include <typeinfo> // std::bad_cast
class A
{
public:
virtual void f(void){}
};
class AA:public A
{
public:
void aa(void){};
};
int main(void)
{
A a;
try
{
dynamic_cast<AA&>(a).aa();
}
catch(const std::bad_cast& ex)
{
std::cout << "["<<ex.what()<<"]" << std::endl;
}
return 0;
}
[Примечание, делать такие вещи, как using namespace std;
Настоятельно не рекомендуется, так как это может вызвать конфликты с идентификаторами в глобальном пространстве имен. Я удалил это в примере выше.]
Ваша проблема не в обработке исключений, а в динамическом приведении:
'AA' is not a reference or pointer
dynamic_cast
безопасно конвертирует указатели и ссылки на class
а не экземпляры.
Так что вы могли бы сделать:
dynamic_cast<AA&>(a).aa();
... который всегда потерпит неудачу и бросит std::bad_cast
исключение.
Вы должны поймать наиболее специфический тип exception
что вы ожидаете и так как рекомендуемый способ catch
По ссылке, вы должны предпочесть:
catch (std::bad_cast const& ex)
Дополнительная информация: преобразование dynamic_cast на http://en.cppreference.com/.
Я просто имел дело с той же ошибкой, но в моем случае я переходил от указателя к указателю, поэтому другие ответы здесь не применимы. Мое сообщение об ошибке немного отличалось: error: cannot dynamic_cast 'f()' (of type 'class B*') to type 'class A*' (target is not pointer or reference to complete type)
,
Основная причина в моем случае была гораздо более простой и обыденной.
Обратите внимание на добавление завершить тип в конце. Это заставило меня вспомнить, что я не включил заголовочный файл для своего класса, который я использовал. Это был не неизвестный символ, потому что A*
был вперед объявлен с class A;
в заголовочном файле, в результате чего он существует, но не является полным, отсюда и ошибка.
Решение в моем случае состояло в том, чтобы включить файл заголовка для класса, к которому я приводил.
Это не проблема вопроса, которая была задана выше, но, как видно из моего случая, может генерировать ошибку такого же типа.
Вы получаете ошибку компилятора, потому что ваш dynamic_cast
не указатель или ссылка.
Измените это на:
dynamic_cast<AA&>(a).aa();
... и вы получите правильное исключение.
Примечание: умные компиляторы, такие как g++, также предупреждают:
предупреждение: dynamic_cast
на объекте (здесь a
) никогда не сможет добиться успеха.
Так что лучше ограничить такой код для игры. В коде качества продукции dynamic_cast
должно выполняться только по указателю / ссылке.