C++ 树的常量和非常量版本的访问者模式
关于树的访问者模式,我遇到了代码重复问题。当前情况如下:我有一棵树,由两个不同的节点类组成,即leafs和non-leafs。此外,我有两个访问者基类,它们看起来非常相似,只是一个访问常量树,另一个访问非常量树。具体访问者必须执行的实际操作独立于节点的具体类型。我将举一个简短的例子:C++ 树的常量和非常量版本的访问者模式,c++,visitor,C++,Visitor,关于树的访问者模式,我遇到了代码重复问题。当前情况如下:我有一棵树,由两个不同的节点类组成,即leafs和non-leafs。此外,我有两个访问者基类,它们看起来非常相似,只是一个访问常量树,另一个访问非常量树。具体访问者必须执行的实际操作独立于节点的具体类型。我将举一个简短的例子: class Visitor; class ConstVisitor; class Node { public: virtual void accept(Visitor&) = 0; virtual
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);
}
};
类访问者;
班级访客;
类节点{
公众:
虚拟无效接受(访问者&)=0;
虚拟无效接受(ConstVisitor&)const=0;
};
类叶:公共节点{
虚拟无效接受(访问者&v){v.visitLeaf(*this);}
虚拟无效接受(ConstVisitor&cv){cv.visitLeaf(*this);}
};
类CompoundNode:公共节点{
公众:
向量getChildren()常量;
虚拟void接受(Visitor&v){v.visitCompoundNode(*this);}
虚拟void接受(ConstVisitor&cv){cv.visitCompoundNode(*this);}
};
班级访客{
受保护的:
虚拟节点(节点和节点)=0;
公众:
无效visitLeaf(叶和叶){
进程节点(叶);
}
无效visitCompoundNode(CompoundNode和cNode){
processNode(cNode);
auto children=cNode.getChildren();
用于(自动子对象:子对象)
孩子->接受(这个);
}
};
班主任访客{
受保护的:
虚拟void进程节点(节点常量和节点)=0;
公众:
无效visitLeaf(叶常数和叶){
进程节点(叶);
}
无效visitCompoundNode(CompoundNode常量和cNode){
processNode(cNode);
auto children=cNode.getChildren();
用于(自动子对象:子对象)
孩子->接受(这个);
}
};
具体的访问者类继承自visitor
或ConstVisitor
,这取决于它们的processNode
方法是否必须更改所访问的节点
你看,这两个访问者之间有很多代码重复,因为我必须实现另一个遍历策略,同样对于常量和非常量节点,我希望避免这种重复。是否有可能提取重复的代码,最好不要到处使用
const\u 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); }
}
};
您可以使用以下模板:
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> {
};
模板
类基本访问者{
受保护的:
虚拟void进程节点(节点类型和节点)=0;
公众:
无效visitLeaf(叶型和叶型){
进程节点(叶);
}
无效visitCompoundNode(CompoundNodeType和cNode){
processNode(cNode);
auto children=cNode.getChildren();
用于(自动子对象:子对象)
孩子->接受(这个);
}
};
类访问者:公共基础访问者{
};
类ConstVisitor:公共BaseVisitor{
};
谢谢,这是一个快速、干净的解决方案。我希望我的同事们不要太讨厌模板;-)
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> {
};