`
mooncui
  • 浏览: 71186 次
社区版块
存档分类
最新评论

《C++沉思录》笔记--一个面向对象设计的例子

    博客分类:
  • C++
阅读更多

一个问题,如下图,没有画出箭头
    *
 -       +
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类就好了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics