2009-06-16 269 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的静态函数。