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

来源:互联网 发布:淘宝红糖销售方案 编辑:程序博客网 时间:2024/04/29 13:29
一个面向对象的程序范例

面向对象编程的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 constrollExpr(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;}
总结:
       当我们分析出表达式是由节点和边组成,便可以设计数据抽象来对树进行建模,继承让我们抓住了各种节点和边之间的相似之处,而动态绑定帮助我们为各种类型的节点定义操作,让编译器来负责安排在运行时能够调用正确的函数。这样,数据抽象加上动态绑定可让我们集中精神考虑每个类型的行为和实现,而不必关心与其他对象的交互


原创粉丝点击