一个C++ delegate的实现

一个C++ delegate的实现

更新说明:
修改了借口,增加了对smart_ptr的支持。

最近需要一个C++delegate的实现,比较接近C#delegate的用法。翻遍了boost,虽然有相近的东西,但是,始终使用起来问题多多:
function:的绑定方式倒也可以接受,成员函数调用的方式实在不爽。而且,同样的函数原型,nativemember对应的function类型不同,不同class的相同原型的member function类型也不同。
signal:用起来不错,但是,一来内置了slot装置,又不便于介入干扰,二来,如何绑定一般的成员函数,不知道如何实现,只能绑定native functionfunctor
bind:正是我所要的。可惜,占位符最大到3
还有个siglib++的库,昨天才看到,为时已晚。粗略的看了一下,调用的方法,似乎也是拖泥带水。
不是我喜欢自己发明轮子,实在是迫不得已,只好自己写delegate了。手写的代码不长,贴在后面共享.

Deltegate的使用 
一.说明:

delegate的用法和C#的有些类似,相对来说还是比较简洁的。实现上,代码并不复杂。没有怎么考虑移植性的问题。 

二.使用:

1.例子

delegate<int(int, int)> dele_binary;

定义了一个委托:dele_binary, dele_binary可以持有如下形式的函数:

  1. int navive_fun(int, int);
  2. struct functor{

int operator()(int, int);

} a_functor;

  1. struct A{

int mem_fun(int, int);

} an_a;

绑定delegate到实际的函数的过程:

dele_binary.connect(&native_fun);  //绑定到普通函数,&运算符是可选的

dele_binary.connect(&a_functor);      //绑定到仿函数,&是必须的

dele_binary.connect(&an_a, &A::mem_fun); //绑定到普通成员函数,两个&都是必须的

注意:dele_binary类型定义的模版参数是:int(int, int)的形式,不要加上*,这可以参考boost::function。这样写是符合标准的,缺点是可能移植性暂时会受到影响。

 

2.调用方式

delegate重载了operator(),对于上述的三种绑定过程,具有统一的调用形式:

int x = dele_binary(1,2);

delegate重载了operator()。同时,可以注意到,例子中的差别只在于connect的形式不同,dele_binary的数据类型是确定的,因此,delegate可以放入容器当中,也可以无差别的调用。此外,delegate本身也是一个functor,也可以放入另一个delegate中,一般而言,建议避免这样做。

为了方便使用,也允许在delegate的构造函数中直接连接被委托的对象,形式如下:

delegate<int(int, int)> dele_binary (&native_fun); 

delegate<int(int, int)> dele_binary (&a_functor);     

delegate<int(int, int)> dele_binary (&an_a, &A::mem_fun);

在通过delegate调用被委托对象之前,必须确保delegate实例已经连接到某个对象。可以通过connected方法检查,是否已经连接到确定对象。也可以通过disconnect断开和对象的连接。方法原型如下:

bool connected() const

void disconnect()

 

3.Copy & assignment

delegate具有深拷贝语义。

三.实现部分

实际的实现使用了相当多的宏,并非我所愿。不过,我的使用仅仅是把宏当作最简单的字符串替换,并没有使用什么复杂的技巧,所以,阅读上应该问题不大,不想在此作冗长的讨论。欢迎讨论实现、语义上的问题。

