Callback 与 C++抽象 函数指针与Functor
我们学习C或C++一定会碰到函数指针(function pointer) 这个概念,而C++中又有了仿函数(Functor)特性,在上课学习的时候了解过但一直没怎么使用它,这段时间在项目中碰到了回调(callback)这样的问题,正好可以拿出来谈谈。
假设我们有这样的一个需求:
我们想实现一个叫床功能,当然不是那个“叫床”哈哈,是叫人起床的意思。
在远古时代,我们只能靠别人叫我们起床:
1 | def wakeup(name,time): |
但现在,我们可以设闹钟让我们起床了:
1 | def wakeup(name,time): |
假如我们的生活是可以程序化的,那么一天将会是这样的:
1 | wakeup(name,time) |
我们发现wakeup可以有不同的动作方式来唤醒,我们可以选择人工叫醒也可以选择闹钟,但是都是
wakeup(name,time)
这样会产生命名冲突,那么我们变成wakeup1(name,time)
和wakeup2(name,time)
怎么样?可以是可以的,但是如果有上百个方式的话,我们得改100遍函数名和里面的方法。
这样既增加了重复代码,又很不好看。
所以我们改进了这个程序:
1 | #我们可以定义这样两个方式: |
1 | wakeup(shout,name,time) |
这样是不是简单多了?
我们定义一个wakeup_method
参数,它就是函数指针,我们把函数当做参数传入wakeup()
,在函数里调用wakeup_method()
。
这样带来的好处是,我们可以针对不同的人用不同的方法(在特定的事件或条件发生时由另外的一方调用,用于对该事件或条件进行响应),我们对懒人可以用人工叫醒,对自觉一些的人用闹钟就可以了。
简单来说,回调函数的使用增加了程序的通用性和简洁性。
那么C++里的Functor又跟函数指针有什么关系?
Functor是一种更抽象化的函数指针。
看下面函数指针的例子:
1 | int fnadd1( int i ) { return i + 1; } |
我们定义了一个数组,和一个函数ApplyToAllElements2()
,它接收一个函数指针funcptr()
,对数组每个元素运用此函数。比如可以用fnadd1()
对每个元素加1,也可以用fntake10()
。但是不好的地方就是我每次有新需求就要定义一个新的函数。那么能不能对这一类加法操作做一个更加通用的办法呢?
1 | class MyFunctor |
这就是Functor,functor对operator()进行重载,我们可以在里面随意编写我们想进行的操作。实际上是把函数变成了一个对象了。
在这个例子中,初始化这个functor时我们要给var
一个值,这个var就相当于fnadd1()
里的1,也可以是2或者任何数。当这个functor被调用时,会执行opeartor()
方法,需要一个参数int x
,也就是数组里的一个元素,对元素进行加法操作。
再看
1 | int aiMyArray[] = { 0,1,2,3,4,5,6 }; |
相比较于第一个方式而言,我们不需要定义那么多的加法函数,而只需要每次变动不同的iAdd
值就可以了。
参考:回调函数(callback)是什么? https://www.zhihu.com/question/19801131)