iCAx开思工具箱

标题: 很有用的回调函数 [打印本页]

作者: 会思考的石头    时间: 2005-5-30 23:44
标题: 很有用的回调函数
引言:
练拳不练功,等于一场空。
我把二次开发比做练拳了,而功则是你用的计算机语言,对于哪种语言好,哪种不好,这个凭各人爱好。我喜欢C/C++。
  
这篇文章是小弟学习回调机制的一些心得。有错的地方,多多指点。认为这个和二次开发没关系的兄弟可以不用看。但我觉得它们关系挺大。
  
准备:打开C语言的教材,仔细阅读指向函数的指针那章,也叫函数指针。最好是K&R的经典的《The C Programming Language》,因为它的用例好,不象谭好强的书里所用的例子纯粹是为教学而写的。
  
关于函数指针,在此只引用《The C Programming Language》在函数指针这一节中的第一段话:
In C, a function itself is not a variable, but it is possible to define pointers to functions, which can be assigned, placed in arrays, passed to functions, returned by functions, and so on.
  
我们关注着其中一句:指向函数的指针可以当作参数传递给另一个函数。利用这个性质,就可以实现回调机制了。
  
///////////////////////////////////////////////////////////////////////////////////
[1]什么是回调。不管正经书上怎么解释,本文说的是大实话。
被调用者调用了调用者的功能,这就是回调。
这句话很拗口。但理解起来不很困难。有人把回调函数的发明比喻为程序设计领域的四大发明之一。了解C#的兄弟也许会知道,C#中的委托是利用函数指针来实现的,事件是由回调来实现的。仅仅因为它是C#中的,而很多人就认为这是C#的优点。
  
第一个回调的例子:
如果写过WIN32 SDK程序的兄弟会知道,那个封装了switch...case的WndProc函数是叫系统回调函数的。程序窗口的消息在这个函数中得以处理。按照上面的定义,可以这样子理解:WIN32操作系统向程序员提供功能,程序员们要调用这些功能来写程序,这样WIN32就是被调用者,程序员写的程序是调用者。由于程序员写的WndProc要由操作系统来调用,那么这就构成了一种回调机制。
  
第二个回调的例子:
我们在UG下做二次开发,也经常碰到回调机制。譬如:
//----------------------------------------------------------------
//菜单动作表,将回调函数与菜单项连接起来  
//----------------------------------------------------------------
static UF_MB_action_t action_table[]=  
{  
   {"DataImport_cb",(UF_MB_callback_t)DataImport_cb,NULL},  
   { NULL, NULL,NULL}  
};
//----------------------------------  
//菜单回调函数  
//----------------------------------
static UF_MB_cb_status_t DataImport_cb(UF_MB_widget_t widget,UF_MB_data_t client_data,UF_MB_activated_button_p_t call_button )  
{  
   UF_initialize();  
   uc1601("read data",1);  
      UF_terminate();  
   return UF_MB_CB_CONTINUE;  
}  
extern void ufsta( char *parm, int *returnCode, int rlen )  
{  
     /* Initialize the API environment */  
     UF_initialize();  
    UF_CALL(UF_MB_add_actions(action_table));  
     /* Terminate the API environment */  
     UF_terminate();  
}
  
我们做UG的二次开发,要调用UG的库函数,那么我们的二次开发程序就是调用者,UG是被调用者。上面为了响应菜单动作,我们写了一个函数,想点击菜单项时调用那个函数,这个函数是由UG调用的。这也是被调用者调用了调用者的功能的例子。
作者: 会思考的石头    时间: 2005-5-31 00:02
2.直接从C++对象的通信开始
两个人见面打招呼。
A问:吃了吗?
B答:嗯。吃过了。
  
就这么简单的一问一答。现在要讨论的问题不是关于吃饭的,而是使用C++怎样模拟这两个人对话。
  
