天天看點

Qt總結_再談:Qt5信号和槽_Qt4信号和槽

有重載的信号

如果信号有重載,比如我們向 Newspaper 類增加一個新的信号:

void newPaper(const QString &name, const QDate &date);
           

此時如果還是按照前面的寫法,編譯器會報出一個錯誤:由于這個函數(注意,信号實際也是一個普通的函數)有重載,是以不能用一個取址操作符擷取其位址。回想一下 Qt 4 中的處理。在 Qt 4 中,我們使用 SIGNAL 和 SLOT 兩個宏來連接配接信号槽。如果有一個帶有兩個參數的信号,像上面那種,那麼,我們就可以使用下面的代碼:

QObject::connect(&newspaper, SIGNAL(newPaper(QString, QDate)),
                 &reader,    SLOT(receiveNewspaper(QString, QDate)));
           

注意,我們臨時增加了一個 receiveNewspaper() 函數的重載,以便支援兩個參數的信号。在 Qt 4 中不存在我們所說的錯誤,因為 Qt 4 的信号槽連接配接是帶有參數的。是以,Qt 能夠自己判斷究竟是哪一個信号對應了哪一個槽。

對此,我們也給出了一個解決方案,使用一個函數指針來指明到底是哪一個信号:

void (Newspaper:: *newPaperNameDate)(const QString &, const QDate &) = &Newspaper::newPaper;
QObject::connect(&newspaper, newPaperNameDate,
                 &reader,    &Reader::receiveNewspaper);
           

這樣,我們使用了函數指針 newspaperNameDate 聲明一個帶有 QString 和 QDate 兩個參數,傳回值是 void 的函數,将該函數作為信号,與 Reader::receiveNewspaper() 槽連接配接起來。這樣,我們就回避了之前編譯器的錯誤。歸根結底,這個錯誤是因為函數重載,編譯器不知道要取哪一個函數的位址,而我們顯式指明一個函數就可以了。

如果你覺得這種寫法很難看,想像前面一樣寫成一行,當然也是由解決方法的:

QObject::connect(&newspaper,
                 (void (Newspaper:: *)(const QString &, const QDate &))&Newspaper::newPaper,
                 &reader,
                 &Reader::receiveNewspaper);
           

這是一種換湯不換藥的做法:我們隻是聲明了一個匿名的函數指針,而之前我們的函數指針是有名字的。不過,我們并不推薦這樣寫,而是希望以下的寫法:

QObject::connect(&newspaper,
                 static_cast<void (Newspaper:: *)(const QString &, const QDate &)>(&Newspaper::newPaper),
                 &reader,
                 &Reader::receiveNewspaper);
           

對比上面兩種寫法。第一個使用的是 C 風格的強制類型轉換。此時,如果你改變了信号的類型,那麼你就會有一個潛在的運作時錯誤。例如,如果我們把 (const QString &, const QDate &) 兩個參數修改成 (const QDate &, const QString &),C 風格的強制類型轉換就會失敗,并且這個錯誤隻能在運作時發現。而第二種則是 C++ 推薦的風格,當參數類型改變時,編譯器會檢測到這個錯誤。

參考:https://www.qter.org/forum.php?mod=viewthread&tid=637&extra=page%3D3

繼續閱讀