| 作业描述 | 详情 |
|---|---|
| 这个作业属于哪个课程 | 2020年面向对象程序设计 |
| 这个作业要求在哪 | 面向对象程序设计寒假作业2 |
| 这个作业目标 | 1. 使用git,建立github仓库 2.优化架构 3.优化命名规范 4.制作编译脚本 5.进行单元测试 6.添加功能 |
| 作业正文 | 博客地址 |
| 其他参考文献 | Python基础之os.system函数 C++ main()函数及其参数 C++中头文件(.h)和源文件(.cpp)的编写 代码命名 Git忽略提交 git教程 |
实践题
新建一个github仓库,使用git,或者github desktop把接下去的编程题的代码及测试脚本传到这个仓库。
请使用.gitignore文件忽略不要上传的文件。用法自行百度。
- 根据廖老师的教程进行安装git
- 在github上创建仓库fzu_oop_work
- 在本地创建代码仓库

- 创建子目录1,2,分别上传上次和本次的作业

- git add . 提交该目录下的所以文件到暂存区,在git commit -m “”
- 编写.gitignore并提交
- 关联远程库
- git push推送到远程

编程题
继续完成作业一的编程题。
优化架构,一般要求每个函数长度不超过15行。
优化规范,尤其是命名规范。
制作一个编译脚本,运行该脚本可以编译你的代码,可选的脚本语言,python(2.7),windows批处理,powershell,shell。
进行单元测试,即测试每一个函数,并制作一个测试脚本,运行该脚本可以进行测试,并显示测试结果。
在作业一编程题的基础上添加以下功能:
- 通过命令行读取一个文件,然后运行这个文件。如我的程序叫lang,
lang 1.txt代表我要运行1.txt这个文本中的代码。 - 假设我的
1.txt内容如下:
整数 钱包 等于 零 钱包 增加 四 钱包 减少 三 看看 钱包
- 输入
lang 1.txt后,命令行输出一。
- 通过命令行读取一个文件,然后运行这个文件。如我的程序叫lang,
一开始对于变量如何存储不太懂,后面向某位廖姓大佬请教后,发现可以直接写一个变量类来搞
- 分为3个类,变量库,数字库,以及主体部分加一个异常处理函数
优化了架构(个人觉得)
头文件(main.h)
#ifndef LANG_H
#define LANG_H
#include <bits/stdc++.h>
class VarRepository {
public:
std::map<std::string, int>var;
bool IsExist(std::string name);
void Create(std::string name, int val);
void Add(std::string name, int val);
void Reduce(std::string name, int val);
};//存储变量
class NumRepository {
private:
std::string base_num[11] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
public:
std::map<std::string, int>chs2num;
std::map<int, std::string>num2chs;
void MakeTable();
};//生成映射表
class Body {
public:
VarRepository Var;
NumRepository Num;
std::string part[5];
int cnt;
void Look(std::string name);
bool Parse(std::string line);
void Clear();
int GetNum(std::string num);
void Choose();
void Define();
void Add();
void Reduce();
};//进行语句解析及后续操作
void Exception(int type);
#endif
异常处理(Exception.cpp)
与上次基本一样,只是放在另一个cpp文件中
#include "main.h"
void Exception(int types) {
if (types == 1)
puts("请正确输入指令");
else if (types == 2)
puts("请勿重复定义相同的变量名");
else if (types == 3)
puts("请输入正确的数字");
else if (types == 4)
puts("这玩意还没被定义过");
else if (types == 5)
puts("请不要用关键词作为变量名");
else if (types == 6)
puts("相加的数字过大");
else if (types == 7)
puts("相减的数字过大");
}
变量库(VarRepository.cpp)
用map容器进行存储,实现多变量
#include "main.h"
bool VarRepository::IsExist(std::string name) {
return var.count(name) != 0;
}
void VarRepository::Create(std::string name, int val) {
if (IsExist(name)) {
Exception(2);
return ;
}
if (name == "看看" || name == "增加" || name == "减少" || name == "整数") {\
Exception(5);
return ;
}
var[name] = val;
}
void VarRepository::Add(std::string name, int val) {
int now = var[name];
now += val;
if (now > 99) {
Exception(6);
return ;
}
var[name] = now;
}
void VarRepository::Reduce(std::string name, int val) {
int now = var[name];
now -= val;
if (now < 0) {
Exception(7);
return ;
}
var[name] = now;
}
数字库(NumRepository.cpp)
#include "main.h"
void NumRepository::MakeTable() {
for (int i = 0; i <= 10; ++i)
chs2num[base_num[i]] = i; // deal with 0 ~ 10
for (int i = 1; i <= 9; ++i) {
std::string a = base_num[10];
a += base_num[i];
chs2num[a] = 10 + i;
}// deal with 11 ~ 19
for (int i = 2; i <= 9; ++i) {
std::string a = base_num[i];
a += base_num[10];
chs2num[a] = i * 10;
}// deal with multiples of 10
for (int i = 2; i <= 9; ++i) {
std::string a = base_num[i];
a += base_num[10];
int num = i * 10;
for (int j = 1; j <= 9; ++j)
chs2num[a + base_num[j]] = num + j;
}
for (auto it : chs2num) {
num2chs[it.second] = it.first;
}// deal with num to chs
}
主体(body.cpp)
#include "main.h"
void Body::Look(std::string name) {
if (!Var.IsExist(name)) {
Exception(4);
return ;
}
std::cout << Num.num2chs[Var.var[name]] << "\n";
}
bool Body::Parse(std::string line) {
for (int i = 0; i < line.length(); ++i) {
if (line[i] != ' ') {
while(line[i] != ' ' && i < line.length()) {
part[cnt] += line[i];
i++;
}
cnt++;
}
}
if (cnt <= 1) {
Exception(1);
return false;
}
return true;
}
void Body::Clear() {
cnt = 0;
for (int i = 0; i < 5; ++i)
part[i] = "";
}
int Body::GetNum(std::string num) {
if (Num.chs2num.count(num))
return int(Num.chs2num[num]);
return -1;
}
void Body::Define() {
int GetedNum = GetNum(part[3]);
if (GetedNum == -1) {
Exception(3);
return ;
}
Var.Create(part[1], GetedNum);
}
void Body::Add() {
if (cnt != 3) {
Exception(1);
return ;
}
if (!Var.IsExist(part[0])) {
Exception(4);
return ;
}
int GetedNum = GetNum(part[2]);
if (GetedNum == -1) {
Exception(3);
return ;
}
Var.Add(part[0], GetedNum);
}
void Body::Reduce() {
if (cnt != 3) {
Exception(1);
return ;
}
if (!Var.IsExist(part[0])) {
Exception(4);
return ;
}
int GetedNum = GetNum(part[2]);
if (GetedNum == -1) {
Exception(3);
return ;
}
Var.Reduce(part[0], GetedNum);
}
void Body::Choose() {
if (part[0] == "整数")
Define();
else if (part[0] == "看看")
Look(part[1]);
else if (part[1] == "增加")
Add();
else if (part[1] == "减少")
Reduce();
else
Exception(1);
}
主函数(main.cpp)
#include "main.h"
int main(int argc, char *argv[])
{
if (argc != 1) {
freopen(argv[1], "r", stdin);
}
std::string s;
Body my;
my.Clear();
my.Num.MakeTable();
while(std::getline(std::cin, s)) {
if (my.Parse(s)) {
my.Choose();
my.Clear();//每次操作后要对part, cnt 进行清空
}
}
return 0;
}
编译脚本(compile.py)
py下的os.system()函数就相当于命令行
在编译过程中,单独编译一个main.cpp 老是报错,一直以为编译器会默认在当前目录下寻找其他相关联的.cpp,结果发现我还是naive啊。
查阅资料后,应该在编译时将相关的.cpp一起编译, 文件输入的先后无影响
脚本代码如下:
import os
file = 'Body.cpp Exception.cpp main.cpp NumRepository.cpp VarRepository.cpp'
os.system('g++ -o main -std=c++11 ' + file)
编译结果:
编译成功,无返回值,目录有main.exe生成

