2009-06-16 266 views
34

我有一個C庫,需要一個回調函數被註冊來定製一些處理。回調函數的類型是int a(int *, int *)使用C++類的成員函數爲C回調函數

我寫類似以下內容並嘗試註冊一個C++類的函數作爲回調函數的C++代碼:

class A { 
    public: 
    A(); 
    ~A(); 
    int e(int *k, int *j); 
}; 

A::A() 
{ 
    register_with_library(e) 
} 

int 
A::e(int *k, int *e) 
{ 
    return 0; 
} 

A::~A() 
{ 

} 

編譯器會引發以下錯誤:

In constructor 'A::A()', 
error: 
argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’. 

我的問題:

  1. ,首先是有可能像我試圖做註冊一個C++類memeber功能,如果SO 3 H流? (我讀32.8在http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html,但在我看來,這並沒有解決問題)
  2. 是否有替代/更好的辦法來解決呢?

回答

37

你可以做,如果成員函數是靜態的。

A類的非靜態成員函數有一個隱含的class A*類型的第一個參數,它對應於這個指針。這就是爲什麼只有在回調的簽名具有class A*類型的第一個參數時才能註冊它們。

+0

是的。該解決方案工作。 (A ::)(A *,int *,int *)'不匹配'int()(int,int *)' – Methos 2009-06-16 10:31:20

+0

它確實存在,但是通過將(答::)這意味着函數是類A的一部分,它從那裏暗示了'this'指針。 – GManNickG 2009-06-16 10:37:19

+0

我只是好奇......這是在標準中指定的嗎?我只是看了一下關於課程的部分,並沒有發現這一點。儘管如此,非常有趣。我只是不會認爲每個編譯器都必須以這種方式處理非靜態成員函數。 – Tom 2009-06-16 10:59:37

1

與使用成員函數的問題是,它需要在其上作用的對象 - 和C犯規知道對象。

最簡單的方法是做到以下幾點:

//In a header file: 
extern "C" int e(int * k, int * e); 

//In your implementation: 
int e(int * k, int * e) { return 0; } 
7

的問題是方法=功能!編譯器將改變你的方法,這樣的事情:

int e(A *this, int *k, int *j); 

所以,它肯定不能傳遞它,因爲類實例不能作爲參數傳遞。解決問題的一種方法是將方法設置爲靜態,這樣它就會具有良好的類型。但它不會有任何類實例,並且訪問非靜態類成員。

另一種方法是聲明一個函數具有靜態指向一個甲初始化的第一次。該功能只將呼叫重定向到該類別:

int callback(int *j, int *k) 
{ 
    static A *obj = new A(); 
    a->(j, k); 
} 

然後您可以註冊回調函數。

13

你也可以做到這一點,如果成員函數是不是靜態的,但它需要多一點的工作(見Convert C++ function pointer to c function pointer):

#include <stdio.h> 
#include <functional> 

template <typename T> 
struct Callback; 

template <typename Ret, typename... Params> 
struct Callback<Ret(Params...)> { 
    template <typename... Args> 
    static Ret callback(Args... args) {      
     func(args...); 
    } 
    static std::function<Ret(Params...)> func; 
}; 

template <typename Ret, typename... Params> 
std::function<Ret(Params...)> Callback<Ret(Params...)>::func; 

void register_with_library(int (*func)(int *k, int *e)) { 
    int x = 0, y = 1; 
    int o = func(&x, &y); 
    printf("Value: %i\n", o); 
} 

class A { 
    public: 
     A(); 
     ~A(); 
     int e(int *k, int *j); 
}; 

typedef int (*callback_t)(int*,int*); 

A::A() { 
    Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2); 
    callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);  
    register_with_library(func);  
} 

int A::e(int *k, int *j) { 
    return *k - *j; 
} 

A::~A() { } 

int main() { 
    A a; 
} 

這個例子是在這個意義上完整的,它編譯:

g++ test.cpp -std=c++11 -o test 

您將需要c++11標誌。在代碼中,您看到調用了register_with_library(func),其中func是一個動態綁定到成員函數e的靜態函數。