String-Based 和 Functor-Base的Connect区别

在Qt5.0之后,QObject::connect在String-Based的基础上增加了Functor-Base形式的语法,他们之间的区别主要如下:

基于字符串的基于函数的
类型检查完成时间运行时编译时
是否可以隐式转换
支持信号连接至Lambda
支持槽参数大于信参数(通过默认参数)
支持C++函数连接至QML函数

下面将对上述几个方面进行解释:

一、类型检查和隐式转换

String-based类型的连接将会在运行时对比字符串来完成检查,这样有三个限制:

  • 只有当程序运行时才能检查到错误
  • 隐式转换无法用在信号和槽
  • typedef和namespace无法被解析

后两者不可行的原因是,string比较器无法获知C++真正的类型,所以需要严格的字符串匹配。

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)));

二、连接Lambda表达式

class TextSender : public QWidget {
    Q_OBJECT

    QLineEdit *lineEdit;
    QPushButton *button;

signals:
    void textCompleted(const QString& text) const;//发送一个QString参数信号

public:
    TextSender(QWidget *parent = nullptr);
};
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信号是无参的,但是通过Lambda捕获可以发送一些额外的信息,如这里的QString.
    });
}

注意:虽然Functor-based类型的连接中函数指针可以是包含普通函数(包括成员函数)的任意类型,但是为了可读性,最好是slots Lambda表达式或者signals中的一种。

三、连接C++对象至QML对象

不了解QML,略

四、在slots中使用默认参数连接更少参数的信号

一般来说,信号参数和槽参数个数是相等的,当然你可以发送多点信号给我,槽可以不接收,但是一般不能少发信号。

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

    // OK: printNumber() will be called with a default value of 42
    connect(qApp, SIGNAL(aboutToQuit()),
            this, SLOT(printNumber()));//String-based参数通过默认实参实现匹配,OK

    // ERROR: Compiler requires compatible arguments
    connect(qApp, &QCoreApplication::aboutToQuit,
            this, &DemoWidget::printNumber);//Functor-based要求参数是完全匹配的,Not OK
}

四、 选择重载的信号和槽

在String-based中,信号与槽参数情况是显式给定的,不存在歧义;在Function-based中,信号与槽的参数列表被省略,存在歧义。解决这个问题也比较简单,有三个方法:

  • static_cast<T>() 强制转换对应的信号与槽
  • 声明一个函数指针作为参数传入
  • QOverload<T>::of() QT方式1 调用QOverload的静态方法of
  • qOverload<T>() QT方式2 调用qOverload函数模板

static_cast和Qt的两种类型QOverload、qOverload的区别在于,QT的T是参数,而static_cast则是完整的函数类型。

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, first alternative
connect(slider, &QSlider::valueChanged,
        lcd, static_cast<void (QLCDNumber::*)(int)>(&QLCDNumber::display));

// Functor-based syntax, second alternative
void (QLCDNumber::*mySlot)(int) = &QLCDNumber::display;
connect(slider, &QSlider::valueChanged,
        lcd, mySlot);

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

// Functor-based syntax, fourth alternative (requires C++14)
connect(slider, &QSlider::valueChanged,
        lcd, qOverload<int>(&QLCDNumber::display));

[1] https://doc.qt.io/qt-5.15/signalsandslots-syntaxes.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值