如何用std::bind为Mosquitto正确设置C++类成员函数回调?
问题分析与解决方案
错误原因
Mosquitto的回调接口要求传入C风格的普通函数指针(如void (*)(mosquitto*, void*, int)),但你用std::bind绑定类的非静态成员函数后,返回的是一个C++可调用对象,并非原始函数指针,两者类型无法直接转换。另外,类的非静态成员函数默认携带隐藏的this指针,这也导致它不能直接适配C风格回调的签名。
解决方案
不用将成员函数改为static,只需利用Mosquitto回调中的void *obj参数(mosquitto_new时传入的用户自定义数据),搭配静态转发函数做中间层,就能间接调用非静态成员函数,具体步骤如下:
1. 修改类声明,添加静态转发函数
在MQTT.hpp的private区域新增两个静态转发函数:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <iostream> #include <cstring> #include <chrono> #include <thread> #include <mosquitto.h> class Mqtt { private: void on_connect(struct mosquitto *mosq, void *obj, int rc); void on_disconnect(struct mosquitto *mosq, void *obj, int rc); // 静态转发函数,用于适配C风格回调 static void connect_callback_wrapper(struct mosquitto *mosq, void *obj, int rc); static void disconnect_callback_wrapper(struct mosquitto *mosq, void *obj, int rc); public: void loop(void); };
2. 实现静态转发函数
在MQTT.cpp中实现转发逻辑,将C回调的调用转接到类的非静态成员函数:
#include "MQTT.hpp" void Mqtt::on_connect(struct mosquitto *mosq, void *obj, int rc) { std::cout << "on_connect" << std::endl; } void Mqtt::on_disconnect(struct mosquitto *mosq, void *obj, int rc) { std::cout << "on_disconnect" << std::endl; } // 静态转发函数:将void*类型的用户数据转为Mqtt对象指针,调用成员函数 void Mqtt::connect_callback_wrapper(struct mosquitto *mosq, void *obj, int rc) { static_cast<Mqtt*>(obj)->on_connect(mosq, obj, rc); } void Mqtt::disconnect_callback_wrapper(struct mosquitto *mosq, void *obj, int rc) { static_cast<Mqtt*>(obj)->on_disconnect(mosq, obj, rc); }
3. 调整loop函数的回调设置
- 在
mosquitto_new时传入当前对象this作为用户数据; - 将回调设置为静态转发函数,而非直接绑定成员函数;
- 修正原代码中
mosquitto_connect多写的一个右括号:
void Mqtt::loop() { mosquitto_lib_init(); // 第三个参数传入this,作为回调时的用户数据 struct mosquitto *mosq = mosquitto_new("myid", true, this); if (!mosq) { std::cout << "Cannot initialize broker" << std::endl; return; } // 设置静态转发函数为回调 mosquitto_connect_callback_set(mosq, Mqtt::connect_callback_wrapper); mosquitto_disconnect_callback_set(mosq, Mqtt::disconnect_callback_wrapper); mosquitto_loop_start(mosq); // 移除多余的右括号 mosquitto_connect(mosq, "192.168.0.1", 1883, 60); while(true) std::this_thread::sleep_for(std::chrono::seconds(1)); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); }
原理说明
静态转发函数符合C风格回调的签名要求,它通过void *obj参数拿到当前Mqtt对象的指针,再调用对应的非静态成员函数,既保留了类成员函数的封装性,又适配了Mosquitto的C接口规范。
内容的提问来源于stack exchange,提问作者Mendes
相关产品推荐
相关产品推荐

