回調(diào)函數(shù)的概念及其使用_第1頁(yè)
回調(diào)函數(shù)的概念及其使用_第2頁(yè)
回調(diào)函數(shù)的概念及其使用_第3頁(yè)
回調(diào)函數(shù)的概念及其使用_第4頁(yè)
回調(diào)函數(shù)的概念及其使用_第5頁(yè)
已閱讀5頁(yè),還剩4頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、回調(diào)函數(shù)的概念及其使用1 什么是回調(diào) 軟件模塊之間總是存在著一定的接口,從調(diào)用方式上,可以把他們分為三類(lèi):同步調(diào)用、回調(diào)和異步調(diào)用。同步調(diào)用是一種阻塞式調(diào)用,調(diào)用方要等待對(duì)方執(zhí)行完畢才返回,它是一種單向調(diào)用;回調(diào)是一種雙向調(diào)用模式,也就是說(shuō),被調(diào)用方在接口被調(diào)用時(shí)也會(huì)調(diào)用對(duì)方的接口;異步調(diào)用是一種類(lèi)似消息或事件的機(jī)制,不過(guò)它的調(diào)用方向剛好相反,接口的服務(wù)在收到某種訊息或發(fā)生某種事件時(shí),會(huì)主動(dòng)通知客戶(hù)方(即調(diào)用客戶(hù)方的接口)?;卣{(diào)和異步調(diào)用的關(guān)系非常緊密,通常我們使用回調(diào)來(lái)實(shí)現(xiàn)異步消息的注冊(cè),通過(guò)異步調(diào)用來(lái)實(shí)現(xiàn)消息的通知。同步調(diào)用是三者當(dāng)中最簡(jiǎn)單的,而回調(diào)又常常是異步調(diào)用的基礎(chǔ),因此,下面我們著

2、重討論回調(diào)機(jī)制在不同軟件架構(gòu)中的實(shí)現(xiàn)。 對(duì)于不同類(lèi)型的語(yǔ)言(如結(jié)構(gòu)化語(yǔ)言和對(duì)象語(yǔ)言)、平臺(tái)(Win32、JDK)或構(gòu)架(CORBA、DCOM、WebService),客戶(hù)和服務(wù)的交互除了同步方式以外,都需要具備一定的異步通知機(jī)制,讓服務(wù)方(或接口提供方)在某些情況下能夠主動(dòng)通知客戶(hù),而回調(diào)是實(shí)現(xiàn)異步的一個(gè)最簡(jiǎn)捷的途徑。 對(duì)于一般的結(jié)構(gòu)化語(yǔ)言,可以通過(guò)回調(diào)函數(shù)來(lái)實(shí)現(xiàn)回調(diào)?;卣{(diào)函數(shù)也是一個(gè)函數(shù)或過(guò)程,不過(guò)它是一個(gè)由調(diào)用方自己實(shí)現(xiàn),供被調(diào)用方使用的特殊函數(shù)。 在面向?qū)ο蟮恼Z(yǔ)言中,回調(diào)則是通過(guò)接口或抽象類(lèi)來(lái)實(shí)現(xiàn)的,我們把實(shí)現(xiàn)這種接口的類(lèi)成為回調(diào)類(lèi),回調(diào)類(lèi)的對(duì)象成為回調(diào)對(duì)象。對(duì)于象C+或Object P

3、ascal這些兼容了過(guò)程特性的對(duì)象語(yǔ)言,不僅提供了回調(diào)對(duì)象、回調(diào)方法等特性,也能兼容過(guò)程語(yǔ)言的回調(diào)函數(shù)機(jī)制。 Windows平臺(tái)的消息機(jī)制也可以看作是回調(diào)的一種應(yīng)用,我們通過(guò)系統(tǒng)提供的接口注冊(cè)消息處理函數(shù)(即回調(diào)函數(shù)),從而實(shí)現(xiàn)接收、處理消息的目的。由于Windows平臺(tái)的API是用C語(yǔ)言來(lái)構(gòu)建的,我們可以認(rèn)為它也是回調(diào)函數(shù)的一個(gè)特例。 對(duì)于分布式組件代理體系CORBA,異步處理有多種方式,如回調(diào)、事件服務(wù)、通知服務(wù)等。事件服務(wù)和通知服務(wù)是CORBA用來(lái)處理異步消息的標(biāo)準(zhǔn)服務(wù),他們主要負(fù)責(zé)消息的處理、派發(fā)、維護(hù)等工作。對(duì)一些簡(jiǎn)單的異步處理過(guò)程,我們可以通過(guò)回調(diào)機(jī)制來(lái)實(shí)現(xiàn)。 下面我們集中比較具有

4、代表性的語(yǔ)言(C、Object Pascal)和架構(gòu)(CORBA)來(lái)分析回調(diào)的實(shí)現(xiàn)方式、具體作用等。 2 過(guò)程語(yǔ)言中的回調(diào)(C) 2.1 函數(shù)指針 回調(diào)在C語(yǔ)言中是通過(guò)函數(shù)指針來(lái)實(shí)現(xiàn)的,通過(guò)將回調(diào)函數(shù)的地址傳給被調(diào)函數(shù)從而實(shí)現(xiàn)回調(diào)。因此,要實(shí)現(xiàn)回調(diào),必須首先定義函數(shù)指針,請(qǐng)看下面的例子: void Func(char *s);/ 函數(shù)原型void (*pFunc) (char *);/函數(shù)指針可以看出,函數(shù)的定義和函數(shù)指針的定義非常類(lèi)似。 一般的化,為了簡(jiǎn)化函數(shù)指針類(lèi)型的變量定義,提高程序的可讀性,我們需要把函數(shù)指針類(lèi)型自定義一下。 typedef void(*pcb)(char *);回調(diào)函

5、數(shù)可以象普通函數(shù)一樣被程序調(diào)用,但是只有它被當(dāng)作參數(shù)傳遞給被調(diào)函數(shù)時(shí)才能稱(chēng)作回調(diào)函數(shù)。 被調(diào)函數(shù)的例子:void GetCallBack(pcb callback)/*do something*/用戶(hù)在調(diào)用上面的函數(shù)時(shí),需要自己實(shí)現(xiàn)一個(gè)pcb類(lèi)型的回調(diào)函數(shù):void fCallback(char *s) /* do something */ 然后,就可以直接把fCallback當(dāng)作一個(gè)變量傳遞給GetCallBack,GetCallBack(fCallback);如果賦了不同的值給該參數(shù),那么調(diào)用者將調(diào)用不同地址的函數(shù)。賦值可以發(fā)生在運(yùn)行時(shí),這樣使你能實(shí)現(xiàn)動(dòng)態(tài)綁定。 回頁(yè)首 2.2 參數(shù)傳遞規(guī)

6、則 到目前為止,我們只討論了函數(shù)指針及回調(diào)而沒(méi)有去注意ANSI C/C+的編譯器規(guī)范。許多編譯器有幾種調(diào)用規(guī)范。如在Visual C+中,可以在函數(shù)類(lèi)型前加_cdecl,_stdcall或者_(dá)pascal來(lái)表示其調(diào)用規(guī)范(默認(rèn)為_(kāi)cdecl)。C+ Builder也支持_fastcall調(diào)用規(guī)范。調(diào)用規(guī)范影響編譯器產(chǎn)生的給定函數(shù)名,參數(shù)傳遞的順序(從右到左或從左到右),堆棧清理責(zé)任(調(diào)用者或者被調(diào)用者)以及參數(shù)傳遞機(jī)制(堆棧,CPU寄存器等)。 將調(diào)用規(guī)范看成是函數(shù)類(lèi)型的一部分是很重要的;不能用不兼容的調(diào)用規(guī)范將地址賦值給函數(shù)指針。例如: / 被調(diào)用函數(shù)是以int為參數(shù),以int為返回值_st

7、dcall int callee(int); / 調(diào)用函數(shù)以函數(shù)指針為參數(shù)void caller( _cdecl int(*ptr)(int); / 在p中企圖存儲(chǔ)被調(diào)用函數(shù)地址的非法操作_cdecl int(*p)(int) = callee; / 出錯(cuò)指針p和callee()的類(lèi)型不兼容,因?yàn)樗鼈冇胁煌恼{(diào)用規(guī)范。因此不能將被調(diào)用者的地址賦值給指針p,盡管兩者有相同的返回值和參數(shù)列 2.3 應(yīng)用舉例 C語(yǔ)言的標(biāo)準(zhǔn)庫(kù)函數(shù)中很多地方就采用了回調(diào)函數(shù)來(lái)讓用戶(hù)定制處理過(guò)程。如常用的快速排序函數(shù)、二分搜索函數(shù)等。 快速排序函數(shù)原型:void qsort(void *base, size_t nele

8、m, size_t width, int (_USERENTRY *fcmp)(const void *, const void *);二分搜索函數(shù)原型:void *bsearch(const void *key, const void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *);其中fcmp就是一個(gè)回調(diào)函數(shù)的變量。 下面給出一個(gè)具體的例子: #include #include int sort_function( const void *a, const void

9、*b);int list5 = 54, 21, 11, 67, 22 ;int main(void) int x; qsort(void *)list, 5, sizeof(list0), sort_function); for (x = 0; x 5; x+) printf(%in, listx); return 0;int sort_function( const void *a, const void *b) return *(int*)a-*(int*)b;3 面向?qū)ο笳Z(yǔ)言中的回調(diào)(Delphi) Dephi與C+一樣,為了保持與過(guò)程語(yǔ)言Pascal的兼容性,它在引入面向?qū)ο髾C(jī)制的同時(shí)

