2012-03-24 104 views
1

我試圖做一個簡單的事件調度系統。簡而言之,我擁有所有派生IEvent接口的事件類。我也有幾個方法的一個eventmanager進行類:C++回調系統

void addListener(int eventID, std::function<void(IEvent *event)> callback); 
void dispatchEvent(int eventID, IEvent *event); 

的eventmanager進行具有圖矢量的:

std::map<int, std::vector<std::function<void(IEvent *)> > > m_events; 

然後,任何物體可以通過的addListener方法寄存器,給它一個回調和它會被通知當有人調用dispatchEvent具有相同事件類型:

// add an event listener 
EventManager::addListener(Event_MouseMove, std::bind(&Obj::callback, this, std::placeholders::_1)); 

// the callback method 
void Obj::callback(IEvent *e) 
{ 
    // here I need to cast e to a MouseEvent * 
    // I want to get rid of this. 
    MouseEvent *me = (MouseEvent *)e; 
} 

當調用dispatchEvent,調用者必須通過IEvent派生類的MouseEvent的考試ple:

// dispatching an Event 
EventManager::dispatchEvent(Event_MouseMove, new MouseEvent()); 

我的問題與回調方法有關。 說你想監聽的MouseEvent,該對象將有一個像這樣的方法:

void eventHandler(MouseEvent *event); 

的問題是,回調不能因爲它期待一個IEvent *,而不是傳遞給的addListener方法MouseEvent *。爲了使其工作,我只使用IEvent類型,然後事件處理程序方法必須將該IEvent *轉換爲它所期望的派生類型;在這種情況下是MouseEvent *。 我該如何讓addListener方法將一個指針指向將接收任何IEvent派生類的方法?

作爲一個例子:

// add an event listener 
EventManager::addListener(Event_MouseMove, std::bind(&Obj::callback, this, std::placeholders::_1)); 

// the callback method 
void Obj::callback(MouseEvent *e) { ... } 

// dispatching an Event 
EventManager::dispatchEvent(Event_MouseMove, new MouseEvent()); 
+1

既然你說'std :: function',我敢打賭,你可以安全地寫'>>>',沒有空格。 – 2012-03-24 21:01:15

+0

什麼是eventID和它如何連接到事件類型? – 2012-03-24 21:25:06

+0

eventID是一個唯一的標識符,它是一個int用作回調映射的鍵。 – dotminic 2012-03-24 21:47:48

回答

1

我不認爲這是可能的,在不改變的addListener()的函數參數具有的MouseEvent *參數(或一個自的MouseEvent派生)而不是IEvent *參數。

如果你有eventHandlers作爲參數將其他類的指針(派生自IEvent)作爲參數,那麼你需要爲每個類添加一個單獨的addListener()函數,這可能不是你想要的。

簡單地傳遞一個IEvent *然後將它轉換爲eventHandler中的適當類型(就像你現在正在做的那樣)可能是要走的路。

舉例來說,Qt的實際執行其eventFilters類似的東西:http://qt-project.org/doc/qt-4.8/eventsandfilters.html

1

排序的浪費,因爲它創造圍繞每一個聽者的僞包裝。但是,我不知道是否可以徹底轉換std::function對象。如果你只接受函數指針(但是然後lambda被排除,meh),你可以直接轉換爲addListener()。此外,有些reinterpret_cast可能會有所幫助,但我不覺得那麼容易,所以解決方案不具有一個功能。

#include <functional> 
#include <iostream> 

struct IEvent { }; 
struct MouseEvent : IEvent { }; 

template <typename type> 
std::function <void (IEvent*)> 
convert_callback (const std::function <void (type*)>& callback) 
{ 
    static_assert (std::is_convertible <type*, IEvent*>::value, "wrong type"); 
    return [=] (IEvent* event) { return callback (static_cast <MouseEvent*> (event)); }; 
} 

struct dispatcher 
{ 
    template <typename type> 
    void 
    addListener (std::function <void (type*)> callback) 
    { 
    std::function <void (IEvent*)> real_callback (convert_callback (callback)); 
    MouseEvent event; 
    real_callback (&event); 
    } 
}; 

void 
callback (MouseEvent*) 
{ 
    std::cout << "hello\n"; 
} 

int 
main() 
{ 
    dispatcher x; 
    x.addListener <MouseEvent> (&callback); 
} 

任何理由通過event作爲指針,而不是引用,btw?

1

這可能不是你正在尋找的,但爲什麼不做一個不同的方法。只是將指針(或smart_ptr s)存儲到具有handleEvent函數的對象中,而不是存儲函數。事情是這樣的:

struct EventHander { 
    virtual ~EventHandler() {} 
    virtual void handle_event(IEvent *e) = 0; 
}; 

struct Myhandler : public Eventhandler { 
    virtual void handle_event(IEvent *e) { 
     // Do whatever 
    } 
}; 

,那麼你只是存儲EventHandler指針,並調用handler->handle_event(e)爲每一個當事件到達。

0

可以很容易地解決這個問題。只需添加一個回調界面,例如Callable。看到我的代碼示例如下,這個類充當Callable<void, Event*>,幷包裝Event的任何子類。

template<typename Arg, /*traits here*/> 
class FunctionWrapper : public Callable<void, Event*> 
{ 
public: 
    FunctionWrapper(Callable<void, Arg*> *func) 
    { 
    mInternal = func; 
    } 

    FunctionWrapper(void (*func)(Arg*)) 
    { 
    mInternal = new Function<void(Arg*)>(func); 
    } 

    template<typename T> 
    FunctionWrapper(T* obj, void (T::*func)(Arg*)) 
    { 
    mInternal = new Function<void(T::*)(Arg*)>(obj, func); 
    } 

    void call(Event *e) 
    { 
    return mInternal->call(static_cast<Arg*>(e)); 
    } 

    void operator()(Event *e) 
    { 
    return call(e); 
    } 

    operator void*() const 
    { 
    return mInternal ? 0 : this; 
    } 

    operator bool() const 
    { 
    return mInternal != 0; 
    } 

    bool operator==(const FunctionWrapper& wrapper) const 
    { 
    return mInternal == wrapper.mInternal; 
    } 

    bool operator!=(const FunctionWrapper& wrapper) const 
    { 
    return mInternal != wrapper.mInternal; 
    } 

    virtual ~FunctionWrapper() 
    { 
    if(mInternal){ 
     delete mInternal; 
     mInternal = 0; 
    } 
    } 
private: 
    Callable<void, Arg*> *mInternal; 

    FunctionWrapper(const FunctionWrapper& wrapper); 
    const FunctionWrapper& operator=(const FunctionWrapper& wrapper); 
};