如何在c ++中使用回调? [重复]

问题描述 投票:-1回答:2

这个问题在这里已有答案:

我正在尝试使用std::function在c ++中使用回调。我有两个文件,mainwindow.cpptcpclient.cppmainwindow的成员函数传递给tcpclient,以便在某个偶数发生时调用传递的函数。

mainwindow.h

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void connectedToServer(int errorCode);

    ~MainWindow();

private slots:
    void on_connectButton_clicked();
    TCPClient *tcpClient_;
private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    tcpClient_ = &TCPClient("localhost", ui->portText->text(), ui->consoleText, this->connectedToServer)
}

tcpclient.h

#ifndef TCPCLIENTH
#define TCPCLIENTH

#include <QTcpSocket>
#include <QString>
#include <QJsonDocument>
#include <QTextEdit>
#include <functional>
#include <tcpclientbadresponse.h>
#include <tcpclientserverdisconnected.h>


class TCPClient : public QTcpSocket
{
public:
    TCPClient(QString hostName, int port, QString clientID, QTextEdit *consoleText,
              std::function<void(int)> *onCompletionCallback);
    void connectToServer(QString requestType, QJsonDocument requestJson);
    QJsonDocument getResponse() const;

private:
    std::function<void(int)> onCompletionCallback;


};

#endif // TCPCLIENTH

tcpclient.cpp

#include "tcpclient.h"
#include <QDebug>
#include <QIODevice>
#include <QAbstractSocket>
#include <QByteArray>
#include <exception>


TCPClient::TCPClient(QString hostName, int port, QString clientID, QTextEdit *consoleText,
                     std::function<void(int)> *onCompletionCallback)
: hostName_(hostName),
  port_(port),
  clientID_(clientID),
  consoleText_(consoleText),
  onCompletionCallback(onCompletionCallback)
{
    this->connectionStatus_ = TCPClient::CONNECTION_STATUS::IDLE;
    qDebug() << "Client " << clientID_ << " created";
}

我收到以下错误

必须调用非静态成员函数

这个错误是什么意思?如何使用std::function传递回调?

编辑:根据第一条评论,我删除了与此问题无关的代码部分,提高了清晰度。

c++ qt std-function
2个回答
2
投票

所示代码中存在多个问题。至少有两个问题是显而易见的:导致编译错误的问题和第二个问题,如果预留了编译错误,将导致未定义的行为,并且几乎可以保证崩溃。

std::function类成员声明如下:

std::function<void(int)> onCompletionCallback;

此声明似乎是正确的,但尝试初始化此类成员如下:

TCPClient::TCPClient(/* ... */
     std::function<void(int)> *onCompletionCallback)
: /* ... */
  onCompletionCallback(onCompletionCallback)

构造函数的参数是指向此std::function的指针,并尝试从指向std::function的指针初始化此std::function

这将无法编译,原因与您无法编译声明为的任何内容相同

int someClassmember;

然后初始化为

someConstructor(int *someClassmember)
   : someClassmember(someClassmember)

你不能从指向int的指针初始化int。同样,你不能从指向std::function的指针初始化std::function。修复应该是显而易见的。构造函数的参数不应该是指针;并且,最佳地,它应该被声明为const std::function<...> &parameterconst参考。

第二个问题是在MainWindow的构造函数中:

tcpClient_ = &TCPClient( /* ... */ )

此表达式“TCPClient(...)”构造一个临时对象。在评估完整表达式后立即销毁此临时对象。

这导致此表达式保存指向立即销毁的临时对象的指针。随后取消引用此指针会导致野指针取消引用,并且几乎可以保证崩溃。一旦修复了编译错误,你就会发现你的代码会崩溃,直到你解决了这个问题。

大多数现代编译器都足够智能,可以检测到这种常见的逻辑错误,并发出警告。如果您的编译器也在此行发出警告,那么即使编译器仍然编译生成的代码,这也是一个不值得忽略编译器诊断的宝贵教训。编译器的警告消息几乎总是有充分理由发出,不应该被忽略。


1
投票

除了Sam Varshavachik的答案之外,错误的解决方案是让void onCompletionCallback(int)成为static的成员函数

© www.soinside.com 2019 - 2024. All rights reserved.