• C++回调函数


    ————这篇文章会随着学习逐步更新,同时和Java接口回调配合记录————

    回调函数

    回调函数是一个时时听到的概念,比如在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 ",stu[i].id,stu[i].age); } return 0; }

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

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

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

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

    什么是回?

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

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

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

    回调函数的重点是什么?

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

    2018-01-22 12:46:14

  • 相关阅读:
    学习笔记:类与类之间的关系
    学习笔记Controller
    学习笔记JPA
    学习笔记dao,domain,service三层理解
    学习笔记@注释
    【练习6.6】拉普拉斯cvLaplace团块及边缘检测、图像数据类型转换cvConvertScaleAbs
    【练习6.5】cvSobel及参数要求、cvCartToPolar坐标空间映射、cvMinMaxLoc求自大最小值、cvAvg求平均值
    【练习6.2】cvFilter2D及3×3高斯核、cvFilter2D当使用一维核时anchor注意事项、float乘法除法注意事项
    【练习6.1】阈值化、腐蚀、cvFilter2D及自定义滤波器
    【练习5.12】阈值化cvThreshold、自适应阈值cvAdaptiveThreshold、各参数效果对比
  • 原文地址:https://www.cnblogs.com/tinaluo/p/8327880.html
Copyright © 2020-2023  润新知