2017-12-25 8 views
-1

私はstd::functionを使用してC++でコールバックを使用しようとしています。私は2つのファイル、mainwindow.cpptcpclient.cppを持っています。 mainwindowのメンバ関数は、ある偶数が発生したときに渡された関数を呼び出すためにtcpclientに渡されます。C++でコールバックを使用するには?

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をコールバックに渡すにはどうすればよいですか?

編集:最初のコメントに従って、私はこの質問に関係のないコード部分を削除して明快さを改善しました。

+0

http://idownvotedbecau.se/toomuchcode/ – Murphy

+1

を作ることです。わかりやすさを高めるために無関係なコード部分を削除しました。私は将来の投稿時にこれを念頭に置いておきます。投票の理由をご提供いただき、ありがとうございます。 – Vino

+0

エラーを生成する行を指定した場合に役立ちます。私はそれがそのエラーを引き起こすかどうかわからないという1つの問題があると思う。あなたのコンストラクタのonCompletionCallbackパラメータは 'std :: functionへのポインタ'なので、 'std :: function '型のオブジェクトに逆参照なしで代入するのはあなたの望むものではありません。パラメータから*を削除するか、初期化を 'onCompletionCallback(* onCompletionCallback)'に変更してください。 – Eelke

答えて

1

別にサムVarshavachikの答えからのエラーを解決するには、私は同意するvoid onCompletionCallback(int)staticメンバ関数

2

示されたコードには複数の問題があります。少なくとも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は(...)"、一時オブジェクトを作成します。この一時的なオブジェクトは完全な式の評価の直後に破棄されます。

この結果、一時的なオブジェクトへのポインタが即座に破棄されます。このポインタを後で参照解除すると、ワイルドポインタの逆参照が発生し、かなりのクラッシュが発生します。コンパイルエラーを修正すると、コードを修正するまでコードがひどくクラッシュすることがわかります。

現代のコンパイラのほとんどは、このような頻繁な種類の論理的なバグを検出し、警告を出すのに十分スマートです。コンパイラがこの行で警告を発行している場合でも、コンパイラが結果のコードをコンパイルしていても、コンパイラの診断を無視しないことが重要です。コンパイラの警告メッセージは、ほとんどの場合正当な理由で発行されており、無視すべきではありません。

+0

Hey Sam。私に詳細な答えを与えるために時間をとってくれてありがとう、ありがとう。本当に役に立ちました。もう一度ありがとう、私は高度なC + +コーダーではありませんが、あなたのような人々からの洞察を得ることは、本当に私が学ぶのを助けています。 – Vino

+0

Hey Sam、アドバイスしたとおりにコードを修正しました(コールバック関数の 'const'参照を受け入れる' TCPClient'の 'コンストラクタ'を修正しました)。どのような考えですか? – Vino

+1

あなたは思ったことを尋ねました。これは、経験豊富なC++コーダーは、最初に大量のコードを書いておらず、全体をコンパイルしようとしています。少しずつ書いてコンパイルしてテストした後、もう少し詳しく書いてコンパイルして、もう一度テストしてみると、一度にいくつかのエラーしか扱わなくてはなりません。あなたが今持っているものを持って、新しい[mcve]を準備し、それを理解できなければ新しい質問を投稿してください。 –

関連する問題