前面在做 http server 的时候,需要做一个回调的接口,要求能够绑定类的函数以及普通的函数到这个回调里,对于这种应用要求,选择 boost 的 bind 和 function 是最合适不过了,但现在情况有些不同,我不准备在现在做的这个东西里加入 boost, 本着以造轮子为乐的精神,现在只能捋起袖子自己来搞一个。

大概原型

使用的时候一直没有太留意它们的实现,现在要做起来,发现也不是想像中那么轻而易举。这个东西做到最后要实现的效果就是设计一个泛型的 function holder,这个 holder 既能包装类的函数,又要能包装一般的函数,换言之就是能像下面一样来使用。

  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. class cs
  6. {
  7. public:
  8.  
  9. int proc(double d) { cout << "mem func proc:" << d << endl; return (int)d;}
  10. };
  11.  
  12. int Proc(double d)
  13. {
  14. cout << "normal proc:" << d << endl;
  15. return (int)d;
  16. }
  17.  
  18. int main()
  19. {
  20. function fun = &Proc;
  21. fun(2.3);
  22.  
  23. cs c;
  24. fun = bind(&cs::proc, &c);
  25. fun(3.3);
  26.  
  27. return ;
  28. }

简单实现

一开始你可能会想,a piece of cake! 直接封装一个 function 就行了。

  1. template<class ret_type, class arg_type>
  2. class function1: public copyable
  3. {
  4. public:
  5. typedef ret_type (* NORM_PROC) (arg_type);
  6.  
  7. function1(NORM_PROC proc = ): fun_(proc){}
  8.  
  9. ret_type operator() (arg_type arg) { fun_->operator()(arg); }
  10.  
  11. private:
  12.  
  13. NORM_PROC fun_;
  14. };

好,这个类可以封装一般的函数了,那类的函数呢?one more!

  1. template<class CS, class ret_type, class arg_type>
  2. class function2: public copyable
  3. {
  4. public:
    typedef ret_type (CS::* MEM_PROC)(arg_type);
  5. function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {}
  6.  
  7. ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); }
  8.  
  9. private:
  10. CS* obj_;
         MEM_PROC proc_;
  11. };

很快我们就发现有问题了,function1 和 function2 是两不同的模板类,bind() 的时候没法处理:bind() 返回的应该要是一个统一的类型。怎么办呢?我们可能想到要抽取出一个基类来,思路是对的!但还有些细节要处理。比如:bind() 返回的是什么类型呢?function1,function2 的基类吗?这好像做不到,不能直接返回 object,所以下面的做法是错的。

  1. template<class ret_type, class arg_type>
  2. class function_base: public copyable
  3. {
  4. public:
    virtual ~function_base(){}
  5. virtual ret_type operator() (arg_type arg) = ;
  6. };
  7.  
  8. template<class CS, class ret_type, class arg_type>
  9. class function2: public function_base<ret_type, arg_type>
  10. {
  11. public:
  12.      typedef ret_type (CS::* MEM_PROC)(arg_type);
  13. function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {}
  14.  
  15. ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); }
  16.  
  17. private:
  18. CS* obj_;
         MEM_PROC proc_;
  19. };
  20.  
  21. template<class CS, class ret_type, class arg_type>
  22. function_base<ret_type, arg_type> bind(ret_type (CS::* proc)(arg_type), CS* pc)
  23. {
  24. function2<CS, ret_type, arg_type> func_holder(pc, proc);
  25. return func_holder; // object slicing
  26. }

