このページでは

文字列ベースの接続とファンクタベースの接続の違い

Qtでは、C++でシグナル・スロット接続を記述するために、文字列ベースの接続構文とファンクタベースの接続構文という2つの異なる方法が用意されています。どちらの構文にも長所と短所があります。以下の表に、それらの違いをまとめました。

機能文字列ベースファンクタベース
型チェック実行時に実行されるコンパイル時に実行
暗黙的な型変換を実行可能。不可はい
シグナルをラムダ式に接続できます。いいえはい
シグナルよりも引数の数が多いスロットにシグナルを接続できる(デフォルトパラメータを使用)。はいいいえ
C++関数をQML関数に接続できます。はいいいえ

以下のセクションでは、これらの違いについて詳しく説明し、それぞれの接続構文に固有の機能の使用方法を示します。

型チェックと暗黙の型変換

文字列ベースの接続では、実行時に文字列を比較することで型チェックが行われます。

以下の制限が適用されます:

制限事項理由
接続エラーは、プログラムの実行が開始されてからでないと検出できません。該当なし
シグナルとスロットの間では、暗黙の型変換を行うことはできません。文字列比較関数は C++ の型情報にアクセスできないため、文字列の完全一致に依存します。
typedef および名前空間は解決できません。

対照的に、ファンクタベースの接続はコンパイラによってチェックされます。コンパイラはコンパイル時にエラーを検出し、互換性のある型間の暗黙の型変換を可能にし、同じ型の異なる名前を認識します。

たとえば、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()));

    // ...

ラムダ式への接続

ファンクタベースの接続構文では、シグナルをラムダ式(実質的にはインラインスロット)に接続することができます。この機能は、文字列ベースの構文では利用できません。

次の例では、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++クラスは以下の通りです:

classCppGui :publicQWidget {
    Q_OBJECT

    QPushButton*button;

signals:
    voidcppSignal(constQVariant&sentMsg)const;

public slots:
    voidcppSlot(constQString&receivedMsg)const{
        qDebug() << "C++ received:" << receivedMsg;
    }

public:
    CppGui(QWidget*parent =nullptr) : QWidget(parent) {
        button= newQPushButton("Click Me!", this);
        connect(button, &QPushButton::clicked, [=]{
            emitcppSignal("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 received: "Hello from C++!"」と表示されます。同様に、Rectangleがクリックされると、コンソールに「C++ received: "Hello from QML!"」と表示されます。

C++ オブジェクトと QML オブジェクトを連携させるその他の方法については、「C++ からQML オブジェクトと連携する」を参照してください。

スロットでデフォルトパラメータを使用して、より少ないパラメータでシグナルに接続する

通常、スロットの引数の数がシグナルの引数の数と同じ(またはそれ以下)であり、かつすべての引数の型が互換性がある場合にのみ、接続を行うことができます。

文字列ベースの接続構文では、このルールに対する回避策が用意されています。スロットにデフォルトパラメータが定義されている場合、シグナル側でそれらのパラメータを省略することができます。シグナルがスロットよりも少ない引数で発火された場合、Qtはデフォルトパラメータ値を使用してスロットを実行します。

ファンクタベースの接続では、この機能はサポートされていません。

DemoWidget というクラスがあり、そのスロットprintNumber() にデフォルト引数がある場合を想定します:

public slots:
    voidprintNumber(intnumber= 42) {
        qDebug() << "Lucky number" << number;
    }

文字列ベースの接続を使用すると、DemoWidget::printNumber() をQApplication::aboutToQuit()に接続できます。後者には引数がないにもかかわらずです。ファンクタベースの接続では、コンパイル時にエラーが発生します:

DemoWidget::DemoWidget(QWidget*parent) : QWidget(parent) {

    // OK: printNumber() はデフォルト値 42 で呼び出されます
    connect(qApp, SIGNAL(aboutToQuit()),
           this,SLOT(printNumber()));

    // エラー:コンパイラは互換性のある引数を要求しています
    connect(qApp, &QCoreApplication::aboutToQuit,
           this, &DemoWidget::printNumber);
}

ファンクタベースの構文におけるこの制限を回避するには、シグナルをスロットを呼び出すラムダ関数に接続してください。上記の「ラムダ式への接続」のセクションを参照してください。

オーバーロードされたシグナルとスロットの選択

文字列ベースの構文では、パラメータ型が明示的に指定されます。その結果、オーバーロードされたシグナルやスロットのうち、どのインスタンスを呼び出すかが曖昧になることはありません。

対照的に、ファンクタベースの構文では、オーバーロードされたシグナルやスロットのどのバージョンに接続したいかを明示的に指定する必要があります。

たとえば、QLCDNumber には、display() スロットの3つのバージョンがあります:

  • QLCDNumber::display(int)
  • QLCDNumber::display(double)
  • QLCDNumber::display(QString)

int のバージョンをQSlider::valueChanged()に接続するには、次の2つの構文があります:

    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()、static_cast、およびラムダ式を使用してオーバーロードされたシグナルやスロットに接続する詳細な例については、「オーバーロードされたシグナルおよびスロットへの接続」を参照してください。

qOverload()も参照してください 。

© 2026 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.