首页 > 其他分享 >怎么理解回调函数? 回调函数合集

怎么理解回调函数? 回调函数合集

时间:2023-05-21 10:07:43浏览次数:65  
标签:调用 函数 int stu Student 回调 合集


网上查了一通,有点体会,特来分享与讨论。

 

****************************************************************************************************************************

SECTION 1

****************************************************************************************************************************

回调函数

回调函数是一个时时听到的概念,比如在windows API编程时遇到的WinProc函数,就是我们编写而由操作系统调用的函数。现在,我们需要慢慢又详细的记录一下这个问题。

库与使用者的问题

在开始之前,首先我们想像这样一个情景,一个大型软件公司开发一套软件库提供给用户使用。在这句话中,出现两个对立面,一个是软件公司,一个是用户。显然,软件公司实力很强大,他们强大的地方在于他们很聪明。请看下图:

 

库开发者是提供方,他们不知道用户想做什么,库开发者对用户的信息是未知的,因为两边的人谁也没见过谁,就像一个人在美国一个人在中国。他们聪明的地方就在于即使不知道用户怎么操作,他们也可以用一种通用的方法来解决用户的问题。换句话说,库开发方不管用户怎么折腾变化,他都能适应。这就是问题的神奇之处,当然,为了达到这种效果,必须有一种规则来约束。

规则 

现在来说规则,规则比较好理解,就是两方达成的约束。比如甲和乙两个人,甲对乙说,你只要提供给我一个塑料球,我都能给它涂上颜色。这里的约束是塑料球,(当然,为了简化问题这里的约束还是比较泛泛而不严谨的),这个时候如果乙给他一个水晶球,或者给他一辆汽车都不行,因为已经超越了约束。所以说,库开发者能适应用户的各种变化就在于他也给了用户一定的约束,是在约束之下的适应,这也是不言自明的。

代码之下无秘密

下面一段代码极好的解释了上述问题:

怎么理解回调函数? 回调函数合集_回调函数

#include <stdio.h>
typedef int student_id;
 typedef int student_age;
 typedef struct _Student{
     student_id id;
     student_age age;
 }Student;//类型重定义:函数指针类型
 typedef bool (*pFun)(Student, Student);//-----------------------------------------------
 //冒泡排序法:能够按AGE或ID排序,用同一个函数实现
 //-----------------------------------------------
 void sort(Student stu[],const int num,pFun fun)
 {
     Student temp;
    
     for(int i = 0; i < num; ++i){
         for(int j = 0; j < num - i -1; ++j)
         {
             if((*fun)(stu[j],stu[j+1]))
             {
                 temp = stu[j];
                 stu[j] = stu[j+1];
                 stu[j+1] = temp;
             }
         }
     }
 }//-----------------------------------------------
 //回调函数:比较年龄
 //-----------------------------------------------
 bool CompareAge(Student stu1,Student stu2)
 {
     //更改从大到小还是从小到大的顺序,只需反一下。
     if(stu1.age < stu2.age)
         return true;
     return false;
 }
 //-----------------------------------------------
 //回调函数:比较id
 //-----------------------------------------------
 bool CompareId(Student stu1,Student stu2)
 {
     //更改从大到小还是从小到大的顺序,只需反一下。
     if(stu1.id < stu2.id)
         return true;
     return false;
 }int main()
 {
     Student stu[] = {
     {1103,24},
     {1102,23},
     {1104,22},
     {1107,25},
     {1105,21}};
    
     pFun fun = CompareAge;
     int size = sizeof(stu)/sizeof(Student);
    
     sort(stu,size,fun);
    
     for(int i = 0; i < size; ++i){
         printf("%d %d\n",stu[i].id,stu[i].age);
     }
    
     return 0;
 }

 

通过代码,我们必须分辨出哪个是库提供方,哪个是用户:

 

sort(...)方法是库开者提供的,只是因为模拟问题所以把它写在一个文件中了,我们可以假想它存放在某个静态库lib里面,这样就和它有了界限。

