信号の溝を深く理解する(四)

18954 ワード

Qtの信号スロットシステムをBoost.Signalsと結合して使用する.
実際には、Qtの信号スロットシステムをBoost.Signalsと結合して使用することは不可能ではない.前の説明を通して、私達は両者の違いを知っています.なぜこの二つを結び付けて使うのかについては、仁見知道です.ここでは,結合して使用する解を示したが,それらを結合して使用すべきであることを示唆したわけではない.これは具体的な問題を具体的に分析するべきです.
Qtの信号スロットシステムをBoost.Signalsと組み合わせて使用することで、最大の障害は、Qtがプリプロセッサを使用してキーワードsignals,slootsおよびemitを定義することである.これらはQtのC++言語への拡張と考えられます.Qtはまた、マクロを使用してこれらのキーワードを実現する別の方法を提供する.これらの拡張されたキーワードをブロックするために、Qt 4.1のproファイルはno_を導入しました.keywordsオプションは標準C++の方式を使うため、Qtは他のC++と同時に使用しやすいです.ノ_を開けてもいいです.keywordsのオプションは、これらのキーワードをブロックします.以下は簡単な実現です.
# 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 
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
注意してください.私たちはもうプロファイルの中でnoを開けました.keywordsオプションは、signalsのようなキーワードはもう機能しません.したがって、これらのキーワードを対応するマクロのバージョンに変更しなければなりません.例えば、私達はsignalsをQ_に変えたいです.SIGNALS、slaotsをQ_に変更します.SLOTSなど.下のコードを見てください.
// Sender.h
#include 
#include 
#include 
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);
    }
};
今は送信者がいます.受信者を見てみます.
// Receiver.h
#include 
#include 

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 

void Receiver::qtSlot( const std::string& message )
{
    std::cout << message << std::endl;
}
次はテストします.
// main.cpp
#include 
#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;
}
このコードは以下のような出力があります.
[506]TestSignals$ ./TestSignals
Boost says 'Hello, World!'
Qt says 'Hello, World!'
この2つの実装の違いは、Boost.Signalsの信号、boot Signalは、publicのものであり、どのオブジェクトも直接にこの信号を送ることができることにある.つまり、次のコードが使えます.
sender->boostSignal("Boost says 'Hello, World!', directly");
これにより、私たちが設定したsendBoost Signal()をバイパスします.また、boots Signalは全体的なオブジェクトであってもよく、この信号はどのオブジェクトでも使用できます.Qtにとって、signalはメンバー変数でなければなりません.ここではSenderだけが定義された信号を使用できます.
この例は簡単ではあるが,Boostの挙動はQtを通して信号を送る方法を明確に示している.ここでは,Qtの信号は共通のsendQtSignal関数を用いて発信した.しかし、Boostの信号からQtの挙動を得るためには、いくつかの作業を行う必要があります.隠し信号ですが、接続を取得する関数を提供する必要があります.このように見ると面倒くさいです.
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);
    }
};
このような実現はかなり醜いというべきです.実際には、Boostの信号と接続を切り離しました.私たちは次のような実現を望んでいます.
// 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);
注意してください.これは私の希望です.実現していません.興味があれば試してみてもいいです.
締め括りをつける
前はうるさいです.今まとめます.
信号と溝の機構は実際に観察者モードの変形である.コンポーネントに向かってプログラミングする強力なツールです.現在、信号スロット機構はコンピュータ科学の用語となり、様々な実装がある.
Qt信号スロットはQt全体のアーキテクチャの基本の一つであり、Qtが提供するコンポーネント、スレッド、反射機構、スクリプト、メタオブジェクト機構、可視化IDEなどと密接に統合されている.Qtの信号は対象のメンバー関数ですので、信号を持つオブジェクトだけが信号を送ることができます.Qtのコンポーネントと接続は、非コード形式のリソースファイルによって与えられ、動作中にこのような接続を動的に確立することができる.Qtの信号スロット実装はQt要素オブジェクト機構上に構築された.Qt要素オブジェクト機構はQtが提供するmocツールによって実現される.mocとは元オブジェクトコンパイラのことで、ユーザーが指定したQ_を持つことができます.OBJECTマクロのクラスはある程度前処理を行い、これにメタオブジェクト能力を増加させます.
Boost.Signalsは、テンプレートベースの信号スロットシステムの実装で静的なタイプのセキュリティチェックを有するものである.すべての信号はテンプレートタイプのbootst:signalの特化です.すべてのスロット関数は、呼出し可能な署名にマッチしています.Boost.Signalsは独立しています.内省、メタオブジェクトシステム、または他の外部ツールのサポートは必要ありません.しかし、Boost.Signalsは、リソースファイルからの接続を動的に確立する能力がない.
この二つの実現は非常に綺麗で、工業強度を持っています.それらを結合して使用することも不可能ではない.Qt 4.1はこの可能性を提供する.
Qt GUIに基づく任意のシステムは、信号スロットを自然に使用する.あなたはそこから大きな利益を得ることができます.どの大型システムも、コンポーネント間の結合レベルを下げることができれば、このような考えを参考にすべきである.他のメカニズムや技術のように、一度を把握することが一番重要です.信号の溝を正確なところで使うと、システムがより分かりやすく、より柔軟に、高度に再利用できます.仕事も早くできます.
転載先:https://blog.51cto.com/devbean/428364