这是this question的后续行动。
我们可以按照this answer中的建议,在上一个问题中实现问题的访问者模式:
class Base {
foo(Parent& p) {
p.accept(*this);
}
virtual void visit(Child_A&) = 0;
virtual void visit(Child_B&) = 0;
};
class Parent {
virtual void accept(Base&) = 0;
};
class Child_A: Parent {
void accept(Base& v) {
v.visit(*this);
}
};
class Child_B: Parent {
void accept(Base& v) {
v.visit(*this);
}
};
class Derived_A: Base {
void treat_same(Parent&) {
// ...
}
void visit(Child_A& a) {
treat_same(a);
}
void visit(Child_B& b) {
treat_same(b);
}
};
class Derived_B: Base {
void visit(Child_A&) {
// ...
}
void visit(Child_B&) {
// ...
}
};
但现在考虑foo
是否期望std::vector<std::shared_ptr<Parent>> const&
作为其参数。
那么我们如何为问题实现访问者模式呢?有可能吗?
修改
foo
将std::vector<std::shared_ptr<Parent>> const&
传递给另一个班级state
。但是,如果向量中的所有对象都是Child_A
类型,则调用state.method_A
,如果向量中的所有对象都是Child_B
类型,则调用state.method_B
,否则调用{{} 1}}。只有state.method_C
可以直接使用state
类。
我希望这会清除一些事情。
答案 0 :(得分:0)
我不太确定我能得到你想要的东西,但我会试一试。
据我了解,您需要在代码中使用以下内容:
std::vector<std::shared_ptr<Parent>> children;
Base * handler = new Derived_A; // or new Derived_B.
for (child : children) {
// You want this call to correctly distinguish
// between objects of Child_A and Child_B
handler->visit(child);
不幸的是,C ++并不允许你这样做。 (*继续阅读)因为函数调用是由类型决定的,所有子元素都是shared_ptr类型,用于此循环。
幸运的是,一切都没有丢失。
你可以做两件事,都要求在运行时确定“真实”类型的孩子。
这需要遵循以下内容。
class Parent {
public:
enum class SubType {
A,
B,
};
virtual void accept(Base &) = 0;
// Subclasses must implement this to
// allow instances of base to correctly handle the objects.
virtual SubType handle_as() const = 0;
};
Base的实现将包含以下内容:
class Base {
void visit( shared_ptr<Parent> p ) {
switch( p->handle_as() ) {
case Parent::SubType::A:
this->accept( *static_ptr_cast<Child_A>(p) );
break;
case Parent::SubType::B:
this->accept( *static_ptr_cast<Child_B>(p) );
break;
}
// In addition to your accept(Child_A &) accept(Child_B &) etc.
};
使用动态强制转换的另一种选择。这将在您的整个可执行文件中启用RTTI,在这种情况下,这可能是您想要的,但请注意,它确实会产生较小的性能+可执行文件的大小成本。
如果强制转换是非法的, dynamic_cast
将返回nullptr,否则它将返回一个有效的指针。
简而言之:
class Base {
void visit( shared_ptr<Parent> p ) {
if ( dynamic_ptr_cast<Child_A>(p) ) {
this->accept( *dynamic_ptr_cast<Child_A>(p) );
}
else if ( dynamic_ptr_cast<Child_B>(p) ) {
this->accept( *dynamic_ptr_cast<Child_B>(p) );
}
}
// In addition to your accept(Child_A &) accept(Child_B &) etc.
};