[爆卦]類別 函式指標是什麼?優點缺點精華區懶人包

為什麼這篇類別 函式指標鄉民發文收入到精華區:因為在類別 函式指標這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者SeamusBerloz (軒摩斯)看板C_and_CPP標題[討論] 取得結構或類別中函式成員...



其實很早就想貼出這段程式,其中程式寫了一段落了,卻一直擺著沒再去想他,
看到最近相關位址轉換議題討論熱烈,也貼出來給大家一個參考。

為什麼要取得結構或類別中定義的成員函式位址?
主要就是為了回呼 (callback),藉想能回呼到某物件或結構成員函式上去。

callback 實在是大型模組化程式中,相當方便模組間階層組合的設計方案之一。
將主程序中的某個函式位址,傳遞給某一個處理模組,當該模組處理出現某狀態,
可以透過所傳遞的函式位址,直接呼叫主程序,告知該模組發生了什麼事。

好,誠如前面所說的,若確定一定得要傳遞某結構或類別的成員函式,
也就是說,將模組的運作通知直接由該成員函式接手,怎辦?
我想第一步驟就是得先正確取得成員函式位址,於是,我做了以下實驗。

(程式焦點將集中在取得成員函式指標,所以請恕刪減回呼實作的部份)

平台:slackware 14.0,
編譯器:gcc version 4.7.1
編譯指令:g++ -o test test.cpp

<< test.cpp >>
/* 檔案開始 */
#include <stdio.h>
/* 模組中所定義的回呼函式原型 */
typedef void (* MYCALLBACKFUNCTION)(int);
/* 某結構 */
struct MyStructure
{
void MyFunction(int iResult)
{
printf("Result = 0x%08X\n", iResult);
}
};
/* 實驗處理程序 */
int main(void)
{
/* 回呼函數指標 */
MYCALLBACKFUNCTION pMyCallbackFunction = NULL;
/* 取得成員函數位址 */
void (MyStructure::*pMyFunction)(int) = &MyStructure::MyFunction;

/* 轉成空指標 */
/* 嘗試方法一:void * 轉型,有警告 */
void *pPointer = (void *)pMyFunction;

/* 嘗試方法二:硬轉,一樣有警告 */
void *pPointer = reinterpret_cast <void *> (pMyFunction);
// 以上警告訊息都是:
// 從「void (MyStructure::*)(int, int)」
// 轉換到 「void*」[-Wpmf-conversions]

/* 嘗試方法三:網路上查到的一個方法 */
void *pPointer = (void *&)pMyFunction;
// 啥?編譯器安靜了?!有興趣的大大們可否勞煩提供原因嗎?

/* 轉成函數指標,準備稍候傳遞給模組 */
pMyCallbackFunction = (MYCALLBACKFUNCTION)pPointer;

/* 那麼,所有位址列印一下看看 */
printf("pMyCallbackFunction => 0x%08X\n", pMyCallbackFunction);
printf("pPointer => 0x%08X\n", pPointer);
printf("pMyFunction => 0x%08X\n", pMyFunction);
printf("&MyStructure::MyFunction => 0x%08X\n", &MyStructure::MyFunction);

/* 呼叫?結果正確嗎? */
pMyCallbackFunction((int)pPointer);

return 0;
}
/* 檔案結束 */

上述程式碼中三種轉 void *pPointer 方法都各自編譯後執行。
其中 void *pPointer = (void *)pMyFunction; 方法的執行結果:

pMyCallbackFunction => 0x08048678
pPointer => 0x08048678
pMyFunction => 0x08048678
&MyStructure::MyFunction => 0x08048678
Result = 0x08048678

然後是...
void *pPointer = reinterpret_cast <void *> (pMyFunction); 方法的執行結果:

pMyCallbackFunction => 0x08048678
pPointer => 0x08048678
pMyFunction => 0x08048678
&MyStructure::MyFunction => 0x08048678
Result = 0x08048678

最後是...
void *pPointer = (void *&)pMyFunction; 方法的執行結果:

pMyCallbackFunction => 0x08048656
pPointer => 0x08048656
pMyFunction => 0x08048656
&MyStructure::MyFunction => 0x08048656
Result = 0x08048656

也給大家參考一下,這個關於成員函式位址轉換實錄。
但是,當關於使用回呼,我還是照老方法,回呼到一般的函式上。

因為我發現這個程式中 MYCALLBACKFUNCTION 當修改想傳遞兩個以上的參數時,
此時就出現問題了,成員函式所接收參數值全部亂掉,我想大概是參數順序的問題,
但就算嘗試想設 __stdcall 或 __cdecl 在結構中成員函式敘述上,
也不確定怎麼寫才對,因為再來牽涉的語法實在也不是非常熟。

自此之後,乾脆取居中的作法,結構中放置的是函式指標,拿去指向一般函式,
然後再來把該函式指標送交給模組去呼叫算了。

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 123.240.167.99
SeamusBerloz:這篇似乎貼得太晚,大家都舉出相當多的實例了... 08/27 23:10
LPH66:嘛, 也就是因為這樣搞麻煩一堆所以才有 std::function 08/27 23:14
littleshan:參數值當然會亂掉,因為成員函式有一個隱藏的參數this 08/27 23:14
LPH66:就只是把這些東西包成一個 functor 拿來用而已 08/27 23:14
littleshan:「成員函式非函式,有個參數叫this」麻煩默念十次 08/27 23:15
SeamusBerloz:押韻耶!...函式,...this ...函式,...this ...函 08/27 23:26
SeamusBerloz:式,...this 呼呼...函式,...this ...函式,...this 08/27 23:26
SeamusBerloz: ...函式,...this! 08/27 23:26
Feis:大舌頭喔~ 08/27 23:27
SeamusBerloz:呵呵,看到好東西,趕快好好記住先呀~ 08/27 23:39
descent:(void *&)pMyFunction void*& 是在轉什麼? 08/28 16:03
Feis:應該是一種騙編譯器的作法類似 *(void **)&pMyFunction 08/28 22:49

你可能也想看看

搜尋相關網站