2011-07-28 77 views
0

我得到一個未處理的異常讀取位置0x00000008下面的注意的行(讀取NULL值),導致該錯誤相關的方法包括:(繼續下面的示例):未處理的異常是由於類切片

事件方法:

Event::Event(Event::EVENTTYPE type) : eventType(type) { } 

KeyEvent的方法:

class KeyboardKeyEvent : public Event { 
public: 
    //... 
    int GetKey() const; 
protected: 
//... 
}; 

int KeyboardKeyEvent::GetKey() const { 
    return this->_scancode; //Errors out here. "this" returns 0x000000 
} 
KeyboardKeyEvent::KeyboardKeyEvent(int key, Event::EVENTTYPE type) : Event(type), _scancode(key) { } 

KeyDownEvent方法:

KeyboardKeyDownEvent::KeyboardKeyDownEvent(int scancode) : KeyboardKeyEvent(scancode, Event::KEYBOARD_KEYDOWN) { } 

事件處理方法:

bool EventHandler::EnqueueEvent(Event* event) { 
    if(event == NULL) return false; 
    try { 
     this->_eventQueue.push(event); 
    } catch (...) { 
     return false; 
    } 
    return true; 
} 

Event* EventHandler::DequeueEvent() { 
    if(this->_eventQueue.empty() == false) { 
     Event* result = new Event(*this->_eventQueue.front()); 
     delete this->_eventQueue.front(); 
     this->_eventQueue.pop(); 
     return result; 
    } 
    return NULL; 
} 

主循環順序:

if(_eh->HasEvents()) { 
    Event* nxtEvent = _eh->DequeueEvent(); 
    switch(nxtEvent->GetType()) { 
     case Event::KEYBOARD_KEYDOWN: 
      allegro_message("You pressed the %d key!", dynamic_cast<KeyboardKeyDownEvent*>(nxtEvent)->GetKey()); 
      break; 
     default: 
      /* DO NOTHING */; 
    } 
    delete nxtEvent; 
    nxtEvent = NULL; 
} 

我知道這是一個分層的問題,我只是不明白爲什麼它的發生或如何解決它(實際上,現在我想到了,它可能是「無法轉換爲請求的類型」錯誤)。所有貫穿整個程序_scancode的步驟是合適的值,但第二行dynamic_cast<KeyboardKeyDownEvent*>(nxtEvent)->GetKey()運行它會引發錯誤。雙重鑄造爲dynamic_cast<KeyboardKeyDownEvent*>(dynamic_cast<KeyboardKeyEvent*>(nxtEvent))->GetKey()失敗,並具有相同的錯誤。

編輯:

一些調整後,該變種完美的作品:

if(_eh->HasEvents()) { 
    switch(_eh->PeekEvent()->GetType()) { 
    case Event::KEYBOARD_KEYDOWN: 
     allegro_message("You pressed the %s key!", scancode_to_name(dynamic_cast<KeyboardKeyDownEvent*>(_eh->PeekEvent())->GetKey())); 
     break; 
    case Event::MOUSE_BUTTONDOWN:{ 
     Mouse::BUTTONS btn = dynamic_cast<MouseButtonDownEvent*>(_eh->PeekEvent())->GetButton(); 
     if(btn == Mouse::BUTTON2) { 
      allegro_message("You pressed the %d button!", dynamic_cast<MouseButtonDownEvent*>(_eh->PeekEvent())->GetButton()); 
     } 
           } 
     break; 
     default: 
      /* DO NOTHING */; 
    } 
} 
+1

這不能成爲你真正的代碼。 GetKey的原型和你的定義不匹配。這不應該編譯。 – pmr

+0

這是複製/粘貼/編輯過程中的拼寫錯誤。固定。 – Casey

回答

1

一個解決方案,以避免切片是讓基類的析構函數虛擬的,所以你的情況,你可以做~Event()虛擬:

class Event 
{ 
public: 
    //...  
    virtual ~Event() {} 
}; 

順便說一句,我不知道爲什麼你做到以下幾點:

//YOUR CODE : its causing the problem! 
Event* EventHandler::DequeueEvent() { 
    if(this->_eventQueue.empty() == false) { 
     Event* result = new Event(*this->_eventQueue.front()); // WHY? 
     delete this->_eventQueue.front(); //WHY? 
     this->_eventQueue.pop(); 
     return result; 
    } 
    return NULL; 
} 

你爲什麼不只是這樣做:

//Use it. Because it should not cause that probem 
Event* EventHandler::DequeueEvent() { 
    if(this->_eventQueue.empty() == false) { 
     Event* result = this->_eventQueue.front(); 
     this->_eventQueue.pop(); 
     return result; 
    } 
    return NULL; 
} 
+0

您的解決方案工作。至於你的問題,我不知道我爲什麼試圖返回一份副本。它完成後違反隊列的定義。雖然,我將如何防止泄漏事件時,聲明如下所示:'_handler-> EnqueueEvent(新KeyboardKeyDownEvent(KEY_A))'? – Casey

+0

@Casey:調用後'DequeueEvent',你必須做一些與返回'事件*',對不對?所以你已經完成了這個事件,並且你不再需要這個了,只需要寫'delete event',它就會釋放內存。您不必擔心「事件」的實際類型。通過使'〜Event()'虛擬,一切都會工作得很好! – Nawaz

+0

虛擬析構函數與切片有什麼關係? – UncleBens

1

Event* EventHandler::DequeueEvent()你行 Event* result = new Event(*this->_eventQueue.front());這裏切片發生。 你可以做到以下幾點:

class Event { 
public: 
virtual Event* clone() { 
    // create a new instance and copy all the fields 
} 

}

然後在派生類中重寫clone(),例如

class KeyboardKeyEvent :public Event { 
public: 
... 
virtual KeyboardKeyEvent* clone(); // note - it returns different type 
} 

然後改變Event* EventHandler::DequeueEvent()Event* result = (*this->_eventQueue.front()).clone();

1

你DequeueEvent方法將總是返回一個事件對象,而不是任何你期望的子類。

Event* result = new Event(*this->_eventQueue.front()); 

你出列的事件要麼返回實際的參考是緩存,或者你的基本事件類需要提供某種形式的虛擬拷貝操作的,將提供一個真正的克隆。

1

你爲什麼要複製的事件,當您從隊列中刪除嗎?這就是做切片的原因,因爲你正在構造基類。相反,將隊列中的指針返回給用戶。

如上所述,事件應該有一個虛擬〜事件(),所以該事件的接收方能夠正確地將其刪除。否則,具體類析構函數將無法正常運行。

Event* EventHandler::DequeueEvent() { 
    if(this->_eventQueue.empty() == false) { 
     Event* result = this->_eventQueue.front(); 
     this->_eventQueue.pop(); 
     return result; 
    } 
    return NULL; 
}