C++委托

来源:互联网 发布:xboxone安卓软件 编辑:程序博客网 时间:2024/05/18 02:22

C++没有提供委托模型,为了达到目的,需要继承一个类并重写virtual方法,这种做法需要很多代码,效率比较低下。然而,在C++面前,没有什么不可能,已经有很多人实现了各种委托。其中比较著名的有FastDelegate,这个模型在《Member Function Pointers and the Fastest Possible C++ Delegates》中,这个模型就是快,因此要依赖编译器的具体实现。下面看实例:

 

成员函数指针的操作

class A{

public:

           void Func(int){...}

};

要取得Func函数指针,void (A::*pFunc)(int)=&A::Func;

::*是一个特殊操作符,表示pFunc是一个指针,指向A的成员。获取成员函数的地址不能通过类对象来获取,必须通过类名获取,而且要加上取地址操作。

那么如果通过指针来调用该函数,成员函数都隐含了一个this参数,表示函数要操作的对象,我们只获取了函数的指针,还缺少一个对象作为this参数,为了这个目的,我们先创建一个对象,然后通过该对象来调用成员函数指针:

A a; ( a.*pFunc)(10);

A* pa=&a;

(pa->*pFunc)(11);

第一种方式通过对象本身调用,第二种方式通过对象指针调用,效果一样。

使用类模板:

要调用一个成员函数,仅仅有成员函数指针是不够的,还需要一个对象指针,所以要用一个类将两者绑到一起。由于对象的类型是无穷多的,所以这里必须使用类模板:

template<typename T>

class DelegateHandler

{

public:

          DelegateHandler(T* pT,void(T::*pFunc)(int)):m_pT(pT),m_pFunc(pFunc)

          {}

          void Invoke(int value)

          {

                   (m_pT->*m_pFunc)(value);

          }

private:

           T* m_pT;

           void (T::*m_pFunc)(int);

};

可以这样使用该模板:

A a; DelegateHandler<A> ah(&a,&A::Func);

ah.Invoke(3);

B b; DelegateHandler<B> bh(&b,&B::Method);

bh.Invoke(4);

如果希望调用的目标是非成员函数,那么需要使用模板偏特化技术:

template<>

class DelegateHandler<void>

{

public:

          DelegateHandler(void(*pFunc)(int)):m_pFunc(pFunc)

          {}

          void Invoke(int value)

          {

                      (*m_pFunc)(value);

          }

private:

            void (*m_pFunc)(int);

}

使用方式:

DelegateHandler<void> h(NonmemberFunc);

h.Invoke(5);

也许有人怀疑,非成员函数不需要将函数指针和函数对象指针绑到一块,为何还用一个类来包装函数指针呢?

使用多态:

对于单目标的委托来说,使用上面的代码就已经足够。我们实现多目标的委托。多目标委托起始就是一个容器,在这个容器里可以存放多个对象,当调用委托的时候一次调用每个对象。容器里的对象应该都是相同的类型,这样才能够放到强类型的容器中;而且委托调用方不应该知道具体的调用目标是什么,所以这些对象也应该要隐藏具体的细节。不过上面的类模板不具备这些能力,DelegateHandler<A>和DelegateHandler<B>是不同的类型,不能放到一个容器中。

解决方法是使用多态,令所有目标类窦继承一个公共接口,调用方只通过这个接口来进行调用

class IDelegateHandler

{

public:

          virtual ~IDelegateHandler(){}

          virtual void Invoke(int)=0;

};

令DelegateHandler继承该接口

template<typename T>

class DelegateHandle:public IDelegateHandler

{

}

template<>

class DelegateHandler<>:public IDelegateHandler

{
}

现在可以将各种类型的DelegateHandler放到同一容器中,并使用同一方法调用了:

A a; B b; DelegateHandler<A> ah(&a,&A::Func);

DelegateHandler<B> bh(&b,&B::Func);

DelegateHandler<> h(NonmemberFunc);

std::vector<IDelegateHandler*>handlers;
handlers.pushback(&ah);
handlers.pushback(&bh);
handlers.pushback(&h);
for(auto it=handlers.cbegin();it!=handlers.cend();++it)
(*it)->Invoke(7);

 

使用宏:

函数参数的声明可以只有类型而没有名字,的女士为了在函数内使用参数,该参数必须有名字。

void Invoke(int){}//不能使用参数

void Invoke(int value){}

另外调用的时候只能使用名字,不能带有类型: int value=10;

Invoke(value);

DELEGATE(void,DelegateHandler,int,int);

从第三个参数开始应该使用可变参数,像这样(只截取了定义的一部分)

#define DELEGATE(retType,name,...)

retType Invoke(__VA_ARGS__)

{

             return (*m_pFunc)(__VA_ARGS__);

}

...