库开发者提供方法sort(...)供我们调用,形参里面还包括一个函数指针,就是调用用户自己写的函数,也即回调函数。所以它提供了规则,也就是说这个回调函数的形参是什么,返回值又是什么,假如用户对于这个回调函数的形参和返回值啥都不知道,随意写了一个函数放进去,sort方法能接受吗?显然是不行的。

那么用户怎么知道回调函数的形参和返回值等信息呢?库开发方会告知,或者在它的文档里面会有说明,就像在windows API开发窗口程序时提供的WinProc() 函数一样,里面的形参必须一模一样。(这个地方会牵涉到接口)

什么是回?

根据上面的代码,我们知道,库开发方提供了一个方法,然后形参又带有一个函数指针,等着用户去写然后拿来调用,并在其实现中调用了这个函数。站在库开发方的立场,我们可以总结为一句话:库开发方调用了用户的函数(回调函数)。

现在,我们把视角移到回调函数的立场上来看,它被调用了。但同时它也有参数,且传进来的参数是库开发方提供的数据,这里我们又可以总结一句话:回调函数调用了库开发方的数据。

这就是“回”的意思,你调我我也调用你,双方互相调用。

怎么理解回调函数? 回调函数合集_函数指针_02

 

回调函数的重点是什么?

根据上文分析,发现回调函数其实也不是难于理解,我觉得重点在于一定要划分清楚谁是库开发方(也可称为提供方,调用者),谁是用户,把职能划分清楚是最关键的。

 

****************************************************************************************************************************

SECTION 2

****************************************************************************************************************************

 

tip1

你就想象你函数的一部分功能被外包给别人。至于被人怎么实现的你不用管,你的函数具有一个完整的功能,但是有的功能可以随你自己定制,参照stl中的for_each

tip2

简单点说,用户是实现方,实现方需要调用A()函数,但为了A()函数具有通用性,需要根据实现方的意愿调用实现方提供的函数cbB(),在这里cbB()即为回调函数。在Windows编程中回调函数用途很广泛。

 

****************************************************************************************************************************

SECTION 3

****************************************************************************************************************************

回调函数是通过函数指针调用的函数:把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就称为回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

 

通俗点说就是:在A类中调用B类中的某个方法C,然后B类反过来调用A类中的方法D,则D就是回调函数。

 

打个比方:

我们将A类看成一个人,就叫他小A;将B类也看成一个人,就叫他小B;

那么使用回调函数D的过程就可以这样理解:

小A在开发过程中遇到了一个麻烦,而这个麻烦只有小B才能解决,于是小A找到了小B求他帮忙,但是由于和小B不怎么熟悉于是带上了名片。小A向小B说明了遇到的麻烦后,正巧小B正在忙于其他事情,于是小B先收下了小A的名片,告诉小A回去等消息。由于这个麻烦不解决就无法继续开发,于是回去等消息的小A就只好先去做别的事情。过了一段时间小B忙完手上的事情,解决了小A的麻烦后,找出小A名片上的电话号码拨了过去,告诉小A,麻烦已经搞定了(小B只是顺着名片把解决方案告诉给小A,而并不关心自己给出的解决方案在小A那里会如何运用)。小A放下电话后,利用小B给他的解决方案继续开发。

简而言之:小A带着名片D通过途径C找到小B求他帮忙,小B不能立即解决于是收下名片D,之后的某天小B解决了小A的问题后又通过名片D告诉了小A解决方法。

即:

A类调用B类中的C方法,D作为函数指针当做C方法的一个参数(小A带着名片D通过途径C找到小B求他帮忙)

B类无法立即处理,就先进行回调函数标记(收下名片)

在未来的某一个时间点,当满足触发条件时(解决问题后)

通过回调函数D传递回信息给A类(通过名片告诉结果)

 

 

 下面以一个例子说明上述过程(解释见注释):

 