代码部分:
/*
copywrite:            
别逗了(非典型秃子)
Description: C++
delegate实现。
可以随意复制、修改、分发、使用。不要说是自己的就可以了。^_^
*/
#ifndef DELEGATE_H
#define DELEGATE_H
#include "contract.h"
namespace nice
{
 template<typename T>
 class delegate;

#define DELEGATE(TEMPLATE_ARGS, FUNCTION_ARGS, FUNCTION_PARA)/
 template< typename Ret TEMPLATE_ARGS >/
 class delegate<Ret (FUNCTION_ARGS)>/
 {/
  struct FunctionHolder/
  {/
   virtual Ret operator()(FUNCTION_ARGS) = 0;/
   virtual FunctionHolder* clone() const = 0;/
   virtual ~FunctionHolder(){};/
  };/
  FunctionHolder* h;/
/
  template<typename FunctorPtr>/
  struct FunctorHolder : public FunctionHolder/
  {/
   FunctorPtr Fun;/
   FunctorHolder(FunctorPtr nfun) : Fun(nfun){}/
   virtual Ret operator()(FUNCTION_ARGS)/
   {/
    return (*Fun)(FUNCTION_PARA);/
   }/
   virtual FunctionHolder* clone() const/
   {/
    return new FunctorHolder(*this);/
   }/
  };/
/
  template<typename U, typename MemFun>/
  struct MemHolder : public FunctionHolder/
  {  /
   U obj;/
   MemFun memFun;   /
/
   MemHolder(U aObj, MemFun amfun) /
    : obj(aObj), memFun(amfun){}/
/
    virtual Ret operator()(FUNCTION_ARGS) /
    {/
     return ((*obj).*memFun)(FUNCTION_PARA);/
    }/
    virtual FunctionHolder* clone() const/
    {/
     return new MemHolder(*this);/
    }/
  };/
  FunctionHolder* cloneHolder() const/
  {/
   if (connected())/
    return h->clone();/
   return NULL;/
  }/
 public:/
  delegate() : h(0)/
  {/
  }/
  ~delegate() /
  { /
   disconnect(); /
  }  /
/
  template<typename FunctorPtr>/
  delegate(FunctorPtr nfun_) /
   : h(new FunctorHolder<FunctorPtr>(nfun_))/
  {/
  }/
/
  delegate(const delegate& rhs) : h(rhs.cloneHolder())/
  {}/
  template <typename U, typename MemFun>/
   delegate(U aObj, MemFun mFun) /
   : h(new MemHolder<U, MemFun>(aObj, mFun))/
  {  /
  }/
  delegate& operator=(const delegate& rhs)/
  {/
   if (&rhs != this)/
   {/
    disconnect();/
    h = rhs.cloneHolder();/
   }/
   return *this;/
  }/
  template<typename FunctorPtr>/
  void connect(FunctorPtr nfun_)/
  {  /
   disconnect();/
   h = new FunctorHolder<FunctorPtr>(nfun_);/
  }/
/
  template <typename U, typename MemFun>/
   void connect(U aObj, MemFun mFun)/
  {/
   if (h) delete h;/
   h = new MemHolder<U, MemFun>(aObj, mFun);/
  }/
/
  void disconnect() /
  {  /
   if (connected()) delete h;  /
   h = 0; /
  } /
/
  bool connected() const/
  {/
   return (h != NULL);/
  }/
/
  Ret operator()(FUNCTION_ARGS)/
  {/
   pre_condition(connected());/
   return (*h)(FUNCTION_PARA);/
  }/
 };
//*/

#define TEMPLATE_ARGS_0
#define FUNCTION_ARGS_0
#define FUNCTION_PARA_0

#define TEMPLATE_ARGS_1         , typename T0
#define FUNCTION_ARGS_1      T0 t0
#define FUNCTION_PARA_1      t0

/* Defines Generate code:
for (int i = 2; i <= 50; i++)
{
 printf("#define TEMPLATE_ARGS_%d TEMPLATE_ARGS_%d, typename T%d/n", i, i - 1, i - 1) ;
 printf("#define FUNCTION_ARGS_%d FUNCTION_ARGS_%d, T%d t%d/n", i, i - 1, i - 1, i - 1);  
 printf("#define FUNCTION_PARA_%d FUNCTION_PARA_%d, t%d/n/n", i, i - 1, i - 1);    
};

for (int i = 0; i <= 50; ++i)
  printf("DELEGATE(TEMPLATE_ARGS_%d, FUNCTION_ARGS_%d, FUNCTION_PARA_%d)/n", i, i, i);
*/
 
//Auto Generate code:----------------------------------------------
#define TEMPLATE_ARGS_2 TEMPLATE_ARGS_1, typename T1
#define FUNCTION_ARGS_2 FUNCTION_ARGS_1, T1 t1
#define FUNCTION_PARA_2 FUNCTION_PARA_1, t1
....
#define TEMPLATE_ARGS_3 TEMPLATE_ARGS_2, typename T2
#define FUNCTION_ARGS_3 FUNCTION_ARGS_2, T2 t2
#define FUNCTION_PARA_3 FUNCTION_PARA_2, t2

#define TEMPLATE_ARGS_4 TEMPLATE_ARGS_3, typename T3
#define FUNCTION_ARGS_4 FUNCTION_ARGS_3, T3 t3
#define FUNCTION_PARA_4 FUNCTION_PARA_3, t3
...

DELEGATE(TEMPLATE_ARGS_0, FUNCTION_ARGS_0, FUNCTION_PARA_0)
DELEGATE(TEMPLATE_ARGS_1, FUNCTION_ARGS_1, FUNCTION_PARA_1)
DELEGATE(TEMPLATE_ARGS_2, FUNCTION_ARGS_2, FUNCTION_PARA_2)
DELEGATE(TEMPLATE_ARGS_3, FUNCTION_ARGS_3, FUNCTION_PARA_3)
...
};
#endif//end DELEGATE_H

