天天看点

在C++实现委托

在前面提到回调了,那么现在就开始说委托吧。个人是这么理解委托的,就是一件事你不做或者不能做或者不想做,那么就委托给别人做,我只调用别人的函数接口就可以了,也就是我要实现一个功能,我只要接口,实际的实现委托给别人,突然有一天我要做的事的逻辑发生了变化,那么我也不需要更改自己的调用,只需要被委托者更换一下逻辑就可以了。同时,如果在一定的场合下要调用很多相同形式的函数,那么使用委托将很方便。

在设计模式中状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托也可以接受多个实例方法,你可以向一个委托注册多个方法。实际上,委托包含了一个方法引用的列表,当委托被调用时,它将顺序调用其列表中的方法引用。

“委托”在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:超级大牛法,二进制层面抽象泛化注册事件

在实现委托的过程中,无碍乎一下的过程:

委托器
事件器
在C++实现委托

其中事件器封装实际的调用过程,而委托器负责响应我们的外部调用,委托器记录了注册的事件器并能够相应的增删操作,在响应外部调用时可以遍历事件器并进行调用,事件器需要向委托器进行注册。

看看下面一位大牛实现的代码吧,超级牛,注意,这个代码使用的是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...