1. #include <iostream>
2. typedef void (*Fun)(int);//定义一个函数指针类型
3. Fun p = NULL;//用Fun定义一个变量p,它指向一个返回值为空参数为int的函数
4. void caller(Fun pCallback)
5. {

6. p = pCallback;
7. //达成某一条件后,通过名片(函数指针p),传回结果
8. int result = 1;
9. (*p)(result);
10. }
11. void callback(int a)//回调函数
12. {

13. std::cout << "callback result = " << a << std::endl;
14. }
15. int main(int argc, char* argv[])
16. {

17. caller(callback);
18. getchar();
19. return 0;
20. }

标签:调用,函数,int,stu,Student,回调,合集
From: https://blog.51cto.com/u_15953444/6318598

相关文章

  • 详解C++STL—函数对象
    1、函数对象1.1、函数对象概念概念:重载函数调用()操作符的类,其对象常称为函数对象函数对象使用重载的()时,行为类似函数调用,也叫仿函数本质:函数对象(仿函数)是一个类,不是一个函数1.2、函数对象的使用特点:函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值函数对象超......
  • C语言函数大全-- _w 开头的函数(5)
    C语言函数大全本篇介绍C语言函数大全--_w开头的函数1._wspawnl1.1函数说明函数声明函数功能int_wspawnl(intmode,constwchar_t*cmdname,constwchar_t*arglist,...);启动一个新的进程并运行指定的可执行文件参数:mode:启动命令的模式,可以是_P_W......
  • Midjourney|文心一格 Prompt:完整参数列表、风格汇总、文生图词典合集
    Midjourney|文心一格Prompt:完整参数列表、风格汇总、文生图词典合集1.Midjourney完整参数列表参数名称调用方法使用案例注意事项V5V4V3niji版本在关键词后加空格,然后带上版本参数:--v或者—v--version或者—versionvibrantcaliforniapoppies--v5......
  • 内置函数——sorted( )函数:返回一个排序后的新列表
     《流畅的Python》14.11可迭代的归约函数sorted()函数可以处理任意的可迭代对象;sorted()函数和归约函数只能处理最终会停止的可迭代对象。否则,这些函数会一直收集元素,永远无法返回结果。......
  • 标准库中的生成器函数——用于重新排列元素的生成器函数
         1注意,itertools.groupby假定输入的可迭代对象要使用分组标准排序;即使不排序,至少也要使用指定的标准分组各个元素。  1#itertools.groupby函数的用法2importitertools3456k1=list(itertools.groupby('LLLLAAGGG'))7print('k1:',k......
  • Jmeter函数助手16-FiletoString
    FiletoString函数用于获取文本文件的值,一次读取一行,可读取多个文件。输入文件的全路径:填入文件路径存储结果的变量名(可选)Startfilesequencenumber(opt):初始序列Finalfilesequencenumber(opt):终止序列1、StringFromFile函数跟组件CSV数据文件设置的区别是:CSV数据......
  • 算法学习笔记合集
    字符串哈希:哈希学习笔记KMP:KMP学习笔记图论分层图最短路:分层图最短路LCA:P3379最近公共祖先模板数据结构线段树:线段树学习笔记ST表:P3865ST表树状数组:P3374树状数组1DP树上背包:P2014选课(树上背包)杂项搜索:搜索学习笔记离散化:离散化学习笔记......
  • 游记合集
    2023.3.42023春季测试:2023.3.4NOI春季赛游记2023.4.1-2023.4.2联合省选:LNOI2023游记......
  • Jmeter函数助手15-FiletoString
    FiletoString函数用于一次读取整个文件值。输入文件的全路径:填入文件路径Fileencodingifnottheplatformdefault(opt):读取文件的编码格式,不传则默认使用系统格式存储结果的变量名(可选)1、首先我的文件内容是4行2列,如下2、调用FiletoString函数会一次性输入多行多列的......
  • 实验4 函数与异常处理编程
    1.实验任务11print(sum)2sum=423print(sum)45definc(n):6sum=n+17print(sum)8returnsum910sum=inc(7)+inc(7)11print(sum)问题:不是。line1中的sum是指Python的内置函数;line3中的sum指的是line2中的全局变量sum;line7中......