如何在 C++ 中使用回调?
How to use callbacks in c++?
我正在尝试使用 std::function
在 C++ 中使用回调。我有两个文件,mainwindow.cpp
和 tcpclient.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";
}
我收到以下错误
non static member function must be called
这个错误是什么意思?如何使用 std::function
传递回调?
编辑:根据第一条评论,我删除了与此问题无关的代码部分以提高清晰度。
显示的代码中存在多个问题。至少有两个问题是显而易见的:一个导致编译错误,第二个将编译错误放在一边,将导致未定义的行为,并且几乎肯定会崩溃。
A std::function
class 成员声明如下:
std::function<void(int)> onCompletionCallback;
这个声明似乎是正确的,但是初始化这个 class 成员的尝试如下:
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<...> ¶meter
、const
引用。
第二个问题在MainWindow
的构造函数中:
tcpClient_ = &TCPClient( /* ... */ )
此表达式 "TCPClient( ... )" 构造一个临时对象。该临时对象在完整表达式求值后立即被销毁。
这导致此表达式保存指向立即销毁的临时对象的指针。随后对该指针的取消引用会导致野指针取消引用,并且几乎肯定会发生崩溃。一旦你修复了你的编译错误,你会发现你的代码会可怕地崩溃,直到你也修复它。
大多数现代编译器都足够聪明,可以检测到这种常见的逻辑错误,并发出警告。如果您的编译器也在这一行发出警告,这是一个宝贵的教训,不要忽略编译器诊断,即使编译器仍在编译生成的代码。编译器的警告消息几乎总是有充分的理由发出,不应被忽视。
除了 Sam Varshavachik 的回答之外,错误的解决方案是使 void onCompletionCallback(int)
成为 static
成员函数
我正在尝试使用 std::function
在 C++ 中使用回调。我有两个文件,mainwindow.cpp
和 tcpclient.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";
}
我收到以下错误
non static member function must be called
这个错误是什么意思?如何使用 std::function
传递回调?
编辑:根据第一条评论,我删除了与此问题无关的代码部分以提高清晰度。
显示的代码中存在多个问题。至少有两个问题是显而易见的:一个导致编译错误,第二个将编译错误放在一边,将导致未定义的行为,并且几乎肯定会崩溃。
A std::function
class 成员声明如下:
std::function<void(int)> onCompletionCallback;
这个声明似乎是正确的,但是初始化这个 class 成员的尝试如下:
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<...> ¶meter
、const
引用。
第二个问题在MainWindow
的构造函数中:
tcpClient_ = &TCPClient( /* ... */ )
此表达式 "TCPClient( ... )" 构造一个临时对象。该临时对象在完整表达式求值后立即被销毁。
这导致此表达式保存指向立即销毁的临时对象的指针。随后对该指针的取消引用会导致野指针取消引用,并且几乎肯定会发生崩溃。一旦你修复了你的编译错误,你会发现你的代码会可怕地崩溃,直到你也修复它。
大多数现代编译器都足够聪明,可以检测到这种常见的逻辑错误,并发出警告。如果您的编译器也在这一行发出警告,这是一个宝贵的教训,不要忽略编译器诊断,即使编译器仍在编译生成的代码。编译器的警告消息几乎总是有充分的理由发出,不应被忽视。
除了 Sam Varshavachik 的回答之外,错误的解决方案是使 void onCompletionCallback(int)
成为 static
成员函数