表达式求值:面向对象版本

 c++沉思录中的一个例子.
 
 
思路:
由图所示, 将节点的概念用类表示.
相同点:每个节点存储一个值以及一些节点   继承
不同点:值的种类, 存储节点的数量               动态绑定
 
进一步:
3种节点类型 
1.只有一个数值, 无子节点
2.一元运算符, 一个子节点
3.二元运算符, 两个子节点
针对每种类型的节点,都需要进行打印动作
不同的事物,具有相同的界面(接口), 意味着需要使用动态绑定.
 
下一步:
考虑到3种节点类型之间均没有 "is-a"的关系, 所以需要创建公共抽象基类ExprNode
class ExprNode
{
	friend std::ostream& operator<<(std::ostream&, const ExprNode&);
protected:	
	virtual ~ExprNode(){};
	virtual void Print(std::ostream&) const = 0;
};
 
std::ostream&
operator<<(std::ostreamosconst ExprNodenode)
{
	node.Print(os);
	return os;
}

继续创建其他节点类:
class NumbericNode : public ExprNode
{
protected:
	NumbericNode(int val): value_(val) {}
	void Print(std::ostreamosconst override
	{
		os << value_;
	}
 
private:
	int value_;
};
 
class UnaryNode : public ExprNode
{
protected:
	UnaryNode(const char _operatorExprNode_expression)
		:operator_(_operator), expression_(_expression)
	{
	}
 
	~UnaryNode()
	{
	}
 
	void Print(std::ostreamosconst override
	{
		os << "(" << operator_ << *expression_ << ")";
	}	
 
private:
	ExprNode* expression_;
	char operator_;
};
 
class BinaryNode : public ExprNode
{
protected:
	BinaryNode(const char _operatorExprNodeleftExprNoderight)
		:operator_(_operator), left_(left), right_(right)
	{
	}
 
	~BinaryNode()
	{
	}
 
	void Print(std::ostreamosconst override
	{
		os << "(" << *left_ << operator_ << *right_ << ")";
	}
 
 
private:
	ExprNode* left_;
	ExprNode* right_;
	char operator_;
};

在创建表达式节点类时,注意到客户端(使用者)并不知晓存在节点类. 所以可以将节点子类的构造函数声明为保护成员.同时将Expr设为所有子类的友元类
以便访问节点类的构造函数.
继续:
此时, 如何构造表达式树呢? 我们发现节点类只是对原始问题中的圆圈建模, 而丢弃了箭头. 那么对其建模就创建了Expr类, 来构造表达式树
但未了减少用户使用的复杂度, 用户不再关心内存管理的问题.即创建每个节点类型实例. 所以将Expr设计为句柄类,对节点实例进行内存管理.同时也起到对用户隐藏ExprNode及其派生类的继承层次和隐藏具体实现
修改完成后的代码版本
源码
posted @ 2013-06-09 16:51  让代码飞一会儿  阅读(846)  评论(0编辑  收藏  举报