首页 > 技术文章 > 《面向对象程序设计》c++第四次作业___calculator plus

vayhang-E-airshiner 2016-04-14 23:30 原文

c++第四次作业 Calculator Plus


git上的作业展示 Calculator 2.0 SourceCode in Git

PS:这次作业orz感谢某同学用windows的dev c++帮我把代码编译成可执行文件,同时感谢某学长帮我克服了sourcetree上的疑难问题。(连在命令行上的截图都是帮我编译的小伙伴帮忙的)

我的计算器的一些特点(以下特点将在下文有操作范例):

  • 1、数字不合法(整数位大于10位)报错(ERROR:Number Not Conform To The Requirement.

  • 2、除以零报错(ERROR:Divided By Zero.

  • 3、9(2+3)形式的表达在括号前自动填充乘号

  • 4、2*-3形式的表达负数可不加括号(与普通科学计算器相同)

  • 5、左右括号数不一样多,自动在相应端补齐括号(如:-(3-(-(2+3)+4 等同于-(3-(-(2+3)+4)) )

  • 6、引入次方计算(如:2^3 等于 2的3次方)

我的计算器的一些不足:

  • 1、没有使用大多数同学的前缀表达式、后缀表达式

  • 2、没能实现四则运算与乘方以外的运算


这里有些特别想说的是,我的代码最希望与别人分享的内容并不是那些实现了计算器功能的部分,而是那些注释掉的过程输出,那些语句一方面体现了程序编码过程中艰辛的调试过程,而且一个编码人对自己的代码进行检测、修改过程中的输出更能体现编程的思想、对自己代码的掌控,所以保留了那部分点代码,仅仅注释掉。也希望更多同行可以和我分享更好的调试方法。


代码:

Scan.hpp

#ifndef Scan_hpp
#define Scan_hpp

#include <iostream>
#include <queue>
#include <string>
#include <cmath>

using namespace std;

class Scan {

private:
    string input;
    string charString;

public:
    bool tooBig;
    queue<string> ToStringQueue(string input,int mol);

};

#endif

Scan.cpp

这个文件生成两个队列,分别用于输出表达式和送入 Calculation 类中计算,分别对应参数1和2

#include "Scan.hpp"

#include <iostream>
#include <queue>
#include <string>
#include <cmath>

using namespace std;

queue<string> Scan::ToStringQueue(string input,int mol) {

    tooBig=false;
    input[input.length()]='+';
    int count=0,flag=0,bracket=0;
    string item = "";
    std::queue<string> outCharQueue,calculationCharQueue;

    for (int i=0; i<input.length(); i++) {
    
        if (input[i]=='(') {
            bracket++;
        }else if (input[i]==')') {
            bracket--;
        }
    
    }
    
    if (bracket<0) {
        for (int i=0; i>bracket; i--) {
            calculationCharQueue.push("(");
        }
    }

    for (int i=0; i<input.length(); i++) {
    
        if ((i==0 && input[i]=='-')||(input[i-1]=='(' && input[i]=='-')) {
        
            outCharQueue.push("-");
            calculationCharQueue.push("0");
            calculationCharQueue.push("-");
            calculationCharQueue.push("1");
            calculationCharQueue.push("*");
        
        }
    
        else if ((input[i]=='-')&&(input[i-1]=='+' ||input[i-1]=='-' ||  
        input[i-1]=='*' ||input[i-1]=='/' ||  input[i-1]=='^')) {
        
            outCharQueue.push("-");
            calculationCharQueue.push("(");
            calculationCharQueue.push("0");
            calculationCharQueue.push("-");
            calculationCharQueue.push("1");
            calculationCharQueue.push("*");
            flag=1;
        
        }
    
        else if (input[i]=='+' || input[i]=='-'|| input[i]=='*' ||
         input[i]=='/' || input[i]=='^'||input[i]=='(' || input[i]==')' ) {
        
            if(!item.empty()){
                outCharQueue.push(item);
                calculationCharQueue.push(item);
            }
            item.clear();
            count = 0;
        
            if (flag==1) {
                calculationCharQueue.push(")");
                flag=0;
            }
        
            if (input[i]=='(' && input[i-1]>='0' && input[i-1]>='9') {
                calculationCharQueue.push("*");
            }
        
            item = input[i];
            outCharQueue.push(item);
            calculationCharQueue.push(item);
            item.clear();
        }
    
        else if ((input[i] >= 48 && input[i] <=57) || input[i] == '.' ) {
        
            item += input[i];
            if (input[i] != '.') {
                count++;
            }
            if (count >= 10) {
                tooBig = true;
            }
        
        }
    }

    if (!item.empty()) {
        outCharQueue.push(item);
        calculationCharQueue.push(item);
    
        if (flag==1) {
            calculationCharQueue.push(")");
            flag=0;
        }
    
    }

    if (bracket>0) {
        for (int i=0; i<bracket; i++) {
            calculationCharQueue.push(")");
        }
    }

    calculationCharQueue.push("|");

    if (mol==2) return calculationCharQueue;
    return outCharQueue;
}

Calculation.hpp

#ifndef Calculation_hpp
#define Calculation_hpp

#include <iostream>
#include <sstream>
#include <queue>
#include <stack>
#include <cmath>

using namespace std;

class Calculation {

private:
	queue<string> q;
	stack<double> num;
	stack<string> op;

public:
	int idbz;
	int oplevel(string op);
	int check(string cur);
	double toDouble(string num);
	double calculating(queue<string> q);
	double solve(double num1,double num2,string op);

};

#endif

Calculation.cpp

这个文件中有很多保留的过程输出语句

solve()函数里的第一行语句可以查看进入函数的两个运算数与一个运算符、倒数第三行语句可以查看计算过后的结果,作用在于查看每次的计算是不是你所想预想的。

calculating()函数里的类似 cout << q.front() << " &push A num" << endl 这样的语句输出每次进入运算数栈、操作符栈的变量是不是你所预想的。


  • 1、solve()函数debug语句的使用


  • 2、calculating()函数debug语句的使用


#include "Calculation.hpp"

#include <iostream>
#include <sstream>
#include <queue>
#include <stack>
#include <cmath>

int Calculation::oplevel(string op) {

	idbz=0;
	int level;
	if (op[0]=='+' || op[0]=='-') {
    	level=2;
	}else if (op[0]=='*' || op[0]=='/') {
    	level=3;
	}else if (op[0]=='^') {
    	level=4;
	}else if (op[0]==')' || op[0]=='(') {
    	level=1;
	}else if (op[0]=='|') {
    	level=0;
	}

	return level;
}

double Calculation::toDouble(string num) {

	stringstream s;
	double number=0;
	s << num;
	s >> number;
	return number;

}

double Calculation::solve(double num1, double num2, string op) {

//  cout << num1 << " " << num2 << " " << op << " ";

	if (op[0]=='+') {
    	num1=num1+num2;
	}
	if (op[0]=='-') {
    	num1=num1-num2;
	}
	if (op[0]=='*') {
    	num1=num1*num2;
	}
	if (op[0]=='/') {
    	if (num2!=0) {
        	num1=num1/num2;
    	}
    	else {
        	idbz=1;
        	return 0;
    	}
	}
	if (op[0]=='^') {
    	num1=pow(num1, num2);
	}

//  cout << num1 << endl;
	return num1;
}

double Calculation::calculating(queue<string> q) {

	double result=0,num1,num2;
	string cur,curop;

	while (!q.empty()) {
    
    	cur=q.front();
    
    	if (cur[0]=='(') {
        	op.push(cur);
        	q.pop();
        	if (q.front()[0]!='(') {//123
            	num.push(toDouble(q.front()));//123
//              cout << q.front() << "   &push A num" << endl;
            	q.pop();
        	}//123
    	}
    
    	else {
        
        	if (num.empty()) {
            	num.push(toDouble(cur));
//              cout << cur << "   &push B num" << endl;
            	q.pop();
            	cur=q.front();
        	}
        
        	while (!op.empty()) {
        	
            	if (oplevel(cur)>oplevel(op.top()) || op.top()[0]=='(') break;
            	num2=num.top();num.pop();
            	num1=num.top();num.pop();
            	curop=op.top();op.pop();
//              cout << num1 << " " << num2 << " " << curop << endl;
            	num1=solve(num1, num2, curop);
            	if (num1==0 && idbz==1) {
                	return 0;
            	}
            	num.push(num1);
//              cout << num1 << "   &push D num" << endl;
        	}
        
        	if (cur[0]==')' && op.top()[0]=='(') {
            	op.pop();
            	q.pop();
        	}else if (cur[0]=='|') {
            	break;
        	}else {
            	op.push(cur);
//              cout << cur << "   &push E op" << endl;
            	q.pop();
            	if (q.front()[0]!='(') {
                	num.push(toDouble(q.front()));
//              	cout << q.front() << "   &push C num" << endl;
                	q.pop();
            	}
       	 	}
        
    	}
	}

	result=num.top();num.pop();
	return result;
}

Print.hpp

#ifndef Print_hpp
#define Print_hpp

#include <iostream>
#include <queue>
#include <string>
#include <cmath>

using namespace std;

class Print {

public:
	void printString(queue<string> charQueue,int mol);

};

#endif

Print.cpp

#include "Print.hpp"

#include <iostream>
#include <queue>
#include <string>
#include <cmath>

void Print::printString(queue<string> charQueue,int mol) {

	if (mol==1) {
    	while (!charQueue.empty()) {
        	cout << charQueue.front() << endl;
        	charQueue.pop();
    	}
    	cout << endl;
	}
	else if (mol==2){
    	while (!charQueue.empty()) {
        	cout << charQueue.front();
        	charQueue.pop();
    	}
    	cout << " = " ;
	}

}

main.cpp

#include <iostream>
#include <queue>
#include <string>
#include <cmath>

#include "Print.hpp"
#include "Calculation.hpp"
#include "Scan.hpp"

using namespace std;
int main(int argc,char *argv[]) {

	string input;
	Scan m_scan;
	Print m_pr;
	Calculation m_cal;
//  getline(cin,input);

	if (argc>1) {

    	if (argc==2) {
        
        	input=*(argv+1);
        	m_scan.ToStringQueue(input, 2);
        	if (m_scan.tooBig==true) {
            	cout << "ERROR:Number Not Conform To The Requirement." << endl;
        	}
        	
        else {
            m_cal.calculating(m_scan.ToStringQueue(input,2));
            if (m_cal.idbz==1) {
                cout << "ERROR:Divided By Zero." << endl;
            }else if (m_cal.idbz==0){
                cout << m_cal.calculating(m_scan.ToStringQueue(input,2)) << endl;
            }
        }

    }else if (argc==3) {
        
        input=*(argv+1);
        if (input=="-a") {
            input=*(argv+2);
            m_pr.printString(m_scan.ToStringQueue(input,1),2);
        }
        
        input=*(argv+2);
        m_scan.ToStringQueue(input, 2);
        if (m_scan.tooBig==true) {
            cout << "ERROR:Number Not Conform To The Requirement." << endl;
        }
        else {
        
            m_pr.printString(m_scan.ToStringQueue(input,1),2);
            m_cal.calculating(m_scan.ToStringQueue(input,2));
            	if (m_cal.idbz==1) {
                	cout << "ERROR:Divided By Zero." << endl;
            	}else if (m_cal.idbz==0){
                	cout << m_cal.calculating(m_scan.ToStringQueue(input,2)) << endl;
            	}
        	}
        
   		}
	}

	return 0;
}

  • 1、数字不合法(整数位大于10位)报错


  • 2、除以零报错


  • 3、9(2+3)形式的表达在括号前自动填充乘号


  • 4、2*-3形式的表达负数可不加括号(与普通科学计算器相同)


  • 5、左右括号数不一样多,自动在相应端补齐括号

对比


  • 6、纯计算结果


  • 7、-a计算结果

推荐阅读