我有一个Message类和Processor类。每个处理器可以即时接收一条或多条消息。由于每条消息都有一些不同的属性,我要将该消息向下转发到concrect消息类,以实际处理该消息。
因为没有。消息类和进程类,我不想使用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;
}
答案 0 :(得分: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;
}
答案 1 :(得分:1)
最简单的做法是取消getMessage()
方法,并在print()
中制作Message
纯虚拟广告,并在MA
和MB
中覆盖此方法。此外,您可以在process()
中将Process
设为纯虚拟方法,并在PA
中覆盖此方法。请参阅以下代码:
#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
是抽象基类(“interfaces”)和MA
,MB
和PA
是实现这些接口的具体类。理想情况下,您还会将std::string
状态从Message
接口中分解出来,但这仍然是一个练习。
如果您要调用特定于派生类的函数,并且如果您在运行时知道您实际上正在调用此类,则需要进行强制转换。这是通过dynamic_cast
到您的基类指针当前指向的特定派生类来完成的。
答案 2 :(得分:1)
您问题的最常见解决方案可能是Visitor pattern。
答案 3 :(得分: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
)充当用户对策略的接口。它可以使用策略类中的接口方法。用户可以通过主机类调用特殊策略方法。
答案 4 :(得分:1)
你遇到了C ++的限制。你真正想要的是多态性处理方法的参数,而不仅仅是调用参数的方法。它通常被称为double dispatch。不幸的是,虽然有一些类型的解决方法,但我还没有看到任何完美的解决方案。维基百科的文章显示了普遍接受的解决方法(使用访问者模式)。