天天看點

《面向對象程式設計》——寒假作業3

《面向對象程式設計》——寒假作業3

1.合作者

林燊 031602325 https://www.cnblogs.com/linshen/

盧澤明 031602328 http://www.cnblogs.com/luzeming/

github連接配接:https://github.com/Travaill/arithmetic.git

2.設計思路

《面向對象程式設計》——寒假作業3

3.程式功能

  • 能對0--10之間的整數進行四則運算(加減乘除)
  • 能實作選擇中文和英文兩種語言
  • 程式能接收使用者輸入的整數答案,并判斷對錯
  • 程式結束時,統計出答對、答錯的題目數量

4.算法分析

  • 類generate 實作随機算式的生成
  • 類calculate 計算算式的結果
  • 類control 控制題目生成的數量 控制生成符合要求的算式 控制程式的退出 控制程式的語言
  • 類printf 輸出算式、判斷結果、統計答題情況

5.代碼規範

  • 函數的命名必須使用英文單詞,不使用拼音縮寫
  • 函數的命名如果一個單詞的必須首字母大寫,如果多個單詞的用下劃線隔開
  • 程式結構清析,簡單易懂,單個函數的程式行數不得超過100行。
  • 要随意定義全局變量,盡量使用局部變量。
  • 函數的旁邊必須注釋上本函數的功能
  • 禁止GOTO語句。

6.代碼展示

代碼部分較長,是以僅截取程式最為核心的部分

随機生成表達式

#include "generate.h"
#include <iostream>
#include <stdlib.h>
#include <time.h> 
#include <string>
#include <sstream>
#include <string.h>
using namespace std;
int Generate::generate_rand(int low,int high)  //生成[low,high]随機數 
{
	return (rand()% (high - low+1) + low);
}  

string Generate::generate_operator(void)     //生成四則運算符 
{
	string ope;
    switch(generate_rand(1,4)) 
    {
    	case 1:ope='+'; break;
    	case 2:ope='-'; break;
    	case 3:ope='*'; break;
    	case 4:ope='/'; break;
	}
	return ope;
}

string Generate::generate_polynomial(void)  //生成多項式 
{
	int a,b,c;
    stringstream ss;
	a=generate_rand(0,10);    
    b=generate_rand(0,10);
    c=generate_rand(1,3);  
   if(c==1) 
  {
  	ss << '(' << a<<generate_operator()<<b<<')';
  } 
    if(c==2)
  {
    ss<<a<< generate_operator()<<b;
  }
    if(c==3)	
  {
	ss<<a;
  }
  	string str = ss.str();  
  	ss.str("");
    return str;
}

string Generate::generate_formula(void)     //生成算式 
{
	stringstream ss;
	ss<<generate_polynomial();
	for(int i=1;i<generate_rand(2,4);i++)
	{
		ss<<generate_operator()<<generate_polynomial();
	}
	string str = ss.str();  
	ss.str("");
    return str;
}
           

計算表達式結果

#include "calculate.h"
#include "generate.h"
#include <iostream>
#include <stdlib.h>
#include <string>
#include <stack>
using namespace std;
stack<double> num_stk;
stack<char> ope_stk;
void Calculate::calculate_polynomial()      //計算多項式結果 
{
	char ope=ope_stk.top();
    double a,b,res;
    b=num_stk.top();
    num_stk.pop();
    a=num_stk.top();
    num_stk.pop();
    switch(ope)
    {
        case '+':res=a+b; break;
        case '-':res=a-b; break;
        case '*':res=a*b; break;
        case '/':res=a/b; break;
        default: break;
    }
    num_stk.push(res);
    ope_stk.pop();
}

int Calculate::Rank(char x)                //計算優先級 
{
    if(x=='(')
        return 0;
    else if(x=='+')
        return 1;
    else if(x=='-')
        return 2;
    else if(x=='*')
        return 3;
    else if(x=='/')
        return 4;
}

double Calculate::calculate_formula(string str)     //計算算式 
{
	
	int x=0;
	int  num_flag=0;
	for(int i=0;i<str.size();i++)
	{
        if((str[i]>='0')&&(str[i]<='9'))
		{
            x=x*10+str[i]-'0';
            num_flag=1;
            if(i==str.size()-1)
            num_stk.push(x);
        }
        else{
            if(x)
			{
                num_stk.push(x);
                x=0;
                num_flag=0;
            }
            if(ope_stk.empty())
                ope_stk.push(str[i]);
            else if(str[i]=='(')
                ope_stk.push(str[i]);
            else if(str[i]==')')
            {
                while(ope_stk.top()!='(')
                    calculate_polynomial();                
                    ope_stk.pop();
            }
            else if((Rank(str[i]))<=Rank(ope_stk.top()))
            {
                calculate_polynomial();
                ope_stk.push(str[i]);
            }
            else
			{
                ope_stk.push(str[i]);
            }
        }
    }
    while(!ope_stk.empty())
    calculate_polynomial();
    double res=num_stk.top();
    return res;
}
           

過濾不符合要求的表達式

