views:

936

answers:

5

I'm using Visual Studio and performing a valid dynamic cast. RTTI is enabled.

Edit : Updated the code to be more realistic

struct base
{
    virtual base* Clone()
    {
        base* ptr = new base;
        CopyValuesTo( ptr );
        return ptr;
    }
    virtual void CopyValuesTo( base* ptr )
    {
       ...
    }
    virtual ~base()
    {
    }
}

struct derived : public base
{
    virtual base* Clone()
    {
        derived* ptr = new derived;
        CopyValuesTo( ptr );
        return ptr;
    }
    virtual void CopyValuesTo( base* ptr )
    {
       ...
    }
    virtual ~derived()
    {
    }
}  

void Class1::UseNewSpec( base* in_ptr ) //part of a totally unrelated class
{
    derived* ptr = dynamic_cast<derived *>(in_ptr);
    if( !ptr )
       return;
    delete m_ptr;
    m_ptr = ptr->Clone(); //m_ptr is a member of Class1 of type base*
}

//usage : 
Class1 obj;
derived new_spec; 
obj.UseNewSpec( &new_spec );

My debugger says that in_ptr is of the correct type when the exception is thrown. Google seems particularly unhelpful. Any ideas? Cheers.

+2  A: 

RTTI exceptions, failures, or errors around a dynamic_cast can mean that you performed an illegal cast. dynamic_cast<derived*>(ptrToBase) is valid if and only if class derived and class base both meet the following constraint: that class, or one of its base classes, has a virtual member function.

This virtual member function can be anything, including the destructor. If you don't have any other member functions, you can try:

struct base
{
    virtual ~base(){}
    ...
}

struct derived : public base
{
    ...
}

Now base has a virtual member function, and so does derived. Try that out and see if it resolves your issue.

EDIT-ADD:

@carleeto -- In "it already had a virtual destructor", doe it==base?

If derived has virtual destructor but base is non-virtual dtor, then you may still get this error.

Also, you should verify that the object hasn't been destructed -- once the destructor runs, dynamic_cast is no longer safe to call. Try adding a trace to the ctors and dtors.

Aaron
It already had a virtual destructor. My fault - I should have indicated that.
carleeto
@carleeto - edit add, see new answer
Aaron
A: 

Does base contain any virtual methods? It must in order for dynamic_cast to work.

j_random_hacker
Yes it does. Sorry, I should have added that to the code.
carleeto
I've just updated the code.
carleeto
+6  A: 

http://msdn.microsoft.com/en-us/library/fyf39xec(VS.80).aspx has info on __non_rtti_object_exception.

From MSDN:

If the pointer does not point to a valid object, a __non_rtti_objectexception is thrown, indicating an attempt to analyze the RTTI that triggered a fault (like access violation), because the object is somehow invalid (bad pointer or the code wasn't compiled with /GR).

Michael
/GR means enable RTTI. It is already enabled by default. /GR- turns it off. Even explicitly adding /GR to the command line doesn't help.
carleeto
+1  A: 

Make doubly sure you have RTTI enabled in all source files.

Otherwise the pointer is invalid.

null
+2  A: 

I ran a test based on your pseudo-code and it works. So if RTTI is truly enabled in your build configuration, then it must be another problem that isn't captured in what you posted.

Skrymsli