zoukankan      html  css  js  c++  java
  • 回调函数

      回调函数:顾名思意,就是使用者自己定义一个函数,使用者自己定义这个函数的功能,然后把 这个函数作为参数 传入到 其他函数 中,由  其他函数 在运行时来调用的函数。该“其他函数”就是回调函数(特点:它 主动调用 别的函数)

      什么是回调函数呢?回调函数其实就是一个通过函数指针调用的函 数!假如你把A函数的指针当作参数传给B函数,然后在B函数中通过A函数传进来的这个指针调用A函数,那么这就是回调机制。B函数就是回调函数,而通常情 况下,A函数是系统在符合你设定条件的情况下会自动执行,比如Windows下的消息触发等等。那么调用者和被调用者的关系就被拉开了,就像是中断处理函 数那样。

       简单的说:由 其他的函数 运行期间来回调 你定义的函数;(这两个函数 被捆绑在一起 运行)

     1 //不带参数版
     2 #include <stdio.h>
     3 
     4 void func()    //定义回调函数的调用函数;
     5 {
     6     printf("hello world !! 
    ");
     7 }
     8 
     9 void mycall_back(void(*call_back_test)()) //实现回调函数
    10 {
    11     call_back_test();
    12 }
    13 
    14 int main()
    15 {
    16     mycall_back(func);
    17     return 0;
    18 }
    //回调函数带参数版
    1
    #include <stdio.h> 2 3 void func(int t) 4 { 5 printf("hello world !! %d ", ++t); 6 } 7 //void mycall_back((*call_back_test) (int), int k) //error; 8 void mycall_back(void (*call_back_test) (int), int k)   //注意参数写法 9 { 10 call_back_test(k); 11 } 12 13 int main() 14 { 15 mycall_back(func, 8);  //注意参数写法; 16 return 0; 17 }

    下面给出回调函数的标准定义:

      简而言之,回调函数就是一个 通过函数指针调用的 函数。如果把 函数的指针(地址)作为参数传递给另一个函数, 当这个指针 被作 调用它指向的函数时,我们就说 这个函数是回调函数;

      为什么要使用回调函数?

      因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。

       如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排 序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、 float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。

      回调可用于通知机制,例如,有时要在程序中设置一个 计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调, 来通知我们的程序事件已经发生。实际上,SetTimer() API使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。

      另一个使用回调机制的 API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,为每个窗口调用一个程序提供的函数,并传递窗口的处理程序。如果被调用者返回一个 值,就继续进行迭代,否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为 基于返回值,它将继续执行或退出。

    示例一个:

     1 #include <stdio.h>
     2 
     3 typedef void (*callback_t)(void *);
     4 
     5 void repeat_three_times(callback_t f, void *para)
     6 {
     7     f(para);
     8 }
     9 
    10 void say_hello(void *str)
    11 {
    12     printf("Hello %s
    ", (const char *)str);
    13 } 
    14 
    15 void count_numbers(void *num)
    16 {
    17     int i;
    18     for(i=1;i<=(int)num;i++)
    19         printf("%d ", i);
    20     putchar('
    ');
    21 }
    22 
    23 int main()
    24 {
    25      repeat_three_times(say_hello, "Guys");
    26      repeat_three_times(count_numbers,  (void *)4);
    27      return 0;
    28 }

     示例二

     1 #include <stdio.h>
     2 typedef int (cmp_t)(void *a, void *b);
     3 
     4 typedef struct
     5 {
     6     const char *name;
     7     int score;
     8 }student_t;
     9 
    10 int cmp_student(void *a, void *b) 
    11 {
    12     if(((student_t *)a)->score > ((student_t *)b)->score)
    13         return 1;
    14     if(((student_t*)a)->score == ((student_t *)b)->score)
    15         return 0;
    16     else
    17         return -1; 
    18 
    19     return 0;
    20 }
    21 
    22 void *max(void *data[], int num, cmp_t cmp)
    23 {
    24     int i;
    25     void *tmp = data[0];
    26     for(i=1; i<num; i++)
    27     {   
    28         if(cmp(tmp, data[i]) < 0)
    29             tmp = data[i];
    30     }   
    31     return tmp;
    32 }
    33 
    34 int main()
    35 {
    36     student_t list[4] = {{"Tom", 68}, {"Jerry", 72}, {"John", "87"}, {"Chris", 99}};
    37     student_t *plist[4] = {&list[0], &list[1], &list[2], &list[3]};
    38     student_t *pmax = max((void**)plist, 4, cmp_student);
    39     printf("%s gets the highest score %d
    ", pmax->name, pmax->score);
    40 
    41     return 0;
    42 }

      max函数之所以能对一组任意类型的对象进行操作,关键在于传给max的是指向对象的指针所构成的数组,而不是对象本身所构成的数组,这样max不必关心对象到底是什么类型,只需要转给比较函数cmp,然后根据比较结果做对应操作即可,cmp是调用者提供的回调函数,调用者就知道对象是什么类型以及如何比较;

    以上举例的回调函数是被同步调用的,调用者调用max函数,max函数则调用cmp函数,相当于调用者间接调了自己提供的回调函数。在实际系统中,异步调用也是回调函数的一种典型用法,调用者首先将回调函数传给实现者,实现者记住这个函数,这称为注册一个回调函数,然后当某个事件发生时实现者再调用先前注册的函数,比如sigaction(2)注册一个信号处理函数,当信号产生时由系统调用该函数进行处理,再比如pthread_create(3)注册一个线程函数,当发生调度时系统切换到新注册的线程函数中运行,在GUI编程中异步回调函数更是有普遍的应用,例如为某个按钮注册一个回调函数,当用户点击按钮时调用它。

  • 相关阅读:
    配置Log4j(非常具体)
    RapeLay(电车之狼R)的结局介绍 (隐藏结局攻略)
    普林斯顿公开课 算法1-11:并查集的应用
    检查Oracle 中死事务的语句
    app被Rejected 的各种原因翻译
    经典语录和思考总结
    Java实现夺冠概率模拟
    Java实现夺冠概率模拟
    Java实现打印回型嵌套
    Java实现打印回型嵌套
  • 原文地址:https://www.cnblogs.com/chris-cp/p/3492423.html
Copyright © 2011-2022 走看看