1. FuncCache
此类用于存放,类和函数信息。关键在于对函数参数的处理,写得妙。因为,类中类的成员,在使用后自动销毁,可以使得函数可以反复调用。 类成员buffer,相当于一个栈,可用于在放任何数据(如:类指针、函数指针、参数指针)。 类成员func,存放MFuncCall_1的静态成员函数。为什么不把这个静函数直接作为成员函数?因为可以用这个函数作为接口,方便用户自定义!
2. MFuncCall_1
用此类编写与目标回调函数最后执行的代码。 读取预存信息:类指针、类成员函数指针、参数值。最后执行这个函数。
3. L_Signal_1继承于L_SignalRoot
这个类主要是封装FuncCache的操作,使用Map可存放多个类的回调函数。
4. EventCallerA和EventCallerB
这两个类主要是用来做测试用例。
// Delegate.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <map>
using namespace std;
typedef unsigned int uint;
typedef unsigned char uchar;
/
/// \class FuncCache
/// \brief 函数对象寄存器
/
template <typename ReturnType>
class FuncCache
{
static const int SIZE = 48;
typedef ReturnType (*func_caller)(FuncCache*);
/// \class MemberFuncAssist
/// \brief 对象成员函数寄存器的辅助器
class FuncCacheAssist
{
public:
/// \brief 构造函数,初始化。
FuncCacheAssist(FuncCache* pFunc)
{
m_Size = 0;
m_pFunc = pFunc;
// 读取用偏移必须归位
m_pFunc->m_Cur = 0;
}
/// \brief 析构函数。
~FuncCacheAssist(void)
{
// 弹出以前压入的参数
if (m_Size > 0)
m_pFunc->Pop(m_Size);
}
/// \brief 压入指定大小的数据。
uint Push(const void* pData, uint size)
{
m_Size += size;
return m_pFunc->Push(pData, size);
}
/// 压入参数的大小
int m_Size;
/// 对象成员函数寄存器
FuncCache* m_pFunc;
};
public:
/// \brief 构造函数,初始化。
FuncCache(func_caller func)
{
m_Size = 0;
m_Cur = 0;
m_Func = func;
}
/// \brief 压入指定大小的数据。
uint Push(const void* pData, uint size)
{
size = (size <= SIZE - m_Size)? size : (SIZE - m_Size);
memcpy(m_Buffer + m_Size, pData, size);
m_Size += size;
return size;
}
/// \brief 弹出指定大小的数据。
uint Pop(uint size)
{
size = (size < m_Size)? size : m_Size;
m_Size -= size;
return size;
}
/// \brief 读取指定大小的数据,返回指针。
void* Read(uint size)
{
m_Cur += size;
return (m_Buffer + m_Cur - size);
}
/// \brief 执行一个参数的函数。
ReturnType Execute(const void* pData)
{
// 用辅助结构控制
FuncCacheAssist assist(this);
// 压入参数
assist.Push(&pData, sizeof(void*));
// 执行函数
return m_Func(this);
}
protected:
/// 对象,函数,参数指针的缓冲区
uchar m_Buffer[SIZE];
/// 缓冲区大小
uint m_Size;
/// 缓冲区读取用的偏移
uint m_Cur;
/// 操作函数的指针
func_caller m_Func;
};
/
/// \class MFuncCall_1
/// \brief 一个参数的成员函数执行体
/
template <typename ReturnType, typename Caller, typename Func, typename ParamType>
class MFuncCall_1
{
public:
/// \brief 执行一个参数的成员函数。
static ReturnType MFuncCall(FuncCache<ReturnType>* pMFunc)
{
// 获得对象指针
Caller* pCaller = *(Caller**)pMFunc->Read(sizeof(Caller*));
// 获得成员函数指针
Func func = *(Func*)pMFunc->Read(sizeof(Func));
// 获得参数的指针
ParamType* pData = *(ParamType**)pMFunc->Read(sizeof(ParamType*));
// 执行成员函数
return (pCaller->*func)(*pData);
}
};
/
/// \class L_SignalRoot
/// \brief 类型检查严格的事件委托器基类
/
template <typename ReturnType>
class L_SignalRoot
{
public:
/// \brief 指定事件名,卸载指定对象的事件委托器。
template <typename Caller>
void MFuncUnregister(Caller* pCaller)
{
func_map& func_list = m_MemberFuncMap;
func_map::iterator it = func_list.find(pCaller);
if (it != func_list.end())
func_list.erase(it);
}
/// \brief 清空所有事件委托器。
void MFuncClear(void)
{
m_MemberFuncMap.clear();
}
protected:
typedef map< void*, FuncCache<ReturnType> > func_map;
/// 事件名和绑定的事件委托器的列表
func_map m_MemberFuncMap;
};
/
/// \class L_Signal_1
/// \brief 类型检查严格,一个参数的事件委托器
/
template <typename ReturnType, typename ParamType>
class L_Signal_1 : public L_SignalRoot<ReturnType>
{
public:
/// \brief 指定事件名,注册对应的一个参数的事件委托器。
template <typename Caller, typename Func>
void MFuncRegister(Caller* pCaller, Func func)
{
// 指定专门处理一个参数的函数执行体
FuncCache<ReturnType> mfunc(MFuncCall_1<ReturnType, Caller, Func, ParamType>::MFuncCall);
// 压入对象和函数
mfunc.Push(&pCaller, sizeof(Caller*));
mfunc.Push(&func, sizeof(Func));
// 添加到事件委托器列表
m_MemberFuncMap.insert(make_pair(pCaller, mfunc));
}
/// \brief 指定事件名,调用其对应的一个参数的事件委托器。
ReturnType MFuncCall(const ParamType& data)
{
// 清空返回值
ReturnType result;
memset(&result, 0, sizeof(result));
// 对于所有委托器,调用注册的函数
func_map::iterator it = m_MemberFuncMap.begin();
while (it != m_MemberFuncMap.end())
{
result = it->second.Execute(&data);
++it;
}
return result;
}
};
class EventCallerA
{
public:
bool Do(int event_id)
{
printf("EventCallerA do event %d.\r\n", event_id);
return true;
}
};
class EventCallerB
{
public:
bool Run(int event_id)
{
printf("EventCallerB run event %d.\r\n", event_id);
return true;
}
};
void main()
{
// 申明返回值是bool类型,参数是int类型,单参数的事件器
L_Signal_1<bool, int> signal;
EventCallerA callerA;
EventCallerB callerB;
// 注册委托器并调用事件
signal.MFuncRegister(&callerA, &EventCallerA::Do);
signal.MFuncRegister(&callerB, &EventCallerB::Run);
signal.MFuncCall(1);
}
扩展:类的回调函数还可以使用以下方法实现。
1. 使用汇编,把回调函数的地址转换为C风格。使用这种方法用完后要转换回来,还有它没有了继承的特性。
2. 使用虚基类,在对方代码里,接收一个己方 继承这个虚基类的对象的指针。
3. 当然如果能完善上面这个实例,这种方法实现的回调函数最灵活。