博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转]你会使用回调函数吗?
阅读量:6993 次
发布时间:2019-06-27

本文共 2160 字,大约阅读时间需要 7 分钟。

之所以以反问的形式提出这个问题,是因为以我的观点来看,“回调函数”对一个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这个接口,回调的管理都在这个接口中,避免了上述管理杂乱的情况。

 

本文出自 “” 博客,请务必保留此出处

转载于:https://www.cnblogs.com/willbin/p/3190404.html

你可能感兴趣的文章
Day10 - Ruby如何调用方法(invoke method)?
查看>>
java中的异常
查看>>
mysql查询重复数据
查看>>
Tesseract 引擎翻译
查看>>
Android之复选框对话框
查看>>
【RabbitMQ系列】队列、绑定、交换器
查看>>
Run as ant build每次都执行两次
查看>>
如何在微信公众号下载保存图片??
查看>>
Spring读书笔记——bean解析
查看>>
算法练习(5)数字列表中 连续最大的和
查看>>
C# 导出 不保存 直接显示
查看>>
bzoj4445&&dtoj#2348. 小凸想跑步(convex)
查看>>
常见模块设计--权限管理(一)
查看>>
powerdesigner中实现PDM到MYSQl数据库的转换《转》
查看>>
解决element-ui 中upload组件使用多个时无法绑定对应的元素
查看>>
[Docker]容器镜像
查看>>
stl学习之模板
查看>>
CentOS-7.3.1611编译安装 Nginx-1.12.1+mysql-5.7.19+PHP-7.1.8+zabbix-3.4.1
查看>>
元学习 - Learning How to Learn - 第一课:集中与发散思维
查看>>
一种具有细节保留功能的磨皮算法。
查看>>