문자열 기반 연결과 함수 기반 연결의 차이점

Qt는 C++에서 신호 슬롯 연결을 작성하는 두 가지 방법을 제공합니다: 문자열 기반 연결 구문과 함수 기반 연결 구문입니다. 두 구문 모두 장단점이 있습니다. 아래 표는 그 차이점을 요약한 것입니다.

문자열 기반함수 기반
유형 검사는 다음에서 수행됩니다.런타임컴파일 타임
암시적 타입 변환 수행 가능Y
신호를 람다 표현식에 연결할 수 있음Y
신호를 신호보다 인수가 많은 슬롯에 연결할 수 있습니다(기본 매개변수 사용).Y
C++ 함수를 QML 함수에 연결 가능Y

다음 섹션에서는 이러한 차이점을 자세히 설명하고 각 연결 구문에 고유한 기능을 사용하는 방법을 설명합니다.

유형 검사 및 암시적 유형 변환

문자열 기반 연결은 런타임에 문자열을 비교하여 유형을 확인합니다. 이 접근 방식에는 세 가지 제한 사항이 있습니다:

  1. 연결 오류는 프로그램 실행이 시작된 후에만 감지할 수 있습니다.
  2. 신호와 슬롯 간에는 암시적 변환을 수행할 수 없습니다.
  3. 타입 정의 및 네임스페이스는 확인할 수 없습니다.

제한 사항 2와 3은 문자열 비교기가 C++ 유형 정보에 액세스할 수 없으므로 정확한 문자열 일치에 의존하기 때문에 존재합니다.

이와 대조적으로, 함수 기반 연결은 컴파일러가 검사합니다. 컴파일러는 컴파일 타임에 오류를 포착하고, 호환되는 유형 간의 암시적 변환을 가능하게 하며, 동일한 유형의 다른 이름을 인식합니다.

예를 들어, int 를 전달하는 신호를 double 을 받는 슬롯에 연결하는 데는 함수 기반 구문만 사용할 수 있습니다. QSlider 에는 int 값이 있고 QDoubleSpinBox 에는 double 값이 있습니다. 다음 스니펫은 이를 동기화하는 방법을 보여줍니다:

    auto slider = new QSlider(this);
    auto doubleSpinBox = new QDoubleSpinBox(this);

    // OK: The compiler can convert an int into a double
    connect(slider, &QSlider::valueChanged,
            doubleSpinBox, &QDoubleSpinBox::setValue);

    // ERROR: The string table doesn't contain conversion information
    connect(slider, SIGNAL(valueChanged(int)),
            doubleSpinBox, SLOT(setValue(double)));

다음 예제는 이름 확인이 필요하지 않은 경우를 보여줍니다. QAudioInput::stateChanged()는 "QAudio::State" 유형의 인수로 선언됩니다. 따라서 문자열 기반 연결은 "State" 이 이미 표시되어 있더라도 "QAudio::State"를 지정해야 합니다. 인수 유형이 연결의 일부가 아니므로 이 문제는 함수 기반 연결에는 적용되지 않습니다.

    auto audioInput = new QAudioInput(QAudioFormat(), this);
    auto widget = new QWidget(this);

    // OK
    connect(audioInput, SIGNAL(stateChanged(QAudio::State)),
            widget, SLOT(show()));

    // ERROR: The strings "State" and "QAudio::State" don't match
    using namespace QAudio;
    connect(audioInput, SIGNAL(stateChanged(State)),
            widget, SLOT(show()));

    // ...

람다 표현식에 연결하기

함수 기반 연결 구문은 사실상 인라인 슬롯인 C++11 람다 표현식에 신호를 연결할 수 있습니다. 이 기능은 문자열 기반 구문에서는 사용할 수 없습니다.

다음 예제에서 TextSender 클래스는 QString 매개 변수를 전달하는 textCompleted() 신호를 내보냅니다. 다음은 클래스 선언입니다:

class TextSender : public QWidget {
    Q_OBJECT

    QLineEdit *lineEdit;
    QPushButton *button;

signals:
    void textCompleted(const QString& text) const;

public:
    TextSender(QWidget *parent = nullptr);
};

다음은 사용자가 버튼을 클릭할 때 TextSender::textCompleted() 을 전송하는 연결입니다:

TextSender::TextSender(QWidget *parent) : QWidget(parent) {
    lineEdit = new QLineEdit(this);
    button = new QPushButton("Send", this);

    connect(button, &QPushButton::clicked, [=] {
        emit textCompleted(lineEdit->text());
    });

    // ...
}

이 예제에서는 QPushButton::clicked()와 TextSender::textCompleted() 에 호환되지 않는 매개변수가 있음에도 불구하고 람다 함수를 사용하여 연결을 간단하게 만들었습니다. 이와 대조적으로 문자열 기반 구현에서는 추가 상용구 코드가 필요합니다.

참고: 함수 기반 연결 구문은 독립형 함수와 일반 멤버 함수를 포함한 모든 함수에 대한 포인터를 허용합니다. 그러나 가독성을 위해 신호는 슬롯, 람다 표현식 및 기타 신호에만 연결해야 합니다.

C++ 객체를 QML 객체에 연결하기

문자열 기반 구문은 C++ 객체를 QML 객체에 연결할 수 있지만, 함수 기반 구문은 연결할 수 없습니다. 이는 QML 유형이 런타임에 확인되므로 C++ 컴파일러에서 사용할 수 없기 때문입니다.