10、,保留了以前的結(jié)構(gòu)化特性。因此,對(duì)回調(diào)的實(shí)現(xiàn),也有兩種截然不同的模式,一種是結(jié)構(gòu)化的函數(shù)回調(diào)模式,一種是面向?qū)ο蟮慕涌谀J健?3.1 回調(diào)函數(shù) 回調(diào)函數(shù)類(lèi)型定義: type TCalcFunc=function (a:integer;b:integer):integer;按照回調(diào)函數(shù)的格式自定義函數(shù)的實(shí)現(xiàn),如function Add(a:integer;b:integer):integerbegin result:=a+b;end;function Sub(a:integer;b:integer):integerbegin result:=a-b;end;回調(diào)的使用function Calc(

11、calc:TcalcFunc;a:integer;b:integer):integer下面,我們就可以在我們的程序里按照需要調(diào)用這兩個(gè)函數(shù)了c:=calc(add,a,b);/c=a+bc:=calc(sub,a,b);/c=a-b3.2 回調(diào)對(duì)象 什么叫回調(diào)對(duì)象呢,它具體用在哪些場(chǎng)合?首先,讓我們把它與回調(diào)函數(shù)對(duì)比一下,回調(diào)函數(shù)是一個(gè)定義了函數(shù)的原型,函數(shù)體則交由第三方來(lái)實(shí)現(xiàn)的一種動(dòng)態(tài)應(yīng)用模式。要實(shí)現(xiàn)一個(gè)回調(diào)函數(shù),我們必須明確知道幾點(diǎn):該函數(shù)需要那些參數(shù),返回什么類(lèi)型的值。同樣,一個(gè)回調(diào)對(duì)象也是一個(gè)定義了對(duì)象接口,但是沒(méi)有具體實(shí)現(xiàn)的抽象類(lèi)(即接口)。要實(shí)現(xiàn)一個(gè)回調(diào)對(duì)象,我們必須知道:它需要實(shí)

