天天看點

深入了解信号槽(四)

将 Qt 的信号槽系統與 Boost.Signals 結合使用

實際上,将 Qt 的信号槽系統與 Boost.Signals 結合在一起使用并非不可能。通過前面的闡述,我們都知道了二者的不同,至于為什麼要将這二者結合使用,則是見仁見智的了。這裡,我們給出一種結合使用的解決方案,但是并不是說我們暗示應該将它們結合使用。這應該是具體問題具體分析的。

将 Qt 的信号槽系統與 Boost.Signals 結合使用,最大的障礙是,Qt 使用預處理器定義了關鍵字 signals,slots 以及 emit。這些可以看做是 Qt 對 C++ 語言的擴充。同時,Qt 也提供了另外一種方式,即使用宏來實作這些關鍵字。為了屏蔽掉這些擴充的關鍵字,Qt 4.1 的 pro 檔案引入了 no_keywords 選項,以便使用标準 C++ 的方式,友善 Qt 與其他 C++ 同時使用。你可以通過打開 no_keywords 選項,來屏蔽掉這些關鍵字。下面是一個簡單的實作:

請注意,我們已經在 pro 檔案中打開了 no_keywords 選項,那麼,類似 signals 這樣的關鍵字已經不起作用了。是以,我們必須将這些關鍵字修改成相應的宏的版本。例如,我們需要将 signals 改為 Q_SIGNALS,将 slots 改為 Q_SLOTS 等等。請看下面的代碼:

現在我們有了一個發送者,下面來看看接收者:

下面,我們來測試一下:

這段代碼将會有類似下面的輸出:

我們可以看到,這兩種實作的不同之處在于,Boost.Signals 的信号,boostSignal,是 public 的,任何對象都可以直接發出這個信号。也就是說,我們可以使用如下的代碼:

進而繞過我們設定的 sendBoostSignal() 這個觸發函數。另外,我們可以看到,boostSignal 完全可以是一個全局對象,這樣,任何對象都可以使用這個信号。而對于 Qt 來說,signal 必須是一個成員變量,在這裡,隻有 Sender 可以使用我們定義的信号。

這個例子雖然簡單,然而已經很清楚地為我們展示了,如何通過 Qt 發出信号來擷取 Boost 的行為。在這裡,我們使用一個公共的 sendQtSignal() 函數發出 Qt 的信号。然而, 為了從 Boost 的信号擷取 Qt 的行為,我們需要多做一些工作:隐藏信号,但是需要提供擷取連接配接的函數。這樣看上去有些麻煩:

應該說,這樣的實作相當醜陋。實際上,我們将 Boost 的信号與連接配接分割開了。我們希望能夠有如下的實作:

注意,這隻是我的希望,并沒有做出實作。如果你有興趣,不妨嘗試一下。

總結

前面啰嗦了這麼多,現在總結一下。

信号和槽的機制實際上是觀察者模式的一種變形。它是面向元件程式設計的一種很強大的工具。現在,信号槽機制已經成為計算機科學的一種術語,也有很多種不同的實作。

Qt 信号槽是 Qt 整個架構的基礎之一,是以它同 Qt 提供的元件、線程、反射機制、腳本、元對象機制以及可視化 IDE 等等緊密地內建在一起。Qt 的信号是對象的成員函數,是以,隻有擁有信号的對象才能發出信号。Qt 的元件和連接配接可以由非代碼形式的資源檔案給出,并且能夠在運作時動态建立這種連接配接。Qt 的信号槽實作建立在 Qt 元對象機制之上。Qt 元對象機制由 Qt 提供的 moc 工具實作。moc 也就是元對象編譯器,它能夠将使用者指定的具有 Q_OBJECT 宏的類進行一定程度的預處理,給這個增加元對象能力。

Boost.Signals 是具有靜态的類型安全檢查的,基于模闆的信号槽系統的實作。所有的信号都是模闆類 boost::signal 的一個特化;所有的槽函數都具有相比對的可調用的簽名。Boost.Signals 是獨立的,不需要内省、元對象系統,或者其他外部工具的支援。然而,Boost.Signals 沒有從資源檔案動态建立連接配接的能力。

這兩種實作都非常漂亮,并且都具有工業強度。将它們結合在一起使用也不是不可能的,Qt 4.1 即提供了這種可能性。

任何基于 Qt GUI 的系統都會自然而然的使用信号槽。你可以從中擷取很大的好處。任何大型的系統,如果希望能夠降低元件之間的耦合程度,都應該借鑒這種思想。正如其他的機制和技術一樣,最重要的是把握一個度。在正确的地方使用信号槽,可以讓你的系統更易于了解、更靈活、高度可重用,并且你的工作也會完成得更快。

本文轉自 FinderCheng 51CTO部落格,原文連結: http://blog.51cto.com/devbean/428364

繼續閱讀