(P39)面向对象版表达式计算器:表达式树,类设计

1.表达式计算器设计:表达式树,类设计

  • 表达式树
    将5+3*6解析成表达式树,整个表达式的值就等于根节点+的值,而根节点的值=其左节点5+右节点*的值(根节点的计算要依赖于其左节点和右节点),而*节点的值=左节点3+右节点6的值。(逐层往下)
    所以,要计算根节点的值,需要递归的遍历底下的子节点来进行计算。
    在这里插入图片描述

  • 类设计,继承体系
    NumberNode数字节点的Calc方法等于数字本身,
    BinaryNode二元运算节点:+或者*运算的节点,有两个操作数,左操作数,右操作数
    加法运算节点AddNode和乘法运算节点MultiplyNode继承至BinaryNode;
    在这里插入图片描述使用startUML
    Node是一个抽象类,其Calc方法是纯虚方法;
    BinaryNode也是一个抽象类,不能实例化一个具体对象;
    每个节点都有一个Calc方法,返回值是double;
    抽象类需要在isAbstract处打勾,字体也变成了斜体;
    在这里插入图片描述
    最终得到的类图如下:
    在这里插入图片描述

  • 改进类继承体系:增加UnaryNode一元计算节点
    与上面的相比,减号运算符是一元运算符,其孩子节点只有一个;
    *,+运算符是二元运算节点,其孩子有2个;
    UnaryNode是一元运算节点,它除了UMinusNode减号节点之外,还有函数调用FuncNode一元计算节点,即f(XXXX),不论XXX里面有多复杂的关系式,都把它看成是一元节点;
    在这里插入图片描述
    使用startUML
    在这里插入图片描述

  • eg:P39\Node.h

#ifndef _NODE_H
#define _NODE_H

class Node
{
public:
    //每个节点都有一个计算的纯虚函数
    //类Node用于多态,派生类都要实现Calc
    //Calc声明为const的,因为Calc不会改变类的成员
    virtual double Calc() const = 0;
    //类Node是多态类,析构函数也要声明为虚析构函数,否则基类指针指向派生类对象,
    //通过基类指针释放对象的时候,是不会调用派生类的析构函数
    virtual ~Node() {};
};

//NumerNode要实现这个纯虚函数Calc,为具体类;若没实现,还是抽象类
class NumberNode : public Node
{
public:
    NumberNode(double number) : number_(number) {}
    double Calc() const;
private:
    const double number_;//加const的原因:因为number_初始化后就不会改变
};

//BinaryNode节点有2个子节点
//BinaryNode类没有实现Calc方法,BinaryNode类仍然是抽象类,只有它的派生类,加、减、乘、除节点才知道该如何计算
class BinaryNode : public Node
{
public:
    BinaryNode(Node* left, Node* right)
        : left_(left), right_(right) {}
    ~BinaryNode();//记得要释放left_和right_节点
protected:
    Node* const left_;//const的作用:指针不能改变(即指针不能指向其它的节点),而不是指针所指向的内容不能改变
    Node* const right_;
};

//于BinaryNode相比,它只有1个孩子
//UnaryNod也是抽象类,因为它没有实现Calc方法
class UnaryNode : public Node
{
public:
    UnaryNode(Node* child)
        : child_(child) {}
    ~UnaryNode();
protected:
    Node* child_;
}

//加法运算节点AddNode
class AddNode : public BinaryNode
{
public:
//构造函数初始化,要调用基类部分的构造函数
    AddNode(Node* left, Node* right)
        : BinaryNode(left, right) {}
    //要实现Calc方法,AddNode类是具体类
    double Calc() const;
};

class SubNode : public BinaryNode
{
public:
    SubNode(Node* left, Node* right)
        : BinaryNode(left, right) {}
    double Calc() const;
};

class MultiplyNode : public BinaryNode
{
public:
    MultiplyNode(Node* left, Node* right)
        : BinaryNode(left, right) {}
    double Calc() const;
};

class DivideNode : public BinaryNode
{
public:
    DivideNode(Node* left, Node* right)
        : BinaryNode(left, right) {}
    double Calc() const;
};

class UminusNode : public UnaryNode
{
public:
    UminusNode(Node* child)
        : UnaryNode(child) {}
    double Calc() const;
};



#endif/* _NODE_H */

P39\Node.cpp

#include "Node.h"
#include <cmath.h>
#include <iostream>

//数字节点的计算方法就等于数字节点本身
double NumberNode::Calc() const
{
    return number_;
}
BinaryNode::~BinaryNode()
{
    delete left_;
    delete right_;
}

UnaryNode::~UnaryNode();
{
    delete child_;
}

double AddNode::Calc() const
{
    //AddNode节点的值等于左计算节点得到的值+右计算节点得到的值
    return left_->Calc() + right_->Calc();
}

double SubNode::Calc() const
{
    return left_->Calc() - right_->Calc();
}

double MultiplyNode::Calc() const
{
    return left_->Calc() * right_->Calc();
}


double AddNode::Calc() const
{
    double divisor = right_->Calc();
    if (divisor != 0.0)
        return left_->Calc() / divisor;
    else
    {
        std::cout << "Error: Divisor by zero" <<std::endl;
        return HUGE_VAL;
    }
}


double UnaryNode::Calc() const 
{
    //孩子节点前面加一个负号,对照改进类继承体系的图看更好理解
    return - child_->Calc();
}

P39\main.cpp

#include <iostream>

int main(void)
{

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值