作为一种面向对象的语言,自然想到要做构造两个对象来模拟对话者了。
在进行模拟时一定要考虑一下,对话中中隐含着一种情况,那就是A在向B打招呼时,就料定了B必须得回答,要不然B就不礼貌。
----------------------------------------------------------------------------
1.  构造两个类,A与B。
//----------------------------------------
//    类B
//----------------------------------------
class B
{
public:
   void Say(void)
   {  
     cout<<"B: 恩,吃了。"<<endl;
   }
};
  
//------------------------------------------
//    类A
//-------------------------------------------
class A
{
public:
   void Say(B *pb,void (B::*pf)(void))
   {  
     cout<<"A: 你吃了吗?"<<endl;
     (pb->*pf)();
   }
};
  
int main(void)
{
   A a;
   B b;
   a.Say([$b,&B::Say)]
  
   return 0;
}
  
程序执行结果:
A: 你吃了吗?
B:恩,吃了。
-----------------------------------------------------------------------------------------------
类B就不用多说啥了,很平常。
类A中的成员函数void Say( void (B::*pf)(void));
看上去怪怪的,void (B::*pf)(void)是声明pf为一个成员函数指针,可以指向类B中所有形如void func(void)的成员函数。
  
与C语言中的函数指针相似,只是加了个class name,再加上个域运算符就是了。使用了函数指针作为函数的参数,这在C程序设计中很常见,如果说不常见,那说明你浅薄,几天前我也很浅薄,认为这没啥用处。通常称pf指向的类B中的成员函数为回调函数。其实这儿不是回调,仅仅是同步调用。因为a对象并没有调用b对象,b对象也没有调用a对象。
  
意义:实现了两个C++对象的简单的通信。
更深的意义:可以把函数指针用于同一进程的两个模块间的通讯。
作者: 会思考的石头    时间: 2005-5-31 00:03
-----
作者: lijz    时间: 2005-5-31 11:09
good. go on
作者: 会思考的石头    时间: 2005-5-31 11:35
先不GO ON。
不知道有没有兄弟对下面的问题感兴趣。
  
把两个人的对话搞的稍微复杂一点,譬如:
A问:吃了吗?
B答:嗯。吃过了。
B问:你呢?吃了么?
A答:吃了。刚吃了一点,胃就胀,生活好也未必就是好事情,唉… …
  
依然利用C++来模拟,A问的时候,要求B回答。B问的时候,要求A回答。
如果真有兄弟感兴趣,就想想这个问题该怎么做,否则也没有GO ON 的必要了。
作者: gao264    时间: 2005-5-31 11:54
回调函数不就是用了个函数指针,把函数作为参数了嘛,是这个意思吧?怎么看你写的这么复杂啊??选择过滤的时候不就是用函数指针的吗!
作者: 会思考的石头    时间: 2005-5-31 12:43
同样是回调函数,但到了面向对象时代,它们摇身一变,就成了消息,事件了.
  
从面向对象的角度来看,世界是由对象组成的,我们所需求的功能是由对象间的协作来完成的。做面向对象的分析时,首先应定义出组成系统的一整套对象,然后描述这些对象如何协调在一起。这些描述可分为两部分。第一部分,必须理解和描述出不同对象之间的交互或通信,这些交互表现为对象之间的消息传递。第二部分,必须描述每个对象对于其它对象所发出的消息如何做出反应以及怎样发送消息给其它对象。
作者: 会思考的石头    时间: 2005-5-31 21:00
没心情写下去了。
  
好象许多兄弟认为会用OPEN API就是做二次开发了
作者: answer1977    时间: 2005-5-31 22:29
继续啊,既然是交流总是有人异议的嘛
作者: wgwang    时间: 2005-6-1 07:46
楼主写的很好啊,搬个凳子过来,请继续
作者: wenxiao_violet    时间: 2005-6-2 20:45
继续啊顶
作者: zzx001    时间: 2005-6-2 22:10
顶一个!!!支持楼主!!!




欢迎光临 iCAx开思工具箱 (https://t.icax.org/) Powered by Discuz! X3.3