为什么可以连接到未声明为 Q_SLOTS 的函数?

Why is it possible to connect to a function that is not declared as Q_SLOTS?

我'accidentally'连接了一个信号到QWidget::setToolTip():

bool ok = connect(source, &Source::textSignal, widget, &QWidget::setToolTip);
Q_ASSERT(ok);

... 成功了。不仅连接成功,函数也被正确调用

自己试一下:
main.cpp

#include <QApplication>
#include <QLineEdit>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLineEdit le;
    bool ok = QObject::connect(&le, &QLineEdit::textChanged, &le, &QWidget::setToolTip);
    Q_ASSERT(ok);
    le.show();
    return a.exec();
}

setToolTip() 未声明为 slot.

来自 qwidget.h:

    // [...]
public Q_SLOTS: // start of Q_SLOTS
    void setWindowTitle(const QString &);
#ifndef QT_NO_STYLE_STYLESHEET
    void setStyleSheet(const QString& styleSheet);
#endif
public: // from my understanding, this should end the Q_SLOTS region
#ifndef QT_NO_STYLE_STYLESHEET
    QString styleSheet() const;
#endif
    QString windowTitle() const;
    // [...]
    bool isWindowModified() const;
#ifndef QT_NO_TOOLTIP
    void setToolTip(const QString &); // no Q_SLOTS!?
    QString toolTip() const;
    void setToolTipDuration(int msec);
    int toolTipDuration() const;
#endif

所以我想:这是因为toolTip声明为Q_PROPERTY吗?

    Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip)

文档中没有提及。

我在 woboq.com ('Connecting to any function' and preceding) 找到了答案:

[...]

class Test : public QObject
{ Q_OBJECT
public:
    Test() {
        connect(this, &Test::someSignal, this, &Test::someSlot);
    }
signals:
    void someSignal(const QString &);
public:
    void someSlot(const QVariant &);
};

Connecting to any function

As you might have seen in the previous example, the slot was just declared as public and not as slot. Qt will indeed call directly the function pointer of the slot, and will not need moc introspection anymore. (It still needs it for the signal)

But what we can also do is connecting to any function or functor:

static void someFunction() {
    qDebug() << "pressed";
}
// ... somewhere else
    QObject::connect(button, &QPushButton::clicked, someFunction);

This can become very powerful when you associate that with boost or tr1::bind.

=> 函数指针无需声明为 public slots: 即可调用。

有不同的连接方式(阅读 QObject 文档),有些需要 函数名 ,有些需要 元方法 ,有些需要成员指针和一些仿函数。您只是在使用接受 指向成员 的指针的那个。

QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)