C++面向对象实现算术表达式树

        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) { } //默认构造,计数1
	virtual 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_node
	Expr(const std::string&, Expr);     //创建一个Unary_node
	Expr(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()
{   //有默认构造,需要判断p是否为nullptr
    //if( p && --p->use==0 )//如果为nullptr中断
	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(int);                            //创建一个Int_node
	Expr(const std::string&, Expr);       //创建一个Unary_node
	Expr(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) { } //默认构造,计数1
	virtual 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;
}

        二、算术表达式树的计算

        要实现表达式的值,要求句柄类有个计算表达式值的函数eval,句柄Expr的eval函数可以将实际工作委托给组成Expr的结点。主函数如下

#include <iostream>
#include <string>
int main()
{
	Expr t = Expr("*",Expr("-",5),Expr("+",3,4) );
	std:: cout << t << "=" << t.eval() << std::endl;
	t = Expr("*",t,t);
	std:: cout << t << "=" << t.eval() << std::endl;
	return 0;
}

       Expr句柄类添加的eval函数,因为委托给Expr_node,所以Expr_node这个基类需要增加一个纯虚函数eval

//句柄Expr类添加的函数
int eval()const {return p->eval(); } //工作委托组成Expr的结点
//Expr_node基类添加的纯虚函数
virtual int eval()const = 0;

        三个子类的eval函数

//1、包含一个整数,没有子结点的结点类
int eval() const { return n; }
//2、一元运算符结点类
int eval()const
{
	if( op=="-" )
		return -t.eval(); //叶子结点
	throw "error, bad op " + op + " in UnaryNode";
}
//3、二元运算符结点类
int eval()const
{
	int op1 = left.eval();
	int op2 = right.eval();
	if(op=="-") return op1 - op2;
	if(op=="+") return op1 + op2;
	if(op=="*") return op1 * op2;
	if(op=="/"&&op2!=0) return op1 / op2;
	throw "error, bad op " + op + " in BinaryNode";
}

        完整测试代码

#include <iostream>
#include <string>
#include <exception>
 
class Expr_node;//前置声明,因为下面的类包装了Expr_node*
 
class Expr{
	friend std::ostream& operator<<(std::ostream&,const Expr&);//重载输出操作符<<
	Expr_node* p; //包装基类指针
public:
	Expr(int);                            //创建一个Int_node
	Expr(const std::string&, Expr);       //创建一个Unary_node
	Expr(const std::string&, Expr, Expr); //创建一个Binary_node
	//复制管理
	Expr(const Expr&);              //复制构造
	Expr& operator=(const Expr&);   //=运算符重载
	~Expr();                        //析构,释放内存
	//计算
	int eval()const;//函数实际工作委托结点,受托结点不完整,需要类外定义
};
 
//基类Expr_node
class Expr_node{
    friend class Expr; //句柄类
	//因虚函数,重载<<的友元可以不在子类声明
	friend std::ostream& operator<<(std::ostream&,const Expr&);
    int use; //计数
protected:
    Expr_node():use(1) { } //默认构造,计数1
	virtual void  print(std::ostream&) const =  0; //打印,纯虚函数
	virtual ~Expr_node(){} //虚析构
	virtual int eval()const = 0; //计算,纯虚函数
};
 
//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; 
	}
	int eval() const { return 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 << ")"; }	
	int eval()const
	{
		if( op=="-" )
			return -t.eval(); //叶子结点
		throw "error, bad op " + op + " in UnaryNode";
	}
};
 
//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 << ")";
	}
	int eval()const
	{
		int op1 = left.eval();
		int op2 = right.eval();
		if(op=="-") return op1 - op2;
		if(op=="+") return op1 + op2;
		if(op=="*") return op1 * op2;
		if(op=="/"&&op2!=0) return op1 / op2;
		throw "error, bad op " + op + " in BinaryNode";
	}
};
 
//句柄类构造函数,构造其包装的基类的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 Expr::eval()const {return p->eval(); } 
 
int main()
{
	Expr t = Expr("*",Expr("-",5),Expr("+",3,4) );
	std:: cout << t << "=" << t.eval() << std::endl;
	t = Expr("*",t,t);
	std:: cout << t << "=" << t.eval() << std::endl;
	/* ((-5)*(3+4))=-35
	   (((-5)*(3+4))*((-5)*(3+4)))=1225 */
	return 0;
}

        三、添加子类三元运算符类

        三元运算符类代码

