支持多语言版本四则运算程序
队员学号和博客主页链接
031602211盖嘉轩 博客主页
031602240许郁杨 博客主页
实现设计思路
首先这次的作业两种普遍的思路。
第一种是将五种语言的翻译版本都存到txt这样的资源文件,然后再存一个目录的资源文件中,然后在代码中添加一个部分来读取这些。 一行一行地读取txt中的内容。这样就实现了在不改动代码的同时能新增加语言和删去语言。只需增加新的翻译版本的txt的资源文件。
第二种是像王源大佬那样去啃文档,调用各种API的高逼格做法(只能仰望)
而我们的做法则十分有创意(),由于我的队友十分熟练的运用visual studio,他看题后经过几次尝试,发现我们可以把字符串和值放入visual studio原有的段-stringtable中。具体过程如下:
首先使用 Visual Studio 的资源编辑器创建一个字符串,然后给每一个字符串取一个ID,一般给它取名字都以 IDS_开头。然后用lordstring方法,LoadString 方法需要一个字符串资源的 ID 作为参数,然后它从 STRINGTABLE 中取出它对应的字符串,赋值给 CString 对象。并且最好设置两个字符串,一个读,一个写。
有些小伙伴可能会想:这怎么可能工作呢。怎么能把 STRINGTABLE ID 转化成一个指针呢。很简单:所有的字符串 ID 都在1~65535这个范围内,也就是说,它所有的高位都是0,而在程序中所使用的指针是不可能小于65535的,因为程序的低 64K 内存永远也不可能存在的,如果试图访问0x00000000到0x0000FFFF之间的内存,将会引发一个内存越界错误。所以说1~65535的值不可能是一个内存地址,所以可以用这些值来作为字符串资源的ID。
然后把不同的翻译文件放在不同的资源文件中,一个一个检测就可以了
还要注意的是,大多数的方法即可以接受一个 UINT 型的参数,也可以接受一个 LPCTSTR 型的参数,这是依赖 C++ 的重载功能做到的。C++重载函数带来的 弊端就是造成所有的强制类型转化都需要显示声明。同样,也可以给很多种结构只传递一个资源名。
程序实现和结果测试的截图
以下是这次作业的主要代码
/*************************************************************
文件名:head.h
作者:盖嘉轩 许郁杨 日期:2017/03/14
描述: 头文件
*************************************************************/
#pragma once
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<cmath>
#include<ctime>
#include<vector>
#include<stack>
#include<cassert>
#include<atlstr.h>
#define Min(x,y) (((x)<(y))?(x):(y))
#define Max(x,y) (((x)>(y))?(x):(y))
#define random(a,b) (rand()%(b-a+1)+a)
#define MAX 1000
using namespace std;
/*generate.cpp*/
int getRand(int down, int up);
void getAndCalculate(int num, int low, int high, int flag0, char flag1, char flag2, char flag3);
/*Stack.cpp*/
void transEquation(string infix, char postfix[]);
string countEquation(string infix);
/*verify.cpp*/
bool ifOnly(string str, vector<string> se);
void checkAndOutput(string equ, int n, string result);
void finalOut();
/*fraction.cpp*/
class Fraction
{
private:
int numerator, denominator;
string numerators, denominators;
int greatestCommonDivisor(int x, int y);
public:
Fraction();
Fraction(int numerator, int denominator);
Fraction getFrac(int l, int h);
bool checkZero(Fraction frac);
bool checkInt(Fraction frac);
Fraction transFrac(int up, int down);
Fraction simplify(Fraction frac);
string transString(Fraction frac);
string transToString(Fraction frac);
friend const Fraction operator +(Fraction frac1, Fraction frac2);
friend const Fraction operator -(Fraction frac1, Fraction frac2);
friend const Fraction operator *(Fraction frac1, Fraction frac2);
friend const Fraction operator /(Fraction frac1, Fraction frac2);
};
/*************************************************************
文件名:main.cpp
作者:盖嘉轩 许郁杨 日期:2017/03/14
描述: 初始界面
主要功能包括:语言切换、功能选择
*************************************************************/
#include"head.h"
UINT idValue;
int main()
{
int i, j, k, num, low, high, flag0, tmp;
char flag1, flag2, flag3;
CString langName, langList, langStr;
string Lang;
wcout.imbue(locale("CHS"));
cout << "Which language you would like to choose?
";
i = 1;
idValue = 0;
langList.LoadString(++idValue);
while (langList != "End")
{
cout << i << '.';
wcout << (LPCTCH)langList << endl;
i++;
langList.LoadString(++idValue);
}
cout << "Please input the name of the language:";
tmp = 0;
idValue = 0;
while (tmp == 0)
{
char tmpc[MAX];
fgets(tmpc, MAX, stdin);
stringstream tmpcs;
tmpcs << tmpc;
tmpcs >> Lang;
langName = Lang.c_str();
langList.LoadString(++idValue);
while (langList != "End")
{
if (langList == langName)
{
tmp = 1;
idValue *= 1000;
break;
}
langList.LoadString(++idValue);
}
if (tmp == 0)
{
idValue = 1;
cout << "Sorry, please choose other language:";
}
}
langStr.LoadString(idValue);
wcout << endl << (LPCTSTR)langStr;
cin >> num;
langStr.LoadString(++idValue);
wcout << (LPCTSTR)langStr;
cin >> low >> high;
langStr.LoadString(++idValue);
wcout << (LPCTSTR)langStr;
cin >> flag0;
langStr.LoadString(++idValue);
wcout << (LPCTSTR)langStr;
cin >> flag1;
langStr.LoadString(++idValue);
wcout << (LPCTSTR)langStr;
cin >> flag2;
langStr.LoadString(++idValue);
wcout << (LPCTSTR)langStr;
cin >> flag3;
idValue++;
cout << endl << "********************************************************************" << endl;
cout << " " << endl;
getAndCalculate(num, low, high, flag0, flag1, flag2, flag3);
return 0;
}
/*************************************************************
文件名:verify.cpp
作者:盖嘉轩 许郁杨 日期:2017/03/14
描述: 检验和输出结果
主要功能包括:判重、检验答案、输出答案
*************************************************************/
#include"head.h"
extern UINT idValue;
int correct = 0, wrong = 0;
bool ifOnly(string str, vector<string> se) //判断表达式是否重复
{
int count = 0;
for (int i = 0; i<se.size(); i++)
{
if (str != se[i]) count++;
else break;
}
if (count == se.size()) return true;
else return false;
}
void checkAndOutput(string equ, int n, string result) //检验答案并输出正确答案
{
string ans;
CString str;
cout << "(" << n << ") " << equ << "=";
wcout.imbue(locale("CHS"));
cin >> ans;
if (ans == result)
{
str.LoadString(idValue);
wcout << (LPCTSTR)str << endl;
correct++;
}
else
{
str.LoadString(idValue + 1);
wcout << (LPCTSTR)str;
cout << result << endl;
wrong++;
}
cout << endl;
}
void finalOut() //输出正误个数
{
CString str;
cout << "********************************************************************" << endl;
cout << endl;
wcout.imbue(locale("CHS"));
str.LoadString(++idValue);
wcout << (LPCTSTR)str;
cout << correct << endl;
str.LoadString(++idValue);
wcout << (LPCTSTR)str;
cout << wrong;
}
以下是测试截图
git
由于这次我在做好文件之后才发现我不小心建了一个新的库,没办法与之前的develop合并,而且马上要提交博客了,所以我把文件传给了我的队友,由他提交。所以这次没有我的提交记录。(这次的失误充分说明我git还是不熟悉,我决定把之前的库删了,重新再创建一个,把整个流程再走一遍)
分工合作
这次主要是由我的队友提供的灵感,我负责 francais deutsch 日本语 这三个文件和 main.cpp中的部分代码,我的队友负责main。cpp和verify。cpp的大部分代码。
差异部分
作业感想
说真的,每次做作业的发现自己不会的东西特别多,每次都要上网百度很长时间,而且还看不懂。但是这次学习之后发现自己的学习理解能力较以前有提高,即使在完全不懂的情况下也可以“啃文档”,虽然还不能像我的队友和我们班的各位大佬那样自学能力超强,但是感觉没有那么难了,对于新的知识,即使完全不懂,也没那么抵触了。
而且这次才发现模块化编程的好处了,因为当时将不同的功能都分类了,所以这次只需要改两个文件-main.cpp和verify.cpp就可以了。而且我们的程序明显在模块化这方面有很大的提升空间。