c++ 之回调函数
2015-11-25 21:43
417 查看
我们会经常碰到需要使用回调函数的场合,比如:异步socket、定时器、windows消息处理等等。
这里将列出几种回调函数的实现机制,分析各自的优劣以供选择。
将 静态函数 或 静态成员函数 作为回调函数的实现比较简单,而且除了像 std::sort 这种地方,一般很少会用到,这里就不多做说明了。下面列出的都是将 成员函数 作为回调函数的实现。
这种方式适用于 Callee 和 CallbackInterface 自然符合继承语义的情况:Callee 是一种 CallbackInterface,而 Caller 作为管理者,面对的是一堆的 CallbackInterface,至于具体是哪个 Callee 在做事,又是怎么做的, Caller 并不需要知道。
如果 Callee 和 CallbackInterface 并不自然符合继承语义,最好不要使用这种方式,不然可能会碰到下列限制:
需要定义 N 个 CallbackInterface,每个 CallbackInterface 需要定义具体接口函数。
一个 Callee 可能需要继承多个 CallbackInterface,且各个 CallbackInterface 的接口函数不能同名。
不支持一个 Callee 对应多个 Caller 的情况。
cocos-2dx 3.0 之前的版本用的就是这种方式。
尽管它已经可以满足大多数需要回调函数的场合,但也还是有一些显而易见的缺点:
所有的 Callee 需要继承自一个公共基类 Object。
register 时需要做强制类型转换,这使得编译期无法对回调函数本身的参数类型和数量进行检查,如果不匹配将导致运行时错误。
无法在 register 时传递不定参数给回调函数。
对比之前的实现,这种方式几乎解决了所有的缺点。
Callee 不需要继承公共基类或者回调接口类。
多个 Callee 可以绑定于多个 Caller。
register 时不需要进行强制类型转换,也能在编译期检查回调函数类型。
register 时还能传递不定参数给回调函数。
需要包含一个回调函数库:http://www.tedfelix.com/software/callback.h
具体的实现原理和过程可以查看: http://www.tutok.sk/fastgl/callback.html
从使用者角度看,除了不能传递不定参数给回调函数,它跟 std::function 方式 几乎一样。
当所用编译器不支持 c++11 特性时,可以考虑用这种方式。
肯定还有其它实现回调机制的方式,碰到的时候再加进来分析。
目前看来 std::function 方式 是一种比较完美的方案,但在实际应用中使用它也还是会碰到一些问题。
而且使用成员函数作为回调函数,还需要考虑当回调函数将被调用时,如何判断绑定的对象是否已经被销毁。
等等这些问题,后续将会有专门的篇幅进行探讨。
这里将列出几种回调函数的实现机制,分析各自的优劣以供选择。
将 静态函数 或 静态成员函数 作为回调函数的实现比较简单,而且除了像 std::sort 这种地方,一般很少会用到,这里就不多做说明了。下面列出的都是将 成员函数 作为回调函数的实现。
接口类
class CallbackInterface { public: virtual void onCallback() = 0; ... }; class Callee : public CallbackInterface { public: virtual void onCallback() { ... } ... }; class Caller { public: void register(CallbackInterface* callback) { ... } void update() { ... callback->onCallback(); ... } ... }; // main caller.register(&callee);
这种方式适用于 Callee 和 CallbackInterface 自然符合继承语义的情况:Callee 是一种 CallbackInterface,而 Caller 作为管理者,面对的是一堆的 CallbackInterface,至于具体是哪个 Callee 在做事,又是怎么做的, Caller 并不需要知道。
如果 Callee 和 CallbackInterface 并不自然符合继承语义,最好不要使用这种方式,不然可能会碰到下列限制:
需要定义 N 个 CallbackInterface,每个 CallbackInterface 需要定义具体接口函数。
一个 Callee 可能需要继承多个 CallbackInterface,且各个 CallbackInterface 的接口函数不能同名。
不支持一个 Callee 对应多个 Caller 的情况。
公共基类
class Object {...} typedef void(Object::*CALLBACK)(); class Callee : public Object { public: void onCallback() { ... } ... } class Caller { public: void register(Object* obj, CALLBACK callback) { ... } void update() { ... obj->*callback(); ... } ... } // main caller.register(&callee, (CALLBACK)(&Callee::onCallback));
cocos-2dx 3.0 之前的版本用的就是这种方式。
尽管它已经可以满足大多数需要回调函数的场合,但也还是有一些显而易见的缺点:
所有的 Callee 需要继承自一个公共基类 Object。
register 时需要做强制类型转换,这使得编译期无法对回调函数本身的参数类型和数量进行检查,如果不匹配将导致运行时错误。
无法在 register 时传递不定参数给回调函数。
std::function
class Callee { public: void onCallback() { ... } ... } class Caller { public: void register(const std::function<void()>& callback) { ... } void update() { ... callback(); ... } ... } // main caller.register(std::bind(&Callee::onCallback, callee));
对比之前的实现,这种方式几乎解决了所有的缺点。
Callee 不需要继承公共基类或者回调接口类。
多个 Callee 可以绑定于多个 Caller。
register 时不需要进行强制类型转换,也能在编译期检查回调函数类型。
register 时还能传递不定参数给回调函数。
模板
class Callee { public: void onCallback() { ... } ... } class Caller { public: void register(const CBFunctor0 & callback) { ... } void update() { ... callback(); ... } ... } // main caller.register(makeFunctor((CBFunctor0*)0,callee,&Callee::onCallback));
需要包含一个回调函数库:http://www.tedfelix.com/software/callback.h
具体的实现原理和过程可以查看: http://www.tutok.sk/fastgl/callback.html
从使用者角度看,除了不能传递不定参数给回调函数,它跟 std::function 方式 几乎一样。
当所用编译器不支持 c++11 特性时,可以考虑用这种方式。
肯定还有其它实现回调机制的方式,碰到的时候再加进来分析。
目前看来 std::function 方式 是一种比较完美的方案,但在实际应用中使用它也还是会碰到一些问题。
而且使用成员函数作为回调函数,还需要考虑当回调函数将被调用时,如何判断绑定的对象是否已经被销毁。
等等这些问题,后续将会有专门的篇幅进行探讨。
相关文章推荐
- 【C语言】 函数指针小谈
- 《C++ primer》英文第五版阅读笔记(十九)——位运算符,sizeof运算符和逗号运算符
- 51nod——寻找第K大的数(C++版)
- gcc在window系统环境下的安装
- C语言交换两个变量数值的几种方法
- c++ 缺少动态库
- C++ 类成员变量为引用时如何编写
- 设计模式之代理模式
- C++11中的POD和Trivial
- #pragma 的使用(c/c++)【转】
- 经典排序算法(三)选择排序--C++
- 扫地僧C++视频学习记录
- C++中 std::vector用法
- C++设计模式 之 “对象性能” 模式:Singleton、Flyweight
- C++11学习笔记(一)
- C++设计模式 之 “接口隔离” 模式:Facade、Proxy、Mediator、Adapter
- 【C语言】【笔试题】使用回调函数编写冒泡排序,可以排序整形数组,也可以排序字符串
- C++ 内存分配(new,operator new、placement new)详解
- C++ pair(对组)用法(转)
- C语言模块化程序设计概念理解