如何在封装在类中的回调函数上发送指针

Posted

技术标签:

【中文标题】如何在封装在类中的回调函数上发送指针【英文标题】:How to send a pointer on a callback function which is encapsulated in a class 【发布时间】:2011-11-28 20:58:56 【问题描述】:

我实际上是在使用库 PortAudio 用 C++ 编写程序。 该库使用回调函数来管理音频输入和输出。 在 C++ 中,我在我的“音频”类中实现了这个回调函数,但我无法将它发送到 Pa_OpenDefaultStream()。编译器用这一行说“这个参数与 PaStreamCallback* 类型的参数不兼容”:

Pa_OpenDefaultStream(&this->_stream, 1, 2, paFloat32, this->_sampleRate, this->_framesPerBuffer, callbackFunction, NULL);

当我使用 C 时,像这样发送我的 callbackFunction 效果很好。 如何将我的回调函数发送到这个 OpenDefaultStream 函数?

【问题讨论】:

PaStreamCallback* 的签名是什么? 重复***.com/questions/8256142/… 好的,非常感谢你们。我使用静态关键字,它可以工作,但我不能使用“this”关键字。 【参考方案1】:

您需要实现一个与 PaStreamCallback 具有相同签名的普通全局函数。

看起来 PaStreamCallback 需要一个参数 void* userData。这就是通常所说的上下文参数。如果不了解 PortAudio,我猜您可以使用它来表示您的类实例。当您调用 Pa_OpenDefaultStream 时,将“this”传递给 userData 指针,您在示例中写的是 NULL。

这是您需要的函数包装器的示例实现:

int MyPaStreamCallback (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)

     MyClass *myClass = reinterpret_cast<MyClass*>(userData);
     return myClass->callbackFunction(input, output, frameCount, timeInfo, statusFlags);

然后将您的原始代码替换为:

Pa_OpenDefaultStream(&this->_stream, 1, 2, paFloat32, this->_sampleRate, this->_framesPerBuffer, MyPaStreamCallback , this); 

我假设你会让你的 callbackFunction 获取所有其他参数。

【讨论】:

【参考方案2】:

当您有机会传递“用户数据”或上下文时,Erik Olson 的答案非常有用。如果这是不可能的,你可能需要一个丑陋的黑客来从回调中获取你的 this 指针。我已经看到带有回调的类也有这个指针的静态副本,只有当你只有一个类的实例时才会起作用。 Ugggggly,但它的工作原理。

这种丑陋是所有 API 都有一个优雅的方式来处理这个问题的论据,理想情况下,使用重新解释强制转换不会破坏类型安全。

【讨论】:

【参考方案3】:

我知道已经有一段时间了,但我遇到了同样的问题并找到了 C++11 风格的解决方案。

所以我们有

 int AudioHandler::CallBackFunction(const void *inputBuffer, void *outputBuffer,
                               unsigned long framesPerBuffer,
                               const PaStreamCallbackTimeInfo* timeInfo,
                               PaStreamCallbackFlags statusFlags,
                               void *userData);

那么,AudioHander.cpp 中哪里做全局变量:

 AudioHandler* veryDangerousHandler;

最后:

PaStreamCallback* callbackus = [](const void *inputBuffer, void *outputBuffer,
        unsigned long framesPerBuffer,
        const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags,
        void *userData) -> int

    return veryDangerousHandler->CallBackFunction(inputBuffer, outputBuffer,
                            framesPerBuffer,
                            timeInfo,
                            statusFlags,
                            userData);
;

【讨论】:

以上是关于如何在封装在类中的回调函数上发送指针的主要内容,如果未能解决你的问题,请参考以下文章

如何在类向量中存储/使用外部函数指针

PCL中将回调函数封装到类中

异步回调函数

回调函数,函数指针

回调函数,函数指针

ctypes给扩展模块中的函数传递回调函数