好的:这是我的问题:我有一个基础复合类,它接受访问者,然后遍历其节点。奇迹般有效。
但是,我必须使用从这个组合派生的一个,并认识到我必须覆盖派生类中的“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/

10-12 16:15