2015-12-08 48 views
2

我正在爲我的遊戲引擎設計一個簡單的事件系統。 我想要實現下列事件調度接口:C++中的簡單事件系統

我想,我也會需要某種形式的內部調度的包裝結構中,持有[pObject,pFunc]對。

struct Wrapper 
{ 
    A* pObj; // Of base class A. 
    // ?? // Pointer to given member function of A. 
}; 

我不知道如何實現成員函數指針邏輯。因爲我需要一個實時系統,所以我想要一個相對較快的解決方案。我欣賞所有建議。

我寧願避免第三方庫。

+3

看看[std :: function](http://en.cppreference.com/w/cpp/utility/functional/function)。 –

+2

[This](http://blog.molecular-matters.com/2011/09/19/generic-type-safe-delegates-and-events-in-c/)也可以是一個好點,從中可以開始。 – skypjack

回答

3

根據意見,您可以使用std::function或與建議的here類似的結構。
它遵循的第二條建議的最小和工作示例:

class Dispatcher { 
    Dispatcher() { } 

    template<class C, void(C::*M)() = C::receive> 
    static void invoke(void *instance) { 
     (static_cast<C*>(instance)->*M)(); 
    } 

public: 
    template<class C, void(C::*M)() = &C::receive> 
    static Dispatcher create(C *instance) { 
     Dispatcher d; 
     d.fn = &invoke<C, M>; 
     d.instance = instance; 
     return d; 
    } 

    void operator()() { 
     (fn)(instance); 
    } 

private: 
    using Fn = void(*)(void *); 
    Fn fn; 
    void *instance; 
}; 

struct S { 
    void receive() { } 
}; 

int main() { 
    S s; 
    Dispatcher d = Dispatcher::create(&s); 
    d(); 
}; 

注意,它必須符合你的要求(目前,有針對性的成員方法沒有返回值,並且不接受參數)相應的修改。
此外,它可以很容易地擴展爲存儲目標成員方法的數組,這就是您要查找的內容:只需存儲一對instance s和invoke函數的向量。
另外,您可以使用Dispatcher函數的可變參數模板使其更加靈活。這樣,您就可以定義具有不同返回類型和參數列表的Dispatcher

EDIT

它遵循一個Dispatcher接受多於一個的目標成員函數的一個例子。
如上所述,通過可變參數模板來擴展它仍然很容易。

#include <vector> 
#include <utility> 

class Dispatcher { 
    template<class C, void(C::*M)() = C::receive> 
    static void invoke(void *instance) { 
     (static_cast<C*>(instance)->*M)(); 
    } 

public: 
    template<class C, void(C::*M)() = &C::receive> 
    void bind(C *instance) { 
     auto pair = std::make_pair(&invoke<C, M>, instance); 
     targets.push_back(pair); 
    } 

    void operator()() { 
     for(auto pair: targets) { 
      (pair.first)(pair.second); 
     } 
    } 

private: 
    using Fn = void(*)(void *); 
    std::vector<std::pair<Fn, void*>> targets; 
}; 

struct S { 
    void receive() { } 
}; 

struct T { 
    void receive() { } 
}; 

int main() { 
    S s; 
    T t; 
    Dispatcher d; 
    d.bind(&s); 
    d.bind(&t); 
    d(); 
}; 

請注意,在上面的例子中,沒有保證提交的instance指針仍然有效,一旦實際使用。您應該照顧綁定對象的生命週期,或者稍微修改示例以引入更安全的句柄。

2

如果你可以適當地構造你的A派生類,這樣你就可以有一個process()方法,你可以簡單地使用多態調度。

喜歡的東西:

struct A 
{ 
    virtual void process() = 0; 
    virtual ~A() {} 
} 
struct B : public A 
{ 
    virtual void process() { /* process event B... */ } 
} 
struct C : public A 
{ 
    virtual void process() { /* process event C... */ } 
} 

您的調度員的觸發方式只會有呼籲指針process()方法所有註冊對象的循環,讓多態性調用適當的方法。

+0

這個解決方案是第一個想到的,但它假設我們知道所有可能的事件。 我的API需要靈活性,爲用戶創建自己的調度員(他自己的事件)並輕鬆註冊所有參與者提供了可能性。 – DannyX