2017-05-12 133 views
0

我想在C++中做C包裝。C++類成員函數C結構函數指針

但我不能將類內的函數轉換爲結構函數指針。

不應將myCallback函數用作靜態函數,因爲它必須被覆蓋。

下面是示例代碼:

#include <iostream> 

extern "C" { 
typedef struct _client_config 
{ 
    void (*on_connect)(void *client, int result); 
} client_config; 
} 

class Parent 
{ 
public: 
    Parent() {}; 
    ~Parent() {}; 

    virtual void myCallback(void* hello, int world) = 0; 
}; 

class Child : public Parent 
{ 
public: 
    Child() {}; 
    ~Child() {}; 

    void myCallback(void* hello, int world) 
    { 
     printf("Hello World! \n"); 
    } 
}; 

int main(void) 
{ 
    Parent* myClass = new Child(); 

    client_config* myClientConfig = (client_config *)malloc(sizeof(client_config)); 

    myClientConfig->on_connect = myClass->myCallback; 

    return 0; 
} 

這是在編譯過程中,編譯器說的話:

Error 1 error C3867: 'Parent::myCallback': function call missing argument list; use '&Parent::myCallback' to create a pointer to member 
Error 2 error C2440: '=' : cannot convert from 'void (__thiscall Parent::*)(void *,int)' to 'void (__cdecl *)(void *,int)' 

任何人都可以指出綁定一個類的成員函數的結構函數指針的方式或我在這裏做錯了什麼?

回答

0

C函數庫的函數指針僅與extern "C"自由函數兼容。 (即使靜態成員函數不兼容,語言鏈接也是錯誤的)。

你將不得不使用蹦牀等函數,詢問你接收到一個指向你的對象的指針的對象(該庫提供了一種方法來存儲某種形式的用戶數據,這些數據可以是在回調中檢索,不是嗎?或許client參數是這樣的,你必須閱讀文檔。),投到Parent*,並執行成員調用。編譯器不會爲你做這件事。

extern "C" void connect_trampoline(void* client, int result) 
{ 
    Parent* my_object = static_cast<Parent*>(client); 
    my_object->myCallback(result); 
} 

myClientConfig->on_connect = &connect_trampoline; 

C++庫通常是由接受std::function它可以攜帶其自身的狀態編碼以使這更容易,例如。但是,在C庫使用的C編程風格中,你必須先找到你的對象,然後在使用成員之前做一個醜陋的表演。

萬一庫做出某種形式的控制,以回調訪問下的指針,但確實傳遞一個指針在回調關聯的庫對象,你可以使用全局std::map<library_object*, Parent*>查找你的對象。這種方法也避免了演員陣容。


要小心,當你手中的指針到對象到圖書館抱你,你給它完全相同的類型(Parent*在這種情況下),你將在稍後投退。如果你給Derived*,效果是做reinterpret_cast<Parent*>(p_derived)這是非常糟糕的。 (static_castvoid*當指針指向庫時,static_castParent*當您收回時,並且C++標準說這個序列與reinterpret_cast)的行爲完全相同)