ошибка: не может dynamic_cast (цель не является указателем или ссылкой)

Я изучаю обработку исключений на С++ и сталкиваюсь с проблемой. Вот код:

#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. Пожалуйста, помогите мне и покажите, что мне нужно сделать, чтобы код работал так, как я задумал. большое спасибо.


person focusHard    schedule 16.06.2013    source источник
comment
Вы получаете ошибку компилятора. Для вас важно поделиться этой ошибкой в ​​своем вопросе, чтобы вы могли научиться читать и понимать их.   -  person Drew Dormann    schedule 16.06.2013
comment
Конечно. не может dynamic_cast 'a' (типа 'класса A') ввести 'класс AA' (цель не является указателем или ссылкой)   -  person focusHard    schedule 16.06.2013
comment
Что является здесь основной проблемой. dynamic_cast работает с указателями или ссылочными типами. AA не является указателем или ссылочным типом.   -  person Chad    schedule 16.06.2013
comment
Поскольку вы изучаете обработку исключений: лучший способ поймать исключение - по константной ссылке, то есть catch(const std::exception& ex)   -  person milleniumbug    schedule 16.06.2013


Ответы (4)


dynamic_cast может привести только к значению указателя или ссылке, о чем и говорит вам ошибка.

От 5,2,7 долл. США за 1 стандарт C++.

Результатом выражения dynamic_cast‹ T >(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; настоятельно не рекомендуется, так как это может привести к конфликтам с идентификаторами в глобальном пространстве имен. Я удалил его в приведенном выше примере.]

person Captain Obvlious    schedule 16.06.2013
comment
после изменения моего кода на ‹AA&› программа выводит [std::exception]. как мне добраться до std::bad_cast? не могли бы вы проиллюстрировать, что всегда полезно использовать исключение, которое лучше всего соответствует ожидаемому условию сбоя, на примере кода? Благодарность - person focusHard; 16.06.2013
comment
@focusHard, поместите catch(std::bad_cast& e) над существующим блоком catch(). И #include<typeinfo>. - person iammilind; 16.06.2013
comment
@focusHard bad_cast находится в заголовке typeinfo. Я обновил свой ответ, включив необходимые изменения в ваш пример. Вам также следует начать использовать cppreference.com в качестве ссылки. Он дает списки соответствующих файлов заголовков и обычно предоставляет примеры. Это может быть большим подспорьем при изучении C++. - person Captain Obvlious; 16.06.2013

Ваша проблема не в обработке исключений, а в вашем динамическом приведении:

'AA' is not a reference or pointer

dynamic_cast безопасно преобразует указатели и ссылки в classes, а не в экземпляры.

Итак, вы можете сделать:

dynamic_cast<AA&>(a).aa();

...который всегда терпит неудачу и выдает std::bad_cast исключение.

Вы должны поймать наиболее конкретный тип exception, который вы ожидаете, и, поскольку рекомендуемый способ catch — по ссылке, вы следует предпочесть:

catch (std::bad_cast const& ex)

Дополнительная литература: преобразование dynamic_cast в cppreference.com.

person Johnsyweb    schedule 16.06.2013
comment
Я попробовал catch(std::bad_cast const& ex), как вы предложили, но получил несколько сообщений об ошибках. ожидаемый спецификатор типа, ожидаемый неполный идентификатор перед 'const' - person focusHard; 16.06.2013
comment
std::bad_cast определяется в заголовке <typeinfo>. Вам нужно #include это. - person Johnsyweb; 16.06.2013

Вы получаете ошибку компилятора, потому что ваш dynamic_cast не находится в указателе или ссылке.
Измените его на:

dynamic_cast<AA&>(a).aa();

... и вы получите правильное исключение.

Дополнительное примечание: умные компиляторы, такие как g++, также будут предупреждать:
предупреждение: dynamic_cast для объекта (здесь a) никогда не будет успешным.

Так что лучше ограничить такой код для игрушек. В производственном коде качества dynamic_cast следует выполнять только для указателя/ссылки.

person iammilind    schedule 16.06.2013

Я только что имел дело с той же ошибкой, но в моем случае я переходил от указателя к указателю, поэтому другие ответы здесь не применялись. Однако мое сообщение об ошибке было немного другим: 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; в заголовочном файле, из-за чего он существовал, но не был полным, отсюда и ошибка.

Решение в моем случае состояло в том, чтобы включить заголовочный файл для класса, к которому я выполнял приведение.

Это не проблема задающего вопрос выше, но, как видно из моего случая, может генерировать тот же тип ошибки.

person Loduwijk    schedule 16.08.2016