轉載於:http://blog.csdn.net/vlily/article/details/7244682
轉載於:http://blog.csdn.net/shengnan_wu/article/details/8116935
轉載於:http://blog.csdn.net/callmeback/article/details/4242260/
轉載於:https://blog.csdn.net/initiallysunny/article/details/53708466
C++中一個函數作爲作爲另一個函數的參數:
把函數名作爲參數就是函數的地址了.
要將函數名作爲參數,需要使用函數指針。
函數指針的定義格式爲
ret_type (*var_name)(arg_list);
表示返回值爲ret_type,參數列表爲arg_list的函數指針var_name.
如
int (*p)(int,int);
表示返回值爲int,參數爲兩個int型的函數指針p。
以函數指針作爲形參,即可實現函數名作爲參數,由另一個函數調用。
一、 定義某一函數的指針類型:
就像自定義數據類型一樣,我們也可以先定義一個函數指針類型,然後再用這個類型來申明函數指針變量。
我先給你一個自定義數據類型的例子。
typedef int* PINT; //爲int* 類型定義了一個PINT的別名
int main()
{
int x;
PINT px=&x; //與int * px=&x;是等價的。PINT類型其實就是int * 類型
*px=10; //px就是int*類型的變量
return 0;
}
根據註釋,應該不難看懂吧!(雖然你可能很少這樣定義使用,但以後學習Win32編程時會經常見到的。)
下面我們來看一下函數指針類型的定義及使用:(請與上對照!)
//自行包含頭文件
void MyFun(int x); //此處的申明也可寫成:void MyFun( int );
typedef void (*FunType)(int ); //這樣只是定義一個函數指針類型
FunType FunP; //然後用FunType類型來申明全局FunP變量
int main(int argc, char* argv[])
{
//FunType FunP; //函數指針變量當然也是可以是局部的 ,那就請在這裏申明瞭。
MyFun(10);
FunP=&MyFun;
(*FunP)(20);
return 0;
}
void MyFun(int x)
{
printf(“%d\n”,x);
}
看黑體部分:
首先,在void (*FunType)(int ); 前加了一個typedef 。這樣只是定義一個名爲FunType函數指針類型,而不是一個FunType變量。
然後,FunType FunP; 這句就如PINT px;一樣地申明一個FunP變量。
其它相同。整個程序完成了相同的事。
這樣做法的好處是:
有了FunType類型後,我們就可以同樣地、很方便地用FunType類型來申明多個同類型的函數指針變量了。如下:
FunType FunP2;
FunType FunP3;
//……
二、 函數指針作爲某個函數的參數
既然函數指針變量是一個變量,當然也可以作爲某個函數的參數來使用的。所以,你還應知道函數指針是如何作爲某個函數的參數來傳遞使用的。
給你一個實例:
要求:我要設計一個CallMyFun函數,這個函數可以通過參數中的函數指針值不同來分別調用MyFun1、MyFun2、MyFun3這三個函數(注:這三個函數的定義格式應相同)。
實現:代碼如下:
//自行包含頭文件
void MyFun1(int x);
void MyFun2(int x);
void MyFun3(int x);
typedef void (*FunType)(int ); //②. 定義一個函數指針類型FunType,與①函數類型一至
void CallMyFun(FunType fp,int x);
int main(int argc, char* argv[])
{
CallMyFun(MyFun1,10); //⑤. 通過CallMyFun函數分別調用三個不同的函數
CallMyFun(MyFun2,20);
CallMyFun(MyFun3,30);
}
void CallMyFun(FunType fp,int x) //③. 參數fp的類型是FunType。
{
fp(x);//④. 通過fp的指針執行傳遞進來的函數,注意fp所指的函數是有一個參數的
}
void MyFun1(int x) // ①. 這是個有一個參數的函數,以下兩個函數也相同
{
printf(“函數MyFun1中輸出:%d\n”,x);
}
void MyFun2(int x)
{
printf(“函數MyFun2中輸出:%d\n”,x);
}
void MyFun3(int x)
{
printf(“函數MyFun3中輸出:%d\n”,x);
}
輸出結果:略
-
函數指針是指向函數的指針變量。c在編譯時,每一個函數都有一個入口地址,該入口地址就是函數指針指向的地址處。有了指向函數的指針變量後。可以通過該指針變量調用函數,函數指針有兩個用途:調用函數、做函數的參數:
-
調用函數,如下所示:
-
輸出結果如下:
由以上可以說明成功調用。
b.無參函數指針做參數的實現,如下(標準寫法)所示:
輸出結果如下:
還有以下寫法也能成功,因爲c語言標準規定可以這樣用:
也能成功輸出
c.帶參有返回值的函數指針做參數的
輸出結果如下:
而不能寫成如下所示:
也可寫成以下形式,其中涉及到函數指針類型的轉換:
2.函數指針數組的實用之處:當我們需要判斷大量條件的時候,並且在每一個條件都有相應的處理函數,這時實用switch...case..的代碼量會很大,並且效率會比較低,這個時候就可以使用函數指針數組來解決這個問題了,可以使用每個條件爲數組下表:如下所示:
結果如下
回調函數
1、基礎知識
所謂回調,就是模塊A要通過模塊B的某個函數b()完成一定的功能,但是函數b()自己無法實現全部功能,需要反過頭來調用模塊A中的某個函數a()來完成,這個a()就是回調函數。如下圖
①約定接口規範。在模塊B必須約定接口規範,也就是定義回調函數a()的函數原型
一開始是不好理解,用下面這個例子可能會有幫助:
諸葛亮(A)給趙子龍(B)一個錦囊(a()),吩咐他在幹活時(b())若遇到危急時打開按錦囊(a())指示辦, 錦囊裏的命令就是回調函數,危急時刻就是回調的時機。
不同的錦囊裏可以有不同的命令。
在看LWIP時,見到用回調函數,再看某老外公司OPC源代碼時,見到用回調函數。看我國內某些代碼(我公司軟件等)時沒用到。於是,我對回調函數產生了很大的好奇。以前,我寫VC程序時用到過回調函數,但是沒有用C語言來使用。最近,看到國外大量的經典代碼中廣泛使用了回調函數(LWIP、某兩個公司的OPC程序等),都是C語言來實現的,而不是VC windows程序中別人實現自己使用的那種。
爲了弄明白這種函數的奧妙,首先提出三個問題:
1. 回調函數是什麼東西?
2. 回調函數怎麼開發,怎麼使用?
3. 回調函數的作用,應該在什麼情況下使用?
帶着問題來學習,有目的!呵呵,個人經驗。
打開baidu.com、google.cn搜索了好多資料,如下:
順便提一下,某君的一個簽名很讓我佩服:1好好活着,因爲我們會死很久。2五千年的文明 兩百年的無奈
第一個問題:
*******************************************************************************
其實回調就是一種利用函數指針進行函數調用的過程.
爲什麼要用回調呢?比如我要寫一個子模塊給你用, 來接收遠程socket發來的命令.當我接收到命令後, 需要調用你的主模塊的函數, 來進行相應的處理.但是我不知道你要用哪個函數來處理這個命令, 我也不知道你的主模塊是什麼.cpp或者.h, 或者說, 我根本不用關心你在主模塊裏怎麼處理它, 也不應該關心用什麼函數處理它...... 怎麼辦?
使用回調!
—— lone wolf
使用回調函數實際上就是在調用某個函數(通常是API函數)時,將自己的一個函數(這個函數爲回調函數)的地址作爲參數傳遞給那個函數。而那個函數在需要的時候,利用傳遞的地址調用回調函數,這時你可以利用這個機會在回調函數中處理消息或完成一定的操作。
—— 某專家
回調函數,就是由你自己寫的。你需要調用另外一個函數,而這個函數的其中一個參數,就是你的這個回調函數名。這樣,系統在必要的時候,就會調用你寫的回調函數,這樣你就可以在回調函數裏完成你要做的事。
—— 綠葉
http://hi.baidu.com/zhuyipeng/blog/item/863fefdb7c736c63d1164eec.html 是一篇比較好的文章。
什麼是回調函數?
回調函數是應用程序提供給Windows系統DLL或其它DLL調用的函數,一般用於截獲消息、獲取系統信息或處理異步事件。應用程序把回調函數的地址指針告訴DLL,而DLL在適當的時候會調用該函數。回調函數必須遵守事先規定好的參數格式和傳遞方式,否則DLL一調用它就會引起程序或系統的崩潰。通常情況下,回調函數採用標準WindowsAPI的調用方式,即__stdcall,當然,DLL編制者可以自己定義調用方式,但客戶程序也必須遵守相同的規定。在__stdcall方式下,函數的參數按從右到左的順序壓入堆棧,除了明確指明是指針或引用外,參數都按值傳遞,函數返回之前自己負責把參數從堆棧中彈出。
理解回調函數!
—— jufengfeng
Function Pointers provide the concept of callback functions.
—— newty.de
*******************************************************************************
看了這麼多的資料,我只將每位的定義總結一下就一句話:回調函數就是函數指針的一種用法。
在部分資料上,大量討論了回調函數怎麼被調用,到底被誰調用,還有好多的圖形,我認爲都沒有看到問題的本質。
第二個問題:
*********************************************************************
我實現了一個很簡單的回調函數。
#include <stdio.h>
void printWelcome(int len)
{
printf("歡迎歡迎 -- %d/n", len);
}
void printGoodbye(int len)
{
printf("送客送客 -- %d/n", len);
}
void callback(int times, void (* print)(int))
{
int i;
for (i = 0; i < times; ++i)
{
print(i);
}
printf("/n我不知道你是迎客還是送客!/n/n");
}
void main(void)
{
callback(10, printWelcome);
callback(10, printGoodbye);
printWelcome(5);
}
*******************************************************************************
上面的代碼沒有被任何系統函數調用,說明那些東西只是撒撒土迷迷路人眼而已。還有面相對象編程時,用class給封裝起來也是掩人耳目,不要被外表所迷惑。
第三個問題:
*********************************************************************
用過STL的人都知道,在STL中衆多算法和程序都用到回調函數,這實現了一種策略。只要任何符合我的標準的函數和計算都可以用我這個公式。你可以實現各種各樣的回調函數,只要符合我的格式就能用。
就上面的程序來說,你只要函數格式符合cllback第二個參數的格式不論你給別人做飯、鋪牀疊被都可以正常工作。這就是回調的作用,把回調實現留給別人。
這是一個用法。
有一位朋友用分層的概念來解釋了回調機制:callback函數爲B層,main函數和print*函數爲A層,A層調用了B層的回調函數callmeback,而B層的回調函數調用了A層的實現函數print*。說白了B層就是一個接口。
這是我的理解。Over!