C++ 访客和双重派遣,无需覆盖“;接受;c+中的方法+;
好的:我的问题是:我有一个基本的composit类,它接受访问者,然后在其节点上迭代。工作起来很有魅力。 但是,我必须使用从这个composit派生的方法,并认识到我必须重写派生类中的“accept()”方法,以获得正确的双重分派(我不理解) 这带来了两个缺陷:第一,我必须打破基础的隐藏结构,第二,我必须复制代码。为了澄清,这里是我的伪代码:C++ 访客和双重派遣,无需覆盖“;接受;c+中的方法+;,c++,visitor,double-dispatch,C++,Visitor,Double Dispatch,好的:我的问题是:我有一个基本的composit类,它接受访问者,然后在其节点上迭代。工作起来很有魅力。 但是,我必须使用从这个composit派生的方法,并认识到我必须重写派生类中的“accept()”方法,以获得正确的双重分派(我不理解) 这带来了两个缺陷:第一,我必须打破基础的隐藏结构,第二,我必须复制代码。为了澄清,这里是我的伪代码: struct Visitor { void visit( BaseComposit*) { throw( "not expected");
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:
};
struct访问者
{
无效访问(BaseComposit*){throw(“不期望”);};
无效访问(DerivedComposit*){throw(“ok”);};
};
类BaseComposit
{
私人:
std::vector节点;
公众:
虚拟无效接受(访客*v)
{
v->参观(本次);
对于(int i=0;i接受(v);
}
};
类DerivedComposit:公共基复合
{
公众:
};
在这方面有什么好办法吗?
谢谢大家!
编辑:在“accept()”中添加了“virtual”以使其更精确
在这方面有什么好办法吗
不是真的。这就是为什么访客模式有点痛苦。尽管您可以借助模板稍微减少重复:
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 ); }
};
但是您仍然需要在每个派生类中使用它来显示定义
class DerivedComposit : public BaseComposit
{
public:
INJECT_ACCEPT();
};
。因此,我想有人可能会说,上面的代码看起来“很自然”。如果您想强制始终执行某些代码,请使用非虚拟接口(NVI)模式:
classbasecomposit
{
私人:
std::向量节点;
虚拟无效调用_visit(Visitor*v){v->visit(this);}
公众:
无效接受(访客*v)
{
拜访(五);
对于(int i=0;i接受(v);
}
};
类DerivedComposit:公共基复合
{
void call_visit(Visitor*v)覆盖{v->visit(this);}
公众:
};
吹毛求疵,但左大括号后的空格与右大括号前的空格不匹配有点令人讨厌。为什么不在基类中将accept声明为virtual,并在派生类中实现重写?访问者模式就是这样。你可能想尝试一下“非循环访问者”的东西。我的(要点)(就是)(这个)
这种风格可能会在代码评审中引起很多讨论。相信我,一个空格可以和多个空格一样突出。我可以得到(这个)
或(这个)
,但我担心(这个)
总是会成为我在代码评审中的一个问题。但是YMMV:)但是“this”始终是一个BaseComposit*?@Oliv-使其虚拟化是另一回事:)谢谢-我将使用模板,是的,当然它必须是虚拟的。这就是我为什么写“伪代码”;-)再次感谢您的快速响应!伟大的社区@user9066185-好吧,我添加了另一个小道消息。它避免了更多的重复,但有点可疑。模板方法在这里有什么用?这仅仅是为了让代码更加C++y吗?@affenärschle:所以,摆脱override
@Jarod42:jup-works。但是我不明白为什么编译器可以选择正确的vtable条目Base/Derived而不是visitor中的vtable条目。。。不管怎样,塞巴斯蒂安,好办法。好的-访客没有vtabel。。。我真丢脸
class DerivedComposit : public BaseComposit
{
public:
INJECT_ACCEPT();
};
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:
};