Qt4与Qt5的信号差异

新旧语法对比

     举例介绍。某个类在值变化时发送valueChanged(QString,QString)信号,需要在槽showValue(QString)中对改变的值做相应的处理。在Qt4中一般这样来关联信号和槽:

     connect(sender,SIGNAL(valueChanged(QString,QString)),receiver,SLOT(showValue(QString)));

     Qt4的SIGNAL和SLOT两个宏,实际是将其参数转换成相应的字符串。在编译之前,Qt的moc工具从源代码中提取出所需要的元数据,形成一张由使用了signals和slots修饰的所有函数组成的字符串表。connect函数将与信号关联起来的槽的字符串,同这张字符串中的信息进行匹配,也就能够在发出信号时知道需要调用哪个槽函数。

     这种实现有下面两个问题

          1、没有编译期检查。由于信号和槽都会被SIGNAL和SLOT宏处理成字符串,字符串的对比是在运行时完成的,并且失去了类型信息。所以,我们在编写Qt4程序时,有时会出现编译通过但是运行时原本应该调用的槽函数却没有执行。此时,编译器不能给出任何错误信息,只能在运行时看有没有警告
          2、无法使用相容类型的参数。由于connect函数使用的是字符串对比,所以槽函数参数类型的名称必须和信号的完全一致,也必须与头文件中的类型一致。这里的”一致“是严格的字符串意义上的相同,因此,那些使用了tyoedef或者namespace的类型,即便实际类型是相同的,依然可能由于字符串名字不一样而不能正常工作。

     为了解决这两个问题,Qt提供了一套全新的信号槽语法。前面在Qt4中的关联可以使用下面的方式代替:

          connect(sender,&Sender::valueChanged,receiver,&Receive::showValue);

     其中,Sender是发出信号的sender对象的类型,Receive是接收信号的receiver对象的类型。需要说明,Qt4中的关联方式在Qt5程序中依然可用,不过新的语法有下面几个优点:

          1、支持编译期检查。Qt5新的关联语法可以在编译时进行检查,信号或槽的拼写错误、槽函数参数数目多于信号的参数数目且等错误在编译时能够被发现。

          2、支持相容参数类型的自动转换。使用心得语法不仅支持使用tyoedef或者命名空间,还支持使用隐式类型转换。例如,当我们的信号参数类型时QString,而槽函数对应的参数类型时QVariant,那么,在进行信号槽的连接时,QString将被自动转换成QVariant。这是因为QVariant有一个可以使用QString的隐式构造函数。

          3、允许连接到任意函数:在Qt4中,槽函数只能是使用slots关键字修饰的成员函数,而新的语法通过函数指针直接调用函数,任意成员函数、静态函数或者C++11Lambda表达式都可以作为槽进行关联。(以前的信号槽语法不受private限制的。槽函数虽然可以被声明为private,但仅作为普通函数调用时起作用,作为槽连接时,SLOT无视private,修饰,因为仅作为字符串连接。而新语法无法取私有函数指针,在编译时就会有警报,因而更安全。)

     
     

新的语法实例

     connect(sender,&Sender::xxx,receive,&Receive::yyy);

     注意:当信号有重载的情况下,使用Qt5的新语法可能会有一些不便。例如,QSpinBox有两个重载的信号:

          void valueChanged(int);
          void valueChanged(const QString &);

     当我们使用下面的语句连接时connect(spinBox,&QSpinBox::valueChanged,this,&Widget::valueChanged);编译器会发出一个错误,因为信号valueChanged有重载,所以使用有歧义。这里我们可以使用Qt4的信号槽连接语法,是可以的。但这样做又失去了编译期检查的优点。为了继续使用Qt5的新语法,需要增加一个显示类型转换:

          connect(spinBox,static_cast<void(QSpinBox:: * )(int)>(&QSpinBox::valueChanged),this,&Widget::yyy);

     同样,若槽函数有参数不同的重载函数。也可按照转换:
          connect(spinBox,static_cast<void(QSpinBox:: * )(int)>(&QSpinBox::valueChanged),this,static_cast<void(Widget:: * )(int)>(&Widget::valueChanged));

关注

微信公众号搜索"Qt_io_"或"Qt开发者中心"了解更多关于Qt、C++开发知识.。

笔者 - jxd

猜你喜欢

转载自blog.csdn.net/automoblie0/article/details/106016079