2012-03-22 14 views
1

私はレシーバが各レシーバが特定のタイプのメッセージに興味があることを送信者に伝えるメカニズムを作成しています。そこに以下の私のサンプル実装は、((メイン参照)、特定の基本型のすべてメッセージを受信したいレシーバーのみが明示的にそのタイプのであり、メッセージが派生型のメッセージを受信しません受信制限が存在すると例えば)。オブジェクトの祖先の型を見つける方法は?

潜在的な解決策は、その特定のメッセージを登録するときに、メッセージの先祖の種類のすべてを登録し、適切にメッセージをルーティングするために、その情報を使用することです。

その他の解決策はありますか?

注:RTTI検索が毎回必要とされないので、実際には、私はRTTIを保存すると思います。ここで私が黙ったり、スキップしたりしたこともあります。私は

例のコードの下に...この例/ wの簡略化のために行くよ:

class Sender 
{ 
    typdef std::vector<Receiver const & > Receivers; 
public: 
    void register(Receiver const & i_recv, typeinfo const & i_type) 
    { 
    m_routingMap[i_type].push_back(i_recv); 
    } 


    void send(BaseMsg const & i_msg) 
    { 
    Receivers receivers = m_routingMap.find(typeid(i_msg)); 
    for (Receivers::iterator receiver = receivers.begin(); receiver != receivers.end(); ++receiver) { 
     receiver.receive(i_msg); 
    } 
    } 

private: 
    std::map<typeinfo const &, Receivers> m_routingMap; 
}; 


class Receiver 
{ 
public: 
    void receiver(BaseMsg const & i_msg) 
    { 
    // React to expected messages here 
    } 
}; 


class BaseMsg {}; 

class ChildMsg : public BaseMsg {}; 

int main() 
{ 
    Sender sndr; 

    Receiver recv1; 
    sndr.register(recv1, typeid(BaseMsg)); 

    Receiver recv2; 
    sndr.register(recv2, typeid(ChildMsg)); 

    BaseMsg baseMsg; 
    sndr.send(baseMsg); // I want only recv1 to receive this message 

    ChildMsg childMsg; 
    sndr.send(childMsg); // I want both Receivers to receive this message, but only recv2 will receive it 
} 

更新:

// Note: implementation is based in gleaning from 
// http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 

class BaseMsg 
{ 
public: 

    typedef std::vector<TypeInfo const & > Types; 

    static TypeInfo const * getType() 
    { 
    TypeInfo static * ms_type = new TypeInfo(typeid(BaseMsg)); 
    return ms_type; 
    } 

    static Types const * getAncestorTypes() 
    { 
    // The base class does not have an ancestor 
    // Static varible, will only be constructed once! 
    Types * ms_ancestorTypes = new Types(); 
    return ms_ancestorTypes; 
    } 
}; 


class ChildMsg 
{ 
public: 
    static TypeInfo const * getType() 
    { 
    TypeInfo static * ms_type = new TypeInfo(typeid(ChildMsg)); 
    return ms_type; 
    } 

    static Types const * getAncestorTypes() 
    { 
    // Add the parent type and all the parent's ancestor's types 
    Types const * ancestorTypes = BaseMsg::getAncestorTypes(); 

    // Static variable, so it will only be constructed once! 
    Types * static ms_ancestorTypes = new Types(ancestorTypes->begin(), ancestorTypes->end()); 

    // This push_back() will occur every time, but it's only one operation, 
    // so hopefully it's not a big deal! 
    ms_ancestorTypes->push_back(BaseMsg::getType()); 

    return ms_ancestorTypes; 
    } 
}; 
:ここで私がまで取得しています解決策です

送信者:

# Python pseudo code 
class Sender: 
    def send(self, i_msg): 
    types_to_check_for = [i_msg.getType()].extend(i_msg.getAncestorTypes()) 

    for type_ in types_to_check_for: 
     for receiver in _routing_list[type_]: 
     receiver.receive(i_msg) 

答えて

0

おそらくオブザーバーパターン(http://en.wikipedia.org/wiki/Observer_pattern)の使用を検討してください。

あなたは送信者が受信者の知識がないと、あなたの観察者がMSGのの分布を制御することができますこの方法。

送信者 - >オブザーバにメッセージがあります。

observer - >は、それぞれの関係者に新しいメッセージがあることを知らせます。

関心のあるパート - >楽しいもの。

これには、何らかの種類のmsg識別システムが必要です。多分、すべてのmsgは、型メンバとidメンバを持つmsg型から継承できます。そうすれば、それらを使ってmsgsに登録することができます。

更新:

迅速MSG構造:

class Message 
{ 
public: 
    size_t m_Type; 
    size_t m_Id; 

protected: 
    Message(size_t type, size_t id) : m_Type(type), m_Id(id) {} 
}; 

class Type1 : public Message 
{ 
public: 
    static const size_t type = 1; 
    Type1(size_t id) : Message(type, id) {} 
}; 

加入者)は、MSGを聴きたい人を意味します。加入者は、これらの機能の両方に基づいてmsgを受け入れるためのインタフェースを持つ必要があります。

Class subscriber 
{ 
    virtual void receiveType(size_t type, char * data) = 0; 
    virtual void receiveMsg(size_t type, size_t id, char * data) = 0; 

}; 

観察者は、MSGのために登録する方法を持っている必要があります。

Class Observer 
{ 
void registerForType(type, subscriber); 
void registerForMsg(type, id, subscriber); 
}; 

別の更新:

