error: cannot dynamic_cast ... (target is not pointer or reference)

focusHard picture focusHard · Jun 16, 2013 · Viewed 24.5k times · Source

I'm learning exception handling in C++ and run into a problem. Here's the code:

#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;
}

So I thought the try catch will allow the function to execute and show me the content of the exception, but my compiler does not compile it. I'm using codeblock with GNU GCC. Please help me and show me what I need to do to get the code run as I intended. thanks a lot.

Answer

Captain Obvlious picture Captain Obvlious · Jun 16, 2013

dynamic_cast can only cast to a pointer value or reference, which is exactly what the error is telling you.

From $5.2.7/1 of the C++ Standard.

The result of the expression dynamic_cast< T >(v) is the result of converting the expression v to type T. T shall be a pointer or reference to a complete class type, or “pointer to cv void.”

In order for dynamic_cast to throw an exception when the object cannot be converted you need to cast to a reference. Change it to the following:

dynamic_cast<AA&>(a).aa();
//           ^^^ cast to reference.

As Johnsyweb pointed out dynamic_cast will always throw std::bad_cast when the conversion fails. Although std::bad_cast is derived from std::exception it is always a good idea to use the exception which best fits the expected fail condition. This prevents inadvertently interpreting other errors as an unsuccessful cast.

To apply this to your example it might look like the code below.

#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;
}

[Note, doing things like using namespace std; is strongly discouraged as it can cause conflicts with identifiers in the global namespace. I have removed it in the example above.]