2

我有消息类和处理器类的雇佣关系。每个处理器都可以即时接收一条或多条消息。由于每条消息都可以有一些不同的属性,我必须将该消息向下转换为具体的消息类,以实际处理它。
因为没有。消息类和进程类,我不想使用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()方法,并在 and 中创建print()纯虚 in并Message覆盖 this 。此外,您可以在中创建一个纯虚方法并在中覆盖它。请参见下面的代码: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上输出。

不需要强制转换,将在运行时通过动态调度(虚拟表查找等)选择虚拟函数。MessageProcess是抽象基类(“接口”)MAMBPA是实现这些接口的具体类。理想情况下,您还可以将std::string状态排除在Message界面之外,但这留作练习。

如果您要调用特定于派生类的函数,并且如果您在运行时知道您实际上正在调用这样的类,则需要进行强制转换。这是通过dynamic_cast您的基类指针当前指向的特定派生类来完成的。

于 2012-10-17T11:09:18.500 回答
1

您的问题最通用的解决方案可能是访问者模式

于 2012-10-17T11:29:00.940 回答
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定义其接口的方法。他们也有一些特殊的方法,比如printMAand printMB。主机类(此处Process)充当策略的用户界面。它可以使用策略类的接口方法。用户可以通过宿主类调用特殊的策略方法。

于 2012-10-17T12:05:26.567 回答
1

您遇到了 C++ 的限制。您真正想要的是让多态性处理方法的参数,而不仅仅是调用参数的方法。它通常被称为双重调度。不幸的是,虽然有一些解决方法,但我还没有看到任何完美的解决方法。该 Wikipedia 文章显示了普遍接受的解决方法(使用访问者模式)。

于 2012-10-17T12:49:18.747 回答