これは本当にただ荒い概念実証です。正確な祖先の連鎖を知らずに、あなたが望むことをすることができます。トリガーとregistrationEntry関数の切り替えを許してください(私は最初は間違っていましたが、これは最も単純な修正であり、再び概念実証でした)。このスケッチのもう一つの欠点は、少なくともmsgは登録する必要があるということです。本当の長期的な解決策を探しているなら、すでにリフレクションを持っているライブラリやフレームワークを見つけることをお勧めします(例えば、QTはメタオブジェクトを持っています)。これらはスーパークラスを見るために使うことができます。または、既にある信号/スロットを使用することもできます。 C開始

:以下のコードから

出力\ Users \ユーザーデビッド\ダウンロード\空自-ビルドデスクトップQt_4_8_0_for_Desktop_- MinGWの _Qt_SDK__Release \リリース\のasdf.exeを...
ベースレジスタ
登録:BaseMsg
託児登録
登録:メッセージ
ベースコール
トリガー:BaseMsg
仮想ボイド加入者1 :: newMessage(const BaseMsg &)
Der。呼び出し
トリガー:BaseMsg
仮想空Subscriber1 :: newMessage(定数BaseMsg &)
トリガー:メッセージ
仮想空subscriber2など:: newMessage(定数BaseMsg &)
C:\ Users \ユーザーデビッド\ダウンロード\ asdf-ビルドデスクトップQt_4_8_0_for_Desktop_- MinGWの _Qt_SDK__Release \リリース\のasdf.exeは私のポストが必要なメッセージ識別システムについてですコード0

#include <string> 
#include <vector> 
#include <map> 
#include <stdio.h> 
using namespace std; 

class BaseMsg 
{ 
public: 
    BaseMsg() 
    { 
     theRealInit(); 
    } 

    //incase you don't want to go all the way down the rabbit hole. 
    //At the bottom they are the same 
    virtual vector<string> const & registrationEntries() const {return m_SubClassChain;} 
    virtual vector<string> const & triggerEntries() const  {return m_SubClassChain;} 

    protected: 
    virtual void init() { printf("Should NOT CALL THIS HERE!");} 
    vector<string> m_SubClassChain; 

private: 

    void theRealInit() 
    { 
     m_SubClassChain.push_back("BaseMsg"); 
    } 


}; 

class Message : public BaseMsg 
{ 
    public: 
    Message() : BaseMsg() 
    { 
     init(); //MUST BE CALLED from child 
    } 

    virtual vector<string> const & triggerEntries() const  {return m_TriggerEntries;} 

protected: 
    virtual void init() 
    { 
     //BaseMsg::init(); 
     m_SubClassChain.push_back("Message"); 
     m_TriggerEntries.push_back("Message"); 
    } 

private: 
    vector<string> m_TriggerEntries; 
}; 

class Subscriber 
{ 
public: 
    virtual void newMessage(BaseMsg const & i_msg) 
    { 
     printf("%s\n", __PRETTY_FUNCTION__); 
    } 
}; 

class Subscriber2 : public Subscriber 
{ 
public: 
    virtual void newMessage(BaseMsg const & i_msg) 
    { 
     printf("%s\n", __PRETTY_FUNCTION__); 
    } 
}; 

class Subscriber1 : public Subscriber 
{ 
public: 
    virtual void newMessage(BaseMsg const & i_msg) 
    { 
     printf("%s\n", __PRETTY_FUNCTION__); 
    } 
}; 



class Sender 
{ 
    //typdef vector<Receiver const & > Receivers; 
public: 

    void registerForMsg(Subscriber * someoneThatCares, BaseMsg const & msg) 
    { 
     vector<string> const & triggers = msg.triggerEntries(); 

     vector<string>::const_iterator it = triggers.begin(); 
     for(; it != triggers.end(); it++) 
     { 
      printf("Registration: %s\n", it->c_str()); 

      m_routingMap.insert(pair<string, Subscriber *>(*it, someoneThatCares)); 
     } 
    } 


    void send(BaseMsg const & msg) 
    { 
     vector<string> const & triggers = msg.registrationEntries(); 
     vector<string>::const_iterator it = triggers.begin(); 
     for(; it != triggers.end(); it++) 
     { 

      printf("Trigger: %s\n", it->c_str()); 
      pair<multimap<string, Subscriber *>::iterator, multimap<string, Subscriber *>::iterator> ret; 

      //borrowed from: http://www.cplusplus.com/reference/stl/multimap/equal_range/ 
      ret = m_routingMap.equal_range(*it); 

      multimap<string, Subscriber *>::iterator it1; 
      for (it1 = ret.first; it1 != ret.second; ++it1) 
      { 

       it1->second->newMessage(msg); 
      } 
     } 
    } 

private: 
    multimap<string, Subscriber *> m_routingMap; 
}; 

int main(int argc, char *argv[]) 
{ 
    Sender sndr; 

    BaseMsg baseMsg; 
    Message message; 

    printf("Base Register\n"); 
    Subscriber1 recv1; 
    sndr.registerForMsg(&recv1, baseMsg); 

    printf("Child Register\n"); 
    Subscriber2 recv2; 
    sndr.registerForMsg(&recv2, message); 


    printf("Base call\n"); 
    sndr.send(baseMsg); // I want only recv1 to receive this message 

    printf("Der. call\n"); 
    sndr.send(message); // I want both Receivers to receive this message, but only recv2 will receive it 

    return 0; 
} 
+0

で終了しました。 –

+0

注:このコードはコンパイルされていません。例のためだけです。 –

+0

これは私が解決しようとしている特定の問題には対処しません。関連する問題を表示するには、私のmain()を参照してください。 –

関連する問題