class Ternary_node:public Expr_node{
	friend class Expr;
	std::string op;
	Expr left;
	Expr middle;
	Expr right;	
	Ternary_node(const std::string& a, Expr b, Expr c, Expr d):
		op(a),left(b),middle(c),right(d) {  }
	void print(std::ostream& o)const;
	int eval()const;	
};

void Ternary_node::print(std::ostream& o)const
{
	o << "(" << left << "?" << middle << ":" << right << ")";
}
int Ternary_node::eval()const
{
	if(left.eval())
		return middle.eval();
	else 
		return right.eval();
}

        句柄类Expr需要添加的构造函数

Expr(const std::string& op, Expr left, Expr middle, Expr right)
{
	p = new Ternary_node(op,left,middle,right);
}

        测试完整代码

#include <iostream>
#include <string>
#include <exception>
 
class Expr_node;//前置声明,因为下面的类包装了Expr_node*
 
class Expr{
	friend std::ostream& operator<<(std::ostream&,const Expr&);//重载输出操作符<<
	Expr_node* p; //包装基类指针
public:
	Expr(int);                                 //创建一个Int_node
	Expr(const std::string&, Expr);            //创建一个Unary_node
	Expr(const std::string&, Expr, Expr);      //创建一个Binary_node
	Expr(const std::string&, Expr, Expr, Expr);//创建一个Ternary_node
	//复制管理
	Expr(const Expr&);              //复制构造
	Expr& operator=(const Expr&);   //=运算符重载
	~Expr();                        //析构,释放内存
	//计算
	int eval()const;//函数实际工作委托结点,受托结点不完整,需要类外定义
};
 
//基类Expr_node
class Expr_node{
    friend class Expr; //句柄类
	//因虚函数,重载<<的友元可以不在子类声明
	friend std::ostream& operator<<(std::ostream&,const Expr&);
    int use; //计数
protected:
    Expr_node():use(1) { } //默认构造,计数1
	virtual void  print(std::ostream&) const =  0; //打印,纯虚函数
	virtual ~Expr_node(){} //虚析构
	virtual int eval()const = 0; //计算,纯虚函数
};
 
//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; 
	}
	int eval() const { return 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 << ")"; }	
	int eval()const
	{
		if( op=="-" )
			return -t.eval(); //叶子结点
		throw "error, bad op " + op + " in UnaryNode";
	}
};
 
//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 << ")";
	}
	int eval()const
	{
		int op1 = left.eval();
		int op2 = right.eval();
		if(op=="-") return op1 - op2;
		if(op=="+") return op1 + op2;
		if(op=="*") return op1 * op2;
		if(op=="/"&&op2!=0) return op1 / op2;
		throw "error, bad op " + op + " in BinaryNode";
	}
};
//4、三元运算符结点类
class Ternary_node:public Expr_node{
	friend class Expr;
	std::string op;
	Expr left;
	Expr middle;
	Expr right;
	
	Ternary_node(const std::string& a, Expr b, Expr c, Expr d):
		op(a),left(b),middle(c),right(d) {  }
	void print(std::ostream& o)const;
	int eval()const;	
};

void Ternary_node::print(std::ostream& o)const
{
	o << "(" << left << "?" << middle << ":" << right << ")";
}
int Ternary_node::eval()const
{
	if(left.eval())
		return middle.eval();
	else 
		return right.eval();
}
 
//句柄类构造函数,构造其包装的基类的4个子类对象
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 std::string& op, Expr left, Expr middle, Expr right)
{
	p = new Ternary_node(op,left,middle,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 Expr::eval()const {return p->eval(); } 
 
int main()
{
	Expr t = Expr("*",Expr("-",5),Expr("+",3,4) );
	std:: cout << t << "=" << t.eval() << std::endl;
	t = Expr("*",t,t);
	std:: cout << t << "=" << t.eval() << std::endl;
	/* ((-5)*(3+4))=-35
	   (((-5)*(3+4))*((-5)*(3+4)))=1225 */
	t = Expr("?:",Expr("-",3,5),Expr("+",5,6),Expr("*",7,8));
	std:: cout << t << "=" << t.eval() << std::endl;
	t = Expr("?:",Expr("-",3,3),Expr("+",5,6),Expr("*",7,8));
	std:: cout << t << "=" << t.eval() << std::endl;
	/* ((3-5)?(5+6):(7*8))=11
	   ((3-3)?(5+6):(7*8))=56 */
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值