如何避免沮丧
How to avoid downcast?
我有一个状态模式的实现,其中每个状态处理它从事件队列中获取的事件。因此,基State
类具有纯虚方法void handleEvent(const Event*)
。事件继承基Event
类,但每个事件都包含其数据,这些数据可以是不同类型的(例如 int、string...或其他什么)。 handleEvent
必须确定接收事件的运行时类型,然后执行向下广播以提取事件数据。事件是动态创建并存储在队列中的(因此向上转换在这里发生...
我知道向下投射是设计不好的标志,但在这种情况下是否有可能避免它?我正在考虑访客模式,其中基类 State 将包含每个事件的虚拟处理程序,但随后需要在代码段中再次向下转换,该代码段将事件从队列中取消排队并将其传递到当前状态。(至少在这种情况下,大switch(eventID)
只会在一个地方......访客模式是避免向下转换的最佳方法(最佳实践)吗?
这是伪代码(我在这个例子中传递boost::shared_ptr
但无论如何都会发生向下转换):
enum EventID
{
EVENT_1,
EVENT_2,
...
};
class Event
{
EventID id;
public:
Event(EventID id):id(id){}
EventID id() const {return id;}
virtual ~Event() = 0;
};
class Event1 : public Event
{
int n;
public:
Event1(int n):Event(EVENT_1), n(n){}
int getN() const {return n;}
};
class Event2 : public Event
{
std::string s;
public:
Event2(std::string s):Event(EVENT_2), s(s){}
std::string getS() const {return s;}
};
typedef boost::shared_ptr<Event> EventPtr;
class State
{
...
public:
...
virtual ~State() = 0;
virtual void handleEvent(const EventPtr& pEvent) = 0;
};
class StateA : public State
{
...
public:
void handleEvent(const EventPtr& pEvent)
{
switch(pEvent->id())
{
case EVENT_1:
int n = boost::static_pointer_cast<Event1>(pEvent)->getN();
...
break;
case EVENT_2:
std::string s = boost::static_pointer_cast<Event2>(pEvent)->getS();
...
break;
...
}
}
}
典型的访客模式不会执行向下转换,这要归功于双重调度策略:
// Visitor.hpp
class EventBar;
class EventFoo;
class Visitor {
public:
virtual void handle(EventBar const&) = 0;
virtual void handle(EventFoo const&) = 0;
};
// Event.hpp
class Visitor;
class Event {
public:
virtual void accept(Visitor&) const = 0;
};
和实现:
// EventBar.hpp
#include <Event.hpp>
class EventBar: public Event {
public:
virtual void accept(Visitor& v);
};
// EventBar.cpp
#include <EventBar.hpp>
#include <Visitor.hpp>
void EventBar::accept(Visitor& v) {
v.handle(*this);
}
这里的关键点是,v.handle(*this)
静态类型的*this
是EventBar const&
,它选择了正确的virtual void handle(EventBar const&) = 0
重载Visitor
。
事件的想法是通过广义(和不可知论)接口传递详细的对象。沮丧是不可避免的,也是设计的一部分。好坏,这是有争议的。
访客模式只会将铸件隐藏起来。它仍然在后台执行,类型通过虚拟方法地址解析。
因为你的Event
已经有 id,所以它与类型并不完全不可知,所以强制转换是完全安全的。在这里,您正在亲自观察该类型,在访问者模式中,您正在使编译器处理它。
"凡是上升的,必是下降的"。
- C++避免重复声明的语法是什么
- 在没有太多条件句的情况下,我如何避免被零除
- 如何重构类层次结构以避免菱形问题
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 以下示例中如何避免代码复制?C++/库达
- Python中的for循环与C++有何不同
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 是否应该在模板化代码中完全避免const
- 我应该避免多重实现继承吗
- 为了方便起见,我应该避免公开私有字段变量吗
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 避免在C++中重复子类定义
- "Inverse SFINAE"避免模棱两可的过载
- 如何避免在仅标头库中C++类/变量重定义
- Python 集合.计数器,如何避免重复查找
- 是否应避免从非常量迭代器转换为常量迭代器?
- 避免矢量中的对象切片<Base><shared_ptr>
- 有没有办法在从编译器获取参数时避免预处理器宏?
- 如何避免LED在循环状态变化中闪烁?