之所以以反问的形式提出这个问题,是因为以我的观点来看,“回调函数”对一个C/C++程序员来说是很平常的,一些API的使用,一些接口的设计均要用到回调函数的概念。但是我面试过的一些有“多年工作经验”的C系程序员,共事过的一些“有经验”的同事竟然对回调函数不了解,更别提使用了。那今天我就以我的理解来梳理一下回调函数的概念和使用场景。
什么是回调函数?
维基百科释义:
在计算机程序设计中,回调函数,或简称回调(Callback),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。
不好理解吧?那举个生活中常见的例子:你在网上买了东西通过快递来配送,给你两个选择:
1. 你可以一遍遍的打快递配送公司的电话,查询你的货是否到了,是否可以领取;
2. 你可以安心的干自己的事,等配送人员把货送到你家门口打电话通知你,你去领取;
你会选择哪种方式处理?当然你会选择第二钟处理方式,好处不言而喻,这也正是回调函数的形象解释。
回调函数的实现原理
对于C/C++语言来说就是将函数指针作为参数传递给其它函数。
回调函数实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <iostream> using namespace std; void Sum( int a, int b) { int c = a + b; cout << "Sum = " << c << endl; } typedef void (*FuncCallBack)( int , int ); void GetCallBack( const int i, FuncCallBack cb) { if (1 == i) { cb(3, 4); } } void main() { GetCallBack(1, Sum); system ( "pause" ); } |
运行结果:Sum = 7 ,对于上面这个例子FuncCallBack就是回调函数的定义,Sum是其实现
另外,在C++的接口设计里常常会遇到这种情况:需要向类接口中注册很多不同的回调函数,这样这些回调函数的定义和管理便比较杂乱,这样我们可以借用delegate类的概念来这么实现回调。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include <iostream> using namespace std; class IEvent { public : virtual void Test1( int i) = 0; virtual void Test2( int i) = 0; virtual void Test3( int i) = 0; }; class TestEvent: public IEvent { public : void Test1( int i) { cout << "Test1 : " << i << endl;} void Test2( int i) { cout << "Test2 : " << i << endl;} void Test3( int i) { cout << "Test3 : " << i << endl;} private : int p; }; class NotifyEvent { public : void Run( int flag) { switch (flag) { case 1: testEvent_->Test1(1); break ; case 2: testEvent_->Test2(2); break ; case 3: testEvent_->Test3(3); break ; default : break ; } } void SetMyEvent(IEvent* testEvent) {testEvent_ = testEvent;} private : IEvent* testEvent_; }; int _tmain( int argc, _TCHAR* argv[]) { IEvent* ptr_event = new TestEvent; NotifyEvent notifyEvent; notifyEvent.SetMyEvent(ptr_event); notifyEvent.Run(1); notifyEvent.Run(3); system ( "pause" ); return 0; } |
运行结果:Test1 : 1 Test3 : 3
对于接口使用者而言,暴露出了IEvent这个接口,回调的管理都在这个接口中,避免了上述管理杂乱的情况。
本文出自 “永远的朋友” 博客,请务必保留此出处http://yaocoder.blog.51cto.com/2668309/1221422