12、現(xiàn)哪些方法,每個(gè)方法中有哪些參數(shù),該方法需要放回什么值。 因此,在回調(diào)對(duì)象這種應(yīng)用模式中,我們會(huì)用到接口。接口可以理解成一個(gè)定義好了但是沒(méi)有實(shí)現(xiàn)的類(lèi),它只能通過(guò)繼承的方式被別的類(lèi)實(shí)現(xiàn)。Delphi 中的接口和COM接口類(lèi)似,所有的接口都繼承與IInterface(等同于IUnknow),并且要實(shí)現(xiàn)三個(gè)基本的方法QueryInterface, _AddRef, 和_Release。 定義一個(gè)接口 type IShape=interface(IInterface)procedure Draw;end實(shí)現(xiàn)回調(diào)類(lèi) type TRect=class(TObject,IShape)protected fu

13、nction QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall;function _Release: Integer; stdcall; public procedure Draw;end;type TRound=class(TObject,IShape)protected function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Int

14、eger; stdcall;function _Release: Integer; stdcall; public procedure Draw;end;使用回調(diào)對(duì)象 procedure MyDraw(shape:IShape);var shape:IShape;beginshape.Draw; end;如果傳入的對(duì)象為T(mén)Rect,那么畫(huà)矩形;如果為T(mén)Round,那么就為圓形。用戶(hù)也可以按照自己的意圖來(lái)實(shí)現(xiàn)IShape接口,畫(huà)出自己的圖形: MyDraw(Trect.Create);MyDraw(Tround.Create);3.3 回調(diào)方法 回調(diào)方法(Callback Method)可以看作

