回调函数的应用误区3(大彻大悟的回调小程序,例子的解释相当给力)

研究了一段时间回调函数,越看越迷惑,分析并改进了从网上看到的几篇好文,看过后有了自己的看法。我也不知道这些跌跌撞撞的认识是否符合回调的真实原理,若有大侠能帮解惑,自当感激不尽。

下面的代码可以在Vs2008下编译并运行:

所有的回调函数文章里,能让我一下看明白回调函数的就是这篇文章了,描述简单,一语中的:http://hi.baidu.com/zht7216/item/1dd32e82a68c40d15f0ec154

摘选如下:

  函数指针是一个指向函数的指针变量,它是专门来存放函数入口地址的,在程序中给它赋予哪个函数的入口地址,它就指向哪个函数,因此在一个程序中,一个函数的指针可被多次赋值,指向不同的函数。

#include <stdio.h>

int max(int x , int y);
int min(int x , int y);
int add(int x , int y);
int process(int x , int y , int(*fun)(int , int));

//客户程序C
void main()
{
    int a=10,b=2;
    printf("a=%d, b=%d\n", a, b);
    printf("process(a,b,max)=%d\n", process(a,b,max));//注册回调函数
    printf("process(a,b,min)=%d\n", process(a,b,min));
    printf("process(a,b,add)=%d\n", process(a,b,add));
}

int max(int x , int y)
{
    return x>y?x:y;
}

int min(int x , int y)
{
    return x<y?x:y;
}



int add(int x, int y)
{
    return x + y;
}

//服务程序S

int process(int x, int y, int(* fun)(int, int))
{
    int result;
    result = (*fun)(x , y);
    return result;
}

在这里我见到了对回调函数大彻大悟的解释:

按照刚才的逻辑,其实所声明的三个功能函数:max ,min ,add 就是回调函数。

      请看:

     使用回调函数实际上就是在调用某个函数时将自己的一个函数(这个函数就是回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这是你可以利用这个机会,在回调函数中处理消息或完成一定的操作。

     也可以这样理解:

      所谓回调,就是客户程序Client(main)调用服务程序Server中的某个函数Sa(process),然后Server又在某个时候反过来调用Client中的某个函数Ca(max),对于Client来说,这个Ca便叫做回调函数。例如Win32下的窗口过程函数就是一个典型的回调函数。

     一般说来,Client不会自己调用Ca,Client提供Ca的目的就是让Server来调用它,而且是Client不得不提供。由于Server并不知道Client提供的Ca叫什么,所以Server会约定Ca的接口规范(函数原 型),然后由Client提前通过Server的一个函数Sr(process)告诉Server,自己将要使用Ca函数,这个过程称为回调函数的注册,Sr称为注册函数。

     这个Client的Ca函数是不是很像个钩子?一旦将它注册到Server后,Server就会在合适的场合来调用它了。

       下面举个通俗的例子:
      假设公司里面有一个小神童,可以回答任何人的问题。

      某天,我向小神童请教问题,当然是个难题,:),小神童一时想不出解决方法,而后面还有一帮人正在等着神童回答他们自己的问题呢,

      现在不能因为我的提问,而影响到后面排队的人的咨询,所以我和小神童约定,我把手机号码留给他,等小神童知道答案了然后再把结果告诉我。

      我就离开小神童办其它事情去了。过了XX分钟,我的手机响了,小神童兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。

     说明:我是Client,小神童是Server,我找小神童办事就是调用函数Sa,由于某种原因不能马上得到结果,又不能占用大家的时间,所以我只能先注册(Sr函数)联系方式给小神童, 等小神童有消息了,就打电话给我。

这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。

      2. 什么情况下使用回调


      如果你是SDK的使用者,一旦别人制定了回调机制,那么你被迫得使用回调函数,因此这个问题只对SDK设计者有意义。
从引入的目的看,回调大致分为三种:
1) SDK有消息需要通知应用程序,比如定时器被触发;
2) SDK的执行需要应用程序的参与,比如SDK需要你提供一种排序算法;
3) SDK的操作比较费时,但又不能让应用程序阻塞在那里,于是采用异步方式,让调用函数及时返回,SDK另起线程在后台执行操作,待操作完成后再将结果通知应用程序。
经上面这样一总结,你也许会恍然大悟:原来“回调机制”无处不在啊!
是的,不光是Win32 API编程中你会用到,也不光是其它SDK编程中会用到,平时我们自己编写程序时也可能用到回调机制,这时,我们既是回调的设计者又是回调的使用者。

posted @ 2014-05-23 16:41  咚咚锵锵  阅读(2799)  评论(0编辑  收藏  举报