第一次在項目中接觸函數指針,以前都是在書本上看到,而且幾乎沒有用到過,具體怎麼用的完全不知道,今天大概的學習了一下,做出了如下的總結:
首先函數指針的聲明
void (*p)();//p是指向某函數的指針,不是一般的指針
該函數無輸入參數,返回值的類型為void
下面定義主調函數
void caller(void(*ptr)()) { //do something }
注意這個主調函數的形參,形參是一個函數指針,也就是說在調用的時候需要把另外一個函數的函數名或者地址傳遞給caller
下面定義回調函數
void func() { //這裡的回調函數就是一個普通的函數就行了 }
下面看實現
int main(int argc, int char *argv[]) { caller(func); //這裡把func()的函數名也就是函數的地址傳遞給caller,那麼caller裡面就 //能使用func這個函數了,具體怎麼用就要看你的func是怎麼寫了! }
好了,下面看大型的工程裡面是如何使用這些功能的吧
首先聲明一種指針類型,這種指針是能夠指向函數的指針
typedef bool (CALLBACK * LoadLibraryExFailCallBack)(const std::wstring &path, int stage) 這裡聲明了一種叫LoadLibraryExFailCallBack類型的函數指針,CALLBACK最後通過宏定義發現是__stdcall一種由調用者清理內存的機制吧。
有了類型就可以定義指針變量了
LoadLibraryExFailCallBack g_callBack = NULL;
這裡用LoadLibraryExFailCallBack類型定義了變量g_callBack並對其初始化,防止指針亂指
下面是主調函數的聲明
void __declspec InstallLoadLibraryExFailCallBack(LoadLibraryExFailCallBack callback);
注意到這個函數的參數了嗎,是的,這個參數是一個函數指針類型的,要求你傳遞一個函數指針進來才能干活!
下面是這個函數的實現
void InstallLoadLibraryExFailCallBack(LoadLibraryExFailCallBack callback) { g_callBack = callback; }
這是鬧哪樣啊,傳進來了你又不用,原因是g_callBack是底層代碼留給上層的一個接口,表示你可以用這樣的方式去實現你想要實現的東西,但是不允許你在我底層的代碼做任何改動,腫麼辦,那就是好好利用這個g_callBack函數指針,你給它什麼地址它就能給你干什麼活,你讓它去醫院,它就是醫生和護士,你讓它去學校,它就是老師和學生,總之,這個東西有了,什麼都可以在上層實現,然後把地址給g_callBack,g_callBack就能在底層看著上層干活了!
是不是很奇葩啊!
下面看是如何奇葩的
首先在上層定義回調函數,
bool __stdcall LoadLibraryMsgCallBack(const std::wstring &path int stage)
這個函數式用來實現上層的功能的,換個名字,再寫一個,能夠實現你想要實現的功能,這裡就不具體寫出回調函數的定義了,隨便寫什麼都行。
下面看主調函數
InstallLoadLibraryExFailCallBack(LoadLibraryMsgCallBack)
好的,把函數名給底層函數接口,雖然在InstallLoadLibraryExFailCallBack函數中可以使用LoadLibraryMsgCallBack函數,但是這裡只做一個轉換,把上層的函數地址傳給底層的函數指針,至於底層什麼時候想用,那就可以隨意調用了,只要你InstallLoadLibraryExFailCallBack了就可以在底層使用g_callBack(path, stage)就可以用了。
如果你要是另外定義回調函數,隨便寫一個
void __stdcall ReadMsgCallBack(const std::wstring &path)
好了,先InstallLoadLibraryExFailCallBack(ReadMsgCallBack);一下,表示這個函數的地址已經被傳到底層的g_callBack中去了,下面就可以在底層g_callBack(path)這樣來調用這個上層的功能了,是不是很強大的函數指針。
本文出自 “賣萌程序員” 博客,轉載請與作者聯系!