基于泛型类模块,使类成员函数作为回调函数

来源:互联网 发布:条码打印软件使用方法 编辑:程序博客网 时间:2024/06/15 07:44

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. 当然如果能完善上面这个实例,这种方法实现的回调函数最灵活。



原创粉丝点击