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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章