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常に適切な値ですが、2番目の行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 */;
    }
}
4

4 に答える 4

1

スライスを回避するための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;
}
于 2011-07-28T17:38:30.003 に答える
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();

于 2011-07-28T17:41:20.460 に答える
1

DequeueEventメソッドは、期待しているサブクラスではなく、常にEventオブジェクトを返します。

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

Dequeueイベントは、キャッシュしている実際の参照を返すか、基本Eventクラスが実際のクローンを提供するある種の仮想コピー操作を提供する必要があります。

于 2011-07-28T17:41:57.860 に答える
1

キューからイベントを削除するときに、なぜイベントをコピーするのですか?基本クラスを構築しているので、それがスライスを行っていることです。代わりに、キューにあったポインターをユーザーに返します。

上記のように、イベントの受信者がイベントを適切に削除できるように、イベントには仮想〜Event()が必要です。そうしないと、具象クラスデストラクタが適切に実行されません。

Event* EventHandler::DequeueEvent() {
    if(this->_eventQueue.empty() == false) {
        Event* result = this->_eventQueue.front();
        this->_eventQueue.pop();
        return result;
    }
    return NULL;
}
于 2011-07-28T17:43:26.093 に答える