1. 程式人生 > >小白學習回撥函式

小白學習回撥函式

見到有一篇文章講的挺好的回撥函式
下面是內容:

回撥函式

回撥函式是一個時時聽到的概念,比如在windows API程式設計時遇到的WinProc函式,就是我們編寫而由作業系統呼叫的函式。現在,我們需要慢慢又詳細的記錄一下這個問題。

庫與使用者的問題

在開始之前,首先我們想像這樣一個情景,一個大型軟體公司開發一套軟體庫提供給使用者使用。在這句話中,出現兩個對立面,一個是軟體公司,一個是使用者。顯然,軟體公司實力很強大,他們強大的地方在於他們很聰明。請看下圖:
在這裡插入圖片描述
庫開發者是提供方,他們不知道使用者想做什麼,庫開發者對使用者的資訊是未知的,因為兩邊的人誰也沒見過誰,就像一個人在美國一個人在中國。他們聰明的地方就在於即使不知道使用者怎麼操作,他們也可以用一種通用的方法來解決使用者的問題。換句話說,庫開發方不管使用者怎麼折騰變化,他都能適應。這就是問題的神奇之處,當然,為了達到這種效果,必須有一種規則來約束。

規則

現在來說規則,規則比較好理解,就是兩方達成的約束。比如甲和乙兩個人,甲對乙說,你只要提供給我一個塑料球,我都能給它塗上顏色。這裡的約束是塑料球,(當然,為了簡化問題這裡的約束還是比較泛泛而不嚴謹的),這個時候如果乙給他一個水晶球,或者給他一輛汽車都不行,因為已經超越了約束。所以說,庫開發者能適應使用者的各種變化就在於他也給了使用者一定的約束,是在約束之下的適應,這也是不言自明的。

程式碼之下無祕密

下面一段程式碼極好的解釋了上述問題:

#include <stdio.h>

typedef int student_id;
typedef int student_age;
typedef struct _Student{ student_id id; student_age age; }Student; //型別重定義:函式指標型別 typedef bool (*pFun)(Student, Student); //----------------------------------------------- //氣泡排序法:能夠按AGE或ID排序,用同一個函式實現 //----------------------------------------------- void sort(Student stu[],const int num,pFun fun)
{ Student temp; for(int i = 0; i < num; ++i)   { for(int j = 0; j < num - i -1; ++j) { if((*fun)(stu[j],stu[j+1])) { temp = stu[j]; stu[j] = stu[j+1]; stu[j+1] = temp; } } } } //----------------------------------------------- //回撥函式:比較年齡 //----------------------------------------------- bool CompareAge(Student stu1,Student stu2) { //更改從大到小還是從小到大的順序,只需反一下。 if(stu1.age < stu2.age) return true; return false; } //----------------------------------------------- //回撥函式:比較id //----------------------------------------------- bool CompareId(Student stu1,Student stu2) { //更改從大到小還是從小到大的順序,只需反一下。 if(stu1.id < stu2.id) return true; return false; } int main() { Student stu[] = { {1103,24}, {1102,23}, {1104,22}, {1107,25}, {1105,21}}; pFun fun = CompareAge; int size = sizeof(stu)/sizeof(Student); sort(stu,size,fun); for(int i = 0; i < size; ++i){ printf("%d %d\n",stu[i].id,stu[i].age); } return 0; }

通過程式碼,我們必須分辨出哪個是庫提供方,哪個是使用者:
在這裡插入圖片描述
sort(…)方法是庫開者提供的,只是因為模擬問題所以把它寫在一個檔案中了,我們可以假想它存放在某個靜態庫lib裡面,這樣就和它有了界限。

庫開發者提供方法sort(…)供我們呼叫,形參裡面還包括一個函式指標,就是呼叫使用者自己寫的函式,也即回撥函式。所以它提供了規則,也就是說這個回撥函式的形參是什麼,返回值又是什麼,假如使用者對於這個回撥函式的形參和返回值啥都不知道,隨意寫了一個函式放進去,sort方法能接受嗎?顯然是不行的。

那麼使用者怎麼知道回撥函式的形參和返回值等資訊呢?庫開發方會告知,或者在它的文件裡面會有說明,就像在windows API開發視窗程式時提供的WinProc() 函式一樣,裡面的形參必須一模一樣。(這個地方會牽涉到介面)

什麼是回?

根據上面的程式碼,我們知道,庫開發方提供了一個方法,然後形參又帶有一個函式指標,等著使用者去寫然後拿來呼叫,並在其實現中呼叫了這個函式。站在庫開發方的立場,我們可以總結為一句話:庫開發方呼叫了使用者的函式(回撥函式)。

現在,我們把視角移到回撥函式的立場上來看,它被呼叫了。但同時它也有引數,且傳進來的引數是庫開發方提供的資料,這裡我們又可以總結一句話:回撥函式呼叫了庫開發方的資料。

這就是“回”的意思,你調我我也呼叫你,雙方互相呼叫。在這裡插入圖片描述