將 Qt 的信號(hào)槽系統(tǒng)與 Boost.Signals 結(jié)合使用 實(shí)際上,,將 Qt 的信號(hào)槽系統(tǒng)與 Boost.Signals 結(jié)合在一起使用并非不可能,。通過前面的闡述,,我們都知道了二者的不同,,至于為什么要將這二者結(jié)合使用,,則是見仁見智的了,。這里,,我們給出一種結(jié)合使用的解決方案,,但是并不是說我們暗示應(yīng)該將它們結(jié)合使用,。這應(yīng)該是具體問題具體分析的。 將 Qt 的信號(hào)槽系統(tǒng)與 Boost.Signals 結(jié)合使用,,最大的障礙是,,Qt 使用預(yù)處理器定義了關(guān)鍵字 signals,slots 以及 emit,。這些可以看做是 Qt 對(duì) C++ 語(yǔ)言的擴(kuò)展,。同時(shí),Qt 也提供了另外一種方式,,即使用宏來(lái)實(shí)現(xiàn)這些關(guān)鍵字,。為了屏蔽掉這些擴(kuò)展的關(guān)鍵字,Qt 4.1 的 pro 文件引入了 no_keywords 選項(xiàng),,以便使用標(biāo)準(zhǔn) C++ 的方式,,方便 Qt 與其他 C++ 同時(shí)使用。你可以通過打開 no_keywords 選項(xiàng),,來(lái)屏蔽掉這些關(guān)鍵字,。下面是一個(gè)簡(jiǎn)單的實(shí)現(xiàn): # TestSignals.pro (platform independent project file, input to qmake) # showing how to mix Qt Signals and Slots with Boost.Signals # # Things you'll have in your .pro when you try this... # CONFIG += no_keywords # so Qt won't #define any non-all-caps `keywords' INCLUDEPATH += . /usr/local/include/boost-1_33_1/ # so we can #include <boost/someheader.hpp> macx:LIBS += /usr/local/lib/libboost_signals-1_33_1.a # ...and we need to link with the Boost.Signals library. # This is where it lives on my Mac, # other platforms would have to add a line here # # Things specific to my demo # CONFIG -= app_bundle # so I'll build a command-line tool instead of a Mac OS X app bundle HEADERS += Sender.h Receiver.h SOURCES += Receiver.cpp main.cpp 請(qǐng)注意,我們已經(jīng)在 pro 文件中打開了 no_keywords 選項(xiàng),,那么,,類似 signals 這樣的關(guān)鍵字已經(jīng)不起作用了。所以,,我們必須將這些關(guān)鍵字修改成相應(yīng)的宏的版本,。例如,我們需要將 signals 改為 Q_SIGNALS,,將 slots 改為 Q_SLOTS 等等,。請(qǐng)看下面的代碼: // Sender.h #include <QObject> #include <string> #include <boost/signal.hpp> class Sender : public QObject { Q_OBJECT Q_SIGNALS: // a Qt signal void qtSignal( const std::string& ); // connect with // QObject::connect(sender, SIGNAL(qtSignal(const std::string&)), ... public: // a Boost signal for the same signature boost::signal< void ( const std::string& ) > boostSignal; // connect with // sender->boostSignal.connect(... public: // an interface to make Sender emit its signals void sendBoostSignal( const std::string& message ) { boostSignal(message); } void sendQtSignal( const std::string& message ) { qtSignal(message); } }; 現(xiàn)在我們有了一個(gè)發(fā)送者,下面來(lái)看看接收者: // Receiver.h #include <QObject> #include <string> class Receiver : public QObject { Q_OBJECT public Q_SLOTS: void qtSlot( const std::string& message ); // a Qt slot is a specially marked member function // a Boost slot is any callable signature }; // Receiver.cpp #include "Receiver.h" #include <iostream> void Receiver::qtSlot( const std::string& message ) { std::cout << message << std::endl; } 下面,,我們來(lái)測(cè)試一下: // main.cpp #include <boost/bind.hpp> #include "Sender.h" #include "Receiver.h" int main( int /*argc*/, char* /*argv*/[] ) { Sender* sender = new Sender; Receiver* receiver = new Receiver; // connect the boost style signal sender->boostSignal.connect(boost::bind(&Receiver::qtSlot, receiver, _1)); // connect the qt style signal QObject::connect(sender, SIGNAL(qtSignal(const std::string&)), receiver, SLOT(qtSlot(const std::string&))); sender->sendBoostSignal("Boost says 'Hello, World!'"); sender->sendQtSignal("Qt says 'Hello, World!'"); return 0; } 這段代碼將會(huì)有類似下面的輸出: [506]TestSignals$ ./TestSignals Boost says 'Hello, World!' Qt says 'Hello, World!' 我們可以看到,,這兩種實(shí)現(xiàn)的不同之處在于,,Boost.Signals 的信號(hào),,boostSignal,是 public 的,,任何對(duì)象都可以直接發(fā)出這個(gè)信號(hào),。也就是說,我們可以使用如下的代碼: sender->boostSignal("Boost says 'Hello, World!', directly"); 從而繞過我們?cè)O(shè)置的 sendBoostSignal() 這個(gè)觸發(fā)函數(shù),。另外,,我們可以看到,,boostSignal 完全可以是一個(gè)全局對(duì)象,這樣,,任何對(duì)象都可以使用這個(gè)信號(hào),。而對(duì)于 Qt 來(lái)說,signal 必須是一個(gè)成員變量,,在這里,,只有 Sender 可以使用我們定義的信號(hào)。 這個(gè)例子雖然簡(jiǎn)單,,然而已經(jīng)很清楚地為我們展示了,,如何通過 Qt 發(fā)出信號(hào)來(lái)獲取 Boost 的行為。在這里,,我們使用一個(gè)公共的 sendQtSignal() 函數(shù)發(fā)出 Qt 的信號(hào),。然而, 為了從 Boost 的信號(hào)獲取 Qt 的行為,,我們需要多做一些工作:隱藏信號(hào),,但是需要提供獲取連接的函數(shù)。這樣看上去有些麻煩: class Sender : public QObject { // just the changes... private: // our new public connect function will be much easier to understand // if we simplify some of the types typedef boost::signal< void ( const std::string& ) > signal_type; typedef signal_type::slot_type slot_type; signal_type boostSignal; // our signal object is now hidden public: boost::signals::connection connectBoostSignal( const slot_type& slot, boost::signals::connect_position pos = boost::signals::at_back ) { return boostSignal.connect(slot, pos); } }; 應(yīng)該說,,這樣的實(shí)現(xiàn)相當(dāng)丑陋,。實(shí)際上,我們將 Boost 的信號(hào)與連接分割開了,。我們希望能夠有如下的實(shí)現(xiàn): // WARNING: no such thing as a connect_proxy class Sender { public: connect_proxy< boost::signal< void ( const std::string& ) > > someSignal() { return someSignal_; // ...automatically wrapped in the proxy } private: boost::signal< void ( const std::string& ) > someSignal_; }; sender->someSignal().connect(someSlot); 注意,,這只是我的希望,并沒有做出實(shí)現(xiàn),。如果你有興趣,,不妨嘗試一下。 總結(jié) 前面啰嗦了這么多,,現(xiàn)在總結(jié)一下,。 信號(hào)和槽的機(jī)制實(shí)際上是觀察者模式的一種變形。它是面向組件編程的一種很強(qiáng)大的工具?,F(xiàn)在,,信號(hào)槽機(jī)制已經(jīng)成為計(jì)算機(jī)科學(xué)的一種術(shù)語(yǔ),也有很多種不同的實(shí)現(xiàn),。 Qt 信號(hào)槽是 Qt 整個(gè)架構(gòu)的基礎(chǔ)之一,,因此它同 Qt 提供的組件、線程,、反射機(jī)制,、腳本、元對(duì)象機(jī)制以及可視化 IDE 等等緊密地集成在一起。Qt 的信號(hào)是對(duì)象的成員函數(shù),,所以,,只有擁有信號(hào)的對(duì)象才能發(fā)出信號(hào)。Qt 的組件和連接可以由非代碼形式的資源文件給出,,并且能夠在運(yùn)行時(shí)動(dòng)態(tài)建立這種連接,。Qt 的信號(hào)槽實(shí)現(xiàn)建立在 Qt 元對(duì)象機(jī)制之上。Qt 元對(duì)象機(jī)制由 Qt 提供的 moc 工具實(shí)現(xiàn),。moc 也就是元對(duì)象編譯器,,它能夠?qū)⒂脩糁付ǖ木哂?Q_OBJECT 宏的類進(jìn)行一定程度的預(yù)處理,給這個(gè)增加元對(duì)象能力,。 Boost.Signals 是具有靜態(tài)的類型安全檢查的,,基于模板的信號(hào)槽系統(tǒng)的實(shí)現(xiàn)。所有的信號(hào)都是模板類 boost::signal 的一個(gè)特化,;所有的槽函數(shù)都具有相匹配的可調(diào)用的簽名,。Boost.Signals 是獨(dú)立的,不需要內(nèi)省,、元對(duì)象系統(tǒng),,或者其他外部工具的支持。然而,,Boost.Signals 沒有從資源文件動(dòng)態(tài)建立連接的能力,。 這兩種實(shí)現(xiàn)都非常漂亮,并且都具有工業(yè)強(qiáng)度,。將它們結(jié)合在一起使用也不是不可能的,,Qt 4.1 即提供了這種可能性。 任何基于 Qt GUI 的系統(tǒng)都會(huì)自然而然的使用信號(hào)槽,。你可以從中獲取很大的好處,。任何大型的系統(tǒng),如果希望能夠降低組件之間的耦合程度,,都應(yīng)該借鑒這種思想,。正如其他的機(jī)制和技術(shù)一樣,最重要的是把握一個(gè)度,。在正確的地方使用信號(hào)槽,,可以讓你的系統(tǒng)更易于理解、更靈活,、高度可重用,,并且你的工作也會(huì)完成得更快。 本文出自 “豆子空間” 博客,,請(qǐng)務(wù)必保留此出處http://devbean.blog.51cto.com/448512/428364 |
|
來(lái)自: just_person > 《文摘》