好的:这是我的问题:我有一个基础复合类,它接受访问者,然后遍历其节点。奇迹般有效。
但是,我必须使用从这个组合派生的一个,并认识到我必须覆盖派生类中的“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:
};
任何优雅的解决方案?
谢谢 !
编辑:将“虚拟”添加到“接受()”以使其更精确......
最佳答案
并不真地。这就是让访问者模式有点痛苦的原因。虽然您可以在模板的帮助下稍微减少重复:
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
成为虚拟函数。否则整件事都行不通。如果你真的喜欢冒险,你可以引入一个宏来简化
accept
到每个类的“注入(inject)”。像这样:#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 。所以我想有人可能会争辩说上述看起来“自然”。
关于c++ - 访问者和双重调度而不覆盖 C++ 中的 "accept"方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47690998/