回调函数

 

  当我们的代码量比较大的时候,需要思考一个问题,是否需要合并重复代码.

  这里用链表举例.比如:我们有两个需求   1.求和  2.求最大值
  

  对于链表来说,这两个函数均会遍历链表,那么我们可以把遍历链表的方法提取出来,因为这个方法很常用,我还可以用来排序的时候用,所以如果我有很多函数用到遍历的时候,我的代码量就直线下降了.

 

  接着,我们介绍回调函数.

 

  1.函数指针

  2.回调函数的上下文

  3.通用性

 

  首先,我们需要知道什么是函数指针,在C语言中函数名其实就是一个符号,用来表示函数的入口地址. 既然是地址我们便懂了些什么.(可以看我的博文函数指针)

  接着,我们从回调函数这个名字想,回调....其实就是我在一个函数里调用另外一个函数,但是我们平时写的函数都是写死的,没有任何通用性.

  仔细想想,我们可以把一个函数当成形参用么?这样就不是写死的了..这个想法非常好,我们的回调函数就是靠这个办法实现的,我们这里用到了函数指针作为一个形参.

  接着好像用文字很难让人明白如何实现这个复杂的描述,我们看代码,顺便把通用性给解决了.

 

  

 1 (这里就用伪代码实现了)
 2 typdef struct _LinkNode
 3 {
 4     LinkNode  *next;
 5     void     * data;    //这里用一个void* 类型来存放数据地址,使用者会知道实际的类型,强制转化即可.通用性就增强了
 6 }LinkNode;
 7 
 8 typedef void (*CallBack)(void *data, void *ctx);
 9 //定义函数指针类型, 两个形参,一个为了返回该函数返回的信息
10 
11 //遍历函数的改造
12 void foreach(Link *link, CallBack c, void *ctx) 
13 {
14        LinkNode *node =  link->head->next;
15        while(node)
16        {
17              c(node->data,ctx);   //调用回调函数,ctx看出用处了么?我们不想用全局变量,所以!
18              node = node->next; 
19         }    
20 }
21 
22 //add方法 ,回调函数!!,
23 void add(int *data, int *ctx)   
24 {
25         *ctx += *data;       //这个方法是具体的整形求值方法
26 }
27 
28 //最终调用该方法,放到想用的地方吧:
29 int count =0;//用来记录求和
30 forseach(link, add,&count);   //很简单吧 调用

         这里我们能看到30行

  forseach(link, add,&count); 
  这个调用的后两个形参,一个是函数指针,一个是指针(变量的地址)
  这样我们的目的也达到了.

  总结一下使用方法:
  我们用一个通用的方法(遍历),来调用特定的某个需求方法(求和).
  我们将需求方法写成一个回调方法.并改造遍历方法使其通用,并可以保存需求方法的上下文.
  这里最终调用的方法: 我们用函数指针作为形参定位回调函数 我们用一个变量记录回调函数的上下文
  

 

 

posted @ 2014-04-14 22:04  敷衍。  阅读(388)  评论(0编辑  收藏  举报