非成员函数指针作为API成员函数的回调

时间:2012-10-29 20:46:16

标签: c++ api callback function-pointers

我正在使用一个API,要求我将函数指针作为回调传递。我正在尝试在C ++中使用我的类中的这个API,但是我遇到了编译错误。

API定义是:

typedef void (__stdcall *STREAM_CALLBACK)(void *userdata);

__declspec(dllimport) int __stdcall set_stream_callback(
    STREAM_CALLBACK streamCB, void *userdata);

第三方提供的一个示例文件是:

void __stdcall streamCB(void *userdata)
{
  // callback implementation
}

int main(int argc, const char argv[])
{
  int mid = 0;
  set_stream_callback(streamCB, &mid);
}

这很好用。 但是当我尝试在课堂上使用它时,我有一个错误:

  

错误C3867:'MyClass :: streamCB':函数调用缺少参数列表;   使用'& MyClass :: streamCB'创建指向成员的指针

建议使用

  

&安培; MyClass的:: streamCB

不起作用。 我知道set_stream_callback只接受非成员函数。

问题非常类似于 How can I pass a class member function as a callback? 约翰内斯提出了一个简明的建议,但我不太了解它。任何人都可以扩大一点,如果我是正确的,它与这个问题有关吗?

我试过了:

void __stdcall MyClass::streamCB(void *userdata)
{
  // callback implementation
}

static void MyClass::Callback( void * other_arg, void * this_pointer ) {
    MyClass * self = static_cast<ri::IsiDevice*>(this_pointer);
    self->streamCB( other_arg );
}

//and in the constructor
int mid = 0;
set_stream_callback(&MyClass::Callback, &mid);

但是

  

错误C2664:'set_stream_callback':无法转换参数1   'void(__ cdecl *)(void *,void *)'到'STREAM_CALLBACK'

我该如何解决这个问题?


Edit1:另外,我想在userdata回调中使用streamCB

2 个答案:

答案 0 :(得分:4)

从仅使用非成员函数的回调调用成员函数的想法是为您的成员函数创建包装器。包装器从某处获取对象,然后调用成员函数。如果回调设计得相当好,它将允许您传入一些用于识别对象的“用户数据”。不幸的是,你遗漏了关于你班级的任何细节,所以我假设它看起来像这样:

class MyClass {
public:
    void streamCB() {
         // whatever
    }
    // other members, constructors, private data, etc.
};

有了这个,你可以这样设置你的回调:

void streamCBWrapper(void* userData) {
    static_cast<MyClass*>(userData)->streamCB()
}

int main() {
    MyClass object;
   set_stream_callback(&streamCBWrapper, &object);
   // ...
}

您可以使用各种游戏来创建streamCBWrapper功能(例如,您可以将其设为班级的static成员),但所有游戏都归结为:您需要从用户数据恢复对象并在此对象上调用成员函数。

答案 1 :(得分:2)

您可以通过将userdata转换为MyClass的属性来实现您想要的功能。然后你不必将它传递给MyClass :: Callback,这是不可能的,因为你只能传递一个参数,它就是对象实例。 这是一个例子。

void __stdcall MyClass::streamCB()
{
  // callback implementation
}

static void MyClass::Callback(void * this_pointer ) {
    MyClass * self = static_cast<MyClass>(this_pointer);
    self->streamCB();
}

MyClass::MyClass(void *userdata) {
    // do whatever you need to do with userdata
    // (...)
    // and setup the callback at C level
    set_stream_callback(&MyClass::Callback, (void *)this);
}

在您的示例中,int mid变量将成为该类的属性,因此可以从回调实现streamCB访问。