Qt5信號與槽C++11風格鏈接簡介

最近在論壇上看到了這個方面的問題,詳見這裏。 
隨後淺淺地學習了一會兒,看到了Qt官方論壇上給出的說明,以爲C++11的functional鏈接方法仍是比Qt4既有的宏鏈接方法有很大不一樣。 
官方論壇的文檔:http://doc.qt.io/qt-5/signalsandslots-syntaxes.htmlcss

1.實驗代碼

咱們在一個簡單的Dialog中,安排以下幾個信號與槽:html

class SSTest : public QDialog { //... signals: void sgn_test1(QByteArray arr); void sgn_test2(int n); void sgn_test2(QString s); void sgn_test3(double c, double d); public slots: void slt_1(); void slt_2(double v); void slt_2(QString s); void slt_3(int s); //... }; //cpp //...... void SSTest::slt_1() { qDebug()<<"SSTest::slt_1()"; } void SSTest::slt_2(double v) { qDebug()<<"SSTest::slt_2(double v):"<<v; } void SSTest::slt_2(QString s) { qDebug()<<"SSTest::slt_2(QString s):"<<s; } void SSTest::slt_3(int s) { qDebug()<<"SSTest::slt_3(int s):"<<s; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

然後,在構造函數中,直接採用文檔所述方法,進行鏈接.markdown

2.各種狀況測試

2.1. 信號、槽均無重載

此類狀況,對應 sgn_test一、slt_1 
直接鏈接便可:函數

connect (this,&SSTest::sgn_test1,this,&SSTest::slt_1); connect (this,&SSTest::sgn_test3,this,&SSTest::slt_3);
  • 1
  • 2

編譯OK,說明,槽的參數能夠比信號少。而且,存在着隱含參數轉換: 
第一行,QByteArray arr 參數被忽略了,由於槽沒有參數。 
第二行,double c, double d 兩個參數,第二個被忽略了,由於槽只有一個int參數。第一個參數被隱含轉換。 
測試:學習

emit sgn_test1(QByteArray()); emit sgn_test3(1.7,2.2);
  • 1
  • 2

輸出:測試

SSTest::slt_1() SSTest::slt_3(int s): 1
  • 1
  • 2

可是,若是咱們把不支持隱含轉換的信號與槽鏈接,則會錯誤:this

connect (this,&SSTest::sgn_test1,this,&SSTest::slt_3);
  • 1

QByteArray 沒法轉換爲 int, 所以沒法經過編譯(具體錯誤與編譯器相關):url

C:\...\qobjectdefs_impl.h:299: error: 'QByteArray::operator QNoImplicitBoolCast() const' is private within this context enum { value = sizeof(test(dummy())) == sizeof(int) }; ~~~~~^~~~~~~~~~
  • 1
  • 2
  • 3

2.2. 信號惟一,槽重載

咱們試着簡單鏈接sgn_test3和slt_2spa

connect (this,&SSTest::sgn_test3,this,&SSTest::slt_2);
  • 1

與估計的同樣,沒法編譯:.net

C:\...\sstest.cpp:15: error: no matching function for call to 'SSTest::connect(SSTest*, void (SSTest::*)(double, double), SSTest*, <unresolved overloaded function type>)' connect (this,&SSTest::sgn_test3,this,&SSTest::slt_2); ^
  • 1
  • 2
  • 3

此時,咱們採用下面這兩種方式之一,便可:

connect (this,&SSTest::sgn_test3,this,static_cast<void(SSTest::*)(double)>(&SSTest::slt_2));
  • 1

或者(C++14以上)

connect (this,&SSTest::sgn_test3,this,qOverload<double>(&SSTest::slt_2));
  • 1

這等於強制指定了鏈接方法。測試:

emit sgn_test3(1.7,2.2);
  • 1

輸出:

SSTest::slt_2(double v): 1.7
  • 1

2.3. 信號重載、槽重載

有了上面的經驗,面對重載已經不怕了:

//C++14風格同時指定信號、槽的參數表 connect (this,qOverload<QString>(&SSTest::sgn_test2),this,qOverload<QString>(&SSTest::slt_2)); //static_cast風格同時指定信號、槽的參數表 connect (this,static_cast<void(SSTest::*)(int)>(&SSTest::sgn_test2),this,static_cast<void(SSTest::*)(double)>(&SSTest::slt_2)); //信號重載,鏈接到單一的槽 connect (this,static_cast<void(SSTest::*)(int)>(&SSTest::sgn_test2),this,&SSTest::slt_1); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

測試:

emit sgn_test2("haha!"); emit sgn_test2(1);
  • 1
  • 2

輸出:

SSTest::slt_2(QString s): "haha!" SSTest::slt_2(double v): 1 SSTest::slt_1()
  • 1
  • 2
  • 3

2.4. 更靈活的lambda表達式

固然,既然Qt5採用的是functional機制,必定能夠用lambda:

int p = 100;
connect (this,&SSTest::sgn_test3,[=](double a ,double b)->void{  qDebug()<<(p*a+b); });
  • 1
  • 2
  • 3
  • 4

測試:

emit sgn_test3(1.7,2.2);
  • 1

輸出:

172.2
  • 1

3. 總結

傳統的Qt4 Signal-Slot宏鏈接兼容性好,可是沒有編譯時檢查,每每會因爲筆誤,產生預料以外的效果。如今,有了C++11 functional的支持,能夠藉助編譯器進行嚴格的類型檢查,明顯是有利於調試了。

 

http://blog.csdn.net/goldenhawking/article/details/78766676

相關文章
相關標籤/搜索