다음 예제에서는 QML 객체를 클릭하면 C++ 객체가 메시지를 출력하고, 그 반대의 경우도 마찬가지입니다. 다음은 QML 유형입니다( QmlGui.qml):

Rectangle {
    width: 100; height: 100

    signal qmlSignal(string sentMsg)
    function qmlSlot(receivedMsg) {
        console.log("QML received: " + receivedMsg)
    }

    MouseArea {
        anchors.fill: parent
        onClicked: qmlSignal("Hello from QML!")
    }
}

다음은 C++ 클래스입니다:

클래스 CppGui : public QWidget { Q_OBJECT    QPushButton *버튼;signals: void cppSignal(const QVariant& sentMsg) const;public slots: void cppSlot(const QString& receivedMsg) const {        qDebug() << "C++ received:" << receivedMsg;
    }public: CppGui(QWidget *부모 = nullptr) : QWidget(부모) { button = new QPushButton("Click Me!", this); connect(button, &(QPushButton::clicked, [=] { emit cppSignal("Hello from C++!"); }); } };

다음은 신호-슬롯 연결을 만드는 코드입니다:

    auto cppObj = new CppGui(this);
    auto quickWidget = new QQuickWidget(QUrl("QmlGui.qml"), this);
    auto qmlObj = quickWidget->rootObject();

    // Connect QML signal to C++ slot
    connect(qmlObj, SIGNAL(qmlSignal(QString)),
            cppObj, SLOT(cppSlot(QString)));

    // Connect C++ signal to QML slot
    connect(cppObj, SIGNAL(cppSignal(QVariant)),
            qmlObj, SLOT(qmlSlot(QVariant)));

참고: QML의 모든 JavaScript 함수는 타입 어노테이션을 사용하지 않는 한 var 타입의 매개변수를 사용하며, 이는 C++의 QVariant 타입에 매핑됩니다. 자세한 내용은 QML 메서드 호출하기를 참조하세요.

QPushButton 을 클릭하면 콘솔에 'QML을 받았습니다: "Hello from C++!"'라고 출력됩니다. 마찬가지로 직사각형을 클릭하면 콘솔에 'C++ 수신됨: "Hello from QML!"'이라고 출력됩니다.

C++ 객체가 QML 객체와 상호 작용할 수 있는 다른 방법은 C++에서 QML 객체와 상호 작용하기를 참조하세요.

슬롯의 기본 매개변수를 사용하여 더 적은 수의 매개변수로 신호에 연결하기

일반적으로 슬롯의 인자 수가 신호와 같거나 그 이하이고 모든 인자 유형이 호환되는 경우에만 연결할 수 있습니다.

문자열 기반 연결 구문은 이 규칙에 대한 해결 방법을 제공합니다. 슬롯에 기본 매개변수가 있는 경우 해당 매개변수를 신호에서 생략할 수 있습니다. 신호가 슬롯보다 적은 수의 인자로 전송되면 Qt는 기본 파라미터 값을 사용하여 슬롯을 실행합니다.

함수 기반 연결은 이 기능을 지원하지 않습니다.

기본 인자가 printNumber() 슬롯을 가진 DemoWidget 클래스가 있다고 가정해 봅시다:

public slots: void printNumber(int number = 42) {        qDebug() << "Lucky number" << number;
    }

문자열 기반 연결을 사용하면 인수가 없는 경우에도 QApplication::aboutToQuit()에 DemoWidget::printNumber() 을 연결할 수 있습니다. 함수 기반 연결은 컴파일 타임 오류를 생성합니다:

DemoWidget::DemoWidget(QWidget *부모) : QWidget(parent) { // OK: printNumber()가 기본값 42로 호출됩니다.    connect(qApp, SIGNAL(aboutToQuit()),
           this, SLOT(printNumber())); // ERROR: 컴파일러에 호환 가능한 인수가 필요합니다.    connect(qApp, &QCoreApplication::aboutToQuit,
           this, &DemoWidget::printNumber); }

함수 기반 구문을 사용하여 이 제한을 해결하려면 슬롯을 호출하는 람다 함수에 신호를 연결하세요. 위의 람다 표현식에 연결하기 섹션을 참조하세요.

과부하된 신호 및 슬롯 선택하기

문자열 기반 구문을 사용하면 매개변수 유형이 명시적으로 지정됩니다. 따라서 원하는 오버로드된 신호 또는 슬롯의 인스턴스가 명확합니다.

반면, 함수 기반 구문을 사용하면 오버로드된 신호 또는 슬롯을 캐스팅하여 컴파일러에 어떤 인스턴스를 사용할지 알려줘야 합니다.

예를 들어 QLCDNumber 에는 display() 슬롯의 세 가지 버전이 있습니다:

  1. QLCDNumber::display(int)
  2. QLCDNumber::display(double)
  3. QLCDNumber::display(QString)

int 버전을 QSlider::valueChanged()에 연결하려면 두 가지 구문이 있습니다:

    auto slider = new QSlider(this);
    auto lcd = new QLCDNumber(this);

    // String-based syntax
    connect(slider, SIGNAL(valueChanged(int)),
            lcd, SLOT(display(int)));

    // Functor-based syntax
    connect(slider, &QSlider::valueChanged,
            lcd, qOverload<int>(&QLCDNumber::display));

qOverload()도 참조하세요 .

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.