那直接返回指针不就完了!返回指针可行,但不好用,而且容易内存泄漏。解决的办法是对返回的指针再包一层,嗯,RAII。但等等,好像如果再包一层,就已经能直接隔开底下的 function holder 与具体的调用了啊!Perfect!

  1. template<class ret_type, class arg_type>
  2. class function_base: public copyable
  3. {
  4. public:
    virtual ~function_base() {}
  5. virtual ret_type operator() (arg_type arg) = ;
  6. };
  7.  
  8. template<class ret_type, class arg_type>
  9. class function1: public function_base<ret_type, arg_type>
  10. {
  11.  public:
           
    typedef ret_type (* NORM_PROC) (arg_type);
           
    function1(NORM_PROC proc = ): fun_(proc){}
  12.  
  13. ret_type operator() (arg_type arg) { fun_->operator()(arg); }
           
    private:
           
    NORM_PROC fun_;

  14. };
  15.  
  16. template<class CS, class ret_type, class arg_type>
  17. class function2: public function_base<ret_type, arg_type>
  18. {
  19. public:
  20.      typedef ret_type (CS::* MEM_PROC)(arg_type);
  21. function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {}
  22.  
  23. ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); }
  24.  
  25. private:
  26. CS* obj_;
         MEM_PROC proc_;
  27. };

  28. template<class ret_type, class arg_type>
    class functioin: public copyable
    {
    public:
  29.  
  30. function(function_base<ret_type, arg_type>* pf): _obj(pf) {}
    ret_type operator()(arg_type arg){obj_->operator()(arg);}
  31.  
  32. private:
    function_base<ret_type, arg_type>* obj_;
    };
  33. template<class CS, class ret_type, class arg_type>
  34. function<ret_type, arg_type> bind(ret_type (CS::* proc)(arg_type), CS* pc)
  35. {
  36. return new function2<CS, ret_type, arg_type>(pc, proc);
  37. }

经过这样一包装,function 类好像已经能够用来 bind 类的成员函数了, 也没那么难嘛!但是,代码很差劲:

1) 没有处理内存释放。

2) 没有处理 copy costructor,assignment operator()。

3) 普通函数还是不能直接赋值给 function 类。

再改一下 function 类:

  1. template<class ret_type, class arg_type>
  2. class function
  3. {
  4. public:
  5. typedef ret_type (* NORM_PROC) (arg_type);
  6.  
  7. function(function_base<ret_type, arg_type>* fun): fun_(fun), ref_(new int()) {}
  8.  
  9. function(NORM_PROC proc = ): fun_(new function1<ret_type, arg_type>(proc)), ref_(new int()) {}
  10.  
  11. ret_type operator() (arg_type arg) { fun_->operator()(arg); }
  12.  
  13. ~function()
  14. {
  15. Release();
  16. }
  17.  
  18. void Release()
  19. {
  20. *ref_ -= ;
  21. if (*ref_ == )
  22. {
  23. delete ref_;
  24. delete fun_;
  25. }
  26. }
  27.  
  28. function(const function& fun)
  29. {
  30. fun_ = fun.fun_;
  31. ref_ = fun.ref_;
  32. *ref_ += ;
  33. }
  34.  
  35. void operator=(const function& fun)
  36. {
  37. Release();
  38. fun_ = fun.fun_;
  39. ref_ = fun.ref_;
  40. *ref_ += ;
  41. }
  42.  
  43. private:
  44.  
  45. int* ref_;
  46. function_base<ret_type, arg_type>* fun_;
  47. };

这样一来,终于能够正常使用了,可以看到,为了使得 function 类能被 copy/assign,这里面使用引用计数来控制内存的释放问题,上面的实现比较简单,也不是线程安全的,只是满足了基本的使用需求,具体的代码参看这里。代码写得较快,暂且就这样了,不知道 boost 是怎样实现的?得找个时间研究研究。

