callback 回调函数
一、调用和回调的定义
回调函数有点绕,可用简单的一个案例说明:
- A给B打电话,问:1+1等于几? B说,我也忘了,我得想一会,想好了再告诉你。这时比较好的方式是断开电话链接,等B想好了再告诉A。于是他们挂断了电话,A又去忙别的事情,B算好了答案,给A打电话,告诉A结果等于2。
- 上述,开始A给B打电话,后来,B想好了答案主动给A打电话的过程就是回调。
1.1 调用
- 同步调用, 是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;
- 异步调用, 是一种类似消息或事件的机制,不过它的调用方向刚好相反, 接口的服务在收到某种讯息或发生某种事件时,会主动通知客户端(即调用客户端的接口)。
1.2 回调
- 回调, 是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;
- 回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。
- 同步调用是三者当中最简单的,而回调又常常是异步调用的基础,
1.3 架构回调实现
下面我们集中比较具有代表性的语言(C)和架构(C++)来分析回调的实现方式、具体作用等。
1.3.1 函数指针
1.函数和函数指针:
//1111111111111111111
void Func(char *s);// 函数原型
void (*pFunc) (char *);//函数指针//222222222222222222
int* func(int params, ...); //这就是指针函数
2.可以看出,函数的定义和函数指针的定义非常类似。 一般的化,为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
//1111111111111111111
typedef void(*pcb)(char *);//222222222222222222
// 为回调函数命名,类型命名为 CallBackFun,参数为char *p 。
typedef int (*CallBackFun)(char *p);
3.回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。
被回调函数的案例:
//11111111111111111
void GetCallBack(pcb callback)
{/*do something*/
}//2222222222222222
//下面的这些是调用者:有几种方式,看你喜欢哪种
int call(CallBackFun pCallBack, char *p){ // 执行回调函数,方式一:通过命名方式
printf("call 直接打印出字符%s!\n", p);
pCallBack(p);
return 0;
}
int call2(char *p, int (*ptr)())
{ // 执行回调函数,方式二:直接通过方法指针
printf("==============\n", p);
(*ptr)(p);
}
int call3(char *p, CallBackFun pCallBack){ // 执行回调函数,方式一:通过命名方式
printf("--------------\n", p);
pCallBack(p);
}
4.用户在调用上面的函数时,需要自己实现一个pcb类型的回调函数:
//111111111111111
void fCallback(char *s)
{/* do something */
} //222222222222222
int CallBackFun(char * p){//TODO
}
5.然后,就可以直接把fCallback当作一个变量传递给GetCallBack,
//1111111111111
GetCallBack(fCallback);//2222222222
//关联
6.如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。
赋值可以发生在运行时,这样使你能实现动态绑定。
1.3.2 参数传递规则
- 到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。
- 如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。
- C++ Builder也支持_fastcall调用规范。
- 调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。
- 将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。
例如:
// 被调用函数是以int为参数,以int为返回值
__stdcall int callee(int); // 调用函数以函数指针为参数
void caller( __cdecl int(*ptr)(int)); // 在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; // 出错, 前者是__cdecl ,后者是__stdcall
指针p和callee()的类型不兼容,因为它们有不同的调用规范。
因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列
1.4 回调函数的优缺点
1.4.1 优点
很多时候回调函数可以用来执行条件驱动的任务。即当该回调函数关心的那个条件被触发时,回调函数将被执行。条件触发可以是某一时间到了或者某一事件发生或者某一中断触发。
回调函数不是由该函数的实现方直接调用,而是在特定的条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
使程序设计更灵活。允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。而且这一设计允许了底层代码调用在高层定义的子程序。
回调函数最大的优势应用就是异步回调。
程序变成异步的了,也就是你不必再调用这个函数的时候一直等待这个时间的到达、事件的发生或中断的发生(万一一直不发生,你的程序会怎么样?)
在此期间你可以做别的事情,或者四处逛逛。当回调函数被执行时,你的程序重新得到执行的机会,此时你可以继续做必要的事情了。
1.4.2 缺点
- 学习成本会比普通函数高,需要有一定的抽象思维能力,需要对应用场景的理解。
- 回调函数很多情况下会附带有跨线程操作甚至于跨进程的操作,这些都是异步带来的成本。
2.案例
// 类A
class A{public:
//A 的构造函数
A(){}
//函数指针类型自定义一下
typedef std::function<void(const std::shared_ptr<Submap2D>&)> UpdateFinishSubmapCallback;//Test 函数,某种情况下会调用回调函数
void Test(){std::shared_ptr<Submap2D> submaps;
if(submaps)SetUpdateSubmapCallback(submaps);
}
//
void SetUpdateSubmapCallback(UpdateFinishSubmapCallback callback) {updateFinishSubmapCallback_ = callback;}
private:
//定义回调函数对象
UpdateFinishSubmapCallback updateFinishSubmapCallback_;}class B{public:
A a_;
B(){// B 构造时,将回调函数关联起来 UpdateFinishSubmapCallback std::placeholders::_1 指一个参数 ,多个参数 std::placeholders::_2...a_.SetUpdateSubmapCallback(std::bind(&A::UpdateFinishSubmapCallback, this, std::placeholders::_1));
}
void spin(){void (
// TODO
a_.Test();
}
private:
//声明和定义回调函数
bool UpdateFinishSubmapCallback(const std::shared_ptr<Submap2D>& submap){//TODO
}
}B b;
b.spin();
- 当B类调用 函数spin()时,会调用A中的 Test() 函数
- A中 Test() 一定条件会调用A的函数SetUpdateSubmapCallback()
- A的函数SetUpdateSubmapCallback() 调用回调函数 UpdateFinishSubmapCallback;
- A的UpdateFinishSubmapCallback 回调函数在B中调用,会调用B中bool
- UpdateFinishSubmapCallback(const std::shared_ptr& submap){} 函数
callback 回调函数相关推荐
- javascript~callback回调函数
函数是对象,所以它可以作为一个参数传递给其他函数. 回调函数作为一个参数传递给其他函数时是没有括号的,只有函数名:使用括号表示立即执行回调函数callback.我们只希望传递一个函数的引用,让其他函数 ...
- js接收php 回调,JS callback回调函数的使用(附代码)
这次给大家带来JS callback回调函数的使用(附代码),JS callback回调函数使用的注意事项有哪些,下面就是实战案例,一起来看一下. 在使用开源项目的时候经常会使用到回调函数,如果把回调 ...
- 十一、【TF2】Callback 回调函数
TF2 Callback 一.回调函数简介 二.TF2中的内置回调函数 1- tf.keras.callbacks.BaseLogger 基础日志 2- tf.keras.callbacks.Hist ...
- php callback,php Callback 回调函数详解
自 PHP 5.4 起可用 callable 类型指定回调类型 callback.本文档基于同样理由使用 callback 类型信息. 一些函数如 call_user_func() 或 usort() ...
- callback(回调函数)
先讲点题外话. 编程分为两类:系统编程(system programming)和应用编程(application programming).所谓系统编程,简单来说,就是编写库:而应用编程就是利用写好的 ...
- Callback回调函数介绍(C语言)
目录 1. 回调函数的定义 2. 为什么要用回调函数 3. 怎么用回调函数 3.1 怎么使用没有参数的回调函数 3.2 怎么使用带参数的回调函数 1. 回调函数的定义 最近在工作中经常用到回调函数ca ...
- c语言 callback回调函数
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这个例子里,你的电话号码就叫回调函数,你把电话留给 ...
- dispatch callback ant design pro 网络请求回调函数
index.jsx 代码解析:在组件初次渲染时调用 model 中 命名空间为 a_models 的 getData 网络请求,传了一个patload 参数和 callback 回调函数过去,然后 ...
- JavaScript 回调(callback)函数
此文适合JavaScript入门级选手阅读,高手就可以飘过了. 先扯点闲话.在中国,有这么一种现象:不管什么词或者概念,总会有些人把这些东西解释的神乎其神,貌似搞得别人听不懂就觉得自己很厉害的样子.其 ...
最新文章
- 鸡肋的PHP单例模式
- 2021-7-26 pytorch深度学习框架学习
- camel_Apache Camel 2.14中的更多指标
- autosys虚拟机定义
- Android AudioTrack/AudioRecord -wav文件读取3
- linux SVN web 同步
- 八进制数转十进制计算机计算器,八进制转十进制计算器
- python转换excel 列号 为数字 数字转为列号
- html制作图片幻灯片效果代码,【JS+CSS3】实现带预览图幻灯片效果的示例代码
- AppWeb认证绕过漏洞(CVE-2018-8715)漏洞复现
- 中小学计算机培训心得体会,中小学计算机管理员培训心得体会材料
- 弗洛伊德(Floyd)算法详解
- 为什么不建议使用免费的IP代理?
- C语言反序输出英文句子,iOS开发-英文句子倒序输出
- .net 本地文件管理 代码_如何在百万行代码中发现隐藏的后门
- oracle财务软件导出报表,OracleFusion财务会计中心报表云服务-UAO.PDF
- 未来时代量计算机科幻游戏,“八本科幻未来时代小说”到那个我们可以想象的极限,享受科幻美...
- 计算机图形学专业 国内大学排名,虚拟现实应用技术专业大学排名 2020全国排行榜...
- Google Earth Engine(GEE)——基本介绍和图像分析、可视化和处理实战
- iOS 逆向获取手机硬件参数
热门文章
- SAP AS ABAP 7.52 SP04, Developer Edition 免费下载
- 华为p10 android几,华为p10国行版和海外版有什么区别 配置参数对比评测
- (亲测解决)Tomcat启动时卡在“ Deploying web application directory ”很久的解决方法
- 如何评价唐卫国公李靖的战功、军事才能、政治才能?
- JAVA的if结构单分支结构简单易懂
- unity 实现手机震动
- 头文件中能否进行函数的定义
- 备份iphoneXR手机照片
- 开发常用到的工具有哪些
- 【论文学习】《“Hello, It’s Me”: Deep Learning-based Speech Synthesis Attacks in the Real World》