C++中关于委派(Delegates)的实现示例
介绍
在C++中通过一个全局函数来绑定到对象的成员函数是很有用的,这个特性也存在于其他语言中,例如C#的委派。在C++中相当于成员函数指针,但是并没有提供相应的特性。在这篇文章中,我想提出一个简单的C++委派的实现,是用C++成员函数指针和C++11的可变模板(variadictemplates),目前这套实现方法仅支持GNUC++4.7.0,在Windows下可使用MinGW。
背景
在我的方法中奖提供一个create_delegate函数,可通过下面两种方法来调用:
create_delegate(&object,&member_function) create_delegate(&function)
第一种方法创建一个对象并提供一个operator()成员函数,第二个方法生成一个函数指针,两种方法都兼容typefunction<...>.
示例程序
首先我们定义一个包含多个方法的类:
classA
{
inti;
public:
A(intk):i(k){}
autoget()const->int{returni;}
autoset(intv)->void{i=v;}
autoinc(intg)->int&{i+=g;returni;}
autoincp(int&g)->int&{g+=i;returng;}
autof5(inta1,inta2,inta3,inta4,inta5)const->int
{
returni+a1+a2+a3+a4+a5;
}
autoset_sum4(int&k,inta1,inta2,inta3,inta4)->void
{
i+=a1+a2+a3+a4;
k=i;
}
autof8(inta1,inta2,inta3,inta4,inta5,inta6,inta7,inta8)const->int
{
returni+a1+a2+a3+a4+a5+a6+a7+a8;
}
staticautosqr(doublex)->double{returnx*x;}
};
请注意你并不需要一定使用C++的auto函数语法,你也可以使用传统的方法,然后我们使用下面方法创建一个类:
Aa(11);
接下来我们创建委派:
autoset1=create_delegate(&a,&A::set); autoinc=create_delegate(&a,&A::inc); std::function<int(int&)>incp=create_delegate(&a,&A::incp); autoaf5=create_delegate(&a,&A::f5); autoset_sum4=create_delegate(&a,&A::set_sum4); autoaf8=create_delegate(&a,&A::f8); autosqr=create_delegate(&A::sqr);//staticfunction</int(int&)> set1(25); intx=5; intk=inc(x); k=incp(x); std::cout<<"a.get():"<<a.get()<<std::endl; std::cout<<"k:"<<k<<std::endl; std::cout<<"x:"<<x<<std::endl; std::cout<<"af5(1,2,3,4,5):"<<af5(1,2,3,4,5)<<std::endl; set_sum4(x,1,2,3,20); std::cout<<"afterset_sum4(x,1,2,3,20)"<<std::endl; std::cout<<"a.get():"<<a.get()<<std::endl; std::cout<<"x:"<<x<<std::endl; std::cout<<"af8(1,2,3,4,5,6,7,8):"<<af8(1,2,3,4,5,6,7,8)<<std::endl; std::cout<<"sqr(2.1):"<<sqr(2.1)<<std::endl;
执行上述程序的打印结果如下:
a.get():30 k:35 x:35 af5(1,2,3,4,5):45 afterset_sum4(x,1,2,3,20) a.get():56 x:56 af8(1,2,3,4,5,6,7,8):92 sqr(2.1):4.41
关键点
对于一个不是volatile和const的简单函数而言,实现是非常简单的,我们只需要创建一个类保存两个指针,一个是对象,另外一个是成员函数:
template<classT,classR,class...P>
struct_mem_delegate
{
T*m_t;
R(T::*m_f)(P...);
_mem_delegate(T*t,R(T::*f)(P...)):m_t(t),m_f(f){}
Roperator()(P...p)
{
return(m_t->*m_f)(p...);
}
};
可变模板variadictemplate允许定义任意个数和类型参数的operator()函数,而create_function实现只需简单返回该类的对象:
template<classT,classR,class...P>
_mem_delegate<T,R,P...>create_delegate(T*t,R(T::*f)(P...))
{
_mem_delegate<T,R,P...>d(t,f);
returnd;
}
实际中,我们需要另外的三个实现用于覆盖const、volatile和constvolatile三种成员函数,这也是为什么传统使用#define宏很便捷的原因,让你无需重写代码段,下面是完整的实现:
template<classF>
F*create_delegate(F*f)
{
returnf;
}
#define_MEM_DELEGATES(_Q,_NAME)\
template<classT,classR,class...P>\
struct_mem_delegate##_NAME\
{\
T*m_t;\
R(T::*m_f)(P...)_Q;\
_mem_delegate##_NAME(T*t,R(T::*f)(P...)_Q):m_t(t),m_f(f){}\
Roperator()(P...p)_Q\
{\
return(m_t->*m_f)(p...);\
}\
};\
\
template<classT,classR,class...P>\
_mem_delegate##_NAME<T,R,P...>create_delegate(T*t,R(T::*f)(P...)_Q)\
{\
_mem_delegate##_NAME<T,R,P...>d(t,f);\
returnd;\
}
_MEM_DELEGATES(,Z)
_MEM_DELEGATES(const,X)
_MEM_DELEGATES(volatile,Y)
_MEM_DELEGATES(constvolatile,W)