<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                #(16):深入 Qt5 信號槽新語法 在前面的章節([信號槽](http://www.devbean.net/2012/08/qt-study-road-2-signal-slot/ "Qt 學習之路 2:信號槽")和[自定義信號槽](http://www.devbean.net/2012/08/qt-study-road-2-custom-signal-slot/ "Qt 學習之路 2:自定義信號槽"))中,我們詳細介紹了有關 Qt 5 的信號槽新語法。由于這次改動很大,許多以前看起來不是問題的問題接踵而來,因此,我們用單獨的一章重新介紹一些 Qt 5 的信號槽新語法。 ## 基本用法 Qt 5 引入了信號槽的新語法:使用函數指針能夠獲得編譯期的類型檢查。使用我們在[自定義信號槽](http://www.devbean.net/2012/08/qt-study-road-2-custom-signal-slot/ "Qt 學習之路 2:自定義信號槽")中設計的`Newspaper`類,我們來看看其基本語法: ~~~ //!!! Qt5 #include <QObject> ////////// newspaper.h class Newspaper : public QObject { Q_OBJECT public: Newspaper(const QString & name) : m_name(name) { } void send() const { emit newPaper(m_name); } signals: void newPaper(const QString &name) const; private: QString m_name; }; ////////// reader.h #include <QObject> #include <QDebug> class Reader : public QObject { Q_OBJECT public: Reader() {} void receiveNewspaper(const QString & name) const { qDebug() << "Receives Newspaper: " << name; } }; ////////// main.cpp #include <QCoreApplication> #include "newspaper.h" #include "reader.h" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Newspaper newspaper("Newspaper A"); Reader reader; QObject::connect(&newspaper, &Newspaper::newPaper, &reader, &Reader::receiveNewspaper); newspaper.send(); return app.exec(); } ~~~ 在`main()`函數中,我們使用`connect()`函數將`newspaper`對象的`newPaper()`信號與`reader`對象的`receiveNewspaper()`槽函數聯系起來。當`newspaper`發出這個信號時,`reader`相應的槽函數就會自動被調用。這里我們使用了取址操作符,取到`Newspaper::newPaper()`信號的地址,同樣類似的取到了`Reader::receiveNewspaper()`函數地址。編譯器能夠利用這兩個地址,在編譯期對這個連接操作進行檢查,如果有個任何錯誤(包括對象沒有這個信號,或者信號參數不匹配等),編譯時就會發現。 ## 有重載的信號 如果信號有重載,比如我們向`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++ 推薦的風格,當參數類型改變時,編譯器會檢測到這個錯誤。 注意,這里我們只是強調了函數參數的問題。如果前面的對象都錯了呢?比如,我們寫的`newspaper`對象并不是一個`Newspaper`,而是`Newspaper2`?此時,編譯器會直接失敗,因為`connect()`函數會去尋找`sender->*signal`,如果這兩個參數不滿足,則會直接報錯。 ## 帶有默認參數的槽函數 Qt 允許信號和槽的參數數目不一致:槽函數的參數數目可以比信號的參數少。這是因為,我們信號的參數實際是作為一種返回值。正如普通的函數調用一樣,我們可以選擇忽略函數返回值,但是不能使用一個并不存在的返回值。如果槽函數的參數數目比信號的多,在槽函數中就使用到這些參數的時候,實際這些參數并不存在(因為信號的參數比槽的少,因此并沒有傳過來),函數就會報錯。這種情況往往有兩個原因:一是槽的參數就是比信號的少,此時我們可以像前面那種寫法直接連接。另外一個原因是,信號的參數帶有默認值。比如 ~~~ void QPushButton::clicked(bool checked = false) ~~~ 就是這種情況。 然而,有一種情況,槽函數的參數可以比信號的多,那就是槽函數的參數帶有默認值。比如,我們的`Newspaper`和`Reader`有下面的代碼: ~~~ // Newspaper signals: void newPaper(const QString &name); // Reader void receiveNewspaper(const QString &name, const QDate &date = QDate::currentDate()); ~~~ 雖然`Reader::receiveNewspaper()`的參數數目比`Newspaper::newPaper()`多,但是由于`Reader::receiveNewspaper()`后面一個參數帶有默認值,所以該參數不是必須提供的。但是,如果你按照前面的寫法,比如如下的代碼: ~~~ QObject::connect(&newspaper, static_cast<void (Newspaper:: *)(const QString &)>(&Newspaper::newPaper), &reader, static_cast<void (Reader:: *)(const QString &, const QDate & =QDate::currentDate())>(&Reader::receiveNewspaper)); ~~~ 你會得到一個斷言錯誤: ~~~ The slot requires more arguments than the signal provides. ~~~ 我們不能在函數指針中使用函數參數的默認值。這是 C++ 語言的限制:**參數默認值只能使用在直接地函數調用中。當使用函數指針取其地址的時候,默認參數是不可見的!** 當然,此時你可以選擇 Qt 4 的連接語法。如果你還是想使用 Qt 5 的新語法,目前的辦法只有一個:Lambda 表達式。不要擔心你的編譯器不支持 Lambda 表達式,因為在你使用 Qt 5 的時候,能夠支持 Qt 5 的編譯器都是支持 Lambda 表達式的。于是,我們的代碼就變成了: ~~~ QObject::connect(&newspaper, static_cast<void (Newspaper:: *)(const QString &)>(&Newspaper::newPaper), [=](const QString &name) { /* Your code here. */ }); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看