zoukankan      html  css  js  c++  java
  • 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中的计算功能,我只需要传递那个表达式,就可以输出一个正确答案。
  • 相关阅读:
    设计模式之观察者模式
    设计模式之备忘录模式
    设计模式之中介者模式
    设计模式之迭代器模式
    设计模式之解释器模式
    设计模式之命令模式
    设计模式之职责链模式
    设计模式之代理模式
    设计模式之享元模式
    设计模式之外观模式
  • 原文地址:https://www.cnblogs.com/vancasola/p/6921028.html
Copyright © 2011-2022 走看看