Qt 5中信号和槽的新文法
參考原文:woboq: Olivier Goffart – Signals and Slots in Qt5
Qt 5 Alpha已經釋出。我曾經工作過的一個新特性就是信号和槽的新文法。本篇部落格将會為您講解這一内容。
Qt 5之前的文法
這裡是我們如何把信号和槽連接配接起來的方法:
1 2 | |
幕後的實際情況是
SIGNAL
和
SLOT
這兩個宏會把它們的參數轉換成字元串。然後
QObject::connect()
将會把這些字元串和
moc
工具所收集的内省(introspection)資料進行比較。
Qt 5之前信号和槽文法的問題
雖然通常情況下都可以正常工作,我們還是發現了如下問題:
- 沒有編譯期檢查:因為函數名被處理成字元串,所有的檢查都是在運作時完成的。這就是為什麼有時會發生編譯通過了,但槽并沒有被調用。此時,你就應該去檢查标準輸出,看看有沒有什麼警告說明這個連接配接沒有成功。
- 因為處理的是字元串,是以槽函數中的類型名字必須與信号的完全一緻,而且在頭檔案中的和實際的
語句中的也必須一緻。也就是說,如果你使用了connect()
或者命名空間,那麼這個連接配接就不能正常工作。typedef
新文法:使用函數指針
在即将到來的Qt 5中提供了一套新的文法。之前的文法依然可以使用,但是現在,我們有了全新的方式:
1 2 | |
哪一種方式更酷可能取決于個人喜好。但大家會更快的适應新方式。
現在讓我們先遠離美學視角,來看看新文法有什麼好處:
編譯期檢查
如果信号或者槽的名字的拼寫發生了錯誤,或者槽函數的參數與信号的不一緻,你會在編譯期就得到一個錯誤。
這肯定會在重構、或者修改信号或槽函數的名字時節省很多時間。
另一個好處是,如果我們少了
Q_OBJECT
宏,可以利用
static_cast
傳回更友好的錯誤資訊。
參數的自動類型轉換
現在,我們不僅可以更好地使用
typedef
或者命名空間,而且可以利用隐式類型轉換。
在下面的例子中,我們的信号有一個
QString
參數,而槽函數需要的是
QVariant
。它可以正常工作,是因為
QVariant
有一個可以使用
QString
的隐式構造函數。
1 2 3 4 5 6 7 8 9 10 11 12 | |
連接配接到任意函數
如果你留心上面的例子,就會發現,我們的信号被連接配接到了一個槽,但是它的聲明隻有
public
,沒有
slot
。Qt的新文法通過函數指針直接調用函數,而不再需要
moc
的内省(但是信号依然需要)。
更進一步,我們可以将信号連接配接到任意函數或者函數對象(functor):
1 2 3 4 5 6 | |
這樣處理,就可以讓你很友善的同
boost
或者
tr1::bind
進行協作。
C++11 Lambda表達式
至此之前,我們所有的示例都是基于
C++98
标準的。但是,如果你的編譯器支援
C++11
,我還是強烈建議你使用一些這個語言的新特性。現在,
Lambda
表達式至少被
MSVC 2010
、
GCC 4.5
、
clang 3.1
這幾個編譯器支援。不過對于後面兩個編譯器,你需要在編譯時加上
-std=c++0x
參數。
然後我們就可以這樣寫代碼了:
1 2 3 4 5 6 7 8 9 10 11 | |
這種文法允許我們更友善地編寫異步代碼。
更新:您還可以看看Qt 5中提供的其它C++11特性。
現在該幹什麼呢?
讓我們來嘗試一下吧。下載下傳Qt 5 Alpha,開始玩吧。不要忘記報告Bug呀。
(譯者注:感謝齊亮對本篇部落格全文進行了修正。)