在前面提到回调了,那么现在就开始说委托吧。个人是这么理解委托的,就是一件事你不做或者不能做或者不想做,那么就委托给别人做,我只调用别人的函数接口就可以了,也就是我要实现一个功能,我只要接口,实际的实现委托给别人,突然有一天我要做的事的逻辑发生了变化,那么我也不需要更改自己的调用,只需要被委托者更换一下逻辑就可以了。同时,如果在一定的场合下要调用很多相同形式的函数,那么使用委托将很方便。
在设计模式中状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托也可以接受多个实例方法,你可以向一个委托注册多个方法。实际上,委托包含了一个方法引用的列表,当委托被调用时,它将顺序调用其列表中的方法引用。
“委托”在C#中是一个语言级特性,C++中是没有的,那么我们来实现吧~
Method1:成员函数指针加模板
记得在回调函数中我们使用的成员函数指针么,如果再加上模板将成员函数泛化,天下无敌~
代码:
- #include <iostream>
- using namespace std;
- template<typename T>
- class A
- {
- private:
- typedef int (T::*delegateFun)(int);
- T* _This;
- delegateFun _deleGate;
- public:
- A(T * This, delegateFun delegatefun)
- {
- _This = This;
- _deleGate = delegatefun;
- }
- int execue(int c)
- {
- return (_This->*_deleGate)(c);
- }
- };
- class B
- {
- public:
- int FunA(int a) {return a + 10;}
- int FunB(int a) {return a - 10;}
- B(){}
- };
- void main(void)
- {
- B *objB = new B();
- A<B> delegateObj1(objB, (&B::FunA));
- A<B> delegateObj2(objB, (&B::FunB));
- cout << delegateObj1.execue(10) <<endl;
- cout << delegateObj2.execue(20) <<endl;
- }
Method2:来个纯面向对象的方法
代码:
- #include <iostream>
- using namespace std;
- class EventHandler {
- public:
- virtual void exec() = 0;
- };
- class Event{
- public:
- void set_handler( EventHandler* h){ _handler = h; }
- void exec(){_handler->exec();}
- private:
- EventHandler* _handler;
- };
- class MyHandler : public EventHandler {
- public:
- void exec() { cout << "Handler---" << endl; }
- };
- void main(void)
- {
- Event e;
- MyHandler h;
- e.set_handler(&h);
- e.exec();
- }
Method3:使用list进行多调用
代码是下面博客里的,大家来感受一下~,这里主要注重的是注册的增删,保存,执行,如果再加上多种回调机制那就更牛了。
http://blog.csdn.net/cambest/archive/2004/04/12/17122.aspx
代码:
- #include <list>
- #include <iostream>
- #include <windows.h>
- using namespace std;
- typedef unsigned int NativePtr;
- typedef void (* Handler)(char *);
- class CDelegate
- {
- private:
- list<NativePtr> ftns;
- public:
- void AddFunction(void *);
- void RemoveFunction(void *);
- int Invoke(char *);
- void operator += (void *);
- void operator -= (void *);
- int operator ()(char *);
- };
- void CDelegate::AddFunction(void *ftn)
- {
- NativePtr np=(NativePtr)ftn;
- ftns.push_back(np);
- }
- void CDelegate::RemoveFunction(void *ftn)
- {
- NativePtr np=(NativePtr)ftn;
- ftns.remove(np);
- }
- void CDelegate::operator += (void *ftn)
- {
- this->AddFunction(ftn);
- }
- void CDelegate::operator -= (void *ftn)
- {
- this->RemoveFunction(ftn);
- }
- int CDelegate::Invoke(char * pch)
- {
- Handler handle;
- list<NativePtr>::iterator itr=ftns.begin();
- try
- {
- for(;itr!=ftns.end();itr++)
- {
- handle=(Handler)*itr;
- handle(pch);
- }
- }
- catch(char *)
- {
- return 0;
- }
- return 1;
- }
- int CDelegate::operator ()(char *pch)
- {
- return Invoke(pch);
- }
- void Say1(char *s)
- {
- cout<<"In Function Say1: ";
- cout<<s<<endl;
- }
- void Say2(char *s)
- {
- cout<<"In Function Say2: ";
- cout<<s<<endl;
- }
- void Say3(char *s)
- {
- cout<<"In Function Say3: ";
- cout<<s<<endl;
- }
- void main()
- {
- CDelegate dlg;
- dlg.AddFunction(Say1);
- dlg.AddFunction(Say2);
- dlg+=Say3;
- int rs=dlg.Invoke("Hello,World!");
- if(!rs) cout<<"Failed."<<endl;
- dlg-=Say2;
- rs=dlg("The second invoking by CDelegate!");
- if(!rs) cout<<"Failed."<<endl;
- dlg-=Say1;
- dlg-=Say3;
- rs=dlg.Invoke("The Third invoking by CDelegate!");
- if(!rs) cout<<"Failed."<<endl;
- }
Method4:functor+模板
使用functor是为了回调的方便,而是用模板就是为了是委托者和被委托者之间解耦,是被委托者对于委托者透明。
代码如下:
- #include <list>
- #include <iostream>
- #include <windows.h>
- using namespace std;
- class Add{
- public:
- Add(int c) {
- this->c = c;
- }
- int operator()(int a, int b) {
- return a + b + c;
- }
- private:
- int c;
- };
- class Mul{
- public:
- Mul(int c) {
- this->c = c;
- }
- int operator()(int a, int b) {
- return a * b * c;
- }
- private:
- int c;
- };
- template<typename T>
- void Do(T& f, int a, int b) {
- int r = f(a, b);
- std::cout << r << std::endl;
- };
- void main(void){
- Add adder(1);
- Do(adder, 1, 2);
- Mul multiplier(10);
- Do(multiplier, 2, 3);
- }
Method5:还是functor+模板,但是搞得复杂点
代码:
- #include <stdio.h>
- #include <iostream>
- #include <windows.h>
- using namespace std;
- template<typename Y, typename X, typename R>
- class FastDelegate
- {
- public:
- FastDelegate(Y* y, R (X::*Fun)())
- {
- m_pPointer = y;
- m_fun = Fun;
- }
- R operator()()
- {
- return (m_pPointer->*m_fun)();
- }
- void CallMemerPointer()
- {
- (m_pPointer->*m_fun)();
- }
- protected:
- private:
- Y* m_pPointer;
- typedef R (X::*Fun)();
- Fun m_fun;
- };
- class FuncPointer
- {
- public:
- int TestFunc1()
- {
- printf("call TestFunc1:/r/n");
- int i = 1;
- return i;
- }
- int TestFunc2()
- {
- printf("call TestFunc2:/r/n");
- int i = 2;
- return i;
- }
- };
- template <class X, class Y, class RetType>
- FastDelegate<Y, X, RetType >
- bind(
- RetType (X::*func)(),
- Y* y,
- ...)
- {
- return FastDelegate<Y,X, RetType>(y, func);
- }
- void main(void)
- {
- FuncPointer* fp = new FuncPointer();
- bind(&FuncPointer::TestFunc1, fp).CallMemerPointer();
- bind(&FuncPointer::TestFunc2, fp).CallMemerPointer();
- bind(&FuncPointer::TestFunc1, fp)();
- bind(&FuncPointer::TestFunc2, fp)();
- }
PS:此时FuncPointer中的函数不能为static
从微软的网站上找到这么篇文章, 创建到 c + + 成员函数的函数指针,地址: http://support.microsoft.com/kb/94579/zh-cn
给了个实例代码来看看:
#include <iostream.h>
class Data
{
private:
int y;
static int x;
public:
void SetData(int value) {y = value; return;};
int GetData() {return y;};
static void SSetData(int value) {x = value; return;};
static int SGetData() {return x;};
};
int Data::x = 0;
void main(void)
{
Data mydata, mydata2;
// Initialize pointer.
void (Data::*pmfnP)(int) = &Data::SetData; // mydata.SetData;
// Initialize static pointer.
void (*psfnP)(int) = &Data::SSetData;
mydata.SetData(5); // Set initial value for private data.
cout << "mydata.data = " << mydata.GetData() << endl;
(mydata.*pmfnP)(20); // Call member function through pointer.
cout << "mydata.data = " << mydata.GetData() << endl;
(mydata2.*pmfnP)(10) ; // Call member function through pointer.
cout << "mydata2.data = " << mydata2.GetData() << endl;
(*psfnP)(30) ; // Call static member function through pointer.
cout << "static data = " << Data::SGetData() << endl ;
}
可以看出不一样的地方来了吧~
Method6:成员函数指针+模板+Vector
再来个高级点的,综合一下,函数指针+模板+Vector。
代码:
- #include <iostream>
- #include <vector>
- using namespace std;
- class BaseDelegate
- {
- public:
- virtual void Invoke()=0;
- protected:
- BaseDelegate()
- {}
- ~BaseDelegate()
- {}
- };
- class NonTypeDelegate : public BaseDelegate
- {
- public:
- void Invoke();
- NonTypeDelegate(void (*pfn)(int),int iParam);
- virtual ~NonTypeDelegate(){}
- private:
- void (*m_pfn)(int);
- int m_iParam;
- };
- NonTypeDelegate::NonTypeDelegate(void (*pfn)(int),
- int iParam):m_pfn(pfn),
- m_iParam(iParam)
- {
- }
- void NonTypeDelegate::Invoke()
- {
- cout << "NonTypeDelegate Invoke/r/n";
- m_pfn(m_iParam);
- }
- template <typename T>
- class TypeDelegate : public BaseDelegate
- {
- public:
- void Invoke();
- TypeDelegate(T &t, void (T::*pfn)(int), int iParam);
- ~TypeDelegate(){}
- private:
- T m_t;
- void (T::*m_pfn)(int);
- int m_iParam;
- };
- template<typename T>
- TypeDelegate<T>::TypeDelegate(T &t,
- void (T::*pfn)(int),
- int iParam):m_t(t),
- m_pfn(pfn),
- m_iParam(iParam)
- {
- }
- template<typename T>
- void TypeDelegate<T>::Invoke()
- {
- cout << "TypeDelegate Invoke/r/n";
- (m_t.*m_pfn)(m_iParam);
- }
- void Test(int iParam)
- {
- cout << "Test Invoked/r/n";
- }
- class A
- {
- public:
- void Test(int iParam)
- {
- cout << "A::Test Invoked/r/n";
- }
- };
- class B
- {
- public:
- static void Test(int iParam)
- {
- cout << "B::Test Invoked/r/n";
- }
- };
- int main(int argc, char* argv[])
- {
- NonTypeDelegate nTDelegate(Test,1);
- NonTypeDelegate nTSDelegate(B::Test,1);
- A a;
- TypeDelegate<A> tDelegate(a,&A::Test,2);
- vector<BaseDelegate*> vecpDelegate;
- vecpDelegate.push_back(&nTDelegate);
- vecpDelegate.push_back(&tDelegate);
- vecpDelegate.push_back(&nTSDelegate);
- for (vector<BaseDelegate*>::const_iterator kItr=vecpDelegate.begin();/
- kItr!=vecpDelegate.end(); ++kItr)
- {
- (*kItr)->Invoke();
- }
- return 0;
- }
在网上还看见了一个,如下
http://kenny-office.blog.163.com/blog/static/3078692720106192313748/
可以参考~
Method7:超级大牛法,二进制层面抽象泛化注册事件
在实现委托的过程中,无碍乎一下的过程:
委托器 |
事件器 |
![](http://hi.csdn.net/attachment/201105/9/0_1304912615e4Hr.gif)
其中事件器封装实际的调用过程,而委托器负责响应我们的外部调用,委托器记录了注册的事件器并能够相应的增删操作,在响应外部调用时可以遍历事件器并进行调用,事件器需要向委托器进行注册。
看看下面一位大牛实现的代码吧,超级牛,注意,这个代码使用的是VS2008,VC6可能会有问题啊。
- #include <stdio.h>
- #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);
- }
Method8:使用FastDelegate
FastDelegate是实现好的开源库,如果有时间的话看看下面这个,很不错~
http://www.cppblog.com/huangwei1024/archive/2010/11/17/133870.html http://www.codeproject.com/KB/cpp/FastDelegate.aspx
好了,到这里为止,其实把我们前面的回调做好封装,就可以实现不错的委托,更新更好的方法还需要一点一滴的努力~
委托,To be, or not to be...