• 2017《面向对象程序设计》课程作业六


    题目描述

    • 本次作业要求将四则运算的核心部分采取栈的知识进行解决。即表达式生成的合法性检验、表达式结果计算。
    • 学习C++界面编程,可以学QT、MFC或者VS,选择其一即可,用博客记录学习到的知识以及心得体会。

    作业要求

    • 本次作业要求实现核心算法,请将表达式生成的代码及相关的检验、计算表达式结果的代码贴在博客中,并对代码进行必要的解释。
    • 发表一篇博客,博客内容为:提供本次作业的github链接,本次程序运行的截图,对界面编程的探索。
    • 作业链接

    完整代码链接

    代码节选

    表达式部分

    思路

    • 这次表达式的存储、检验和输出都是使用栈来完成的。
    • 为了后面表达式格式的检验,即确保表达式是如(a+b)/(c-d)的形式,不会出现“)a+b)”或是其他错乱的情况,所有的数字和运算符都以字符的形式存储,这样便于每个部分的检验。
    • 参考16进制,把占用两个字符的10处理成只占用一个字符的'A'。这样表达式所有的元素都是以字符的形式存储,而且表达式长度为11个字符。
    • 过程:将随机生成的运算符、数字进行检验后(包括除数不为0,不出现小数结果),都push入栈,复制一份进行格式检验,再将表达式pop出来。
    if (j == 0)
    	{
    		sta.push("=");
    		sta.push(")");
    		if (d == 10)sta.push("A");//对10的处理,push数字进栈
    		else
    		{
    			sprintf(temp, "%d", d);
    			sta.push(temp);
    		}
    		sprintf(temp, "%c", sign2);//push运算符进栈
    		sta.push(temp);
    		}
    
    
    
    	stack tempsta;//复制一份表达式
    	tempsta.initstack();
    	tempsta = sta;
    	
    
    
    	while (tempsta.isempty())
    	{
    		char t,L=0;
    		
    		if (tempsta.isempty()) { j = true; break; }//检验括号
    		else
    		{
    			t = tempsta.pop();
    			if (t == '(') L++;
    			else { j = true; break; }
    			}
    		
    		if (tempsta.isempty()) { j = true; break; }//检验数字
    		else 
    		{ 
    			t = tempsta.pop();
    		    if ((t >= '0'&&t <= '9') || t == 'A')L++; 
    		    else { j = true; break; }
    		}
    		
    		if (tempsta.isempty()) { j = true; break; }//检验运算符
    		else
    		{	t = tempsta.pop();
    			if (t=='+'||t=='-'||t=='*'||t=='/')L++;
    			else { j = true; break; }
    		}
    		
    		
    
    		if (L != 11 )j = true;//检验表达式长度
    
    //主函数中输出表达式
    while (ex.sta.isempty() == false)
    		{
    			t = ex.sta.pop();
    			if (t == 'A')
    				cout << "10";
    			else
    			cout << t;
    		}
    

    计算部分

    • 这次修改,加强了类的封装。在主函数中接受一个表达式对象,输出一个表达式的值,简化了使用。
    • 接受栈以后,把栈的运算符和数字传提取出来,计算后return 最后的结果。
    int Calculator::total_result(stack & ex)
    {
    	int x1, x2, x3, x4, count_ab = 0, count_cd = 0;//以下是提取表达式的数字和运算符。
    	char temp,sign1,sign2,sign3;
    	temp = ex.pop();
    
    	temp = ex.pop();
    	if (temp == 'A')x1 = 10;
    	else x1 = temp - '0';
    	
    	sign1 = ex.pop();
    	
    	temp = ex.pop();
    	if (temp == 'A')x2 = 10;
    	else x2 = temp - '0';
    	
    	temp = ex.pop();
    
    	sign2 = ex.pop();
    	
    	temp = ex.pop();
    
    	temp = ex.pop();
    	if (temp == 'A')x3 = 10;
    	else x3 = temp - '0';
    
    	sign3 = ex.pop();
    	
    	temp = ex.pop();
    	if (temp == 'A')x4 = 10;
    	else x4 = temp - '0';
    //以下是答案的计算
    	this->getnum(x1, x2);
    	count_ab = this->calculateResult(sign1);
    	this->getnum(x3, x4);
    	count_cd = this->calculateResult(sign3);
    	this->getnum(count_ab, count_cd);
    	return this->calculateResult(sign2);
    }
    
    
    //计算部分
    void Calculator::getnum(int a1, int a2)
    {
    	a = a1;
    	b = a2;
    }
    int Calculator::calculateResult(char sign)
    {
    	switch (sign)//注意除数不能为0,整数输出 
    	{
    	case '+':result = a + b; break;
    	case '-':result = a - b; break;
    	case '*':result = a*b; break;
    	case '/':result = a / b; break;
    	}
    	return result;
    }
    

    运行示例

    对界面编程的探索

    void CMFCcountDlg::OnBnClickedButton1()
    {
    	UpdateData();
    	Expression Ex;
    	mex = " ";
    	while (1)
    	{
    		Ex.getsign();
    		Ex.randomNumber();
    		if (Ex.generateExpression())continue;
    		for (int i = 0; i < 11; i++)
    		{
    			if (Ex.ch[i] == 'A')
    			{
    				mex += "10";
    			}
    			else
    			{
    				mex += Ex.ch[i];
    			}
    		}
    		for (int i = 0; i < 10; i++)
    		{
    			EX[i] = Ex.ch[i];
    		}
    		break;
    	}
    	UpdateData(FALSE);
    	
    }
    
    
    void CMFCcountDlg::OnBnClickedButton2()
    {
    	UpdateData();
    	Calculator cal;
    	Counter cou;
    	int rightanswer;
    	mrightanswer=rightanswer = cal.total_result(EX);
    	cou.getanswer(manswer, rightanswer);
    	mresult = " ";
    	if (cou.judge())
    	{
    		mresult += "You're right!
    ";
    		cou.count_right_answer();
    		mnumber++;
    	}
    	else {
    		mresult += "It's wrong.";
    	}
    	UpdateData(FALSE);
    }
    

    遇到问题

    • 创建mfc应用程序的时候,出现 “无法找到资源编译器dll,请确保路径正确”的提示框。
    • 解决办法:在所有文件中搜索出rcdll.dll,然后将这个文件放入c:program.files.(x86)Microsoft.Visual.Studio.10.0vcin中(或者是提示框中的路径)。
    • 在.cpp文件中各个头文件的最后添加了#include "stdafx.h"后,会出现已经声明并且定义了类、变量、函数,但是在编译的时候显示无法找到。
    • 解决办法:将#include "stdafx.h"作为第一个头文件。
    • 上网查了以后才知道:编译器通过一个头文件stdafx.h来使用预编译头文件。stdafx.h这个头文件名是可以在project的编译设置里指定的。编译器认为,所有在指令#include "stdafx.h"前的代码都是预编译的,它跳过#include "stdafx.h"指令,使用projectname.pch编译这条指令之后的所有代码。因此,所有的MFC实现文件第一条语句都是:#include "stdafx.h"。在它前面的所有代码将被忽略,所以其他的头文件应该在这一行后面被包含。否则,你将会得到“No such file or directory”这样让你百思不得其解的错误提示。

    体会

    • 这次作业的完成是一个不断遇到问题、解决问题的过程,遇到的问题远比上述的多,但是最后做出来这个四则运算器,还是很开心的。
    • 将DOS窗口改成MFC,代码的改动不亚于重写一份代码,需要考虑变量新的特性,比如从窗口接受的变量各个函数都可以使用,使用UpdateData()时所有窗口的变量都会更新。我删除了两个大的部分,一个是交互窗口,一个是主函数,而且计数的过程也更加简洁。但是设置了静态变量略微破坏了类的封装性,是一个让我纠结的问题。
    • 由于没有系统地学过MFC,所以完成的过程类似于半学习半尝试,一步一步地将这个四则运算器做出来。虽然界面和功能都很简单,但是将原来DOS窗口的代码移植到MFC中并不是一件简单的事。由于没有主函数,每一个button相当于一个自定义函数,点击后就运行这个自定义函数。这样做,面向对象的感觉就更明显,每个button都是独立的,button与button之间需要消息来联系。
    • 就比如这个四则运算软件,点击“出题”,就显示出一个算式,点击“运算”就要将这个算式算出来。“出题”和“运算”这两个button就需要联系。因为对MFC中的数据类型不是特别的了解,所以我建立了一个静态变量作为“消息”用于传递生成的表达式。而这次作业要求修改的代码也正好方便了我在MFC中的计算功能,我只需要传递那个表达式,就可以输出一个正确答案。
  • 相关阅读:
    OLAP ODS项目的总结 平台选型,架构确定
    ORACLE ORA12520
    ORACLE管道函数
    ORACLE RAC JDBC 配置
    ORACLE RAC OCFS连接产生的错误
    ORACLE 启动和关闭详解
    OLAP ODS项目的总结 起步阶段
    ORACLE RAC 配置更改IP
    ORACLE RAC OCR cann't Access
    ORACLE RAC Debug 之路 CRS0184错误与CRS初始化
  • 原文地址:https://www.cnblogs.com/vancasola/p/6921028.html
Copyright © 2020-2023  润新知