单元测试(test.py)
通过编译test.cpp 等文件来实现
仅仅验证了数字表是否正确。。。
#include "main.h"
Body my;
void CheckChs2Num() {
if (my.Num.chs2num["十"] == 10)
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.chs2num["二十"] == 20)
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.chs2num["零"] == 00)
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.chs2num["五十五"] == 55)
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.chs2num["二十三"] == 23)
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.chs2num["十七"] == 17)
std::cout << "pass\n";
else
std::cout << "error\n";
}
void CheckNum2Chs() {
if (my.Num.num2chs[11] == "十一")
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.num2chs[21] == "二十一")
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.num2chs[17] == "十七")
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.num2chs[30] == "三十")
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.num2chs[50] == "五十")
std::cout << "pass\n";
else
std::cout << "error\n";
if (my.Num.num2chs[63] == "六十三")
std::cout << "pass\n";
else
std::cout << "error\n";
}
int main() {
my.Num.MakeTable();
my.Clear();
std::cout << "Now is checking num2chs\n";
CheckNum2Chs();
std::cout << "check end\n";
std::cout << "Now is checking chs2num\n";
CheckChs2Num();
std::cout << "check end";
system("pause");
return 0;
}
import os
file = 'Body.cpp Exception.cpp test.cpp NumRepository.cpp VarRepository.cpp'
os.system('g++ -o test -std=c++11 ' + file)
os.system('test.exe')
os.system('del test.exe')
测试结果:
添加功能
命令行的指令会被保留在argv[]里面,如果输入指令main 1.txt,那么argv[1] = '1.txt',基于这个方法,就可以简单的获得文件名,再用freopen()来实现从特定文件中读取文本(代码)
具体实现代码在(main.cpp)中,可以在上面看到,前提是已经编译好main.cpp并且有main.exe文件,给出测试结果:


总结
真t喵的累,学的东西也挺多的,摸了摸了。。。
来源:https://www.cnblogs.com/Tajx/p/12250239.html


