2

Message クラスと Processor クラスの階層があります。各プロセッサは、1 つ以上のメッセージをオンザフライで受信できます。各メッセージはいくつかの異なる属性を持つ可能性があるため、実際に処理するために、そのメッセージを具体的なメッセージ クラスにダウンキャストする必要があります。
ないので。メッセージ クラスとプロセス クラスの代わりに、dynamic_cast を使用したくありません。
次のコードを使用しようとしましたが、コンパイル時にエラーが発生しています。また、(必要に応じて) プロセッサ ポインタをメッセージに添付する柔軟性がありますが、その逆はできません。

class Message  
{  
    public:  
    virtual const Message* const getMessage() const = 0;
};

class MA : public Message  
{  
    public:  
    const MA* const getMessage() const {return this;}
    void printMA() const{std::cout<<"I am MA"<<std::endl;}
};

class MB : public Message  
{  
    public:  
    const MB* const getMessage() const {return this;}
    void printMB() const{std::cout<<"I am MB"<<std::endl;}
};

class Processor  
{  
public:  
    virtual void process(const Message* m) = 0;

};

class PA : public Processor  
{  
    public:  
    void process(const Message* m) {processM(m->getMessage());}

    void processM(const MA*  m) {m->printMA();}
    void processM(const MB*  m) {m->printMB();}
};

int main()  
{  
    Message* m1 = new MA();  
    Message* m2 = new MB();  

    Processor* p1 = new PA();  
    p1->process(m1);
    p1->process(m2);
    return 0;
}
4

5 に答える 5

2

これを回避するために、最終的に「ダブルディスパッチ」を使用しました。さて、唯一のことは、新しいメッセージタイプを追加するたびに、MessageProcessor のクラスに関数を追加する必要があることですが、それで問題ないと思います。

class MessageProcessor
{
    public:
        virtual void process(const MA*) const{std::cout<<"unhandled:MA"<<std::endl;}
        virtual void process(const MB*) const{std::cout<<"unhandled:MB"<<std::endl;}
        virtual void process(const MC*) const{std::cout<<"unhandled:MC"<<std::endl;}
};

class Message
{
    public:
    virtual void process(const MessageProcessor*) const = 0;
};

class MA : public Message
{
    public:
    void printMA() const{std::cout<<"I am MA"<<std::endl;}
    virtual void process(const MessageProcessor* p) const {p->process(this);}
};

class MB : public Message
{
    public:
    void printMB() const{std::cout<<"I am MB"<<std::endl;}
    virtual void process(const MessageProcessor* p) const {p->process(this);}
};

class MC : public Message
{
    public:
    void printMC() const{std::cout<<"I am MC"<<std::endl;}
    virtual void process(const MessageProcessor* p) const {p->process(this);}
};

class Processor : public MessageProcessor
{
    public:
    void processM(const Message* m){m->process(this);}

};

class PA : public Processor
{
    public:
    void process(const MA*  m) const {m->printMA();}
    void process(const MB*  m) const {m->printMB();}
};

class PB : public Processor
{
    public:
    void process(const MA*  m) const {m->printMA();}
    void process(const MC*  m) const {m->printMC();}
};

int main()
{
    const Message* m1 = new MA();
    const Message* m2 = new MB();
    const Message* m3 = new MC();

    Processor* p1 = new PA();
    p1->processM(m1);
    p1->processM(m2);
    p1->processM(m3);

    Processor* p2 = new PB();
    p2->processM(m1);
    p2->processM(m2);
    p2->processM(m3);

    return 0;
}
于 2012-10-18T07:13:42.630 に答える
1

最も簡単な方法は、getMessage()メソッドを削除し、print()純粋な仮想をinにして、これをinとMessageでオーバーライドすることです。さらに、で純粋仮想メソッドを作成し、でこれをオーバーライドできます。以下のコードを参照してください。MAMBprocess()ProcessPA

#include <iostream>

class Message  
{  
    public:  
    const std::string _id;

    Message(std::string id):_id(id) {}

    virtual void print() const = 0;
    virtual void other_fun() const = 0;
};