boost bind及function的简单实现的更多相关文章

  1. boost bind function用法说明

    目录(?)[+] 1 bind/function 引 (1)头文件 bind函数#include <boost/bind.hpp> function使用头文件#include <bo ...

  2. 基于boost的bind与function的一个简单示例消息处理框架

    前两年开始接触boost,boost库真是博大精深:今天简单介绍一下boost中之前用到的的bind与function,感觉挺实用的,分享给大家,我对boost用的也不多,让大家见笑了. 上次文发了一 ...

  3. boost::bind 和 boost::function 基本用法

    这是一篇介绍bind和function用法的文章,起因是近来读陈硕的文章,提到用bind和function替代继承,于是就熟悉了下bind和function的用法,都是一些网上都有的知识,记录一下,期 ...

  4. [置顶] 编程模仿boost::function和boost::bind

    boost::function和boost::bind结合使用是非常强大的,他可以将成员函数和非成员函数绑定对一个对象上,实现了类似C#的委托机制.委托在许多时候可以替代C++里面的继承,实现对象解耦 ...

  5. boost::bind的简单实现

    前言 在上一篇blog中简单的实现了boost::function,支持带有2个参数的函数/函数指针,函数对象,函数适配器/bind类,以及带有1个参数的成员函数指针. 本文接着来介绍如何实现一个简单 ...

  6. boost::function的简单实现

    前言 boost::function和boost:bind是一对强大的利器.相信用过的童鞋多少有些体会. 虽然平时在用boost::function,但是用的时候心中总会一些不安,因为不知道它是怎么实 ...

  7. boost::bind 不能处理函数重载 (error: no matching function for call to 'bind')

    前言 最近任务多.工期紧,没有时间更新博客,就水一期吧.虽然是水,也不能太失水准,刚好最近工作中遇到一个 boost::bind 的问题,花费了半天时间来定位解决,就说说它吧. 问题背景 项目中使用了 ...

  8. 以boost::function和boost:bind取代虚函数

    转自:http://blog.csdn.net/Solstice/archive/2008/10/13/3066268.aspx 这是一篇比较情绪化的blog,中心思想是“继承就像一条贼船,上去就下不 ...

  9. 关于boost::function与boost::bind函数的使用心得

    最近开始写一个线程池,期间想用一个通用的函数模板来使得各个线程执行不同的任务,找到了Boost库中的function函数. Boost::function是一个函数包装器,也即一个函数模板,可以用来代 ...

随机推荐

  1. JSON数据映射之元素可见控制

    1.效果: 2.demo 源码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  2. IOS初级:UIwindow

    AppDelegate.h @property (strong, nonatomic) UIWindow *window; AppDelegate.m - (BOOL)application:(UIA ...

  3. activiti 清库脚本(转)

    在使用activiti 的时候会经常遇到需要清空数据库中的数据,因此本文重点讲解如何解决该问题. 再删除数据的时候,需要注意有主外键约束的问题?下面罗列的DDL可以结合自身的业务需求进行灵活改造. D ...

  4. Python 中Lambda 表达式 实例解析

    Lambda 表达式 lambda表达式是一种简洁格式的函数.该表达式不是正常的函数结构,而是属于表达式的类型.而且它可以调用其它函数. 1.基本格式: lambda 参数,参数...:函数功能代码 ...

  5. springMVC 学习 五 参数传递(包括restful风格)

    (一)SpringMVC Controller接受参数的方式 (1) 前端传递的参数,在springMVC的controller中使用基本数据类型或者String 类型进行接受 在前端有一个form表 ...

  6. PHP字符串替换函数

    str_replace函数 描述:实现字符串替换,区分大小写 语法:mixed str_replace(mixed $search, mixed replace, mixed $subject, [i ...

  7. Linux 在文档中查找满足条件的行并输出到文件:

    Linux 在文档中查找满足条件的行并输出到文件: 文件名称: dlog.log    输出文件: out.log 1.满足一个条件(包含  “TJ”  )的语句: grep  “TJ”  dlog. ...

  8. 2018.12.15 bzoj3998: [TJOI2015]弦论(后缀自动机)

    传送门 后缀自动机基础题. 求第kkk小的子串(有可能要求本质不同) 直接建出samsamsam,然后给每个状态赋值之后在上面贪心选最小的(过程可以类比主席树/平衡树的查询操作)即可. 代码: #in ...

  9. 学习devexpresschartControl控件

    devexpress官网chart:https://documentation.devexpress.com/WindowsForms/8117/Controls-and-Libraries/Char ...

  10. abaqus UMAT二次开发能用fortran90吗?

    SUBROUTINE UMAT(STRESS,STATEV,DDSDDE,SSE,SPD,SCD,RPL,DDSDDT, # DRPLDE,DRPLDT,STRAN,DSTRAN,TIME,DTIME ...