2009-01-13 167 views
5

首先,我不得不承認,我的編程技能相當有限,而且我接管了一個(非常小的)現有的C++ OOP項目,我嘗試推送自己的東西。不幸的是,遇到超出我所知的問題,我希望能在這裏找到一些幫助。我正在使用第三方庫(無法更改)從相機中抓取圖像,並在此處使用一些佔位符名稱。指向類成員函數問題的函數指針

第三方庫有一個函數「ThirdPartyGrab」來啓動一個連續的實時抓取,並獲取一個指向每次新幀到達時都會調用的函數的指針。因此,在一個普通的C應用程序它是這樣的:

ThirdPartyGrab (HookFunction); 

「HookFunction」 需要被聲明爲:

long _stdcall HookFunction (long, long, void*); 

或聲明爲

typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*); 

現在 「BUF_HOOK_FUNCTION_PTR」我有一個C++應用程序和一個「MyFrameGrabber」類,它應該封裝我所做的一切。所以,我把掛鉤函數作爲這樣一個私有成員:

long _stdcall HookFunction (long, long, void*); 

也有是在我的類中的公共void函數「StartGrab」,這應該開始抓鬥。我嘗試撥打電話:

ThirdPartyGrab (..., HookFunction, ...); 

哪(不奇怪)失敗。它表示函數調用MyFrameGrabber :: HookFunction時忽略了參數列表,我應該嘗試使用MyFrameGrabber :: HookFunction來創建一個指針。但是,傳遞「& MyFrameGrabber :: HookFunction」會導致出現另一個無法轉換爲BUF_HOOK_FUNCTION_PTR的錯誤。

閱讀完C++ FAQ function pointers之後,我想我理解了這個問題,但無法解決問題。我試圖使鉤函數靜態,但這也導致轉換錯誤。我也想過把鉤子函數放在類外,但我需要在鉤子函數中使用類函數。還有其他方法還是我需要改變我的整個概念?

編輯14.01.08: 我測試了單例解決方法,因爲我無法更改第三方庫,而且void指針僅適用於掛鉤函數內部使用的數據。遺憾的是它並沒有制定出的方塊就像我希望....我不知道如果靜態函數需要在一個單獨的類,所以我把它放在我的「MyFrameGrabber」類:

static MyFrameGrabber& instance() 
{ 
     static MyFrameGrabber _instance; 
     return _instance; 
} 
long Hook(long, long, void*); // Implementation is in a separate cpp file 

在我的cpp文件我有call_hook功能:

long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z) 
{ 
    return MyFrameGrabber::instance().Hook(x,y,z); 
} 
void 
MyFrameGrabber::grab() 
{ 
    ThirdPartyGrab(..., call_hook, ...); 
} 

但是這給了我,沒​​有匹配的標準構造發現在static MatroxFrameGrabber _instance;錯誤。

MyFrameGrabber (void* x, 
       const std::string &y, int z, 
       std::string &zz); 

我試圖把一個空的構造MyFrameGrabber();但這會導致鏈接錯誤:因爲我的MyFrameGrabber構造看起來像這樣是正確的。我應該將空參數傳遞給單例中的MyFrameGrabber構造函數嗎?或者我需要單獨的鉤子類,如果是,我怎樣才能訪問MyFrameGrabber函數?提前致謝。

SECOND EDIT 15.01.08: 我應用了更改,現在編譯和鏈接。不幸的是,我不能在運行時測試它,因爲它是一個DLL,並且我還沒有調用調用程序,並且在初始化期間還有其他問題。我將標記爲答案,因爲我確信這是正確的方式。

回答

2

原因「& MyFrameGrabber :: HookFunction」不能被轉換爲BUF_HOOK_FUNCTION_PTR是,作爲類的一個成員,它具有隱式地第一個參數「this」指針,從而不能將成員函數轉換爲非成員函數:兩個簽名看起來相同,但實際上是不同的。

我將聲明一個接口,定義要調用的函數,讓您的類實現它並傳遞對象本身而不是回調函數(您可以將接口看作是函數指針的面向對象替換):

class IHookInterface{ 
public: 
    virtual long HookFunction(long, long, void*) = 0; 
}; 
class HookClass : public IHookInterface{ 
public: 
    virtual long Hook(long, long, void*) { 
     // your code here... 
    } 
}; 

//新定義: ThirdPartyGrab(...,IHookInterface,...);

編輯 - 其他可能的解決方案,如果你不能修改庫:使用單身而不是靜態函數。

class HookClass{ 
public: 
    static HookClass& instance(){ 
     static HookClass _instance; 
     return _instance; 
    } 
    long Hook(long, long, void*) { 
     // your code here... 
    } 
}; 

long call_hook(long x,long y,void * z){ 
    return HookClass::instance().Hook(x,y,z); 
} 

第二個編輯:你可能稍微修改的單身類的初始化方法調用用適當的參數的構造函數,但也許並不比下面的解決方案,這是更簡單更優雅:

class HookClass{ 
public: 

    HookClass(string x,string y...){ 
    } 

    long Hook(long, long, void*) { 
     // your code here... 
    } 
}; 

static HookClass * hook_instance = 0; 

long call_hook(long x,long y,void * z){ 
    if (0 != hook_instance){ 
     return hook_instance->Hook(x,y,z); 
    } 
} 

int main(){ 
    hook_instance = new HookClass("x","y"); 
    ThirdPartyGrab(..., call_hook, ...); 
} 
+0

我認爲與「第三方圖書館」的OP意味着他不能改變圖書館。不過,我的假設可能是錯誤的。 – gimpf 2009-01-13 16:13:01

7

您的私有成員方法有一個隱含的this指針作爲第一個參數。如果你寫出來,很明顯功能簽名不匹配。

您需要編寫一個靜態成員函數,它可以作爲回調函數傳遞給庫。該最後一個參數HookFunction,一個void*,在我看來很象一個cookie,在那裏人們可以通過那些自己指針

所以,一切的一切,應該是這樣的:

 
class MyClass { 
    long MyCallback(long, long) { 
    // implement your callback code here 
    } 

    static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) { 
    return reinterpret_cast<MyClass*>(self)->MyCallback(a, b); 
    } 
public: 
    void StartGrab() { 
    ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...); 
    } 
}; 

這當然只適用於如果void*論點正在做我說的。在包含參數名稱的完整功能簽名時,應該很容易找到thisThirdPartyGrab()調用中的位置。