15、是回調(diào)對(duì)象的一部分,Delphi對(duì)windows消息的封裝就采用了回調(diào)方法這個(gè)概念。在有些場(chǎng)合,我們不需要按照給定的要求實(shí)現(xiàn)整個(gè)對(duì)象,而只要實(shí)現(xiàn)其中的一個(gè)方法就可以了,這是我們就會(huì)用到回調(diào)方法。 回調(diào)方法的定義如下:TNotifyEvent = procedure(Sender: TObject) of object; TMyEvent=procedure(Sender:Tobject;EventId:Integer) of object;TNotifyEvent 是Delphi中最常用的回調(diào)方法,窗體、控件的很多事件,如單擊事件、關(guān)閉事件等都是采用了TnotifyEvent。回調(diào)方法的變量一

16、般通過(guò)事件屬性的方式來(lái)定義,如TCustomForm的創(chuàng)建事件的定義: property OnCreate: TNotifyEvent read FOnCreate write FOnCreate stored IsForm;我們通過(guò)給事件屬性變量賦值就可以定制事件處理器。用戶(hù)定義對(duì)象(包含回調(diào)方法的對(duì)象):type TCallback=Class procedure ClickFunc(sender:TObject);end;procedure Tcallback.ClickFunc(sender:TObject);begin showmessage(the caller is clicke

17、d!);end;窗體對(duì)象:type TCustomFrm=class(TForm) publicprocedure RegisterClickFunc(cb:procedure(sender:Tobject) of object);end;procedure TcustomFrm.RegisterClickFunc(cb:TNotifyEvent);begin self.OnClick=cb;end;使用方法:var frm:TcustomFrm;begin frm:=TcustomFrm.Create(Application); frm.RegisterClickFunc(Tcallback

18、.Create().ClickFunc);end; 4 回調(diào)在分布式計(jì)算中的應(yīng)用(CORBA) 4.1 回調(diào)接口模型 CORBA的消息傳遞機(jī)制有很多種,比如回調(diào)接口、事件服務(wù)和通知服務(wù)等。回調(diào)接口的原理很簡(jiǎn)單,CORBA客戶(hù)和服務(wù)器都具有雙重角色,即充當(dāng)服務(wù)器也是客戶(hù)客戶(hù)。 回調(diào)接口的反向調(diào)用與正向調(diào)用往往是同時(shí)進(jìn)行的,如果服務(wù)端多次調(diào)用該回調(diào)接口,那么這個(gè)回調(diào)接口就變成異步接口了。因此,回調(diào)接口在CORBA中常常充當(dāng)事件注冊(cè)的用途,客戶(hù)端調(diào)用該注冊(cè)函數(shù)時(shí),客戶(hù)函數(shù)就是回調(diào)函數(shù),在此后的調(diào)用中,由于不需要客戶(hù)端的主動(dòng)參與,該函數(shù)就是實(shí)現(xiàn)了一種異步機(jī)制。 從CORBA規(guī)范我們知道,一個(gè)CORBA接口在服務(wù)端和客戶(hù)端有不同的表現(xiàn)形式,在客戶(hù)端一般使用樁(Stub)文件,服務(wù)端則用到框架(Skeleton)文件,接口的規(guī)格采用IDL來(lái)定義。而回調(diào)函數(shù)的引入,使得服務(wù)端和客戶(hù)端都需要實(shí)現(xiàn)一定的樁和框架。下面是回調(diào)接口的實(shí)現(xiàn)模型: 4.1.1 范例 下面給出了一個(gè)使用回調(diào)的接口文件,服務(wù)端需要實(shí)現(xiàn)Server接口的框架,客戶(hù)端需要實(shí)現(xiàn)CallBack的框架:module cbinterface CallBack;interface Server

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論