為什麼這篇類別 函式指標鄉民發文收入到精華區:因為在類別 函式指標這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者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