在C++中实现对象向量的访问者模式



这是这个问题的后续内容。

我们可以为上一个问题中的问题实现访问者模式,如以下答案所示:

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&作为其自变量。那么我们如何实现访问者模式来解决这个问题呢?有可能吗?

编辑

foostd::vector<std::shared_ptr<Parent>> const&传递给另一个类state。但是,如果矢量中的所有对象都是Child_A类型,则它调用state.method_A,如果矢量上的所有对象是Child_B类型,则调用state.method_B,否则调用state.method_C。只有state可以直接与parent类一起使用。

我希望这能澄清一些问题。

我不太确定我能不能得到你想要的,但我会试试的。

据我所知,您希望在代码中包含以下内容:

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类型。

幸运的是,一切都没有失去。


您可以做两件事,这两件事都需要在运行时确定子级的"真实"类型。

选项1:在Parent中添加一个字段,标识应如何处理它

这需要以下内容。

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.
};

选项2:使用运行时类型标识。(RTTI)

另一种选择是使用动态强制转换。这将在您的整个可执行文件中启用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.
};

最新更新