【问题标题】:How to use callbacks in c++? [duplicate]如何在 C++ 中使用回调? [复制]
【发布时间】:2017-12-25 02:21:49
【问题描述】:

我正在尝试使用 std::function 在 c++ 中使用回调。我有两个文件,mainwindow.cpptcpclient.cpp。将mainwindow 的成员函数传递给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 传递回调?

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

【问题讨论】:

  • 我同意。我删除了不相关的代码部分以提高清晰度。以后发帖时我会牢记这一点。感谢您提供拒绝投票的理由。
  • 如果您指定哪一行会产生该错误,将会有所帮助。我想我看到一个问题,我不确定它是否会导致该错误。构造函数的 onCompletionCallback 参数是 pointer to std::function&lt;void(int)&gt;,因此在不取消引用的情况下将其分配给 std::function&lt;void(int)&gt; 类型的对象不是您想要的。要么去掉参数中的*,要么调整初始化为onCompletionCallback(*onCompletionCallback)

标签: c++ qt std-function


【解决方案1】:

显示的代码中有多个问题。至少有两个问题是显而易见的:一个是导致编译错误的问题,另一个是编译错误放在一边,将导致未定义的行为,并且几乎可以保证崩溃。

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&lt;...&gt; &amp;parameterconst 引用。

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

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

这个表达式“TCPClient( ... )”构造了一个临时对象。这个临时对象在完成表达式的计算后立即被销毁。

这会导致该表达式保存一个指向立即销毁的临时对象的指针。此指针的后续取消引用会导致野指针取消引用,并且几乎可以保证崩溃。修复编译错误后,您会发现代码会严重崩溃,直到您也修复此问题为止。

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

【讨论】:

  • 嘿山姆。非常感谢您花时间给我一个详细的答复。这真的很有帮助。再次感谢,我不是那么高级的 c++ 编码器,但是从像你这样的人那里获得见解确实有助于我学习。
  • 嘿 Sam,我按照您的建议修复了代码(我修改了 TCPClientconstructor 以接受对回调函数的 const 引用。但我仍然收到错误 reference to a non-static member function must be called . 有什么想法吗?
  • 你问了一个想法,这里有一个:有经验的 C++ 编码人员不要先写一大堆代码,然后再尝试编译整个东西。大量的代码总是从很小的开始。编写、编译和测试了一点点。然后再写一点,再次编译和测试。这样,一个人一次只需要处理几个错误。这就是我写“至少有两个问题很明显”的原因。解决明显的问题可能会让其他问题曝光。拿着你现在的东西,准备一个新的minimal reproducible example,如果你想不通,就发布一个新问题。
  • 但是你应该在你的新问题中证明你试图自己理解和修复你的编译错误。
  • 感谢您的建议。我认为您编写小代码单元并对其进行测试的方法非常好且有用。我将使用这种方法。无论如何,我解决了我的问题,谢谢。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    相关资源
    最近更新 更多