更多课程 选择中心

C/C++培训
美国上市教育机构

400-111-8989

C++培训

C++回调函数是什么?

  • 发布:C++培训
  • 来源:BOT Man
  • 时间:2019-10-25 15:23

维基百科(Wikipedia):在计算机编程中,回调函数是

可执行代码作为参数传入其他的可执行代码,并由其他的可执行代码执行这段可执行代码

的过程。

具体过程(以函数为例1):

A() {

// output P

}

B(fn) {

fn(); // B knows only fn, not A

// B treats fn as a variable

}

B(A); // B called at T

// B calling fn() (i.e. calling A())

函数 A 作为参数 fn 传入 函数 B

B 不知道 A 的存在,只知道 fn

B 将 fn 当作一个传入函数的局部变量处理

函数 B 通过 fn() 的语法,调用函数 A

B 在 调用时刻 T,调用 fn

B 调用 fn 可能是是为了得到结果 P

对于没有接触过函数式编程 (functional programming) 的初学者,这里有两个难以理解的地方:

函数竟然可以作为参数传递到另一个函数里

函数是程序设计语言中的一等公民 (first-class function)(函数 A)

将函数作为参数的函数,叫做高阶函数 (higher-order function)(函数 B)

通过参数传入的函数 fn,可以直接通过 fn() 的语法调用

生活中的回调函数

场景一

有一个房间里没有灯,只有一个灯座

你给 灯座装上了一盏白炽灯

到了晚上,你打开了灯座上的开关

灯座通了电,点亮了灯座上的那盏灯

于是,那盏白炽灯发出的温暖的光浸满了整个房间

这里对应了例1描述的五个要素:

白炽灯相当于是函数 A

灯座相当于是函数 B

对于灯座来说,灯座上的那盏灯相当于是参数 fn

对于灯座来说,打开灯座上的开关相当于是调用的时刻 T

温暖的光 相当于是 回调结果 P

场景二

一天,你在房间里开了一个聚会,希望把灯光换成彩色的

于是,把灯座上的 白炽灯 换成了 彩灯

当你 打开灯座上的开关时,房间里充满了 彩色的光

场景二和场景一相比,

相同的要素是:灯座、灯座上的那盏灯、打开灯座上的开关

不同的要素是:彩灯、彩色的光

这里说明了回调函数的设计初衷 —— 控制反转,即将控制权下发给回调函数:

灯座不需要知道灯座上的灯是白炽灯还是彩灯

灯座只需要知道灯座上有一盏灯

灯座在你打开灯座上的开关时,会点亮 灯座上有一盏灯

这样就可以换上不同的灯泡,得到不同颜色的灯光。

同步和异步

实际上,不管是什么程序设计语言,回调函数都分为同步和异步两种。这里以 C 语言为例,分析两者的区别。

同步回调

下面的代码展示了如何给一个数组从小到大排序的代码。代码调用了函数 qsort 进行排序,并通过指定 compare 为参数,实现元素大小的比较。

int compare (const void * a, const void * b) {

return (*(int*) a - *(int*) b);

}

...

int values[] = { 20, 10, 50, 30, 60, 40 };

qsort (values, sizeof (values) / sizeof (int), sizeof(int), compare);

代码对应了例1描述的五个要素:

compare 相当于是 函数 A

qsort 相当于是 函数 B

对于 qsort 来说,qsort 的第四个参数相当于是参数 fn

对于 qsort 来说,排序过程中,比较两个元素大小的时刻相当于是调用时刻 T

compare 返回两个元素比较大小的结果 相当于是回调结果 P

由于调用 compare 的时刻 T 均是在调用 qsort 结束之前(qsort 未返回),所以这样的回调被称为同步回调。

异步回调

下面的代码展示了如何在 Linux 下,阻止用户使用 Ctrl C 退出程序,并打印 Press ^C 提示。代码调用了函数 signal 进行回调函数的注册(和同步回调不同,这里仅是注册)。

void block_interrupt (int code) { printf("\rPress ^C\n"); }

...

signal (SIGINT, block_interrupt)

代码对应了例1描述的五个要素:

block_interrupt 相当于是函数 A

Linux 终端(Ctrl C 信号的发送者) 相当于是函数 B

调用 signal 函数注册 SIGINT 事件时的参数 相当于是参数 fn

对于 Linux 终端来说,用户按下 Ctrl C 的时刻 相当于是 调用时刻 T

block_interrupt 打印 Press ^C 提示 相当于是回调结果 P

由于调用 block_interrupt 的时刻 T 是用户按下 Ctrl C 的时刻,均是在调用 signal 结束之后(signal 已返回),所以这样的回调被称为异步回调。

同步和异步方式的不同

同步方式通过参数传递 的方法(例如 qsort)传递回调函数;调用者 直接使用回调函数,从而完成回调(调用时刻在函数返回前)

异步方式通过注册 的方式(例如 signal)告知未来的调用者,并 存储回调函数;调用者在未来某个调用时刻 T,取出并调用回调函数,从而完成回调。

免责声明:内容和图片源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

预约申请免费试听课

填写下面表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:C++ 中的 new/delete 和 new[]/delete[]
下一篇:C++中的面向对象

C++ Swap函数有几种写法?

C++基础-内存管理

C++数组相关

C++冒泡排序是这么回事

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省