boost bind及function的简单实现
前面在做 http server 的时候,需要做一个回调的接口,要求能够绑定类的函数以及普通的函数到这个回调里,对于这种应用要求,选择 boost 的 bind 和 function 是最合适不过了,但现在情况有些不同,我不准备在现在做的这个东西里加入 boost, 本着以造轮子为乐的精神,现在只能捋起袖子自己来搞一个。
大概原型
使用的时候一直没有太留意它们的实现,现在要做起来,发现也不是想像中那么轻而易举。这个东西做到最后要实现的效果就是设计一个泛型的 function holder,这个 holder 既能包装类的函数,又要能包装一般的函数,换言之就是能像下面一样来使用。
#include <iostream> using namespace std; class cs
{
public: int proc(double d) { cout << "mem func proc:" << d << endl; return (int)d;}
}; int Proc(double d)
{
cout << "normal proc:" << d << endl;
return (int)d;
} int main()
{
function fun = &Proc;
fun(2.3); cs c;
fun = bind(&cs::proc, &c);
fun(3.3); return ;
}
简单实现
一开始你可能会想,a piece of cake! 直接封装一个 function 就行了。
template<class ret_type, class arg_type>
class function1: public copyable
{
public:
typedef ret_type (* NORM_PROC) (arg_type); function1(NORM_PROC proc = ): fun_(proc){} ret_type operator() (arg_type arg) { fun_->operator()(arg); } private: NORM_PROC fun_;
};
好,这个类可以封装一般的函数了,那类的函数呢?one more!
template<class CS, class ret_type, class arg_type>
class function2: public copyable
{
public:
typedef ret_type (CS::* MEM_PROC)(arg_type);
function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {} ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); } private:
CS* obj_;
MEM_PROC proc_;
};
很快我们就发现有问题了,function1 和 function2 是两不同的模板类,bind() 的时候没法处理:bind() 返回的应该要是一个统一的类型。怎么办呢?我们可能想到要抽取出一个基类来,思路是对的!但还有些细节要处理。比如:bind() 返回的是什么类型呢?function1,function2 的基类吗?这好像做不到,不能直接返回 object,所以下面的做法是错的。
template<class ret_type, class arg_type>
class function_base: public copyable
{
public:
virtual ~function_base(){}
virtual ret_type operator() (arg_type arg) = ;
}; template<class CS, class ret_type, class arg_type>
class function2: public function_base<ret_type, arg_type>
{
public:
typedef ret_type (CS::* MEM_PROC)(arg_type);
function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {} ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); } private:
CS* obj_;
MEM_PROC proc_;
}; template<class CS, class ret_type, class arg_type>
function_base<ret_type, arg_type> bind(ret_type (CS::* proc)(arg_type), CS* pc)
{
function2<CS, ret_type, arg_type> func_holder(pc, proc);
return func_holder; // object slicing
}
那直接返回指针不就完了!返回指针可行,但不好用,而且容易内存泄漏。解决的办法是对返回的指针再包一层,嗯,RAII。但等等,好像如果再包一层,就已经能直接隔开底下的 function holder 与具体的调用了啊!Perfect!
template<class ret_type, class arg_type>
class function_base: public copyable
{
public:
virtual ~function_base() {}
virtual ret_type operator() (arg_type arg) = ;
}; template<class ret_type, class arg_type>
class function1: public function_base<ret_type, arg_type>
{
public:
typedef ret_type (* NORM_PROC) (arg_type);
function1(NORM_PROC proc = ): fun_(proc){} ret_type operator() (arg_type arg) { fun_->operator()(arg); }
private:
NORM_PROC fun_;
}; template<class CS, class ret_type, class arg_type>
class function2: public function_base<ret_type, arg_type>
{
public:
typedef ret_type (CS::* MEM_PROC)(arg_type);
function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {} ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); } private:
CS* obj_;
MEM_PROC proc_;
};
template<class ret_type, class arg_type>
class functioin: public copyable
{
public: function(function_base<ret_type, arg_type>* pf): _obj(pf) {}
ret_type operator()(arg_type arg){obj_->operator()(arg);} private:
function_base<ret_type, arg_type>* obj_;
};
template<class CS, class ret_type, class arg_type>
function<ret_type, arg_type> bind(ret_type (CS::* proc)(arg_type), CS* pc)
{
return new function2<CS, ret_type, arg_type>(pc, proc);
}
经过这样一包装,function 类好像已经能够用来 bind 类的成员函数了, 也没那么难嘛!但是,代码很差劲:
1) 没有处理内存释放。
2) 没有处理 copy costructor,assignment operator()。
3) 普通函数还是不能直接赋值给 function 类。
再改一下 function 类:
template<class ret_type, class arg_type>
class function
{
public:
typedef ret_type (* NORM_PROC) (arg_type); function(function_base<ret_type, arg_type>* fun): fun_(fun), ref_(new int()) {} function(NORM_PROC proc = ): fun_(new function1<ret_type, arg_type>(proc)), ref_(new int()) {} ret_type operator() (arg_type arg) { fun_->operator()(arg); } ~function()
{
Release();
} void Release()
{
*ref_ -= ;
if (*ref_ == )
{
delete ref_;
delete fun_;
}
} function(const function& fun)
{
fun_ = fun.fun_;
ref_ = fun.ref_;
*ref_ += ;
} void operator=(const function& fun)
{
Release();
fun_ = fun.fun_;
ref_ = fun.ref_;
*ref_ += ;
} private: int* ref_;
function_base<ret_type, arg_type>* fun_;
};
这样一来,终于能够正常使用了,可以看到,为了使得 function 类能被 copy/assign,这里面使用引用计数来控制内存的释放问题,上面的实现比较简单,也不是线程安全的,只是满足了基本的使用需求,具体的代码参看这里。代码写得较快,暂且就这样了,不知道 boost 是怎样实现的?得找个时间研究研究。
boost bind及function的简单实现的更多相关文章
- boost bind function用法说明
目录(?)[+] 1 bind/function 引 (1)头文件 bind函数#include <boost/bind.hpp> function使用头文件#include <bo ...
- 基于boost的bind与function的一个简单示例消息处理框架
前两年开始接触boost,boost库真是博大精深:今天简单介绍一下boost中之前用到的的bind与function,感觉挺实用的,分享给大家,我对boost用的也不多,让大家见笑了. 上次文发了一 ...
- boost::bind 和 boost::function 基本用法
这是一篇介绍bind和function用法的文章,起因是近来读陈硕的文章,提到用bind和function替代继承,于是就熟悉了下bind和function的用法,都是一些网上都有的知识,记录一下,期 ...
- [置顶] 编程模仿boost::function和boost::bind
boost::function和boost::bind结合使用是非常强大的,他可以将成员函数和非成员函数绑定对一个对象上,实现了类似C#的委托机制.委托在许多时候可以替代C++里面的继承,实现对象解耦 ...
- boost::bind的简单实现
前言 在上一篇blog中简单的实现了boost::function,支持带有2个参数的函数/函数指针,函数对象,函数适配器/bind类,以及带有1个参数的成员函数指针. 本文接着来介绍如何实现一个简单 ...
- boost::function的简单实现
前言 boost::function和boost:bind是一对强大的利器.相信用过的童鞋多少有些体会. 虽然平时在用boost::function,但是用的时候心中总会一些不安,因为不知道它是怎么实 ...
- boost::bind 不能处理函数重载 (error: no matching function for call to 'bind')
前言 最近任务多.工期紧,没有时间更新博客,就水一期吧.虽然是水,也不能太失水准,刚好最近工作中遇到一个 boost::bind 的问题,花费了半天时间来定位解决,就说说它吧. 问题背景 项目中使用了 ...
- 以boost::function和boost:bind取代虚函数
转自:http://blog.csdn.net/Solstice/archive/2008/10/13/3066268.aspx 这是一篇比较情绪化的blog,中心思想是“继承就像一条贼船,上去就下不 ...
- 关于boost::function与boost::bind函数的使用心得
最近开始写一个线程池,期间想用一个通用的函数模板来使得各个线程执行不同的任务,找到了Boost库中的function函数. Boost::function是一个函数包装器,也即一个函数模板,可以用来代 ...
随机推荐
- Web Api 2 认证与授权 2
HTTP Message Handler 在 Web Api 2 认证与授权 中讲解了几种实现机制,本篇就详细讲解 Message Handler 的实现方式 关于 Message Handler 在 ...
- hdu 6073
题意: 给出一个二部图,U.V分别是二部图的两个点集,其中,U中每个点会有两条边连到V中两个不同的点. 完美匹配定义为:所有点都成功匹配. 思路:已知一定是完美匹配了呀(也一定存在),我们先把度数为一 ...
- PHP获取手机号
/** * 类名: mobile * 描述: 手机信息类 * 其他: 偶然 编写 */ class mobile{ /** * 函数名称: getPhoneNumber * 函数功能: 取手机号 * ...
- MFC控件Slider Control的使用
写MFC界面程序时,今天恰好用到Slider控件,做一个小小的记录. 步骤 1.在工具栏中添加Slider Control控件: 2.在控件上右键->添加变量(Add Variable...), ...
- RabbitMQ c#版实现(转)
出处:https://www.cnblogs.com/hanfan/p/9842301.html 网上很多人已经总结的很好了,比如今天看到的这个.https://www.cnblogs.com/Lip ...
- Java之spilt()函数,trim()函数
一.单个符号作为分隔符 package com.regix; public class FuncSpilt { public static void main(String[] args) { // ...
- i2c_client的生成
网上很多文档都是介绍源码,包括i2c_client结构体的源码都有贴出,看上去似乎需要手动写该结构体,但实际上,i2c_client的生成是用如下方法. \arch\arm\mach-omap2/bo ...
- SQL编写-谁和谁是好朋友
problem: 用户表 姓名 张三 李四 王五 好友表 姓名 好友姓名 张三 李四 张三 王五 李四 张三 用户表里面姓名必须在好友表里面互加为好友,请问如何找出还没有加为好友的姓名 ...
- 何时使用Delegate或接口
在以下情况下使用Delegates很有用: 调用一个单一方法: 一个类要进行方法规范(method specification)的多种执行: 使用一个静态方法来执行规范: 想获得类似事件设计的模式: ...
- c#+web下载文件夹
最近公司在做工程项目,实现文件夹下载. 网上找了很久,发现网上的代码都有相似的问题,不过最终还是让我找到了一个符合的项目. 工程: 进行项目文件夹下载功能分析,弄清楚文件夹下载的原理,提供的数据支持. ...