一个问题,如下图,没有画出箭头
*
- +
5 3 4
Class Expr_node{
friend ostream operate<<(ostream&,const Expr_node&); //<<符号是不能用动态绑定的,所以用print函数采用动态绑定,用<<符号调用print函数
//而且由于不准备提供print函数给用户使用,则把print定为protected,把<<符号定为友元。
protected:
virtual void print(ostream&) const = 0;
virtual ~Expr_node(){};
}
从Expr_node中派生出Int_node,Unary_node,Binary_node
class Int_node: public Expr_node{
friend class Expr;
int n;
Int_node(int k):n(k){}
Void print(ostream& o) const {o<<n;}
}
class Unary_node: public Expr_node{
friend class Expr;
String op;
Expr_node* opnd;
Unary_node(const String& a,Expr_node* b):op(a),opnd(b){}
Void print(ostream& o) const {o<<"(" << op << *opnd << ")";}
}
class Binary_node: public Expr_node{
friend class Expr;
String op;
Expr_node* left;
Expr_node* right;
Binary_node(const String& a,Expr_node* b,Expr_node* c):op(a),left(b),right(c){}
Void print(ostream& o) const {o<<"("<<*left << op << *right << ")";}
}
这样用户必须自己去维护那些指针分配的内存。这里没有对图中的箭头进行建模,而是把箭头作为一个简单的指针,然后还强迫
用户亲自操作这些指针。
所以我们另外定义个Expr这个句柄类来表示箭头。并用这个结构来代表一个树或子树,隐藏Expr_node节点。
class Expr{
friend ostream operate<<(ostream&,const Expr&);
Expr_node* p;
public:
Expr(int); //创建一个Int_node
Expr(const String&,Expr); //创建一个Unary_node
Expr(const String&,Expr,Expr); //创建一个Binary_node
Expr(const Expr&);
Expr& operate=(const Expr&);
~Expr(){delete p;}
}
考虑复制构造函数和赋值操作符,中要copy Expr_node指针,这里也涉及内存的问题,但最好还是不要真正实现复制操作了,仅copy指针
然后在Expr_node中增加一个计数:int use,初始化为1
Expr(const Expr& t){
p = t.p;
++p->use;
}
Expr& operate=(const Expr& rhs){
rhs.p->use++;
if(--p->use == 0)
delete p;
p = rhs.p;
return *this;
}
ostream operate<<(ostream& o,const Expr& t){
t.p->print(o);
return o;
}
然后修改各个派生自Expr_node的类,令其操作为私有的,将Expr类声明为友元,存储Expr,而不是存储指向Expr_node的指针。例如Binary_node
class Binary_node: public Expr_node{
friend class Expr;
String op;
Expr left;
Expr right;
Binary_node(const String& a,Expr b,Expr c):op(a),left(b),right(c){}
Void print(ostream& o) const {o<<"("<<left << op << right << ")";}
}
现在这种设计就非常好了,如果再增加一个功能,如计算运算结果,则只要在每个节点类中增加一个eval函数就可以了。
如果要再增加一个运算符,如类似?:(if then else),那么只要增加一个派生Expr_node的子类Ternary_node类就好了。