????????C++面向對象,實現算術表達式樹的創建和打印的案例,來源于《C++沉思錄》第八章,涉及數據抽象、繼承、多態(動態綁定)、句柄,其中句柄的使用是核心,關于句柄的較為簡單的文章鏈接點擊這里,較為復雜的文章鏈接點擊這里
????????表達式(-5)*(3+4)對應的樹如圖,包括常數、一元運算符和二元運算符的結點,結點為圖中的圓圈,“邊”用箭頭表示,一個結點或連接一個子結點、兩個子結點或不連接子結點
????????結點有三種形式:表示整數表達式,包含一個整數值,無子結點,另外兩個分別表示一元表達式和二元表達式包含一個操作符,分別有一個或兩個子結點,三種形式對應三個類
? ? ? ? 三個類抽象出來一個結點概念,為它們的基類,即結點類,有子結點的類用包裝基類指針的句柄表示“邊”,使用句柄的作用就是隱藏繼承層次,動態綁定,管理內存,避免結點復制
????????基類代碼
//基類Expr_node
class Expr_node{friend class Expr; //句柄類//因虛函數,重載<<的友元可以不在子類聲明friend std::ostream& operator<<(std::ostream&,const Expr&);int use; //計數
protected:Expr_node():use(1) { } //默認構造,計數1virtual void print(std::ostream&) const = 0;virtual ~Expr_node(){} //虛析構
};
? ? ? ? 重載<<操作符函數代碼(句柄類對象引用隱藏繼承層次)
std::ostream& operator<<(std::ostream& o, const Expr& t)//句柄類對象t.p->print(o);return o;
}
? ? ? ?三個子類代碼
//1、包含一個整數,沒有子結點的結點類
class Int_node:public Expr_node{friend class Expr; //句柄類int n;Int_node(int k):n(k) { } //構造void print(std::ostream& o) const { o << n; }
};//2、一元運算符結點類
class Unary_node:public Expr_node{friend class Expr; //句柄類std::string op; //操作符Expr t; //句柄對象,表示"邊",指向子結點Unary_node(const std::string& a, Expr t):op(a),t(t) { }void print(std::ostream& o)const{ o << "(" << op << t << ")"; }
};//3、二元算法符結點類
class Binary_node: public Expr_node{friend class Expr;std::string op;Expr left;Expr right;Binary_node(const std::string&a, Expr b, Expr c):op(a),left(b),right(c) { }void print(std::ostream& o)const{o << "(" << left << op << right << ")";}
};
????????句柄類代碼(包裝基類指針,動態綁定,隱藏繼承層次,引用計數避免復制)
class Expr{friend std::ostream& operator<<(std::ostream&,const Expr&);//重載輸出操作符<<Expr_node* p; //包裝基類指針
public:Expr():p(nullptr){ } //默認構造Expr(int); //創建一個Int_nodeExpr(const std::string& op, Expr t); //創建一個Unary_nodeExpr(const std::string&, Expr, Expr); //創建一個Binary_node//復制管理Expr(const Expr&); //復制構造Expr& operator=(const Expr&); //=運算符重載~Expr(); //析構,釋放內存
};
//句柄類構造函數,構造其包裝的基類的3個子類對象
Expr::Expr(int n)
{p = new Int_node(n);
}
Expr::Expr(const std::string& op, Expr t)
{p = new Unary_node(op,t);
}
Expr::Expr(const std::string& op, Expr left, Expr right)
{p = new Binary_node(op,left, right);
}
//復制管理
Expr::Expr(const Expr& t){ p = t.p; ++p->use; };
Expr& Expr::operator=(const Expr& rhs)
{rhs.p->use++;if(--p->use==0)delete p;p = rhs.p;return *this;
}
Expr::~Expr()
{if(--p->use==0)//計數為0刪除delete p;
}
? ? ? ? 句柄的使用,所有對象只構造一次,句柄的復制只是復制基類指針,對象引用計數,并不復制對象,隱藏了繼承層次,管理動態內存?
????????主函數測試代碼
#include <iostream>
#include <string>
int main()
{Expr t = Expr("*",Expr("-",5),Expr("+",3,4) );std:: cout << t << std::endl;t = Expr("*",t,t);std:: cout << t <<std:: endl;return 0;
}
? ? ? ? 完整測試代碼
#include <iostream>
#include <string>class Expr_node;//前置聲明,因為下面的類包裝了Expr_node*class Expr{friend std::ostream& operator<<(std::ostream&,const Expr&);//重載輸出操作符<<Expr_node* p; //包裝基類指針
public:Expr():p(nullptr){ } //默認構造Expr(int); //創建一個Int_nodeExpr(const std::string& op, Expr t); //創建一個Unary_nodeExpr(const std::string&, Expr, Expr); //創建一個Binary_node//復制管理Expr(const Expr&); //復制構造Expr& operator=(const Expr&); //=運算符重載~Expr(); //析構,釋放內存
};//基類Expr_node
class Expr_node{friend class Expr; //句柄類//因虛函數,重載<<的友元可以不在子類聲明friend std::ostream& operator<<(std::ostream&,const Expr&);int use; //計數
protected:Expr_node():use(1) { } //默認構造,計數1virtual void print(std::ostream&) const = 0;virtual ~Expr_node(){} //虛析構
};//1、包含一個整數,沒有子結點的結點類
class Int_node:public Expr_node{friend class Expr; //句柄類int n;Int_node(int k):n(k) { } //構造void print(std::ostream& o) const { o << n; }
};//2、一元運算符結點類
class Unary_node:public Expr_node{friend class Expr; //句柄類std::string op; //操作符Expr t; //句柄對象,表示"邊",指向子結點Unary_node(const std::string& a, Expr t):op(a),t(t) { }void print(std::ostream& o)const{ o << "(" << op << t << ")"; }
};//3、二元算法符結點類
class Binary_node: public Expr_node{friend class Expr;std::string op;Expr left;Expr right;Binary_node(const std::string&a, Expr b, Expr c):op(a),left(b),right(c) { }void print(std::ostream& o)const{o << "(" << left << op << right << ")";}
};//句柄類構造函數,構造其包裝的基類的3個子類對象
Expr::Expr(int n)
{p = new Int_node(n);
}
Expr::Expr(const std::string& op, Expr t)
{p = new Unary_node(op,t);
}
Expr::Expr(const std::string& op, Expr left, Expr right)
{p = new Binary_node(op,left, right);
}
//復制管理
Expr::Expr(const Expr& t){ p = t.p; ++p->use; };
Expr& Expr::operator=(const Expr& rhs)
{rhs.p->use++;if(--p->use==0)delete p;p = rhs.p;return *this;
}
Expr::~Expr()
{if(--p->use==0)delete p;
}
//重載運算符<<
std::ostream& operator<<(std::ostream& o,const Expr&t)
{t.p->print(o);return o;
}int main()
{Expr t = Expr("*",Expr("-",5),Expr("+",3,4) );std:: cout << t << std::endl;t = Expr("*",t,t);std:: cout << t <<std:: endl;/* ((-5)*(3+4))(((-5)*(3+4))*((-5)*(3+4))) */return 0;
}