天天看點

回調函數和鈎子函數

什麼是回調函數? 

  簡而言之,回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(位址)作為參數傳遞給另一個函數,當這個指針被用為調用它所指向的函數時,我們就說這是回調函數。 

  為什麼要使用回調函數? 

  因為可以把調用者與被調用者分開。調用者不關心誰是被調用者,所有它需知道的,隻是存在一個具有某種特定原型、某些限制條件(如傳回值為 int )的被調用函數。 

  如果想知道回調函數在實際中有什麼作用,先假設有這樣一種情況,我們要編寫一個庫,它提供了某些排序算法的實作,如冒泡排序、快速排序、 shell 排序、 shake 排序等等,但為使庫更加通用,不想在函數中嵌入排序邏輯,而讓使用者來實作相應的邏輯;或者,想讓庫可用于多種資料類型( int 、 float 、 string ),此時,該怎麼辦呢?可以使用函數指針,并進行回調。 

  回調可用于通知機制,例如,有時要在程式中設定一個計時器,每到一定時間,程式會得到相應的通知,但通知機制的實作者對我們的程式一無所知。而此時,就需有一個特定原型的函數指針,用這個指針來進行回調,來通知我們的程式事件已經發生。實際上, settimer() api 使用了一個回調函數來通知計時器,而且,萬一沒有提供回調函數,它還會把一個消息發往程式的消息隊列。 

  另一個使用回調機制的 api 函數是 enumwindow() ,它枚舉螢幕上所有的頂層視窗,為每個視窗調用一個程式提供的函數,并傳遞視窗的處理程式。如果被調用者傳回一個值,就繼續進行疊代,否則,退出。 enumwindow() 并不關心被調用者在何處,也不關心被調用者用它傳遞的處理程式做了什麼,它隻關心傳回值,因為基于傳回值,它将繼續執行或退出。 

  不管怎麼說,回調函數是繼續自 c 語言的,因而,在 c++ 中,應隻在與 c 代碼建立接口,或與已有的回調接口打交道時,才使用回調函數。除了上述情況,在 c++ 中應使用虛拟方法或函數符( functor ),而不是回調函數。

什麼是鈎子函數?

     鈎子實際上是一個處理消息的程式段,通過系統調用,把它挂入系統。每當特定的消息發出,在沒有到達目的視窗前,鈎子程式就先捕獲該消息,亦即鈎子函數先得到控制權。這時鈎子函數即可以加工處理(改變)該消息,也可以不作處理而繼續傳遞該消息,還可以強制結束消息的傳遞。對每種類型的鈎子由系統來維護一個鈎子鍊,最近安裝的鈎子放在鍊的開始,而最先安裝的鈎子放在最後,也就是後加入的先獲得控制權。

也可以這樣,更容易了解:回調函數就好像是一個中斷處理函數,系統在符合你設定的條件時自動調用。為此,你需要做三件事:

1.       聲明;

2.       定義;

3.       設定觸發條件,就是在你的函數中把你的回調函數名稱轉化為位址作為一個參數,以便于系統調用。

聲明和定義時應注意:回調函數由系統調用,是以可以認為它屬于windows系統,不要把它當作你的某個類的成員函數

回調函數是一個程式員不能顯式調用的函數;通過将回調函數的位址傳給調用者進而實作調用。回調函數使用是必要的,在我們想通過一個統一接口實作不同的内容,這時用回掉函數非常合适。比如,我們為幾個不同的裝置分别寫了不同的顯示函數:void tvshow(); void computershow(); void notebookshow()...等等。這是我們想用一個統一的顯示函數,我們這時就可以用回掉函數了。void show(void (*ptr)()); 使用時根據所傳入的參數不同而調用不同的回調函數。

繼續閱讀