使用枚举和开关代替访问者模式 我有一棵树,代表一个数学表达式,我想为了计算表达式树的值,我将实现访问者模式,但是在C++中,这涉及到很多重复,因为接受访问者的方法必须在每个子类上,因为即使方法是相同的,类型不是 class Node { virtual void Acccept(Visitor *visitor) = 0; }; class ConstantNode : Node { virtual void Accept(Visitor *visitor) { visitor->visit( this ); } }; class VariableNode : Node { virtual void Accept( Visitor *visitor) { visitor->visit( this ); } }; class Visitor { virtual void visit(ConstantNode *node) = 0; virtual void visit(VariableNode *node) = 0; }; class CalculateVisitor : Visitor { virtual void visit(ConstantNode *node) { /* code */ } virtual void visit(VariableNode *node) { /* code */ } };

使用枚举和开关代替访问者模式 我有一棵树,代表一个数学表达式,我想为了计算表达式树的值,我将实现访问者模式,但是在C++中,这涉及到很多重复,因为接受访问者的方法必须在每个子类上,因为即使方法是相同的,类型不是 class Node { virtual void Acccept(Visitor *visitor) = 0; }; class ConstantNode : Node { virtual void Accept(Visitor *visitor) { visitor->visit( this ); } }; class VariableNode : Node { virtual void Accept( Visitor *visitor) { visitor->visit( this ); } }; class Visitor { virtual void visit(ConstantNode *node) = 0; virtual void visit(VariableNode *node) = 0; }; class CalculateVisitor : Visitor { virtual void visit(ConstantNode *node) { /* code */ } virtual void visit(VariableNode *node) { /* code */ } };,c++,enums,visitor-pattern,C++,Enums,Visitor Pattern,这也有一个问题,因为方法是虚拟的,所以不能有模板节点 有一个枚举似乎容易得多,每个节点有一个实例,您只需在一个方法而不是访问者模式中打开枚举 class Node { enum NodeType { Constant, Variable } Node(NodeType type) : m_nodeType(type) {} NodeType m_nodeType; }; class ConstantNode { ConstantNode() : Node(C

这也有一个问题,因为方法是虚拟的,所以不能有模板节点

有一个枚举似乎容易得多,每个节点有一个实例,您只需在一个方法而不是访问者模式中打开枚举

class Node {
  enum NodeType {
    Constant,
    Variable
  }
  Node(NodeType type) : m_nodeType(type) {}
  NodeType m_nodeType;
};

class ConstantNode {
  ConstantNode() : Node(Constant) {}
};
class VariableNode {
  VariableNode() : Node(Variable) {}
};

int calculate(Node* node) {
  switch (node->m_nodeType) {
    case Constant:
      //...
    case Variable:
      //...
  }
}
我知道enum版本需要动态强制转换,但总的来说,似乎需要重复大量相同的代码,这意味着它将允许模板节点,例如(
BinOpNode

可替代的是,在C++中有一些改进访问者模式的方法,所以不需要所有的重复? (将代码直接输入stackoverflow,很抱歉有任何错误,但它基于真实代码)

编辑:对于BinOpNode:

template<class T>
class BinOpNode {
  T m_op = T();
  BinOpNode() : Node(BinOp) {}
};

//in calculate:
case BinOpNode:
  BinOpNode* n = dynamic_cast<BinOpNode*>(node);
  return n->m_op(calculate(n->m_left), calculate(n->m_right));
模板
类二项式节点{
T m_op=T();
BinOpNode():节点(BinOp){}
};
//在计算中:
案例双节点:
BinOpNode*n=动态_转换(节点);
返回n->m_op(计算(n->m_左),计算(n->m_右));

您可以使用模板删除重复:

// Classes implementing the mechanism

class Node {
  virtual void Accept(Visitor *visitor) = 0;
};

template<typename NodeType> class ConcreteNode
{
  virtual void Accept(Visitor* visitor)
  {
    visits<NodeType>* v = visitor;
    v->visit((NodeType*)this);
  }
};

template<typename NodeType> class visits
{
  virtual void visit(NodeType* node) = 0;
};

// The actual visitors/visited classes

class Visitor:
  visits<ConstantNode>,
  visits<VariableNode>
{
};

class ConstantNode : ConcreteNode<ConstantNote> {};
class VariableNode : ConcreteNode<VariableNode> {};

class CalculateVisitor : Visitor {
  virtual void visit(ConstantNode *node) { /* code */ }
  virtual void visit(VariableNode *node) { /* code */ }
};
但这也被访问者模式完美地处理了;使用上面的模板代码:

class Visitor:
  public visits<BinOpNode<int> >,
  public visits<BinOpNode<double> >,
  ...
{
};

template<typename T> class BinOpNode:
  public ConcreteNode<BinOpNode<T> >
{
  ...
};
类访问者:
公众访问,
公众访问,
...
{
};
模板类双节点:
公共节点
{
...
};

这似乎一点也不容易。重复的数量相同(大小写标签与虚拟函数)。您也没有解释您计划如何处理模板<代码>case BinOp:现在怎么办?重复次数少了,因为它不再需要所有的Accept函数。在这两种情况下都会有节点的构造函数。添加新访问者不需要重复。并避免忘记与switch/enum情况相反的类型。“不再需要所有接受函数”CRTP是您的朋友。还可以查看“非循环访问者”。不,这是一些我不熟悉的变体。它似乎构建在每个类的唯一标记上(这正是您的类型enum)。对于原始非循环访客搜索,请参阅Robert C Martin的一篇论文。
BinOpNode<int>* n = dynamic_cast<BinOpNode<int>*>(node);
class Visitor:
  public visits<BinOpNode<int> >,
  public visits<BinOpNode<double> >,
  ...
{
};

template<typename T> class BinOpNode:
  public ConcreteNode<BinOpNode<T> >
{
  ...
};