The 3rd part of the Calculator program _ FILE I/O

题目链接:第五次作业(计算器第三步)
github链接:Calculator_1.5.0 第五次作业

第三部分,开篇最想说的是,不知不觉进化到version1.5.0了(hhh~)

言归正传,这篇随笔有需要说明的一点是,由于在修改第四次作业的中途发布了第五次作业,所以这篇也会是上一次博客随笔面向对象程序设计_Task4_Calculator1.1的延续(评论中的下回分解hhh~)

So,在下文的代码前后,会结合第四、第五次作业的感受一起瞎掰。

以上。

Part 1

第五次作业代码方面的要求较之前相比,多了一个对文件读写的支持,且表达式自带等号。第二个问题很好解决,至于第一个,在对文件的读写有大致的了解之后也不是难题。

另外,用图形的方式描述整个项目的框架,即各个类之间的调用关系。

一脸懵逼.jpg

这是要用UML(Unified Modeling Language, 统一建模语言)的意思吗(貌似之前学JAVA过程中听过这个东西,类图用例图对象图各种图orz...)?

管他是不是,反正用了准没错= =,之后懵逼的去百度类图,还是没搞怎么明白,不过也大致画出了一点框架

下面,附上心得体会和代码实现...

Part 2

那么,依次对不同类进行分析,首先是:

  • Scan类

    在Scan类中,唯一的改变是ToStringQueue函数,针对第五次作业在表达式后自带等号的情况,所取得的表达式长度应为实际长度-1

    Scan.cpp

      queue<string> Scan::ToStringQueue(string input){queue<string> q;     // q即为最后所要return的队列,用于保存input表达式中的数字和符号string res = "";     // res为扫描input表达式时用于临时存储的字符串string strArr[N];     // strArr为扫描input表达式时用于存储数字和符号的string数组int len = input.length() - 1; // 省略最后的等号'='int cnt = 0;     // 作为strArr的下标记录已完成提取的数字和符号的个数for (int i = 0; i < len; i++){if ((input[i] >= '0' && input[i] <= '9') || input[i] == '.'){res += input[i];     // 若是数字或 '.' 则添加到临时存储器res里,if (i == len - 1)     // 若已完成扫描{strArr[cnt++] = res;break;}continue;     // 继续判断下一元素}else{if (i == 0 && res.empty())     // 若第一个元素为‘-’{res += input[i];continue;}if (!res.empty())     // res非空表示此时res中缓存着一个数字 或 第一个元素为 '-'{strArr[cnt++] = res;}res = "";     // res置空strArr[cnt++] = res + input[i];     // 将不是数字或 "." 的元素(即符号元素)添加到strArr中}}for (int i =0; i < cnt; i++)     // 将strArr中各个元素添加到q队列中{if (strArr[i].length() > 10){setIsExceed10(true);     // 存在大于10位数的数字}q.push(strArr[i]);}return q;}

接下来则是:

  • Calculation类

    这个类是有颇多的改动,其一是改变了栈中提取出来的操作数的类型,由int转为double,防止小数部分的截断以至于WA;

    其二则是对类成员的封装保护,将几个成员变量定义为private,并为其中一些变量提供了getter和setter方法;

    其三是在重复利用stringstream对象时,除了.clear(),还进行了.str("")操作;

    其四是将多个if-else语句简化为switch-case语句,优化、美观;

    最后,则是digitStack的改动,由stack换成了stack,处理上,简单的还真不是一星半点...orz...减少了stringstream流的使用频率,也缩减了代码量。

    calculation.h

      const int SIZE = 250;     // 表达式的最大长度(即q.size() <= SIZE)class Calculation{public:Calculation(void);~Calculation(void);void setPriorityLevel();stack<double>& getDigitStack();bool isOperator(string s);bool isDigit(string s);void toPostfixExpression(queue<string> q);void calculatingExpression(queue<string> q, bool is_Exceed10);private:int priority[128];     // 存储运算符的优先级stack<string> cacheStack;     // 缓存栈stack<string> operatorStack;     // 操作符栈,包括"+", "-", "*", "/", "(", ")"stack<double> digitStack;     // 数字栈,包括处理与运算过程};

    Calculation.cpp

      void Calculation::calculatingExpression(queue<string> q, bool is_Exceed10){if (is_Exceed10)     // 若超过10位数的数字存在为真{cout << "Input error !  Not exceeding 10 digits expected! " << endl;return;}toPostfixExpression(q);     // 将中缀表达式转换为后缀表达式/**********计算部分***********/string postfixExp[SIZE];     // 由于计算时需对缓存栈从栈底到栈顶的逐一扫描,故用string数组进行遍历操作int expLen = 0;while (!cacheStack.empty()){postfixExp[expLen++] = cacheStack.top();cacheStack.pop();}stringstream str_stream;     // 用stringstream流进行string和double的格式转换double res = 0;     // res用于临时存储,push进数字栈double rightNum = 0;     // 右操作数double leftNum = 0;     // 左操作数for (int i = expLen - 1; i >= 0; i--){if (isDigit(postfixExp[i]))     // 若该元素为数字,则直接入数字栈digitStack{str_stream << postfixExp[i];     // 格式转换:string->doublestr_stream >> res;digitStack.push(res);str_stream.clear();     // stringstream流的清空,以便重复利用str_stream.str("");}else if (isOperator(postfixExp[i]))     // 若该元素为运算符,则弹出数字栈的两个数进行相应的运算并将结果push进数字栈{if (!digitStack.empty()){rightNum = digitStack.top();digitStack.pop();}if (!digitStack.empty()){leftNum = digitStack.top();digitStack.pop();}switch (postfixExp[i][0])     // 对应加法、减法、乘法、除法运算{case '+':digitStack.push(leftNum + rightNum);break;case '-':digitStack.push(leftNum - rightNum);break;case '*':digitStack.push(leftNum * rightNum);break;case '/':digitStack.push(leftNum / rightNum);break;default:break;}}}}

最后的就是第五次作业的主体:

  • Print类

    ######作业要求:所有关于输出的代码,都写在Print类里面

    相较之前,这次几乎将所有的输出都放在了Print类,而且这次作业的一个很大的改进是,终于想到在类的构造函数和析构函数里面写点东西了→_→

    而且,在一段纠结是否要重载PrintResult函数的时间之后,还是选用了不同的输出函数处理,更便于理解(理解万岁~)

    这里还有要说到的就是文件的读写,我用的是fstream文件流来操作,(文件流参考博客),用file_read和file_write关联两个文件,循环从输入文件开头读到文件尾,一次读取一个表达式并将表达式的值输出到输出文件内。

    print.h

      class Print{public:Print(void);~Print(void);void printError();void printResult(string input);void printResult_a(string input);void printResult_f(string inputAddr, string outputAddr);void printQueue(queue<string> q, bool isExceed10);private:Scan *sc;Calculation *ca;};

    print.cpp

      #include "Print.h"#include <iostream>#include <fstream>Print::Print(void)     // 在构造函数中初始化 *sc 和 *ca{sc = new Scan();ca = new Calculation();}Print::~Print(void)     // 在析构函数中释放{delete sc;sc = NULL;delete ca;ca = NULL;}void Print::printError(){cout << "Input error!" << endl;}/*************************************************Description: 针对命令行参数为 表达式 的输出Input: string input: 待计算的表达式Output: 表达式的值*************************************************/void Print::printResult(string input){ca->calculatingExpression(sc->ToStringQueue(input), sc->getIsExceed10());cout << ca->getDigitStack().top() << endl;ca->getDigitStack().pop();}/*************************************************Description: 针对命令行参数为 "-a"和表达式 的输出Input: string input: 待计算的表达式Output: 表达式及表达式的值*************************************************/void Print::printResult_a(string input){cout << input << " ";ca->calculatingExpression(sc->ToStringQueue(input), sc->getIsExceed10());cout << ca->getDigitStack().top() << endl;ca->getDigitStack().pop();}/*************************************************Description: 针对命令行参数为 "-f"和输入、输出文件地址 的输出Input: string inputAddr: 即读取的文件地址string outputAddr: 即写入的文件地址*************************************************/void Print::printResult_f(string inputAddr, string outputAddr){string input;fstream file_read(inputAddr);fstream file_write(outputAddr, ios::out);while (!file_read.eof()){file_read >> input;ca->calculatingExpression(sc->ToStringQueue(input), sc->getIsExceed10());file_write << input  << " " << ca->getDigitStack().top() << "\n";ca->getDigitStack().pop();}file_read.close();file_write.close();}

Part 3

下面则是main函数的实战部分,由于将输出部分移到了Print类,故main函数只需对传进的命令行参数进行判断即可(依旧用了strcmp...),针对不同输入格式调用Print类的不同方法。

main.cpp

#include "Print.h"
#include <iostream>
#include <cstring>using namespace std;/*************************************************Description: 接收表达式的输入并求值Input: int argc: 命令行参数个数char *argv[] : 实际传入的命令行参数Return: 若正常结束,则返回0
*************************************************/
int main(int argc, char *argv[])
{Print *pr = new Print();if (argc == 2)     // 对传入的参数只有表达式的处理,调用Print类对应的PrintResult方法输出{pr->printResult(argv[1]);}else if (!strcmp(argv[1], "-a") && argc == 3)     // 对传入的参数为"-a"的处理,调用Print类对应的PrintResult_a方法输出{pr->printResult_a(argv[2]);}else if (!strcmp(argv[1], "-f") && argc == 4)     // 对传入的参数为"-f"的处理,调用Print类对应的PrintResult_f方法输出{pr->printResult_f(argv[2], argv[3]);}else{pr->printError();}//   system("pause");return 0;
}

然后附上实战结果= =

Part 4

最后,则是框架图...模仿着加上几个类和清一色的几个箭头----------→→→→欧啦= =

Part 5

胡乱讲了一大堆导致篇幅有点长,感觉自己的代码还是有很多提升的空间的,比如Scan类的ToStringQueue方法可以改进,而且初始化也是一个需要注意的点,再加上对构造、析构函数的运用,函数的重载等等。

期待指点,期待vision 1.6.0的到来(hhh~)

参考资料:

  • C++中文件流(fstream)的使用方法及示例 - sead+ - 博客频道 - CSDN.NET
  • UML类图几种关系的总结 - PlayBoy's 部落格 - 博客频道 - CSDN.NET

The End

转载于:https://www.cnblogs.com/monsterJang/p/5479487.html

面向对象程序设计_Task5_Calculator1.5.0相关推荐

  1. [.net 面向对象程序设计深入](4)MVC 6 —— 谈谈MVC的版本变迁及新版本6.0发展方向...

    [.net 面向对象程序设计深入](4)MVC 6 --谈谈MVC的版本变迁及新版本6.0发展方向 1.关于MVC 在本篇中不再详细介绍MVC的基础概念,这些东西百度要比我写的全面多了,MVC从1.0 ...

  2. php面向对象程序设计,PHP面向对象程序设计类的定义与用法简单示例

    本文实例讲述了PHP面向对象程序设计类的定义与用法.分享给大家供大家参考,具体如下: class Person { private $name; private $sex; private $age; ...

  3. 常惠琢 201771010102《面向对象程序设计(java)》第七周学习总结

    实验七 继承附加实验 实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: (2)掌握Object类的常用API用法: (3)掌握ArrayList类用法 ...

  4. java面向对象电子科大版答案_电子科大17秋《面向对象程序设计》在线作业1

    电子科大17秋<面向对象程序设计>在线作业1 ----------------------------------------------------------------------- ...

  5. 20155328 《Java程序设计》 实验二(Java面向对象程序设计) 实验报告

    20155328 <Java程序设计> 实验二(Java面向对象程序设计) 实验报告 单元测试 一.单元测试和TDD 编程时需理清思路,将编程需求等想好,再开始编.此部分可用伪代码实现. ...

  6. JavaScript中的面向对象程序设计

    本文内容目录顺序: 1.Object概念讲述: 2.面向对象程序设计特点: 3.JavaScript中类和实例对象的创建: 4.原型概念: 5.原型API: 6.原型对象的具体使用:7.深入理解使用原 ...

  7. [.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)...

    [.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(二) 利用多线程提高程序性能(下) 本节导读: 上节说了线程同步中使用线程锁和线程通知的方式来处理资源共享问题,这 ...

  8. 面向对象程序设计上机练习一(函数重载)

    面向对象程序设计上机练习一(函数重载) Time Limit: 1000MS Memory Limit: 65536KB Problem Description 利用数组和函数重载求5个数最大值(分别 ...

  9. 面向对象程序设计作业 6.1~6.4

    面向对象程序设计作业 6.1-6.4 面对对象基础题三道.继承多态一道. #include <iostream> #include <string> #include < ...

  10. 201771010106东文财《面向对象程序设计(java)》实验12

    实验十二  图形程序设计 实验时间 2018-11-14 1.实验目的与要求 (1) 掌握Java GUI中框架创建及属性设置中常用类的API: (2) 掌握Java GUI中2D图形绘制常用类的AP ...

最新文章

  1. Linux多线程管理: 多线程编程
  2. iOS 13 如何删除SceneDelegate
  3. arm 饱和指令_ARM平台下NEON使用方法详解
  4. IDEA Project Structure 配置说明
  5. reactjs三个常用的Hook:State Hook、 Effect Hook、 Ref Hook
  6. 【STM32】ESP8266 AT指令
  7. WebKit Event
  8. 算法:把数组排成最小的数
  9. Scratch3 二次开发系列
  10. html搜索框代码_解放双手 | 10行Python代码实现一款网页自动化工具
  11. QThread实现多线程
  12. DBeaverEE-优秀的数据库连接工具
  13. php工程师等级划分,PCB工程师的这四个等级,你都修炼到了什么级别?
  14. python 绘图中文显示_Python绘图实现显示中文
  15. 记一次修复Mac和Win7双系统启动菜单的经历
  16. linux下搭建svn仓库
  17. 【nRF Connect】三、连接蓝牙设备
  18. SCI论文应该怎样修改?有哪些技巧?
  19. java面试(二十五)--(1)redis为什么读写速率快性能好(2)说说web.xml文件中可以配置哪些内容(3)和的区别(4)扑克牌顺子
  20. 计算机启动进入桌面非常慢,电脑开机加载桌面很慢的解决办法

热门文章

  1. 为什么我们需要研究迁移学习?
  2. VIM编辑器使用的小技巧
  3. pytorch learning
  4. PyQt4打包exe文件
  5. JavaOO 常用类
  6. iOS 给任意一个view转换为image的方法封装
  7. Java 多并发之原子访问(Atomic Access)
  8. 判断服务是否开启,应用是否安装,并安装应用
  9. sharepoint2010无法创建网站集
  10. [导入]新手入门 Fedora Linux 7系统的安装指南