2015-11-25 3 views
0

Пожалуйста, помогите мне понять странное поведение:C++ dynamic_cast исключение

Я использую dynamic_cast от MyObject к MyLogicObject, когда деструктор ~MyLogicObject() в обработке, но компилятор сгенерирует исключение: non_rtti_object.

Я уверен, что объект MyObject является полиморфным типом. Где я ошибаюсь?

#ifndef MYOBJECT_H 
#define MYOBJECT_H 

#include <string> 

class A 
{ 
    int a; 
}; 

class B 
{ 
    int b; 
}; 

class MyObject: public A, 
       public B// if comment this row, and don't use multi inheritable, everything will be fine 
{ 
    private: std::string name; 
    private: bool singleshot; 


    public: MyObject(void); 

    public: virtual ~MyObject(void); 

    protected: void Destroying(void); 

    public: std::string GetName(void); 

    public: virtual bool Rename(std::string _newName); 
}; 

#endif 

#include "MyObject.h" 
#include "MyLogicObject.h" 

MyObject::MyObject(void): singleshot(true) 
{} 


MyObject::~MyObject(void) 
{ 
    printf("\n~my object\n"); 
    Destroying(); 
} 


void MyObject::Destroying(void) 
{ 
    if(singleshot) 
    { 
     printf("\nexception!\n"); 
     dynamic_cast<MyLogicObject*>(this);// exception: non_rtti_object 
     singleshot = false; 
    } 
} 


std::string MyObject::GetName(void) 
{ 
    return name; 
} 


bool MyObject::Rename(std::string _newName) 
{ 
    name = _newName; 
    return true; 
} 


#ifndef MYLOGICOBJECT_H 
#define MYLOGICOBJECT_H 
#include "MyObject.h" 

    class MyLogicObject: public virtual MyObject // if not use virtual inheritance (instead, use the standard inheritance), everything will be fine 
    { 
     public: MyLogicObject(void); 

     public: virtual ~MyLogicObject(void); 

     public: virtual void Update(float _delta = 0.0f); 

     // if reimplement virtual method of base class, everything will be fine 
     /* 
     public: virtual bool Rename(std::string _newName) 
     { 
      return MyObject::Rename(_newName); 
     } 
     */ 
    }; 

    #endif 

#include "MyLogicObject.h" 


MyLogicObject::MyLogicObject(void) 
{} 


MyLogicObject::~MyLogicObject(void) 
{ 
    printf("\n~my logic object\n"); 
    Destroying(); 
} 



void MyLogicObject::Update(float _delta) 
{} 

#include <conio.h> 
#include <stdio.h> 
#include "MyLogicScene.h" 


class C 
{ 
    int c; 
}; 



class DerivedObject: public MyLogicObject, 
        public C// if comment this row, and don't use multi inheritable, everything will be fine 
{ 
    public: DerivedObject(void) 
    {} 

    public: virtual ~DerivedObject(void) 
    { 
     printf("~derived object: %s\n", GetName().c_str()); 
     //Destroying(); // if call Destroying in this place, overything will be file 
    } 
}; 


int main() 
{ 
    DerivedObject* object1 = new DerivedObject(); 
    object1->Rename("object1"); 

    printf("delete object1...\n"); 
    delete object1; 


    getch(); 
    return 0; 
} 
+6

Изнутри деструктора MyObject уже уничтожил часть объекта MyLogicObject. – qPCR4vir

+1

«Но я уверен, что объект B является типом полиморфа». 'Класс B {int b; }; 'не является полиморфным. Он должен иметь либо определенный, либо унаследованный, по меньшей мере, один виртуальный метод (например, виртуальный деструктор), который должен быть полиморфным. Но в вашем примере я думаю, что неважно, является ли B полиморфным или нет. –

+0

, если вы запустите мой код, вы увидите, что ошибка произошла до того, как закончен файл MyLogicObject. Это значит, что MyLogicObject все еще существует. Кроме того, почему код работает нормально, если вы удаляете наследование класса C? – Gregory

ответ

1

Вы пытаетесь динамическим гипс объекта базового класса (MyObject) типа для производного класса (MyLogicObject). И это преобразование не допускается с помощью dynamic_cast, если базовый класс не является полиморфным, а rtti включен. См. this для справки.

Таким образом, вам в основном нужно включить rtti в ваших настройках компилятора. После того, как это сделано, убедитесь, что object1 является полным объектом производного класса (MyLogicObject) для приведения в действие без повышения исключения.

Это будет работать и в противоположном сценарии. Если вы пытались, например, динамически преобразовать объект типа производного класса (MyLogicObject) в базовый класс (MyObject).

+0

, но моя опция rtti включена по умолчанию, я проверил это в закладке project-> properties-> C++ -> language. я нашел свою проблему: предупреждение C4436: dynamic_cast от виртуальной базы «MyObject» до «MyLogicObject» в конструкторе или деструкторе может завершиться неудачей с частично построенным объектом https://msdn.microsoft.com/en-us/library/jj155805.aspx – Gregory

+0

См. Второй абзац: «убедитесь, что object1 является полным объектом производного класса (MyLogicObject)». –

+0

Он говорит то же самое с разными словами. –