我陷入了关于树的访客模式的代码重复问题。当前的情况如下:我有一棵树,由两个不同的节点类组成,即叶子和非叶子。另外,我有两个访问者基类,它们看起来非常相似,除了一个访问const树而另一个访问非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);
  }
};

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

您会看到,两个访问者之间有很多代码重复,并且由于我将不得不针对const和nonconst节点实现另一种遍历策略,因此我想避免这种重复。是否有可能提取重复的代码,最好不要在整个地方都使用const_cast

最佳答案

您可以按以下方式定义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;

07-24 14:09