class MA : public Message  
{ 
    private: double d_; 
    public:  
    MA():Message("MA"), d_(0.0) {}

    virtual void print() const
    {
        std::cout<<"I am MA"<<std::endl;
        std::cout << "I also have a double" << std::endl; 
    }

    virtual void other_fun() const { std::cout << "I am MA specific" << std::endl; }

    void do_hoops () const { std::cout << "Hoop!"<<std::endl;}
};

class MB : public Message  
{  
    private: int i_;
    public:  
    MB():Message("MB"), i_(0) {}

    virtual void print() const
    {
        std::cout<<"I am MB"<<std::endl;
        std::cout << "I also have an int"<<std::endl;
    }

    virtual void other_fun() const { std::cout << "I am MB specific" << std::endl; }

    void do_twist() const { std::cout << "Twist!"<<std::endl; }
};

class Processor  
{  
public:  
    const std::string _id;
    Processor(std::string id) : _id(id){}

    virtual void process(const Message* m) = 0;

};

class PA : public Processor  
{  
    public:  
    PA():Processor("PA") {}

    virtual void process(const Message* m) 
    {
        m->print();
        m->other_fun();
    }
};

int main()  
{  
    Message* m1 = new MA();  
    Message* m2 = new MB();  

    // generic handling of message
    Processor* p1 = new PA();  
    p1->process(m1);
    p1->process(m2);

    // message specific stuff
    dynamic_cast<MA*>(m1)->do_hoops();
    dynamic_cast<MB*>(m2)->do_twist();
    return 0;
}

Ideoneに出力します。

キャストは必要ありません。仮想関数は、実行時に動的ディスパッチ(仮想テーブルルックアップなど)によって選択されます。MessageおよびProcessは抽象基本クラス(「インターフェース」)およびMA、でMBあり、PAこれらのインターフェースを実装する具象クラスです。理想的にstd::stringは、インターフェースから状態を除外することもできMessageますが、それは演習として残されています。

派生クラスに固有の関数を呼び出す場合、および実行時にそのようなクラスを実際に呼び出していることがわかっている場合は、キャストが必要になります。これはdynamic_cast、基本クラスポインタが現在指している特定の派生クラスを介して行われます。

于 2012-10-17T11:09:18.500 に答える
1

設計上の欠陥があります。の署名は、が必要でProcessor::processあることを示唆しています。Messageその場合、 のパブリック インターフェイスではないものにアクセスしようとして、この約束を破ってはなりませんMessage

Processユーザー提供のポリシーを継承するテンプレート クラス (ホスト) を作成できます。ここでのポリシーは具体的なMessageクラスです。このようなもの:

#include <iostream>

struct MA
{
    void print ()
    {  
        std::cout << "MA: I'm the interface" << std::endl;
    }

    void printMA ()
    {  
        std::cout << "MA: I'm special" << std::endl;
    }
};

struct MB
{
    void print ()
    {  
        std::cout << "MB: I'm the interface" << std::endl;
    }

    void printMB ()
    {  
        std::cout << "MB: I'm special" << std::endl;
    }
};

template <typename M>
struct Process :
    public M
{
    void process()
    {  
        M::print();
    }
};

int main ()
{
    Process<MA> p1;
    Process<MB> p2;

    p1.print();     // MA: I'm the interface
    p1.printMA();   // MA: I'm special

    p2.print();     // MB: I'm the interface
    p2.printMB();   // MB: I'm special
}

ポリシーにprintは、そのインターフェースを定義するメソッドがあります。また、 や などの特別なメソッドもprintMAありprintMBます。ホスト クラス (ここではProcess) は、ポリシーへのユーザー インターフェイスとして機能します。ポリシー クラスのインターフェイス メソッドを使用できます。ユーザーは、ホスト クラスを介して特別なポリシー メソッドを呼び出すことができます。

于 2012-10-17T12:05:26.567 に答える
1

あなたの問題に対する最も一般的な解決策は、おそらくVisitor patternです。

于 2012-10-17T11:29:00.940 に答える