鉤子函數聽起來很抽象,其實只要我們瞭解了回調函數,就好理解了,其實鉤子函數就是回調函數的特殊用法,
利用函數指針進行不同函數的調用,實現不同功能。
首先我們對函數指針的用法進行說明,例如,定義函數指針:
int (* g_pFun) (int x, int y);
有兩個函數:
/*返回兩個參數中的最大值、最小值*/
int Max(int x, int y){ }
int Min(int x, int y){ }
int main(int argc, char* argv[])
{
int r;
/*我們讓函數指針先後指向不同的函數*/
int a = 10;
int b = 15;
g_pFun = Max;//函數指針的調用
r= g_pFun(a, b); /*相當於執行函數Max*/
printf("%d\n", r);
g_pFun = Min;
r= g_pFun(a, b); /*相當於執行函數Min*/
printf("%d\n", r);
return 0;
}
分別輸出:15、10
這樣,同樣調用g_fun ,兩次卻完成不同的功能,神奇吧?這就是函數指針的妙用。
Max,Min函數就是鉤子函數了,把函數指針g_pFun指向函數Max,Min的過程,就是“掛鉤子”的過程,把鉤子函數“掛”到函數指針上,很形象。
有人可能有疑問,那麼這裏爲什麼不直接調用Max和Min函數呢?
這是因爲,我們在寫main函數的時候,可能還不知道它會完成什麼功能,這時候留下函數指針作爲接口,可以掛上不同的函數完成不同的功能,究竟執行什麼功能由鉤子函數的編寫者完成。
那我們平時怎麼用的呢?在我們的代碼中,常常把掛鉤子的過程叫做註冊,會提供一個註冊函數,讓使用者把自己編寫的鉤子函數掛在已經聲明的函數指針上,這個註冊函數的參數就是我們的函數指針了,比如,我們可以給剛纔的函數指針提供一個註冊函數:
int RegFun( int (* pFun)(int x, int y) ) /*註冊函數的參數是函數指針*/
{
g_pFun = pFun;
return 0;
}
調用RegFun(Max)和RegFun(Min),就可以把鉤子函數掛上去了。
注意:爲了便於使用,函數指針往往被聲明爲全局變量,這也是剛纔把函數指針的名字命名爲g_pFun的原因。
下面我們來進行一下實戰演習,比如,平臺部分要執行某一個操作,但是具體的操作還不確定,我們完成這樣的代碼:
int (* g_pFun) (int x, int y); /*函數指針*/
int Plat()
{
int r;
int a = 10;
int b = 15;
r= g_pFun(a, b); /*這裏要做一個操作,但是具體的操作還不確定*/
printf("%d\n", r);
return 0;
}
另外,平臺部分再提供一個註冊函數:
int RegFun(int (* pFun)(int x, int y))
{
g_pFun = pFun;
return 0;
}
應用模塊完成具體的函數的功能:
int Max(int x, int y)
{
if(x>y)
return x;
else
return y;
}
int Min(int x, int y)
{
if(x<y)
return x;
else
return y;
}
因爲應用模塊無法修改平臺的代碼,只能調用平臺提供的註冊函數:
如果應用模塊註冊:
RegFun(Max);
則運行 main 函數時,輸出:15
如果應用模塊註冊:
RegFun(Min)
運行 main 函數時,輸出:10
這樣,平臺部分無需修改任何代碼,只是應用模塊註冊了不同的鉤子函數,就能夠完成不同的功能,這就是鉤子函數的妙用。