C++实现Delegate

大家都知道C#的Delegate非常的好用,特别是应用在Subject-Observer模式的时候,具有很好的灵活性,但是C++只有function pointers,前面有一篇blog讲到了它的问题,以及难以理解的地方。不过也提到boost使用模板实现了boost::function基本具备了delegate的特点,我稍加改造,去除了boost的依赖关系,实现了一个小巧的Delegate,不过鉴于VC6.0的编译器还不支持“偏特化”,因此使用上还有点不爽的地方。
class Subject
{
public:
 void notify()
 {
  myHandler();
 }
 mylib::delegate0<int> myHandler;
 std::string myString;
};
class Observer
{
public:
 int OnNotify()
 {
  std::cout << "Observer::OnNotify" << std::endl;
  return 0;
 }
};
 
int main(int argc, char* argv[])
{
 Subject subject;
 Observer observer;
 subject.myHandler += mylib::mem_fun0(&Observer::OnNotify, &observer);
 subject.myString = "changed";
 subject.notify();
}
这样的用法看起来和C#的已经很接近了!下面我们来一步步的解渎boost::function()的原理吧,鉴于很多人都和我一样对于模板和宏技巧都是入门级的,我主要介绍几个要点吧(卡了我超过一个小时的点):
1、【技巧】使用VC工程编译参数加 /E可以把预处理的结果输出到output,/P输出到中间文件*.i;
2、【置疑】下面是两个宏定义,结果完全不同的:
#define PARAM_COUNT 3
#define _DELEGATE_FUNC_P(i) delegate_func ##i
#define _DELEGATE_FUNC(count) _DELEGATE_FUNC_P(count)
 _DELEGATE_FUNC(PARAM_COUNT)
 
#define PARAM_COUNT 3
#define _DELEGATE_FUNC_P(i) delegate_func ##i
 _DELEGATE_FUNC_P(PARAM_COUNT)
 3、【基础】函数模板,以前从来没有使用过函数模板,不过看到这个例子就会发现模板的好处了:
template<class _R, class _Ty, class _A>
 class mem_fun1_t{
public:
 explicit mem_fun1_t(_R (_Ty::*_Pm)(_A))
  : _Ptr(_Pm){}
private:
 _R (_Ty::*_Ptr)(_A);
 };
  // TEMPLATE FUNCTION mem_fun1
template<class _R, class _Ty, class _A> inline
 mem_fun1_t<_R, _Ty, _A> mem_fun1(_R (_Ty::*_Pm)(_A))
 {return (mem_fun1_t<_R, _Ty, _A>(_Pm)); }

4、【技巧】现在遇到的问题是,虽然通过函数模板,在函数内可以提取出类的名字,生成对象,但是该对象如果需要保存下来,下次调用的时候又无法知道开始的时候是什么类了。举个例子来说明问题所在:在delegate类中保存了CTest的指针强制转换成了void*后面需要调用CTest的函数,需要把void*指针重新转换成CTest的指针,可是delegate类并不知道CTest类,这怎么办呢?方法是使用了一个类和静态函数的方法,静态函数的形式是固定的,这样就可以保存下CTest类的类型了,下面是示例:

template<typename FuncPtr, typename _R, typename T1>
struct delegate_h{
 static _R invoker(void* p, T1 i)
 {
  FuncPtr* mp= (FuncPtr*)p;
  return (*mp)(i);
 }
};

template<class _R, class _A1>
class delegate{
public:
 typedef _R(*FuncPtr)(_A1);

 template<typename Mem>
  delegate(Mem& f)
 {
  m_mem = new Mem(f);
  invoker = delegate_h<Mem,_R, _A1>::invoker;
 }
 _R operator() (_A1 a)
 {
  return invoker(m_mem, a);
 }
private:
 void* m_mem;
 typedef _R (*invoke_type)(void*, _A1);
 invoke_type invoker;
};

