标签:ack 就是 turn 情况下 应用编程 响应 ios inux end
在说回调函数之前,先谈谈编程。
什么是编程?就是通过使用编程语言,去实现人与机器间的交流与沟通。随着编程语言的不断进步,编程也逐渐分类,渐渐分为系统编程和应用编程。
系统编程:简单的来说,就是编写各种功能库;应用编程:就是利用各种已写好的库来编写具某种功能的程序,也即应用。
库位于应用之下。一般情况下,应用的实现,需要时常通过API去调用库里所预先准备好的函数。
在编程中,我们提到应用程序需要去调用库函数,而有一些库函数的参数却是一个函数,以备调用来完成目标,这个被传入、后又被调用的函数就是回调函数。
在知乎上有一个非常清楚的例子:
有一家旅馆提供叫醒服务,但是叫醒的方式由顾客自己决定。打客房电话、派服务员去敲门、亦或是要求向自己头上浇水等等。这里的“叫醒”行为是旅馆本身提供的,它就相当于库函数;叫醒的方式由旅客告诉旅馆,就相当于是回调函数。这当中,还有一个动作,就是旅客告诉旅馆怎么叫醒自己,相当于是把回调函数传入库函数的动作,称位登记回调函数。
在维基百科上,是这样的关系图:
(Application program)Main program Callback function
? Library function (Software library)
回调函数通常和应用处于同一抽象层。
Main program先calls Library function,再calls Callback function。就形成了一个高层调用底层,底层在回过头来调用高层的过程。
就是整个程序的引擎,来调度各个函数的按序执行。
独立的功能函数
一个介于主函数与回调函数之间的功能函数,用于登记回调函数,通知主函数,起到一个桥梁作用。也可以称它为一个事件,触发回调函数的事件。
在这三个中,容易忽略主函数的作用。不少人都认为回调机制的实现只需要回调函数与中间函数。而事实上,这却是一个三方间的回调机制。
示例代码:
//回调函数
#include <iostream>
using namespace std;
//A(),B()都是两个回调函数
int A(int x) {
return x * 2;
}
int B(int x) {
return x * 4;
}
//C()是一个中间函数,用于登记回调函数
int C(int x, int(*P)(int)) {
return x + P(x);
}
//主函数
int main() {
int x;
cin >> x;
int x1 = C(x, A);
cout << x1 << endl;
int x2 = C(x, B);
cout << x2 << endl;
int x3 = C(x, [](int x) {return x * 8; });//这里使用了匿名函数的方法
cout << x3 << endl;
return 0;
}
通过这个例子,我们可以看出,在主函数中,通过中间函数回调了A()、B()、匿名函数三个回调函数。回调函数执行的流程是:
①主函数需要调用回调函数;
②中间函数登记回调函数;
③触发回调函数事件;
④调用回调函数;
⑤响应回调事件。
我们知道了传入中间函数的参数是一个函数,那么对于这个函数我们该怎样选择?是一个函数,还是一个函数指针。个人看法,最好的选择是函数指针,除了某些特定的地方必须使用函数指针,例如linux系统中的异步信号中断处理;设置为函数指针还能0提高代码的灵活性和后期维护的便捷性。
在上述简例中,我们只是将回调函数设置为了只有一个参数函数,但遇到要设计很多参数的函数时,定义为一个结构体比较方便。
回调实际上有两种:阻塞式回调和延迟式回调
也被称为同步回调,把函数b传递给函数a,执行a的时候,回调了b,只有当b执行完了a才能继续执行。上述的简例就是一个阻塞式回调。
也被称为异步回调,把函数b传递给函数a,执行a的时候,回调了b,然后a就继续往后执行,b独自执行。
在阻塞式回调里,回调函数的调用一定发生在主函数返回之前
在延迟式回调里,回调函数的调用有可能是在起始函数返回之后
标签:ack 就是 turn 情况下 应用编程 响应 ios inux end
原文地址:https://www.cnblogs.com/IcoveJLearningBlog/p/13948312.html