回調函數的使用封裝在了callback.h中,main.cpp用于測試回調。
Ref CEGUI。。。
callback.h (回調封裝)
#######################################
#ifndef __CALLBACK_H__
#define __CALLBACK_H__
#include <map>
using std::map;
using std::make_pair;
typedef int EventArgs;
typedef int EventID;
//回調基類
class SlotFunctorBase
{
public:
virtual ~SlotFunctorBase() {};
//使用操作符來調用函數
virtual bool operator()(const EventArgs& args) = 0;
};
//全局函數、靜态函數或類的靜态成員函數做回調
class FreeFunctionSlot : public SlotFunctorBase
{
public:
//定義回調函數的格式
typedef bool (SlotFunction)(const EventArgs&); //函數指針
public:
FreeFunctionSlot(SlotFunction* func) : d_function(func)
{}
virtual bool operator()(const EventArgs& args)
{
return d_function(args);
}
private:
SlotFunction* d_function;
};
//類的普通成員函數做回調
template<typename T>
class MemberFunctionSlot : public SlotFunctorBase
{
public:
//!成員變量的回調函數定義
typedef bool (T::*MemberFunctionType)(const EventArgs&); //類的成員函數指針的類型
public:
MemberFunctionSlot(MemberFunctionType func, T* obj) :
d_function(func), d_object(obj)
{}
virtual bool operator()(const EventArgs& args)
{
return (d_object->*d_function)(args); //調用類的成員函數
}
private:
MemberFunctionType d_function;
T* d_object;
};
//對上面2種實作的封裝
class SubscriberSlot
{
public:
//預設構造函數
SubscriberSlot()
{
d_functor_impl = NULL;
}
//标準析構函數
~SubscriberSlot()
{
delete d_functor_impl;
d_functor_impl = NULL;
}
//調用函數的()重載,具體由第一類Functor實作
bool operator()(const EventArgs& args) const
{
return (*d_functor_impl)(args);
}
//傳回成員是否有效,是否已經連接配接到一個具體的Functor實作
bool connected() const
{
return d_functor_impl != NULL;
}
//FreeFunctionSlot,自由函數的封裝類
SubscriberSlot(FreeFunctionSlot::SlotFunction* func) :
d_functor_impl(new FreeFunctionSlot(func))
{}
// 模闆構造函數,以成員函數的封裝為參數,MemberFunctionSlot。
template<typename T>
SubscriberSlot(bool (T::*function)(const EventArgs&), T* obj) :
d_functor_impl(new MemberFunctionSlot<T>(function, obj))
{}
private:
//内部基本Functor的指針,SlotFunctorBase基類的優勢在這裡用到了
SlotFunctorBase* d_functor_impl;
};
// 注冊函數宏
// 注冊全局函數、類靜态成員函數作為回調函數
#define REGISTER_FUNC(id, subscribeSlot, func, q) \
SubscriberSlot* subscribeSlot = new SubscriberSlot((FreeFunctionSlot::SlotFunction*)&func);\
q->subscribe(id, subscribeSlot);
// 注冊類成員函數作為回調函數
// param0: 事件id
// param1: psubscribeSlot, 随便一個變量名
// param2: func, 要注冊的類的普通成員函數(即:回調函數)
// param3: p, func所在類的一個執行個體指針
// param4: q, 注冊類(調用注冊函數的類)的一個執行個體指針
#define REGISTER_OBJFUNC(id, subscribeSlot, func, p, q) \
SubscriberSlot* subscribeSlot = new SubscriberSlot(&func, p);\
q->subscribe(id, subscribeSlot);
// 回調
class Callback
{
public:
typedef map<EventID, SubscriberSlot*> EventMap;
public:
Callback() {eventList.clear();}
~Callback() {eventList.clear();}
bool subscribe(EventID id, SubscriberSlot* subscriberSlot)
{
if (NULL == subscriberSlot)
return false;
EventMap::iterator iter = eventList.find(id);
if (iter != eventList.end())
return false;
eventList.insert(make_pair(id, subscriberSlot));
return true;
}
bool evoke(EventID id)
{
EventMap::iterator iter = eventList.find(id);
if(iter == eventList.end())
return false;
SubscriberSlot* subscribeSlot = eventList[id];
if (subscribeSlot)
{
EventArgs args = 0;
(*subscribeSlot)(args);
return true;
}
return false;
}
private:
EventMap eventList;
};
#endif
#######################################
main.cpp (測試)
######################################
#include "stdafx.h"
#include "callback.h"
#include <iostream>
using namespace std;
class A
{
public:
bool Test1(const EventArgs&)
{
cout<<"Test1..."<<endl;
return true;
}
static bool Test2(const EventArgs&)
{
cout<<"Test2..."<<endl;
return true;
}
};
class B : public Callback
{
public:
enum EVENT_TYPE
{
EVENT_TYPE_INVALID = -1,
EVENT_TYPE1,
EVENT_TYPE2,
EVENT_TYPE_NUMBER,
};
public:
B(A *pA) : m_pAObj(pA)
{}
void registerCallback()
{
// 類成員函數
REGISTER_OBJFUNC(EVENT_TYPE1, subscribeSlot, A::Test1, m_pAObj, this);
// 類靜态函數
REGISTER_FUNC(EVENT_TYPE2, subscribeSlot2, A::Test2, this);
}
void evoke()
{
Callback::evoke(EVENT_TYPE1);
Callback::evoke(EVENT_TYPE2);
}
private:
A *m_pAObj;
};
// 主函數
int _tmain(int argc, _TCHAR* argv[])
{
A *pA = new A();
B *pB = new B(pA);
if (pB)
{
pB->registerCallback();
pB->evoke();
}
system("pause");
return 0;
}
######################################