5、【技巧】宏定义进行重复,这个是为了降低工作量的,因为对于不同的参数个数,需要定义不同的类,因此需要重复的代码,这个非常不好,我们可以使用宏定义来进行重复。比如需要生成3个参数的模板就需要template<typename R, typename A1, typename A2, typename A3>,如何通过简单的代码生成任意长度的列表呢?

#define BOOST_PP_REPEAT(n, m, p) BOOST_PP_REPEAT ## n(m, p)
#define BOOST_PP_REPEAT0(m, p)
#define BOOST_PP_REPEAT1(m, p) m(0, p)
#define BOOST_PP_REPEAT2(m, p) m(0, p) m(1, p)
#define BOOST_PP_REPEAT3(m, p) BOOST_PP_REPEAT2(m, p) m(2, p)
#define BOOST_PP_REPEAT4(m, p) BOOST_PP_REPEAT3(m, p) m(3, p)
#define BOOST_PP_REPEAT5(m, p) BOOST_PP_REPEAT4(m, p) m(4, p)

....

//typename A1, typename A2, typename A3
#define DEFINE_TYPENAME(i, k) MY_COMMA_I(BOOST_PP_BOOL_I(i)) typename A##i
#define REPEAT_TYPENAME(count) REPEAT_TYPENAME_I(count)
#define REPEAT_TYPENAME_I(count) BOOST_PP_REPEAT(count, DEFINE_TYPENAME, count)
6、【技巧】上面的例子里面使用了BOOST_PP_BOOL_I(i),这个是一个条件语句,表示第一个参数前面不要加逗号,这个是因为这个重复出来的字符串,可能作为operator()的参数,那么参数列表的第一个参数前面不能有逗号,而重复出来的代码肯定有,所以需要通过条件宏来解决,第一个不加逗号。下面是条件宏的实现:

//BOOST BOOL
#define BOOST_PP_BOOL_I(x) BOOST_PP_BOOL_ ## x
#define BOOST_PP_BOOL_0 0
#define BOOST_PP_BOOL_1 1
#define BOOST_PP_BOOL_2 1
#define BOOST_PP_BOOL_3 1
#define BOOST_PP_BOOL_4 1
#define BOOST_PP_BOOL_5 1

......
#define MY_COMMA(bit) MY_COMMA_##bit
#define MY_COMMA_I(count) MY_COMMA(count)

#define MY_COMMA_0
#define MY_COMMA_1 ,

7、【基础】使用模板函数之后如果希望对特定的类型做不同的处理,那么这个特定的函数一定需要在模板函数后面定义,否则就会出现二意性。

8、【技巧】重复引用同一个文件,给定不同的宏定义,这样可以生成很多个类,用来生成delegate0, delegate1, delegate2....下面是一个例子:
#include "funcbase.h"
#include <stdio.h>
#include <vector>

#define PARAM_COUNT 0
#include "function_temp.h"
#undef PARAM_COUNT

#define PARAM_COUNT 1
#include "function_temp.h"
#undef PARAM_COUNT

9、【问题】最后的问题是返回值必须不能是void,因为对于void类型的返回return后面不能跟任何的东西,解决的方法是定义result_type把void进行封装,返回一个不需要的类型,但是这样需要增加不少代码,故我没有采用这个方法。

好了,现在已经完整的讲了boost::function实现过程中会碰到的问题,也温习了一些知识点,相信这个对于boost的描述和很多其它的资料很不同:)。

PS:讲个自己的故事,记得以前还在上大学的时候,勤工俭学需要对一批WORD文档进行同样的编辑处理,我当时仅会最简单的WORD编辑,因此我用我自己的知识加上勤奋的双手奋斗了一个通宵完成了任务。第二天我们班一个精通电脑的家伙看我很辛苦,就帮我研究了一下WORD,然后让我使用一些自动的工具,大幅度的提高了效率!这个给我很深的印象,我们很多时候都只是在使用最简单的技术搭建巨大的应用,却不愿意多花10分钟学习一下,以提高效率,这是可悲的。

PS2:这里不能加附件,如果需要源代码的可以和联系,代码比较简单。另外有志同道合的也希望多多交流加个链接哦~ oeichenwei@gmail.com

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值