C++沉思录读书笔记(三)

一个面向对象的程序范例

面向对象编程的3个要素:数据抽象、继承及动态绑定。这个例程非常完整的展示了这3个要素。

程序要做的内容就是要将这个算术表达树输出,即得到:(-5)*(3+4)

 

            


Expressions头文件:
#ifndef EXPRESSION_H_H
#define EXPRESSION_H_H
#include<iostream>
#include<string>
using namespace std;

//基类
class  ExprNode
{
public:
	ExprNode(): m_use(1) { }    //ExprNode的子类在执行自己的构造函数时,会调用父类的构造函数
	                                          //在里这个父类的构造函数为子类其进行引用计数
	virtual void print(ostream&) const = 0; //虚函数,在其子类中进行重新定义,运行时动态绑定
	virtual ~ExprNode() { }     //保证在删除由ExprNode*指针指向的对象时能够调用到正确的派生类析构造函数  
    virtual int Result() const = 0;
private:
	friend ostream& operator << (ostream &os, const ExprNode &rhs)  //友元函数重载输出操作符
	{
		rhs.print(os);
		return os;
	}
	friend class Expr;
	int m_use;    //计数
};

//句柄类
class Expr
{
public:
	Expr(int);                                //创建一个int对象
	Expr(const string&, Expr);        //创建一个UnaryNode对象
	Expr(const string&, Expr, Expr); //创建一个BianryNode对象
	Expr(const string&, Expr, Expr, Expr); //创建一个TernaryNode对象
	//copy constroll
	Expr(const Expr &t);
	Expr& operator = (const Expr&);
	~Expr() { if (--m_pENode->m_use == 0)  delete m_pENode; }
	int Result() const { return m_pENode->Result(); }

private:
	friend ostream& operator<<(ostream &os, const Expr &rhs)
	{
		rhs.m_pENode->print(os);
		return os;
	}
	// friend class ExprNode;
	ExprNode *m_pENode;
};

//派生类:数节点
class IntCode :public ExprNode
{
	friend class Expr; 
	IntCode(int k) : m_Ncount(k) { }
	void print(ostream &os) const {os<<m_Ncount;}
	int Result() const { return m_Ncount;}

private:
		int m_Ncount;    //数值
};
//派生类:单目运算符
class UnaryNode : public ExprNode
{
	friend class Expr;
	UnaryNode(const string& a, Expr b) : m_Ustr(a), m_pNode(b) { }
	void print(ostream &os) const {os<<"("<<m_Ustr<<m_pNode<<")";}
	int Result() const;
private:
	string m_Ustr;    //单目运算符
	Expr m_pNode; //操作数
};
//派生类:双目运算符
class BianryNode : public ExprNode
{
	friend class Expr;
    BianryNode(const string &a, Expr b, Expr c) : m_Bstr(a), m_bLeft(b), m_bRight(c) { }
	void print(ostream& os) const
	{ os<<"("<<m_bLeft<<m_Bstr<<m_bRight<<")";}
	int Result() const;
private:
	string m_Bstr;      //双目运算符
	Expr m_bLeft;    //左操作数
	Expr m_bRight; //右操作数
};
//派生类:三目运算符
class TernaryNode :public ExprNode 
{
	TernaryNode(const string &a, Expr b, Expr c, Expr d):  
    m_Tstr(a), m_tLeft(b), m_tMiddle(c), m_tRight(d) { }
	void print(ostream &os) const;
	int Result() const;
private:
	friend class Expr;
	string m_Tstr;
	Expr m_tLeft;
	Expr m_tMiddle;
	Expr m_tRight;
};
#endif

Expressions实现文件:
#include "Expressions.h"

//句柄类实现
Expr::Expr(int n)
{
	m_pENode = new IntCode(n); 
}
Expr::Expr(const string &op, Expr t)
{
	m_pENode = new UnaryNode(op, t);
}
Expr::Expr(const string &op, Expr left, Expr right)
{
	m_pENode = new BianryNode(op, left, right);
}
Expr::Expr(const string &op, Expr left, Expr middle, Expr right)
{
	m_pENode = new TernaryNode(op, left, middle, right);
}
Expr::Expr(const Expr &t)
{
	m_pENode = t.m_pENode; 
	++m_pENode->m_use;
}
Expr& Expr::operator = (const Expr &rhs)
{
	++rhs.m_pENode->m_use;
	if (--m_pENode->m_use == 0)
		delete m_pENode;
	m_pENode = rhs.m_pENode;
	return *this;
}
//单目运算符
int UnaryNode::Result() const
{
	if (m_Ustr == "-")  return -m_pNode.Result();

	throw "error, bad m_Ustr"+m_Ustr+"in UnaryNode";
}
//双目运算符
int BianryNode::Result() const
{
	int val1 = m_bLeft.Result();
	int val2 = m_bRight.Result();
	if (m_Bstr == "-")  return val1 - val2;
	if (m_Bstr == "+")  return val1 + val2;
	if (m_Bstr == "*")  return val1 * val2;
	if (m_Bstr == "/" && val2 != 0)  return val1 / val2;
	throw "error, bad m_Bstr"+m_Bstr+"in BianryNode";
}
//三目运算符
void TernaryNode::print(ostream &os) const
{
	os<<"("<<m_tLeft<<" ? "<<
		m_tMiddle<<" : "<<m_tRight<<")";
}
int TernaryNode::Result() const
{
	if (m_tLeft.Result())
	{
		return m_tMiddle.Result();
	}
	else
	{
		return m_tRight.Result();
	}
}

TestDemo文件:
#include "stdafx.h"
#include "Expressions.h"


int main(int argc, char* argv[])
{
	Expr t = Expr("*", Expr("-", 5), Expr("+", 3, 4));
	cout<<t<<"="<<t.Result() <<endl;
	t = Expr("*", t, t);
    cout<<t<< "=" <<t.Result() <<endl;
	return 0;
}
总结:
       当我们分析出表达式是由节点和边组成,便可以设计数据抽象来对树进行建模,继承让我们抓住了各种节点和边之间的相似之处,而动态绑定帮助我们为各种类型的节点定义操作,让编译器来负责安排在运行时能够调用正确的函数。这样,数据抽象加上动态绑定可让我们集中精神考虑每个类型的行为和实现,而不必关心与其他对象的交互


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值