【问题标题】:Visitor pattern for const and nonconst versions of a tree树的 const 和 nonconst 版本的访问者模式
【发布时间】:2013-05-13 21:34:24
【问题描述】:

我遇到了关于树的访问者模式的代码重复问题。目前的情况如下:我有一棵树,由两个不同的节点类组成,即叶子和非叶子。此外,我有两个看起来非常相似的访问者基类,除了一个访问 const 树和另一个非常量树。具体访问者必须执行的实际操作与节点的具体类型无关。我举一个简短的例子:

class Visitor;
class ConstVisitor;

class Node {
public:
  virtual void accept(Visitor&) = 0;
  virtual void accept(ConstVisitor&) const = 0;
};

class Leaf : public Node {
  virtual void accept(Visitor& v)        {v.visitLeaf(*this);}
  virtual void accept(ConstVisitor& cv)  {cv.visitLeaf(*this);}
};

class CompoundNode : public Node {
public:
  vector<Node*> getChildren() const;
  virtual void accept(Visitor& v)        {v.visitCompoundNode(*this);}
  virtual void accept(ConstVisitor& cv)  {cv.visitCompoundNode(*this);}
};

class Visitor {
protected:
  virtual void processNode(Node& node) = 0;
public:
  void visitLeaf(Leaf& leaf) {
    processNode(leaf);
  }
  void visitCompoundNode(CompoundNode& cNode) {
    processNode(cNode);
    auto children = cNode.getChildren();
    for (auto child : children)
      child->accept(this);
  }
};

class ConstVisitor {
protected:
  virtual void processNode(Node const& node) = 0;
public:
  void visitLeaf(Leaf const& leaf) {
    processNode(leaf);
  }
  void visitCompoundNode(CompoundNode const& cNode) {
    processNode(cNode);
    auto children = cNode.getChildren();
    for (auto child : children)
      child->accept(this);
  }
};

具体的访问者类继承自 VisitorConstVisitor,这取决于它们的 processNode 方法是否必须更改访问的节点。

你看,两个访问者之间有很多代码重复,因为我将不得不实现另一个遍历策略,也适用于 const 和 nonconst 节点,我想避免这种重复。是否有可能提取重复代码,最好不要到处使用const_cast

【问题讨论】:

    标签: c++ visitor-pattern


    【解决方案1】:

    您可以定义一个TVisitor 类模板,如下所示:

    #include <type_traits>
    
    class Node;
    class CompoundNode;
    class Leaf;
    
    template<bool isNonConstVisitor>
    class TVisitor
    {
        typedef typename std::conditional<isNonConstVisitor, 
            Node, Node const>::type node_type;
    
        typedef typename std::conditional<isNonConstVisitor, 
            CompoundNode, CompoundNode const>::type compound_node_type;
    
        typedef typename std::conditional<isNonConstVisitor, 
            Leaf, Leaf const>::type leaf_node_type;
    
    protected:
    
        virtual void processNode(node_type& node) = 0;
    
    public:
    
        void visitLeaf(leaf_node_type& leaf) { processNode(leaf); }
    
        void visitCompoundNode(compound_node_type& cNode) {
            processNode(cNode);
            auto children = cNode.getChildren();
            for (auto child : children) { child->accept(*this); }
        }
    };
    

    然后使用VisitorConstVisitor 作为该类模板的相应实例化的类型别名:

    typedef TVisitor<true> Visitor;
    typedef TVisitor<false> ConstVisitor;
    

    【讨论】:

    • 谢谢,这是一个快速而干净的解决方案。我希望我的同事不要太讨厌模板 ;-)
    【解决方案2】:

    你可以使用模板:

    template<typename NodeType,
             typename CompoundNodeType,
             typename LeafType>
    class BaseVisitor {
    protected:
        virtual void processNode(NodeType& node) = 0;
    public:
        void visitLeaf(LeafType& leaf) {
            processNode(leaf);
        }
        void visitCompoundNode(CompoundNodeType& cNode) {
            processNode(cNode);
            auto children = cNode.getChildren();
            for (auto child : children)
            child->accept(this);
        }
    };
    
    class Visitor: public BaseVisitor<Node, CompoundNode, Leaf> {
    };
    
    class ConstVisitor: public BaseVisitor<const Node, const CompoundNode, const Leaf> {
    };
    

    【讨论】:

      猜你喜欢
      • 2011-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-04
      • 2014-09-28
      • 1970-01-01
      相关资源
      最近更新 更多