gpt4 book ai didi

c++ - 在 C++ 类中实现回调函数

转载 作者:搜寻专家 更新时间:2023-10-31 02:08:17 25 4
gpt4 key购买 nike

我想实现一个解决方法,将非静态类用作回调函数。我正在使用 Eclipse Paho MQTT 代码。以下类型被实现并用作回调:

typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response);

MQTTAsync_onSuccess* onSuccess;

onSuccess = myStaticCallback;

void myStaticCallback (void* context, MQTTAsync_successData* response)
{
//...callback actions...
}

我想包装这个 C API(不修改现有的 MQTT C API)并实现属于对象/类的非静态/非集中式回调函数。

typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response);

class myMQTTClass
{
private:
void myCallback (void* context, MQTTAsync_successData* response);
MQTTAsync_onSuccess* onSuccess;

public:
void foo (void)
{
this->onSuccess = this->myCallback;
}
}

正如您可能猜到的,上面的代码导致了错误:无法将 myCallback 从类型 'void (myMQTTClass::) (void*, MQTTAsync_successData*)' 转换为类型 'void (*)(void*, MQTTAsync_successData*)'

非常感谢有关如何解决此问题或任何解决方法的任何指导。我愿意提供任何可能遗漏的信息。提前致谢。

编辑:有一些遗漏的实际代码

   namespace rover
{
typedef struct
{
char * clientID;
char * topic;
char * payload;
int qos; // 1
long int timeout; // Such as 10000L usec
} RoverMQTT_Configure_t;

class RoverPahoMQTT
{
public:
RoverPahoMQTT (char * host_name, int port, RoverMQTT_Configure_t MQTT_Configure);

private:

/**
* @brief Host name used for connecting to the Eclipse Paho MQTT server
*/
char * HOST_NAME;

/**
* @brief Port used for connecting to the Eclipse Paho MQTT server
*/
int PORT;

RoverMQTT_Configure_t rover_MQTT_configure;

/* Internal attributes */
MQTTAsync client;

/**
* @brief Connect options
*/
MQTTAsync_connectOptions conn_opts;

/**
* @brief Disconnect options
*/
MQTTAsync_disconnectOptions disc_opts;

//...
static void onPublisherConnect (void* context, MQTTAsync_successData* response);
void onPublisherConnect_ (MQTTAsync_successData* response);

//...

}
}

int rover::RoverPahoMQTT::publish (void)
{
this->flushFlags ();

this->conn_opts = MQTTAsync_connectOptions_initializer;
this->client = new MQTTAsync;
int rc;

char my_addr[20];
this->constructAddress (my_addr);
printf ("address: %s", my_addr);
MQTTAsync_create ( &(this->client),
my_addr,
this->rover_MQTT_configure.clientID,
MQTTCLIENT_PERSISTENCE_NONE,
NULL);

MQTTAsync_setCallbacks(this->client, NULL, onConnectionLost, NULL, NULL);

conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = rover::RoverPahoMQTT::onPublisherConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = this->client;

if ((rc = MQTTAsync_connect(this->client, &(this->conn_opts))) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
return rc;
}

/*printf("Waiting for publication of %s\n"
"on topic %s for client with ClientID: %s\n",
PAYLOAD, TOPIC, CLIENTID);*/
while (!mqtt_finished)
usleep(this->rover_MQTT_configure.timeout);

MQTTAsync_destroy(&client);
return rc;
}

void rover::RoverPahoMQTT::onPublisherConnect_(MQTTAsync_successData* response)
{
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc;

printf("Successful connection\n");

opts.onSuccess = onPublisherSend;
opts.context = client;

pubmsg.payload = &default_MQTT_configure.payload;
pubmsg.payloadlen = strlen(default_MQTT_configure.payload);
pubmsg.qos = default_MQTT_configure.qos;
pubmsg.retained = 0;
deliveredtoken = 0;

if ((rc = MQTTAsync_sendMessage(client, default_MQTT_configure.topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start sendMessage, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}

void rover::RoverPahoMQTT::onPublisherConnect (void* context, MQTTAsync_successData* response)
{
rover::RoverPahoMQTT* m = (rover::RoverPahoMQTT*) context;
m->onPublisherConnect_(response);
//((rover::RoverPahoMQTT*)context)->onPublisherConnect_(response);
// ^^^HERE IS THE SEGMENTATION FAULT

}

最佳答案

如明确说明here , 回调必须是

registered with the client library by passing it as an argument in MQTTAsync_responseOptions

context 参数是一个

pointer to the context value originally passed to MQTTAsync_responseOptions, which contains any application-specific context.

我建议您的类使用一个通用接口(interface),它提供一个与回调原型(prototype)相匹配的静态方法:

class myMQTTClass
{
public:
static void callback(void* context, MQTTAsync_successData* response)
{
myMQTTClass * m = (myMQTTClass*)context;
m->myCallback(response);
}
protected:
virtual void myCallback(MQTTAsync_successData* response) = 0;
};

您现在可以在子类中实现不同的行为:

class myMQTTClassImpl : public myMQTTClass
{
protected:
void myCallback(MQTTAsync_successData *response)
{
std::cout << "success!!!" << std::endl;
}
};

让我们看看如何使用它:

int main()
{
myMQTTClass * m = new myMQTTClassImpl();

MQTTAsync_responseOptions options;
options.onSuccess = myMQTTClass::callback;
options.context = m;
}

编辑(指发布的实际代码):

在您的publish 方法中,这是正确的:

conn_opts.onSuccess = rover::RoverPahoMQTT::onPublisherConnect;

这是错误的:

conn_opts.context = this->client;

应该是:

conn_opts.context = this;

关于c++ - 在 C++ 类中实现回调函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47731244/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com