2
我有一棵树表示一个数学表达式,我想为了计算表达式树的值,我会实现访问者模式,但是在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 */ }
};
这也有问题,因为方法是虚拟的,你不能有模板节点。
这似乎有一个枚举,其中有一个每个节点的情况下,你只需打开一个方法,而不是访客模式的枚举。
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:
//...
}
}
我知道枚举版本将需要动态铸造,但总体而言,似乎最好要重复很多相同的代码,它意味着将允许模板节点如(BinOpNode<std::plus>
)。
或者,有一些方法可以改进C++中的访问者模式,以便它不需要所有这些重复?
(键入的代码直接到计算器,对不起任何错误,但它是基于真正的代码)
编辑:为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));
它似乎并不容易。重复的数量是相同的(案例标签vs虚拟功能)。你也没有解释你计划如何处理模板。 '情况BinOp:'现在怎么样? –
重复性较低,因为它不需要所有的Accept功能。在任何情况下都会有节点的构造函数。 –
添加新访客不需要重复。并避免忘记与switch/enum case相反的类型。 “ – Jarod42