好的:这是我的问题:我有一个基础复合类,它接受一个访问者,然后迭代它的节点。奇迹般有效。 但是,我必须使用从这个composit派生的并且认识到我必须覆盖派生类中的“accept()”方法才能进行正确的双重调度(我不明白)。
这带来了两个缺陷:首先,我必须打破基础的隐藏结构,其次,我必须重复代码。要清除,这是我的伪代码:
struct Visitor
{
void visit( BaseComposit*) { throw( "not expected"); };
void visit( DerivedComposit*) { throw( "ok"); };
};
class BaseComposit
{
private:
std::vector< BaseComposit*> nodes;
public:
virtual void accept( Visitor* v)
{
v->visit( this);
for( int i = 0; i < nodes.size(); i++)
nodes[ i]->accept( v);
}
};
class DerivedComposit : public BaseComposit
{
public:
};
任何优雅的解决方案? 谢谢!
编辑:将“虚拟”添加到“接受()”以使其更精确......
答案 0 :(得分:1)
任何优雅的解决方案?
不是真的。这是让访客模式有点痛苦的原因。虽然您可以借助模板缓解重复:
class BaseComposit
{
private:
std::vector<BaseComposit*> nodes;
protected:
template<class T>
void accept_impl( Visitor* v, T* this_ )
{
v->visit( this_ );
for(int i = 0; i < nodes.size(); i++)
nodes[i]->accept(v);
}
public:
virtual void accept( Visitor* v ) { accept_impl( v, this ); }
};
现在accept
必须产生的重复更小。
另外,正如@Oliv指出的那样,你的例子确实应该accept
是一个虚函数。否则整件事都不会奏效。
如果你真的喜欢冒险,你可以引入一个宏来缓解&#34;注射&#34;每个班级accept
。像这样:
#define INJECT_ACCEPT() void accept( Visitor* v ) override { accept_impl( v, this ); }
但是你仍然需要在每个派生类中使用它来使定义出现。
class DerivedComposit : public BaseComposit
{
public:
INJECT_ACCEPT();
};
The semi-colon is allowed by a curious feature of the C++ grammar。所以我想有人可能会争论上面的看法&#34;自然&#34;。
答案 1 :(得分:1)
如果要强制某些代码始终执行,请使用非虚拟接口(NVI)模式:
class BaseComposit
{
private:
std::vector<BaseComposit*> nodes;
virtual void call_visit(Visitor* v) { v->visit(this); }
public:
void accept(Visitor* v)
{
call_visit(v);
for(int i = 0; i < nodes.size(); i++)
nodes[i]->accept(v);
}
};
class DerivedComposit : public BaseComposit
{
void call_visit(Visitor* v) override { v->visit(this); }
public:
};