zoukankan      html  css  js  c++  java
  • 第三次作业——计算器

    作业链接
    GitHub链接

    预备知识

    在自学的过程还未了解到关于queue的知识,所以预先Google了一下相关知识。

    queue

    queue模板类的定义在头文件中。queue模板类需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型。定义queue对象的示例代码如下:

    queue<int> q1;
    
    queue<double> q2
    

    queue基本操作

    • push——入队:eg. que.push(x): 将x接到队列que的末端。
     queue<string> que;
     que.push("Hello World!");
     que.push("OK");
    
    • pop——出队:eg.que.pop():弹出队列的第一个元素即最先被插入的元素,注意,并不会返回被弹出元素的值。
     que<string>que;
     que.push("Hello World!");
     que.push("OK");
     que.pop(); //此时"Hello World"被删除
    
    • size——访问队列中的元素个数。
     queue<string> que;
     cout<<que.size()<<endl;
     que.push("Hello World!");
     que.push("OK");
     cout << que.size() << endl; //输出分别为“0”和“2”
    
    • empty——判断队列是否空,如果队列为空,返回true。
     queue<string> que;
     cout << que.empty() << endl;
     que.push("Hello World!");
     que.push("OK");
     cout << que.empty() << endl; //输出分别为“1”和“0”
    
    • front——访问队首元素,即最早被压入队列的元素。
     queue<string> que;
     q.push("Hello World!");
     q.push("OK");
     cout << que.front() << endl;
     que.pop();
     cout << que.front() << endl; //输出为"Hello World"和"OK"
    
    • back——访问队尾元素,即最后被压入队列的元素。
     queue<string> que;
     que.push("Hello World!");
     que.push("OK");
     cout << que.back() << endl; //输出为"OK"
    

    思路

    按照题目要求,将输入交给Scan类,输出交给Print类

    • 头文件
    #ifndef CALCULATOR_H_
    #define CALCULATOR_H_
    #include<string>
    #include<queue>
    using namespace std;
    
    class Scan
    {
    	friend istream &read(istream &, Scan &);
    	friend class Print;
    	private:
    		string ipt;
    		queue<string>que;
    	public:
    		void ToStringQueue(string input);
    };
    
    class Print
    {
    	public:
    		void output(queue<string>q);
    }; 
    
    
    istream &read(istream &, Scan &);
    #endif
    
    • 实现文件
    #include<iostream>
    #include<string>
    #include<queue>
    #include "calculator.h"
    using namespace std;
    
    
    /*********************************** 
    
    Description:  读取并扫描表达式,将数字与符号分开压入队列 
    Others:      当输入数学表达式中有数字(含小数位)超过10位即报错并终止程序 
    
    ***********************************/ 
    void Scan::ToStringQueue(string input)
    {
    	int len = input.size();
    	
    	
    	for (int i;i<len;)
    	{
    		string tmp = "";
    		
    		while (i < len && input[i] <= '9'  && input[i] >= '0')
    		{
    			tmp += input[i++];
    		}
    		
    		if(tmp.size() > 10)
    		{
    			cerr << "ERROR!";
    			
    			while (!que.empty())
    			{
    				que.pop();
    			}
    			
    			break;
    		}
    		
    		if (!tmp.empty())
    		{
    			que.push(tmp); 
    		}
    		
    		while (i < len && 
    		             (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/'
    					                                     || input[i] == '(' ||input[i] == ')'))
    		{
    			tmp = input[i++];
    			que.push(tmp);
    		}
    	}
    }
    
    
    /*********************************** 
    Description :  输出队列中的数据
    
    ***********************************/ 
    void Print::output(queue<string>q)
    {
    	while (!q.empty())
    	{
    		cout << q.front() << endl;
    		q.pop();
    	}
    }
    
    /***********************************
    Description:从给定流中 将数据读到给定的对象中 
    Others:      本意是将此函数包含至Scan类中,让读入的功能都让专门的类实现,
                 但是在实际操作过程中,确颇感困难,所以就独自定义了一个类相关的非成员函数
    
    ***********************************/ 
    istream &read(istream &is, Scan &expr)
    {
    	is >> expr.ipt;
    	return is;
    }
    
    • 客户文件
    #include<iostream>
    #include<string>
    #include"calculator.h"
    
    int main()
    {
    	Scan in;
    	Print opt;
    	read(cin,in);
    	in.ToStringQueue(in.ipt);
    	opt.output(in.que);
    	return 0;
    } 
    

    运行结果

    程序分析

    error中的信息提示我可能是通过非成员函数访问操作了私有部分的数据,但是回看代码的过程颇为迷茫,因为我将Print类与read函数都设为Scan的友元,所以在试了多次改正的办法都没有解决,半天下来也有些心浮气躁,可能因为书此时看得还是颇少,掌握东西的量还不足,对于一些错误无法查找出来。在Google中也并未找到解决的方法。在自学有时还是颇感迷茫的,因为时常出了问题在搜索的基础上不足以解决,又无旁人的指点。这个问题也暂且放下,同时也在此作为一个保存,等再一步深入学习C++再回头来解决。

    第二次尝试:

    • 头文件:
    #ifndef CALCULATOR_H_
    #define CALCULATOR_H_
    #include<string>
    #include<queue>
    using namespace std;
    
    class Scan
    {
    	private:
    		//string in;
    	friend istream &read(istream &, Scan &);
    	public:
    		string in;
    		queue<string>ToStringQueue(string  input);
    };
    
    
    class Print
    {
    	public:
    		void output(queue<string>q);
    }; 
    
    
    istream &read(istream &, Scan &);
    
    
    #endif
    
    • 实现文件:
    #include<iostream>
    #include<string>
    #include<queue>
    #include "calculator.h"
    using namespace std;
    
    /*********************************** 
    
    Description:  读取并扫描表达式,将数字与符号分开压入队列 
    Others:      当输入数学表达式中有数字(含小数位)超过10位即报错并终止程序 
    
    ***********************************/ 
    queue<string>Scan::ToStringQueue(string  input)
    {
    	int len = input.size();
    	queue<string>que;
    	
    	
    	for (int i=0;i<len;)
    	{
    		string tmp = "";
    		
    		while (i < len && input[i] <= '9'  && input[i] >= '0')
    		{
    			tmp += input[i++];
    		}
    		
    		if(tmp.size() > 10)
    		{
    			cerr << "ERROR!";
    			
    			while (!que.empty())
    			{
    				que.pop();
    			}
    			
    			break;
    		}
    		
    		if (!tmp.empty())
    		{
    			que.push(tmp); 
    		}
    		
    		while (i < len && 
    		             (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/'
    					                                     || input[i] == '(' ||input[i] == ')'))
    		{
    			tmp = input[i++];
    			que.push(tmp);
    		}
    	}
    	return que;
    }
    
    
    void Print::output(queue<string>q)
    {
    	while (!q.empty())
    	{
    		cout << q.front() << endl;
    		q.pop();
    	}
    }
    
    
    /***********************************
    Description:从给定流中 将数据读到给定的对象中 
    Others:      本意是将此函数包含至Scan类中,让读入的功能都让专门的类实现,
                 但是在实际操作过程中,确颇感困难,所以就独自定义了一个类相关的非成员函数
    
    ***********************************/ 
    istream &read(istream &is, Scan &expr)
    {
    	is >> expr.in;
    	return is;
    }
    
    • 客户文件
    #include<iostream>
    #include<string>
    #include<queue>
    #include"calculator.h"
    
    int main()
    {
    	Scan ipt;
    	Print opt;
    	queue<string>que;
    	read(cin,ipt);
    	que = ipt.ToStringQueue(ipt.in);
    	opt.output(que);
    	return 0;
    } 
    

    运行结果

    程序分析

    经过第一次的失败(包含多次试验失败)又暂时没有有效的解决方法后,放弃了原有的思路。在ToStringQueue函数编写中不再使用void类型,因为没有返回值的同时一定要对private里面的队列数据进行访问,而此时编写的函数一直访问失败,所以直接让ToStringQueue函数返回一个队列,这样在使用Print类过程中就无需访问Scan类中的私有数据了。

    反思

    OPP编程思想的实现需要去努力理解并且融会贯通,虽然在之前学习有接触到这个思想,在之前博客关于链表实现的实例也有提到,但仍需加强理解。数据隐藏作为OPP编程思想的一大特点,虽然第一次尝试代码中有想着将数据隐藏起来,但是在实现中不尽人意,也没有解决的方案。

    总结

    这个作业前后花了不少时间,一开始的计划是学习关于类等语法知识,然后完成作业。但是在学习的过程中,一开始并没有动手自己实践一些代码,看书学习的这个过程总是萌生困意,对于类的知识也是迷迷糊糊,一知半解,浪费了不少时间。最后改变了计划,一边动手实践代码一边看书,但是这样也有着很大的弊端,因为在程序出问题的时候,没有对于类的总体把关,很难看出其中错误,搜索的过程也显得较为费力。总之,“试了很多错”,在这些错误中也了解到一些知识。希望在以后的学习过程中,在多多少少的“试错”过程中,能尽快找到合适自己的学习方法。现在回看这整个程序,好像都是简简单单的代码,实现也颇显简单,但是完成这份程序又确确实实用了不少时间。所以,这同时给了自己一个很大的警钟——路阻且长,仍需更加努力。

  • 相关阅读:
    PyQt5使用http请求获取天气
    Qt获取某地的天气情况
    各种编码方式
    Qt获取天气信息并解析
    QFile读文件
    QUrl
    Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())的注意点
    adb命令开关蓝牙及NFC
    fragment重叠问题解决方法
    Android跨进程启动另外一个应用界面时存在的问题解决办法
  • 原文地址:https://www.cnblogs.com/ZhaoxiCheung/p/5206811.html
Copyright © 2011-2022 走看看