2

基本クラスMessageHandlerには派生クラスがあります。彼らはお互いにメッセージを伝えたいと思っています。メッセージは異なるクラスのものである可能性がありますが、基本クラスを共有するように作成することができます。MessageHandler受信したメッセージのダウンキャストを回避するにはどうすればよいですか?receiveMessageMessageHandlerの仮想関数をテンプレートパラメータ化する効果がある何かを行うことはどういうわけか可能ですか?

基本的に、私は次のコードをダウンキャストしないものに置き換えようとしています。できればコンパイル時のものです。

// ...
virtual void MessageHandler::receiveMessage(Message &msg) = 0;
// ...

// to receive a message
void DerivedMessageHandler::receiveMessage(Message& msg)
{
    switch (msg.MsgType()) // enum
    {
        case Message::MessageType::A:
            MessageA& = dynamic_cast<MessageA&>(msg);
            break;

        case Message::MessageType::B:
            MessageB& = dynamic_cast<MessageB&>(msg);
            break;
        default:
            // don't process unknown messages
            break;
    }
}

// to send a message
list<MessageHandler> mhList;
// populate list
for (MessageHandler& mh : mhList)
{
    mh.receiveMessage(msg);
}

私はこれができないことを知っていますが、

template <typename M>
void MessageHandler::receiveMessage(M& msg) {}

そして、それぞれがDerivedMessageHandler専門にしていMますか?各ハンドラーがサポートされているメッセージオブジェクトをきれいに処理できるようにするデザインパターンは何でしょうか。

4

3 に答える 3

6

これはとても簡単です。通常、次の 2 つの方法があります。

Boost.Variant

派生クラスを渡す代わりに、メッセージの可能な型を列挙するだけです。これらの型は、互いに派生する必要はありません。これらの型をboost::variantにラップします:

typedef boost::variant<MessageData1, MessageData2, MessageData3, ...> MessageData;

これは、考えられるメッセージのデータ型が列挙可能でなければならないことを意味することに注意してください。Boost.Variant の訪問メソッドを使用すると、格納されている型を正確に知らなくても、これらの型のオブジェクトを簡単に操作できます。

Boost.Any

boost::any:で何かを渡すだけです。

void MessageHandler::receiveMessage(const boost::any &msg)
{
  const MessageType1 *pMsg = boost::any_cast<MessageType1>(&msg);
  if(!pMsg)
    //Cannot process
    return;

  //Process message.
}

boost::anyタイプセーフのようなものvoid*です。入れられた正確な型を覚えており、格納されているもの以外にキャストしようとすると失敗します。boost::any何でも保存できることから、この名前が付けられました。

また、値のセマンティクスも備えているため、コンテンツのようにコピーできます。

于 2012-02-17T01:17:07.290 に答える
3

あなたの質問を正しく理解していれば、仮想関数を使用した直接継承が必要です。何かのようなもの:

class BaseMessage 
{
    public:
    virtual ~BaseMessage() {}

    virtual void processMsg() = 0;
};

class MessageA : public BaseMessage
{
    public:
    MessageA() {}
    virtual ~MessageA() {}    
    virtual void processMsg()
    {
        // ... do something for MessageA ...
    }
};

class MessageB : public BaseMessage
{
    public:
    MessageB() {}
    virtual ~MessageB() {}    
    virtual void processMsg()
    {
        // ... do something for MessageB ...
    }
};

メッセージを処理する場合は、受信したメッセージに対して processMsg() 関数を呼び出すだけで、各メッセージを各クラスで指定されたとおりに処理できます。

std::auto_ptr<BaseMessage> m(mailbox.getMessage()); // Returns whatever msg is sent to your handler
m->processMsg();
于 2012-02-17T01:05:51.290 に答える
2

訪問者パターンを使用できます。

ただし、訪問者は各サブタイプを知っていて、それに対するアクションを定義する必要があるため、デフォルトのアクションはありません。

class Visitor;
class BaseMsg {
//..
public:
virtual void acceptVisitor(Visitor * v) = 0;
};

class Msg1;
class Msg2;
class Visitor {     
// You can put here pure virtuals for sure every visitor will implement them
public:
virtual void action (Msg1 * msg) = 0;
virtual void action (Msg2 * msg) = 0;
};

class Msg1: public BaseMsg {
//..
public:
void acceptVisitor(Visitor * v){v->action(this);}
};

class Msg2: public BaseMsg  {
//..
public:
void acceptVisitor(Visitor * v){v->action(this);}
};



class Visitor1 : public Visitor {
// ...
public:
void action (Msg1 * msg) {/*...*/ cout << "I like the message!\n";}
void action (Msg2 * msg) {/*...*/ cout << "I hate the message!\n";}
// more messages and actions for them
};

class Visitor2 : public Visitor{
// ...
public:
void action (Msg1 * msg) {/*...*/ cout << "Just fine\n";}
void action (Msg2 * msg) {/*...*/ cout << "Sorry, I'm busy\n";}
// more messages and actions for them
};

int main() {

BaseMsg * a = new Msg1;
BaseMsg * b = new Msg2;

Visitor * act = new Visitor1;
Visitor * lazy = new Visitor2;
// ............
// somewhere in a deep deep forest of your code

a->acceptVisitor(act);
b->acceptVisitor(act);

// somewhere else

a->acceptVisitor(lazy);
b->acceptVisitor(lazy);

delete act;
delete lazy;
delete a;
delete b;
return 0;
}  

出力:

  • メッセージいいね!
  • メッセージが嫌い!
  • 大丈夫
  • すみません、忙しいです
于 2012-02-17T01:39:30.610 に答える