假设我想避免以下代码中的dynamic_cast
:
struct Base { ... stuff ... };
struct HasColor {
virtual Color getColor() const = 0;
virtual void setColor(Color) = 0;
};
struct Foo : public Base, public HasColor {
... implements HasColor methods
};
...
vector<Base*> collection;
...
for(auto element : collection) {
if(auto hasColor = dynamic_cast<HasColor*>(element)) {
hasColor->SetColor(myColor);
}
}
一种解决方案是添加一个向下转换的方法:
struct Base {
HasColor* toHasColor() { return nullptr; }
};
struct Foo : public Base, public HasColor {
...
HasColor* toHasColor() { return this; }
};
但这意味着Base
需要了解每个Has
接口,从而增加耦合。
让我们尝试一下访客模式:
struct BaseVisitor {
void visitHasColor(HasColor& hasColor) = 0
};
struct Base {
virtual void visit(BaseVisitor& visitor) = 0;
};
但是我们面临着同样的问题:每个Has
类都需要添加到BaseVisitor
中,从而导致更多的耦合和更多的重新编译(这是C ++,对Base
的每次修改都意味着等待几分钟)。
如果我要支持插件,情况会变得更糟。插件无法修改Base
或BaseVisitor
,因此插件无法添加其他Has
类。 (我意识到典型的C ++ RTTI在库之间可能无法很好地工作,但是我已经看到了一个自定义的RTTI系统,而Qt中的一个显然可以。)
我可以在保持代码可扩展性的同时避免使用RTTI / dynamic_cast
吗?
This question似乎很相似。就我而言,我愿意采用其他方式来表示我的数据。
(在this one之类的C ++样式指南中,建议避免使用dynamic_cast
。)
答案 0 :(得分:3)
如果您收集了各种各样的东西,其中有些是HasColor
,有些不是,那么您必须依靠dynamic_cast
或类似的RTTI才能将对象用作{ {1}},否则您必须使用访问者模式来反转依赖关系,这会引入问题所在。
不需要使用HasColor
或其他RTTI的解决方案是仅使用dynamic_cast
个实例的集合。