测试用例:
CPPUNIT_TEST_SUITE_REGISTRATION(test_delegate);
using namespace nice;

int local_add(int a, int b)
{
 return a + b;
}

struct functor_add
{
 int m;
 int mem_add(int a, int b)
 {
  return a + b + m;
 }
};

struct functor_mul
{
 int m;
 int operator()(int a, int b)
 {
  return (a + b) * m;
 }
};


void test_delegate::testMain()
{
 typedef delegate<int(int, int)> testDele2;

 //默认ctor没有连接上
 testDele2 dele1;
 CPPUNIT_ASSERT(!dele1.connected());

 //connect
 testDele2 dele2(local_add);
 CPPUNIT_ASSERT(dele2.connected());

 //调用
 CPPUNIT_ASSERT(dele2(2, 3) == 5);

 //copy ctor
 testDele2 dele3 = dele2;
 CPPUNIT_ASSERT(dele3.connected());
 CPPUNIT_ASSERT(dele3(2, 3) == 5);

 //disconnect
 dele2.disconnect();
 CPPUNIT_ASSERT(!dele2.connected());
 
 //test clone
 CPPUNIT_ASSERT(dele3.connected());
 dele3(2, 3);
 CPPUNIT_ASSERT(dele3(2, 3) == 5);
 
 //assign
 dele2 = dele3;
 CPPUNIT_ASSERT(dele2(2, 3) == 5);

 //member function
 functor_add fctor;
 fctor.m = 7;
 dele2.connect(&fctor, &functor_add::mem_add);
 CPPUNIT_ASSERT(dele2(2, 3) == 12);

 //functor
 functor_mul fm;
 fm.m = 3;
 testDele2 dele4(&fm);
 CPPUNIT_ASSERT(dele4(2, 3) == 15);
 fm.m = 4;
 CPPUNIT_ASSERT(dele4(2, 3) == 20);

 dele2.connect(&fm);
 
 //smart ptr
 boost::shared_ptr<functor_mul> sh_ptr(new functor_mul);
 (*sh_ptr).m = 10; 
 
 dele2.connect(sh_ptr);
 CPPUNIT_ASSERT(dele2(2, 3) == 50);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中的委托(delegate)是一种函数指针的高级形式,它可以将函数作为参数传递给其他函数或存储在数据结构中。委托提供了一种灵活的方式来实现回调机制和事件处理。 在C++中,可以使用函数指针、函数对象和Lambda表达式来实现委托。下面是几种常见的委托用法: 1. 函数指针委托: 可以使用函数指针作为委托类型,将一个函数指针赋值给委托变量,然后通过委托变量调用相应的函数。 示例代码: ```cpp void Function1() { // 函数1的实现 } void Function2() { // 函数2的实现 } typedef void (*DelegateType)(); // 定义委托类型 int main() { DelegateType delegate = nullptr; delegate = &Function1; // 将函数1赋值给委托变量 delegate(); // 调用委托,实际上调用了函数1 delegate = &Function2; // 将函数2赋值给委托变量 delegate(); // 调用委托,实际上调用了函数2 return 0; } ``` 2. 函数对象委托: 可以使用函数对象(重载了函数调用运算符operator()的类对象)作为委托类型,将一个函数对象赋值给委托变量,然后通过委托变量调用相应的函数。 示例代码: ```cpp class FunctionObject { public: void operator()() { // 函数对象的实现 } }; int main() { FunctionObject functionObject; typedef void (FunctionObject::*DelegateType)(); // 定义委托类型 DelegateType delegate = nullptr; delegate = &FunctionObject::operator(); // 将函数对象的函数调用运算符赋值给委托变量 (functionObject.*delegate)(); // 调用委托,实际上调用了函数对象的函数调用运算符 return 0; } ``` 3. Lambda表达式委托: 可以使用Lambda表达式作为委托类型,直接将Lambda表达式赋值给委托变量,然后通过委托变量调用相应的函数。 示例代码: ```cpp int main() { auto lambda = []() { // Lambda表达式的实现 }; typedef decltype(lambda) DelegateType; // 定义委托类型 DelegateType delegate = lambda; // 将Lambda表达式赋值给委托变量 delegate(); // 调用委托,实际上调用了Lambda表达式 return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值