c++ - 如何使用 C++ 函数指针作为 C 函数指针/回调的参数
问题描述
我确实知道 C++ lambda 或 C 函数指针,但我不知道如何将它们混合在一起。我已经找到了Mixing C++ instance methods with C callback functions,但它不依赖于我的需要。
我有一个包含 C 标头的 C++ 类,如下所示:
extern "C" {
#include <jack/jack.h>
#include <jack/types.h`enter code here`>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
}
#include <QDialog>
#include <QFile>
#include <QString>
#include "Cliente.h"
class FormQStudio : public QDialog
{
Q_OBJECT
public:
explicit FormQStudio(QWidget *parent = nullptr);
~FormQStudio();
void playMIDIFile(QString file) noexcept(false);
int theCallback(jack_nframes_t nframes, void *arg);
};
C 头文件定义了一些类型:
typedef uint32_t jack_nframes_t;
typedef int (*JackProcessCallback)(jack_nframes_t nframes, void *arg);
int jack_set_process_callback (jack_client_t *client,
JackProcessCallback process_callback,
void *arg) JACK_OPTIONAL_WEAK_EXPORT;
我的 C++ 类的实现需要theCallback(jack_nframes_t nframes, void *arg)
作为参数传递给 C 函数jack_set_process_callback
。但我不知道该怎么做。
#include "FormQStudio.h"
FormQStudio::FormQStudio(QWidget *parent) :
QDialog(parent),
ui(new Ui::FormQStudio)
{
ui->setupUi(this);
}
void FormQStudio::playMIDIFile(QString file) noexcept(false){
smf_t *smf = smf_load(file.toUtf8());
smf_event_t *event;
Cliente *c = new Cliente("QStudio");
c->inicializarCliente(
/* HOW TO REFERENCE this->processJackCallback as a parameter? */
);
}
};
“Cliente”类是这样的:
extern "C" {
#include <jack/jack.h>
#include <jack/types.h>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
}
#include <QString>
#include <QMap>
#include "ClientePorta.h"
#include "QStageException.h"
class Cliente
{
public:
Cliente(QString clientName);
struct MidiMessage {
jack_nframes_t time;
int len; /* Length of MIDI message, in bytes. */
unsigned char data[3];
};
jack_client_t *getClient();
void conectar(QString portaOrigem, QString clienteDestino, QString portaDestino) noexcept(false);
void inicializarCliente(JackProcessCallback callback) noexcept(false);
void addClientePorta(ClientePorta * cp);
ClientePorta* getClientePorta(QString nomePorta);
void sendMIDI(QString outputPortName, jack_nframes_t nframes ) noexcept(false);
private:
QString clientName;
QString inputPortName;
QString outputPortName;
QMap<QString,ClientePorta*> portas;
jack_client_t *jackClient = NULL;
};
Cliente.cpp 是:
#include "Cliente.h"
#include <QDebug>
Cliente::Cliente(QString clientName)
{
this->clientName = clientName;
}
void Cliente::inicializarCliente(JackProcessCallback callback) noexcept(false){
jackClient = jack_client_open(clientName.toUtf8().data(), JackNoStartServer, NULL);
int err = jack_set_process_callback(jackClient, callback , this);
}
};
我省略了其余的实现,因为它不相关。我也不是在问 lib jack。重点是如何将 C++ 函数作为参数传递给 C 回调,如上所示。
解决方案
注意jack_set_process_callback
() 的最后一个参数是 a void *
,它被传递给回调函数。
这是 C 库的一种常见设计模式,可以使它们与 C++ 一起使用。
您要做的是传递this
您希望调用其方法的对象,作为回调,void *
将回调指针指向一个extern "C"
链接包装函数,该函数接受void *
,然后reinterpret_cast
将其返回到类实例指针,然后调用它的方法,例如:
extern "C" {
int fwd_callback(jack_nframes_t nframes, void *arg)
{
FormQStudio *p=reintrerpret_cast<FormQStudio *>(arg);
return p->theCallback(nframes);
}
};
// ...
FormQStudio *some_object;
// ...
jack_set_process_callback(client, fwd_callback, reinterpret_cast<void *>(some_object));
some_object
当然,当回调被调用时,你要确保它仍然存在并且是一个有效的对象。
推荐阅读
- c# - 如何在软件 stimulsoft 报告中显示 Gridview 信息?
- c# - 尝试在 Caliburn.Micro 中创建新 ViewModel 时的 StackOverflow
- arrays - 阵列与内存数据库
- java - 以高性能的方式计算字符串中出现的字符?‽?
- javascript - JQuery 无法过滤我所有的依赖选择选项
- r - 如何在 ggplot2 中使用 geom_sf 来骑乘多边形边界
- typescript - lite-server 和 live-server 有什么区别?
- shell - Jenkins 管道因随机连接问题而失败
- reactjs - 如何在 React 中访问和更新嵌套对象数组
- html - 在仅使用 CSS 离开页面之前单击链接时如何淡出整个页面?