2017-12-25 12 views
-1

std::function을 사용하여 C++에서 콜백을 사용하려고합니다. 두 파일, 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

오류를 생성하는 행을 지정한 경우 도움이됩니다. 한 가지 문제가 그 오류를 일으키는 지 확실하지 않다고 생각하는 것 같습니다. 생성자의 onCompletionCallback 매개 변수는'std :: function에 대한 포인터 '이므로 참조 해제하지 않고'std :: function '유형의 객체에 할당하는 것은 원하지 않습니다. 매개 변수에서 *를 제거하거나 초기화를 'onCompletionCallback (* onCompletionCallback)'으로 조정하십시오. – Eelke

답변

1

솔루션은 void onCompletionCallback(int)에게 동의 static 멤버 함수

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<...> &parameter, const 참조로 선언해야합니다.

두번째 문제 MainWindow의 생성자이다

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

이 표현은 "하여 TcpClient은 (...)"임시 객체를 구성한다. 이 임시 객체는 완전한 표현식을 평가 한 직후에 파기됩니다.

이 표현식은 즉시 삭제되는 임시 객체에 대한 포인터를 저장합니다. 이후에이 포인터를 역 참조하면 와일드 포인터 역 참조가 발생하고 거의 확실한 충돌이 발생합니다. 컴파일 오류를 수정하면 코드를 고칠 때까지 코드가 심각하게 손상된다는 것을 알 수 있습니다.

대부분의 최신 컴파일러는 이러한 잦은 종류의 논리적 버그를 감지하고 경고를 표시 할 정도로 똑똑합니다. 컴파일러가이 줄에서 경고를 발행하는 경우 컴파일러에서 여전히 결과 코드를 컴파일하더라도 컴파일러 진단을 무시하지 않는 것이 중요합니다. 컴파일러의 경고 메시지는 거의 항상 좋은 이유로 발행되며 무시해서는 안됩니다. 에러에 대한 샘 Varshavachik의 대답은 그렇다

+0

Hey Sam. 나에게 상세한 답변을 주셔서 감사합니다. 정말 도움이되었습니다. 다시 한 번 감사드립니다. 저는 C++ 코더가 그렇게 진보적 인 것은 아니지만, 여러분 같은 사람들로부터 통찰력을 얻는 것은 실제로 제가 배울 수 있도록 도와줍니다. – Vino

+0

Hey Sam, 조언 한대로 코드를 수정했습니다 (콜백 함수에 대한'const' 참조를 받아들이도록'TCPClient'의'constructor '을 수정했습니다.)하지만 여전히 정적이 아닌 멤버 함수에 대한 참조가 반드시 있어야합니다. 어떤 생각? – Vino

+1

당신은 생각해 보았습니다. 경험있는 C++ 코더는 먼저 많은 양의 코드를 작성한 다음 전체를 컴파일하려고 시도합니다. 많은 양의 코드가 항상 작은 것으로 시작합니다. 작은 비트를 작성하고 컴파일하고 테스트 한 다음 조금 더 작성하고 다시 컴파일하고 테스트합니다. 이렇게하면 한 번에 몇 가지 오류 만 처리해야하므로 "적어도 두 가지 문제가 있습니다. 명백한 문제를 해결하면 다른 사람들이 빛을 보게 될 것입니다. 지금 가지고있는 것을 가지고 새로운 [mcve]를 준비하고, 알아낼 수없는 경우 새로운 질문을 올리십시오. –