2013-04-11 60 views
0

我遇到了函數指針的問題,並且我在網絡上找到的任何東西都幫助我解決了這個問題。如何從成員函數中獲取「簡單」函數指針

我有選自C API,它需要一個void函數的指針的函數:

extern int APIFunction(int, void (*func)(int));

我有,我想,當我調用API函數把函數的類。

class MyClass 
{ 
    public: 
     void myFunction(int status, otherAPi arguments...); 
}; 

然後,我創建了一個指向我的會員功能,創建了類的新實例

typedef void (MyClass::*MyClassFunctionPointer)(int stat, otherAPi arguments...); 
MyClassFunctionPointer fctPointer= &MyClass::myFunction; 
LicenseSecurity instance; 

我得到一個錯誤,當我嘗試打電話給我的API函數與我創建的函數指針:

E2034 Impossible to convert 'void (MyClass::*)(int, otherAPITypes...)' into 'void (*) (int, otherAPITypes...)' 
E2342 Bad type correspondence in the parameter 'func' ('void (*)(int, otherAPITypes...)' desired, 'void(int, otherAPITypes...)' obtained) 

int stat = APIFunction(5, fctPointer); // -> error 1 
int stat = APIFunction(5, instance.*fctPointer); // -> error 2 

我在第一和第二種情況分別得到了錯誤

我無法訪問API函數,因此我無法修改它。爲了總結這個問題:如何獲得一個「簡單的」C函數指針來放入我的類的成員函數的函數參數?

謝謝

+0

我認爲boost :: bind在這裏很有幫助 – Constantin 2013-04-11 20:49:33

+0

@Constantin然後他會有一個包裝成員函數調用的函子......但他仍然無法將它傳遞給API函數。 – 2013-04-11 20:55:01

+0

[C++類成員函數回調]可能的重複(http://stackoverflow.com/questions/8079453/c-class-member-function-callback) – 2013-04-11 20:55:16

回答

2

不幸的是,你不能。抱歉。

理想情況下,您的API將接受類似std::function的東西,這將允許您包裝自由函數或成員函數。但是如果你不能修改API,那麼你別無選擇,只能提供一個免費的功能。

+0

其實,在某些情況下,您可以這樣做。出於這個原因,GCC有一個稱爲PMI轉換的特殊功能。但是這對於所有方法都不適用(認爲是多重虛擬繼承)並且當然不是標準的,甚至在編譯器中也不可移植。 – 2013-04-11 20:51:40

+0

gcc可以編譯C++嗎?因爲我從來沒見過c中的成員函數... – Constantin 2013-04-11 20:52:59

+1

@Constantin:是的,g ++只是gcc的包裝器,具有特定選項 – newacct 2013-04-12 09:05:18

0

由於該函數在調用時需要該指針,因此無法獲得指向非靜態成員函數的「簡單」函數指針。如果你要創建一個像這樣的函數指針,那麼當函數被調用時,就不會有這個指針供它引用。

0

用這種古老的C API,你不幸沒有辦法做到這一點。

你需要做的是使一個靜態或非成員函數接受回調,然後找出哪個對象的實例調用成員。有些C API允許將用戶數據傳遞給回調函數,在這種情況下,您可以使用它來存儲有問題的this指針。如果這不是一個選項,您可以使用全局或單例對象,並且只允許註冊一個這樣的回調。

+0

問題是,使用靜態或非成員函數時,我無法使用我的屬性我需要它。 – Pierre 2013-04-12 12:15:50

0

您可以將回調聲明爲獨立函數或類的方法爲靜態。棘手的部分是在回調中訪問類實例指針。

理想情況下,精心設計的API允許您爲回調指定用戶定義的值。這允許您輕鬆傳入一個類實例並直接在回調中訪問它。但是這聽起來像你沒有使用這樣的API,所以你需要使用一種解決方法。

如果您一次只有1個類實例與API一起使用,則可以將實例指針存儲到全局變量中,並讓回調使用全局變量來訪問該實例。

但是,如果你有在同一時間使用了多類實例,你正在尋找一個解決方案置信轉換,類似VCL的MakeObjectInstance()功能,它允許TWndMethod -signatured類的方法被用作Win32的窗口過程的回調。本質上,一塊可執行的內存是動態分配的,存根彙編代碼被寫入塊中,而實例指針和類方法指針也被存儲在塊中。然後將該塊作爲函數指針傳遞給API。當API調用「函數」時,存根代碼被執行,必須操縱調用堆棧和CPU寄存器來調用存儲的類方法指針,將存儲的實例指針作爲其隱藏參數this,同時保留其他參數的語義,調用堆棧,函數結果等等。

C++中沒有任何東西真正實現了這種thunking本地。手動實現並不困難,但也不是微不足道的(查看VCL的Classes.pas源文件中的MakeObjectInstance()的源代碼)。最難的部分是提出必要的存根代碼,以匹配您特定類方法簽名的語義。