学习 Boost:bind/Boost::functions closure as delegate in C++

来源:互联网 发布:js checkbox onchange 编辑:程序博客网 时间:2024/06/05 02:41

今天分享一篇比较短的博文. 关于Boost bind/function. 

最近读了陈硕的博文 http://blog.csdn.net/solstice/article/details/3066268, 有一些自己的看法, 感觉最后那个麻雀,企鹅的例子没有把bind的妙处表示清楚. 于是自己有了一些思考,分享如下:

1) Boost::function是一些类模板, 实质是函数对象的封装, 也就是把一个回调(函数指针) 封装起来, 使之具有对象的语义, 在对象的生命周期内推迟真正的调用时机.

2) Boost::bind是一个函数对象的工厂, 用来产生需要的函数对象. 从Boost的文档里得知, 其可用于函数,函数对象,成员函数,函数指针等多种回调类型.

3) 这个东西, 个人认为并没有很多东西, 是Boost提供的对委托/回调的一种比较干净优雅的解决方案.

那这个东西到底有什么用? 该何时使用呢? 个人浅见, 欢迎拍砖:

1) 使用Boost::bind的委托对象, 如果封装的是对象的方法, 则在创建的时候就传入了对象实例, 调用的时候不需要对象实例.

2) 封装/定义回调的方法比函数指针要简洁.

3) 不是说这个东西要代替OO, 回调/委托和OO虚函数是不同的技术, 各自有适用的问题域. 如果是对象族有公共的行为或状态,  使用继承和多态是合理的. 如果对象间的协作和调用具有较少的公共行为, 可以使用委托和回调组合对象的行为, 用继承的显得笨重.

来个例子建模上述观点:

有很多小动物, 有企鹅, 可以跑,可以游泳, 有麻雀, 可以跑, 可以飞, 有聪明的猴子,会跑, 会骑车, 还有小马, 擅长跑.

现在来举办一场动物的铁人三项赛, 有跑步, 游泳, 骑自行车三个子项目, 请选择合适的选手, 编程实现比赛.

分析:

1) 动物对象的协作和调用似乎具有较少的公共行为, 跑,游泳, 骑车, 飞, 似乎用虚函数建模不会有明显的收益.

2) 赛事对象的关键是跑步, 游泳, 骑车三个动作, 提取动物的动作(回调), 组装到我们的赛事对象里, 就可以了.

围绕委托来编程, 首先定义这些动作:

// Use closuer allback as interfacestypedef boost::function<void()> FlyCallback;typedef boost::function<void()> RunCallback;typedef boost::function<void()> SwimCallback;typedef boost::function<void()> RideCallback;
定义我们的参赛选手:

// Pengin can run, and swimclass Penguin{ public:  void run() {std::cout<<"Penguin running"<<std::endl;}  void swim(){std::cout<<"Penguin swimming"<<std::endl;}};// Sparrow can fly, can runclass Sparrow{ public:  void fly() {std::cout<<"Sparrow flying"<<std::endl;}  void run() {std::cout<<"Sparrow running"<<std::endl;}};//Horse runs goodclass Horse{ public:  void run() {std::cout<<"Horse running"<<std::endl;}};//Monkey is clever, can ride a bicycle and runclass CleverMonkey{public: void ride() {std::cout<<"Monkey riding"<<std::endl;} void run()  {std::cout<<"Monkey running"<<std::endl;}};
定义我们的赛事, 有跑, 游泳, 骑车三个子回调组成:

// Anmial triathlon's matchclass Triathlon{ public:    Triathlon(SwimCallback swimCb, RunCallback runCb, RideCallback rideCb) : swimCb_(swimCb), runCb_(runCb), rideCb_(rideCb)  { }    void Start()    {        std::cout<<"The match start! first is running event."<<std::endl;        runCb_();        std::cout<<"Running completed! now is swimming event."<<std::endl;        swimCb_();        std::cout<<"Swimming completed! now is riding event."<<std::endl;        rideCb_();        std::cout<<"Riding completed! you've got a good score."<<std::endl;    } private:  RunCallback  runCb_;  SwimCallback swimCb_;  RideCallback rideCb_;};
最后,选拔我们的队员, 参加赛事(使用Boost::bind将动物的动作通过回调组合到赛事:

int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    Sparrow      s;    Penguin      p;    Horse        h;    CleverMonkey m;    //Now, we have a trathlon match for animals.    //Looks only penguin can swim, let he take swimming    //The horse should run better than sparrow and monkey and penguin, let he take running.    //The monkey is the only candidate for smart enough for riding a bicycle, it's his job.    Triathlon triathlon(boost::bind(&Penguin::swim, &p), boost::bind(&Horse::run, &h), boost::bind(&CleverMonkey::ride, &m));    triathlon.Start();    return a.exec();}
完毕. 用起来似乎比使用面向对象虚函数建模要顺手不少. 总结一下Boost::bind/Boost::function会有用武之地的地方:

1) 方便用回调委托建模的地方 ( 似乎设计模式的行为型模式(策略, 模板方法) 可以考虑用这个代替了)
2) Command模式.

不复杂, 就是说C++的用户们, 用回调委托的话, 多多用Boost::bind, Boost::function吧.




 

0 0
原创粉丝点击