string Control::judge_formula(void)               //生成的算式是否合法 
{
	string str=Generate().generate_formula();
	char ptr[35];
    strcpy(ptr,str.c_str()); 
	const char *substr1="/0";
	const char *substr2="/(1-1)";
	const char *substr3="/(2-2)";
	const char *substr4="/(3-3)";
	const char *substr5="/(4-4)";
	const char *substr6="/(5-5)";
	const char *substr7="/(6-6)";
	const char *substr8="/(7-7)";
	const char *substr9="/(8-8)";
	const char *substr10="/(9-9)";
	const char *substr11="/(10-10)";
	const char *substr12="0*";
	const char *substr13="0/";
    char *s1 = strstr(ptr, substr1);
    char *s2 = strstr(ptr, substr2);
    char *s3 = strstr(ptr, substr3);
    char *s4 = strstr(ptr, substr4);
    char *s5 = strstr(ptr, substr5);
    char *s6 = strstr(ptr, substr6);
    char *s7 = strstr(ptr, substr7);
    char *s8 = strstr(ptr, substr8);
    char *s9 = strstr(ptr, substr9);
    char *s10 = strstr(ptr, substr10);
    char *s11 = strstr(ptr, substr11);
    char *s12 = strstr(ptr, substr12);
    char *s13 = strstr(ptr, substr13);
     if(s1==NULL&&s2==NULL&&s3==NULL&&s4==NULL&&s5==NULL&&s6==NULL&&s7==NULL&&s8==NULL&&s9==NULL&&s10==NULL&&s11==NULL&&s12==NULL&&s13==NULL)
     {
     	return str;
	 }
	 else
	 {
	 	return judge_formula();
	 }
    
}
           
string Control::judge_result(void)          //判斷結果是否為整數  
{
  	string str=Control().judge_formula();
  	double res=Calculate().calculate_formula(str);
  	if((int)res==res)
  	{
  		return str;
	}
	else
	{
		return Control().judge_result();
	}
}
           

7.合作證明

《面向對象程式設計》——寒假作業3
《面向對象程式設計》——寒假作業3

8.程式測試結果

《面向對象程式設計》——寒假作業3
《面向對象程式設計》——寒假作業3

9.個人感受

此次的作業對于我一個剛接觸C++來說的人确實挑戰挺大,剛開始的幾天還在看視訊學習C++,後面開始動手寫程式的時候,我們先建立了一個大概的思路,發現計算算式的結果是最為複雜的一個部分,是以我們的分工就是,一個人負責算式計算的實作,另一個人負責算式生成和檢驗,控制語言等等.

那麼剛開始我不知道如何用類的寫我的代碼,是以就把所有的函數寫在一個CPP檔案中,直到我想要的功能全部都能實作的時候,便思考着如何去把這個程式,轉變為面對對象的思想.也請教了很多人,閱讀了很多資料.現在這裡感謝那些幫助我很多的人,感謝暢暢和燊哥還有齊老大等等...

先從程式本身的功能開始說起就有很多值得為記錄的東西

随機數生成

首先就是這個随機數生成的辦法,使用rand()函數來生成随機數,那麼想要生成[low,high]的随機數有一個公式rand()% (high - low+1) + low

其次便是要使用srand((unsigned)time(NULL));以及頭檔案 < time.h >将系統的時間作為種子,才能保證随機數是真的随機生成

string的應用

C++和C語言相比多了一個string的類型,頭檔案為 < string >,讓我們對字元串的操作更加的友善。比如說我們string str=“HELLO”,那麼str[0]就為"H"

stringstream的應用

當我用随機數的辦法生成随機的表達式的時候,我能夠随機生成的隻是一個多項式而已,那麼如何把他們連接配接起來變成一個算式呢?

這個問題困擾了我很久,後來找到了stringstream這個東西,頭檔案為

< sstream > 通過使用stringstream,創造了一個臨時的資料流,可以讓我使用非常簡單的文法,例如 :

stringstream ss

ss << '(' << a<<generate_operator()<<b<<')';

通過這樣就可以把這些字元串連接配接在一起了,不過要提醒大家的是,由于這隻是一個臨時的字元串操作完要傳回的時候,不能直接傳回,要通過string str=ss.str()的方式存儲,然後使用ss.str("")來清空,不然很容易發生資料的錯誤,最後return str

判斷生成的算式是否符合要求

剛開始使用的是string自帶的find(substr,pos)函數,可是find的函數的使用機制是在源串中從位置pos起往後查找,隻要在源串中遇到一個字元,該字元與目标串中任意一個字元相同,就停止查找,傳回該字元在源串中的位置;若比對失敗,傳回npos。

那麼後來通過網上資料的查找,找到了C語言< string.h >庫中的,strstr(str,substr)這個函數是非常嚴格的查找,如果沒有找到則傳回NULL,使用這個函數就滿足了我的需求

面對對象的思想

在上述的難題都解決了之後,我就開始思考,如何将這個程式轉變為面對對象的思想,首先我思考整個程式的結構,将程式按功能分為兩個大類,一個是對象,一個控制,對象是生成我所需要,而控制類是控制整個程式

比如說輸入數值來控制我所需要的題目的量,輸入E控制程式結束,這都是屬于一個大類中的。

再說到對象類,對象中,按照功能,我分為了三個類,一個是生成,一個是計算,一個是輸出。

多個檔案引用

在頭檔案也就是.h的檔案中,使用class來定義類,可以簡單的了解為,需要和其他類進行變量的傳遞的就寫在public中,隻是在類中進行操作的就可以寫在private中.

同時然後.h寫完之後需要有一個.cpp的實作檔案,在實作檔案中函數名應該加上類::才能被調用.

例如 在Control類中,我寫函數應該是 void Control::chosse(void)

如有不同意見歡迎在我的部落格下面評論指出!