使用 C++ 类成员函数作为 C 回调函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1000663/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using a C++ class member function as a C callback function
提问by Methos
I have a C library that needs a callback function to be registered to customize some processing. Type of the callback function is int a(int *, int *)
.
我有一个 C 库,需要注册一个回调函数来自定义一些处理。回调函数的类型是int a(int *, int *)
。
I am writing C++ code similar to the following and try to register a C++ class function as the callback function:
我正在编写类似于以下内容的 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()
{
}
The compiler throws following error:
编译器抛出以下错误:
In constructor 'A::A()',
error:
argument of type ‘int (A::)(int*, int*)' does not match ‘int (*)(int*, int*)'.
My questions:
我的问题:
- First of all is it possible to register a C++ class memeber function like I am trying to do and if so how? (I read 32.8 at http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html. But in my opinion it does not solve the problem)
- Is there a alternate/better way to tackle this?
- 首先,是否可以像我尝试那样注册 C++ 类成员函数,如果可以,如何注册?(我在http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html阅读了 32.8 。但在我看来它并没有解决问题)
- 有没有替代/更好的方法来解决这个问题?
采纳答案by sharptooth
You can do that if the member function is static.
如果成员函数是静态的,您可以这样做。
Non-static member functions of class A have an implicit first parameter of type class A*
which corresponds to thispointer. That's why you could only register them if the signature of the callback also had the first parameter of class A*
type.
类 A 的非静态成员函数具有class A*
与this指针对应的类型的隐式第一个参数。这就是为什么你只能在回调的签名也有class A*
类型的第一个参数时注册它们。
回答by Anne van Rossum
You can also do this if the member function is not static, but it requires a bit more work (see also Convert C++ function pointer to c function pointer):
如果成员函数不是静态的,您也可以这样做,但它需要更多的工作(另请参阅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) {
return 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;
}
This example is complete in the sense that it compiles:
这个例子在编译的意义上是完整的:
g++ test.cpp -std=c++11 -o test
You will need the c++11
flag. In the code you see that register_with_library(func)
is called, where func
is a static function dynamically bound to the member function e
.
你将需要c++11
旗帜。在您看到的代码中,它register_with_library(func)
被调用,其中func
是一个动态绑定到成员函数的静态函数e
。
回答by Raoul Supercopter
The problem is that method != function. The compiler will transform your method to something like that:
问题是方法 != 函数。编译器会将您的方法转换为以下内容:
int e( A *this, int *k, int *j );
So, it's sure you can't pass it, because the class instance can't be passed as argument. One way to work around is to make the method as static, this way it would have the good type. But it won't any class instance, and access to non-static class members.
所以,你肯定不能传递它,因为类实例不能作为参数传递。一种解决方法是将方法设为静态,这样它就会有好的类型。但它不会访问任何类实例,并访问非静态类成员。
The other way is to declare a function with a static Pointer to a A initialised the first time. The function only redirect the call to the class :
另一种方法是声明一个带有静态指针的函数,该指针指向第一次初始化的 A。该函数仅将调用重定向到类:
int callback( int *j, int *k )
{
static A *obj = new A();
a->(j, k);
}
Then you can register the callback function.
然后就可以注册回调函数了。
回答by TimW
Well ...if you are on a win32 platform there is always the nasty Thunking way ...
好吧......如果你在一个 win32 平台上,总是有令人讨厌的 Thunking 方式......
Thunking in Win32: Simplifying callbacks to non-static member functions
Win32 中的 Thunking:简化对非静态成员函数的回调
It is a solution but I don't recommend using it.
It has a good explanation and it is nice to know it exists.
这是一个解决方案,但我不建议使用它。
它有一个很好的解释,很高兴知道它存在。
回答by PaulJWilliams
The problem with using a member function is that it needs an object on which to act - and C doesnt know about objects.
使用成员函数的问题在于它需要一个对象来执行操作——而 C 不知道对象。
The easiest way would be to do the following:
最简单的方法是执行以下操作:
//In a header file:
extern "C" int e(int * k, int * e);
//In your implementation:
int e(int * k, int * e) { return 0; }
回答by cibercitizen1
In this solution, we have a template class with the static method to be given to the "c function" as a callback. This class holds a "ordinary" object ( with a member function named callback() which will be finally called).
在这个解决方案中,我们有一个模板类,其中包含作为回调提供给“c 函数”的静态方法。这个类拥有一个“普通”对象(带有一个名为 callback() 的成员函数,最终将被调用)。
Once your class (here, A) is defined, it can be easily used:
一旦定义了类(此处为 A),就可以轻松使用它:
int main() {
Holder<A> o ( A(23, 23) );
std::cout << o().getN() << "\n";
callACFunctionPtr( fun );
callACFunctionPtr( o.callback );
} // ()
Complete example:
完整示例:
#include <iostream>
// ----------------------------------------------------------
// library class: Holder
// ----------------------------------------------------------
template< typename HeldObjectType >
class Holder {
public:
static inline HeldObjectType object;
static void callback( ) {
object.callback();
} // ()
HeldObjectType & operator() ( ) {
return object;
}
Holder( HeldObjectType && obj )
{
object = obj;
}
Holder() = delete;
}; // class
// ----------------------------------------------------------
// "old" C function receivin a ptr to function as a callback
// ----------------------------------------------------------
using Callback = void (*) (void);
// ..........................................................
// ..........................................................
void callACFunctionPtr( Callback f ) {
f();
} // ()
// ----------------------------------------------------------
// ----------------------------------------------------------
void fun() {
std::cout << "I'm fun\n";
} //
// ----------------------------------------------------------
//
// Common class where we want to write the
// callback to be called from callACFunctionPtr.
// Name this function: callback
//
// ----------------------------------------------------------
class A {
private:
int n;
public:
A( ) : n( 0 ) { }
A( int a, int b ) : n( a+b ) { }
void callback( ) {
std::cout << "A's callback(): " << n << "\n";
}
int getN() {
return n;
}
}; // class
// ----------------------------------------------------------
// ----------------------------------------------------------
int main() {
Holder<A> o ( A(23, 23) );
std::cout << o().getN() << "\n";
callACFunctionPtr( fun );
callACFunctionPtr( o.callback );
} // ()