SEP课程代码分享(2023SPRING)-lab1


写在前面:

为了小学期不上课(bushi),所有上海交通大学软件工程的同学都要在大一春学期进行一学分的软件基础实践学习,平时的主要内容就是写lab。

不得不说,写lab耗费了我大量的时间,平均一个lab是3天工作日的空余时间。但是也不得不承认,一次次lab的磨练给予了自己代码能力的提升。此系列用于记录保存自己写的所有lab内容,新lab的代码会在截止之后上传(当然得我有空的情况下),不过……千万不要抄袭哟~(自恋)


下面是lab1的具体要求:

Lab1: X老师的小程序

[toc]

X老师需要一个统计和计算学生成绩的小程序,以协助他录入学生成绩、计算课程均分以及查看学生的学分绩。
学生名单、课程列表和学生的选课情况已经存在于文本文件中,小程序需要从这些文件中读出内容并建立相应的对象,以完成后续的成绩录入和计算工作。

学生名单存在于文件 Students.txt 中,其中学生分为本科生(Undergraduate)和研究生(Graduate),分别以字母 UG 表示,文件格式如下(# 开头的是注释):

1
2
3
# id;name;year;degree
F180370001;Apple;2019;U
B180370010;Boy;2018;G

课程列表和学生选课情况存在于文件 Classes.txt 中,文件每一段表示一个课程和选择该课程的学生学号列表,格式如下(# 开头的是注释):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Class name and points followed by student ids
Class:ICS
Points:5
F180370001
F180370002

Class:English
Points:3
F180370003
B180370001

Class:ADS
Points:2
B180370001
B180370002

小程序需要实现的功能主要有以下三个:

  1. 记录成绩:记录某一门课程的一名学生的成绩,为了简便该程序不要求将成绩写入文件,只需存储在内存中即可。
  2. 计算课程平均分:在成绩录入完成以后,选择一门课程并计算出该课程所有选课学生的平均分。
  3. 计算学生学分绩:在成绩录入完成以后,选择一名学生并计算 ta 的学分绩。其中本科生和研究生的学分绩计算方法不同,本科生的总学分绩是 5.0,计算方法是每门课程的分数除以 20 然后按照学分数量加权平均;研究生的总学分绩是 4.0,计算方法是先分档次记分:90~100分 => 4.0,80~89分 => 3.5,70~79 => 3.0,60~69 => 2.5,60以下 => 2.0,然后再按照学分数量加权平均。

小程序通过命令行与用户进行交互,用户通过输入一些特定的命令、课程名、学号和成绩来完成操作流程,流程图如下:

流程图

在系统设计中,类的关系要求如下:

类图

其中 getGrade 函数是 Student 类的纯虚函数,它的子类 UndergraduateGraduate 继承后具体实现了 getGrade 函数。(图例可参考:https://en.wikipedia.org/wiki/Class_diagram)

任务

  1. 小程序的部分代码已经给出,现在需要你将其补全(即解决所给代码中所有的 TODO):

    1. Classes.txt 文件中读出课程列表和学生选课情况,将其创建成对应的对象;
    2. 实现 Student 类、Undergraduate 类和 Graduate 类;
    3. 完成计算课程平均分功能、记录成绩功能和计算学生学分绩功能。
  2. 所给代码中 StudentWrapper 类的构造函数是有错误的,请改正这个错误详细说明原因(创建一个新的 BugReport.txt 文本文件进行说明)。
  3. 处理程序异常输入,例如输入不存在的课程名、学号或者无效的分数时程序不应该崩溃(提示:考虑使用try...catch)。

提交

注意,作业的完成包括两部分:

  1. 完成作业后,在抽查名单上的同学需要在上机课时找到助教进行功能演示,表明程序可以运行,且完成了规定的功能;
  2. 所有同学都需要提交项目代码到 Canvas 平台。

提交时请将你完成的项目代码(请不要包含生成的中间文件和可执行文件)和说明文件 BugReport.txt 打包(格式为 7z)命名为 lab1-XXX.7z 上传到 Canvas 中,其中 XXX 为你的学号。

解压后你的项目目录结构大概是下面这样,可以有一些小的区别,比如多一些你自己使用的小文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
lab1
├── Class.cc
├── Class.h
├── Classes.txt
├── Student.cc
├── Student.h
├── Students.txt
├── main.cc
├── BugReport.txt
├── CMakeLists.txt
└── spec
├── lab1.md
├── lab1.pdf
├── sep-lab1-class.png
├── sep-lab1-liucheng.png
└── sep-lab1-clion.png

由于 zip 格式有中文乱码问题,rar 的压缩工具为收费软件,请使用 7z 格式进行打包和压缩,关于 7z 压缩的工具:

关于 Clion 的一些使用提示

  1. 在解压缩之后,你可以直接使用 Clion 打开 lab1 文件夹,建议将 lab1 文件夹放在全英目录下,否则可能会出现本地编译不通过的情况。

  2. 使用 Clion 打开后会出现如下所示的配置确认,直接点 OK 即可。注意:请不要修改 CMakeLists.txt 文件中的内容!

    Clion 配置确认

    如果没有自己跳出可以自行右击 lab1 文件夹选择 Reload Cmake Project 来生成 cmake-build-debug

  3. 请注意不要提交本地的 cmake-build-debug 文件夹。

  4. 之后,可以通过点击运行和调试按钮来尝试运行项目。注意,第一次运行项目并不会编译通过,因为所给代码中 StudentWrapper 类的构造函数是有错误的,请自己完成修改。

  5. 请注意程序中文件的路径问题。由于 Clion 会将可执行文件在 cmake-build-debug 文件夹中生成,程序中需要引用的输入文件在上一层目录,因此输入文件名为 ../xxx.txt 。如果用其他集成终端可能会直接将可执行文件在 lab1 文件夹中生成,因此输入文件名为 ./xxx.txt 。这里统一为 ./xxx.txt ,使用 Clion 的同学在提交时需要将 ../xxx.txt 改为 ./xxx.txt

补充说明

为执行统⼀的测试脚本,现统⼀规定SEP-2023-lab1的输出格式。对于所有计算数据输出均保留两位小数
具体格式如下:(请注意空格和换行)

成绩计算

1
2
printAvgScore: "The average score is: %.2f\n"
printGpa: "GPA = %.2f\n"

异常处理

1
2
3
成绩格式错误,命令行输出:"Wrong score!\n"
课程名称错误,命令行输出:"No match class!\n"
学生ID输⼊错误,命令行输出: "No match student!\n"

测试用例

lab1文件夹中已经给出了一个测试用例的输入(spec/input0.txt)和输出(spec/output0.txt),在你认为完成后请先自行在本地进行测试,方便定位自己的问题。(注意敲对输入!仔细对比输出!)

1. 关于测试结果的说明

1.1 xxxxxx(line xx)

给出的错误信息(line xx)意思是在一个测试里输出到第几行的时候出错了,因为一个测试里会要求不止一条输出。比如line 2说明输出的0和1行内容是对的,在第2行错了。

line xx表示的是助教这里的答案的行数,不是你们程序运行结果的行数。

1.2 错误处理

“Wrong score!”不匹配

  • Test #%d: Fail. Exception handle(score) error

“No match class!”不匹配

  • Test #%d: Fail. Exception handle(class) error

“No match student!”不匹配

  • Test #%d: Fail. Exception handle(student) error

1.3 数值计算错误

含有”The format of”的信息表示输出格式肯定不对,没有该信息的是计算错误或格式错误(保留小数)。

1.4 其他

“Answer is too short”表示输出的结果进过匹配后发现答案缺失。

“Compile error…No such file…”表示作业提交格式没有按照说明提交(含lab1文件夹且不要修改名称)。

2. 测试结果可能的错误原因

2.1 程序本身计算错误

2.2 多余输出信息

这里的多余输出信息不是说不能输出辅助信息,而是在给出的《lab1.pdf》文档中规定的输出不是以换行结束的。也就是说这一行输出的末尾要和说明匹配,不能有多余的信息赘述在这行的后面。(这行的前面有多余信息是不影响的)。

正确示例:

1
2
jdlfjs111kdj000fjlsdkf--jljjs....some_info_. ....sjfldsjkfGPA = 96.00
GPA = 96.00

错误示例:

1
jdlfjs111kdj000fjlsdkf--jljjs....some_info_. ....sjfldsjkfGPA = 96.00please input ...

2.3 多余的错误处理

这里的多余意思是,把正确的输入也通过文档中的三种错误信息格式进行输出。

3. 什么时候测试

并不是你提交了就立刻有结果的!!!

测试结果只有我这里跑了测试脚本才会上传到课程网站。

隔30分钟测试一次。

4. 我自己跑的是通过的,为什么助教那里的没有过

有一些同学在问助教测试为什么过不了,测试数据是不会公开的。测试用例有一部分是非常基础的测试,不包含错误处理,大家可以先考虑过正常流程。这里提示一下,正常流程是【输入课程和学生成绩(不止一个课程,一个课程也不止一个学生),查询课程平均分(不止一个),查询学生GPA(不止一个)】

助教这里也不会告诉你为什么错了,毕竟一个一个人查助教一个人也没有精力做到,可以确定的是如果程序都正确肯定得分是100,不用怀疑测试脚本的问题。

额外提示

测试用例1-4、7最终需要的结果是不含错误处理信息的

一定一定要注意输出格式!!!每一个字母每一个空格每一个空行都要一样!!!

测试判断的流程是:如果一行输出含有《lab1.pdf》文件中要求的任意一种输出语句,那么会判定这一行为一行答案,与助教的标准答案的一行进行匹配。所以给同学们的错误提示,不一定就是与之相关的问题。比如说,“GPA is wrong.”这个提示不一定是GPA计算错误,也可能是你的输出含有GPA = xx,而助教的答案这一行是错误处理的“Wrong score!”之类的信息。再比如说,“Exception handle(class) error.”这个提示不一定是课程异常处理出错,非常可能是因为你的输出含有No match class!,而助教的答案这一行不是错误信息,而是gpa或者score等其他信息。

5. 其他问题汇总

5.1 得分范围的切分

不存在89-90这种范围内的奇怪测试数据,可以不考虑

5.2 成绩输入错误的下一步,回到输入学生ID这一步

5.3 查询均分出现非法输入返回输入查询均分这一步;查询绩点出现非法输入返回输入查询绩点这一步(都是同一步不断循环)

5.4 整个输入成绩过程出现要求输入课程名时,输入非法课程名返回输入课程名这一步

5.5 我的程序为什么读文件都读不成功?

请参考《lab1.pdf》的使用提示。

5.6 使用mac电脑的同学们注意:如果遇到mac电脑运行不过的程序在windows上能过/输入的字符串和存储的字符串总是不相等?

注意对于输入文件处理的时候,字符串需要把macos系统默认的换行符’\r’做丢弃处理


要求结束,下面奉上自己写的代码(可能不够完美,也欢迎大家提供意见)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//Class.cc

#include "Class.h"
#include <string>
#include "Student.h"
#include "iostream"
using namespace std;

void Class::addStudent(const Student &st)
{
StudentWrapper sw(st.id, st);
students.push_back(sw);
}

StudentWrapper &Class::getStudentWrapper(const std::string &studentId) {
try {
for (std::vector<StudentWrapper>::iterator it = students.begin();
it != students.end();
++it) {
if (it->id == studentId)
return *it;
}

throw int(5);
}


//std::cout<<"No match student!"<<std::endl;
catch(int)
{
cout<<"No match student!"<<endl;
}
}



double Class::getAvgScore()
{
// TODO: implement getAvgScore.
double allScore;
int num=0;
for(std::vector<StudentWrapper>::iterator it = students.begin();
it != students.end();
++it) {
num++;
allScore+=it->getScore();
}
double averageScore=allScore/num;

return averageScore;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Class.h

#ifndef CLASS_H_
#define CLASS_H_

#include "Student.h"
#include <string>
#include <vector>

class Class {
private:


public:
std::vector<StudentWrapper> students;
const std::string name;
const int point;
Class(const std::string &name, const int point)
: name(name), point(point) { }



void addStudent(const Student &st);


StudentWrapper &getStudentWrapper(const std::string &studentId);
double getAvgScore();
};

#endif // CLASS_H_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Class.txt
# Class: 课程名
# Points: 学分
Class:ICS
Points:5
F180370001
F180370002
F180370003
F180370004
F180370005

Class:English
Points:3
F180370001
F180370002
F180370003
F180370004
F180370005
B180370001
B180370002
B180370003

Class:ADS
Points:2
B180370001
B180370002
B180370003

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
//main.cc
#include <vector>
#include <iostream>
#include <fstream>
#include "Class.h"
#include "Student.h"
#include "iomanip"

using namespace std;

class AppX {
private:
vector<Student *> studentVec;
vector<Class *> classVec;

void loadFiles();
void inputScore();
void printAvgScore();
void printGpa();

public:
AppX();
~AppX();
int run();
};

AppX::~AppX()
{
// You can use the traditional loop, which is more clear.
for (vector<Class *>::iterator it = classVec.begin();
it != classVec.end();
++it) {
if (*it) delete (*it);
}
// You can use modern and simpler loops only if you know what it is doing.
for (const auto &s: studentVec) {
if (s) delete (s);
}
}

AppX::AppX()
{
loadFiles();
}

void AppX::loadFiles()
{
string line;
size_t pos1, pos2;
vector<string> bufv;
Student *st = nullptr;
string clsname;
int point;
Class *cl = nullptr;

// Open a file as a input stream.
ifstream stfile("../Students.txt");

while (getline(stfile, line)) {
if (line.empty()) // It's an empty line.
continue;
if (line[0] == '#') // It's a comment line.
continue;

// The bufv vector stores each columnes in the line.
bufv.clear();
// Split the line into columes.
// pos1: begining the the column.
// pos2: end of the column.
pos1 = 0;
while (true) {
pos2 = line.find(';', pos1 + 1);
if (pos2 == string::npos) { // No more columns.
// Save the last column (pos1 ~ eol).
bufv.push_back(line.substr(pos1, string::npos));
break;
} else {
// Save the column (pos1 ~ pos2).
bufv.push_back(line.substr(pos1, pos2 - pos1));
}
pos1 = pos2 + 1;
}

// TODO: uncomment next lines after implementing class Undergraduate
// and Graduate.

if (bufv[3] == "U")
st = new Undergraduate(bufv[0], bufv[1], bufv[2]);
else
st = new Graduate(bufv[0], bufv[1], bufv[2]);


studentVec.push_back(st);
}
stfile.close();

// TODO: load data from ./Classes.txt and push objects to the vector.
ifstream afile("../Classes.txt");

while(getline(afile,line)){
if(line.empty())
continue;
if(line[0]=='#')
continue;
//bufv.clear();
if(line[0]=='C'&&line[1]=='l'&&line[2]=='a'&&line[3]=='s')
{
clsname=line.substr(6);
}
if(line.substr(0,6)=="Points")
{
point=line[7]-'0';
cl=new Class(clsname,point);
//此处还应该录入学生选课情况。
while(getline(afile,line))
{
if(line.empty())
break;
else
{
string tmp=line.substr(0);

for(std::vector<Student *>::iterator it=studentVec.begin();it!=studentVec.end();it++)
{
// cout<<(*it)->id<<endl;


if(tmp==(*it)->id){
const Student* tmpOfStudent=*it;
cl->addStudent(*tmpOfStudent);
(*it)->addClass(cl);
}
}


}
}
classVec.push_back(cl);
}


}
afile.close();


/*ifstream bfile("../Classes.txt");
while(getline(bfile,line)){
Class* tmpClass;
if(line.empty())
continue;
if(line[0]=='#')
continue;
if(line[0]=='C'&&line[1]=='l'&&line[2]=='a'&&line[3]=='s')
{
clsname=line.substr(6);
for(std::vector<Class*>::iterator it=classVec.begin();it!=classVec.end();it++)
{
if(clsname==(*it)->name)
tmpClass=*it;
}

while (getline(bfile,line))
{
if(line.empty())
break;
if(line[0]=='P'&&line[1]=='o')
break;
else
{
string tmpName=line.substr(0);
for(std::vector<Student *>::iterator it=studentVec.begin();it!=studentVec.end();++it)
{
if(tmpName==(*it)->name)
(*it)->addClass(tmpClass);
}
}
}
}



}
bfile.close();*/

// Hint: how is student information read?
}

void AppX::inputScore()
{
// TODO: implement inputScore.
// Hint: Take a look at printAvgScore().



while(true) {
string sbuf;
Class *cl;

cout << "Please input the class name (or input q to quit): ";
cin >> sbuf;
if (sbuf == "q")
break;

cl = nullptr;
for (vector<Class *>::iterator it = classVec.begin();
it != classVec.end();
++it) {
if ((*it)->name == sbuf) {
cl = *it;
break;
}
}
if (cl == nullptr) {
cout << "No match class!" << endl;
continue;
}

while (true) {
string inputString;
//StudentWrapper* temp;
bool flag = true;

cout << "Please input the student number (or input q to quit): ";
cin >> inputString;
if (inputString == "q")
break;

for (vector<StudentWrapper>::iterator it = cl->students.begin(); it != cl->students.end(); it++) {
if (it->id == inputString) {
cout<<it->toString();
cout << "please input the score: ";
double inputScore;
string stringA;
cin>>stringA;
if(stringA=="q")
break;
bool flag1=true;
if(stringA[1]=='\0'||stringA[2]=='\0'||stringA[3]=='\0')
flag1=false;
if(flag1== true)
{
cout<<"Wrong score!"<<endl;
flag=false;
continue;

}
if(stringA[1]=='\0')
{
if(stringA[0]-'0'>=0&&stringA[0]-'0'<=9)
inputScore=stringA[0]-'0';
else
{
cout<<"Wrong score!"<<endl;
flag=false;
continue;

}
}

if(stringA[2]=='\0'&&stringA[1]!='\0')
{
if((stringA[0]-'0'>=0&&stringA[0]-'0'<=9)&&(stringA[1]-'0'>=0&&stringA[1]-'0'<=9))
{
inputScore=(stringA[0]-'0')*10+stringA[1]-'0';
}
else
{
cout<<"Wrong score!"<<endl;
flag=false;
continue;

}
}

if(stringA[3]=='\0'&&stringA[2]!='\0')
{
if(stringA=="100")
inputScore=100;
else
{
cout<<"Wrong score!"<<endl;
flag=false;
continue;

}
}
if(inputScore<0||inputScore>100)
{
cout<<"Wrong score!"<<endl;
flag=false;
continue;

}


it->setScore(inputScore);
flag = false;

continue;
}
}

if (flag == true) {
cout << "No match student!" << endl;
continue;
}


}
}
}

void AppX::printAvgScore()
{
string sbuf;
Class *cl;
double avg;

while (true) {
cout << "Please input the class name (or input q to quit): ";
cin >> sbuf;
if (sbuf == "q")
break;

cl = nullptr;
for (vector<Class *>::iterator it = classVec.begin();
it != classVec.end();
++it) {
if ((*it)->name == sbuf) {
cl = *it;
break;
}
}
if (cl == nullptr) {
cout << "No match class!" << endl;
continue;
}

avg = cl->getAvgScore();
cout << "The average score is: " ;
cout<<setiosflags(ios::fixed)<<setprecision(2)<< avg << endl;
}
}

void AppX::printGpa()
{
// TODO: implement printGpa.
// Hint: Take a look at printAvgScore().
while(true)
{
string inputString;
cout<<"Please input the student number (or input q to quit): ";
cin>>inputString;
if(inputString=="q")
break;

Student* cl;
cl= nullptr;
for(vector<Student *>::iterator it =studentVec.begin();it!=studentVec.end();++it)
{
if((*it)->id==inputString)
{
cl=*it;
break;
}

}
if(cl== nullptr)
{
cout<<"No match student!"<<endl;
continue;
}
double Grade=cl->getGrade();
cout<<"GPA = ";
cout<<setiosflags(ios::fixed)<<setprecision(2)<<Grade<<endl;
}
}

int AppX::run()
{
char cmd;
while (true) {
cout << "Command menu:\n"
<< "\ti: Input score\n"
<< "\ta: Compute average score of a class\n"
<< "\tg: Compute grade of a student\n"
<< "\tq: Quit\n"
<< "Please input the command: ";
cin >> cmd;
if (cmd == 'i') {
inputScore();
} else if (cmd == 'a') {
printAvgScore();
} else if (cmd == 'g') {
printGpa();
} else if (cmd == 'q') {
break;
} else {
cout << "Invalid command!\n" << endl;
}
}
return 0;
}

int main()
{
AppX app;
return app.run();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//Student.cc
#include "Student.h"
#include <string>
#include <sstream>
#include "Class.h"

std::string Student::toString() const
{
// TODO: uncomment the following code after implementing class Student.

std::ostringstream oss;
oss << "Student Information:"
<< "\n\tid: " << id
<< "\n\tname: " << name
<< "\n\tenrollment year: " << year
<< "\n\tdegree: " << (degree == graduate ? "graduate" : "undergraduate")
<< std::endl;
return oss.str();

return "";
}

// TODO: implement functions which are declared in Student.h.

void Student::addClass(Class *c) {
bool flag;
Class *target;
/* for(std::vector<Class*>::iterator it=classes.begin();it!=classes.end();++it)
{
flag=true;
if((*it)->name==(*c).name)
{
flag=false;
target=*it;
}
if(flag==true)
throw "No matching class!";*/
classes.push_back(c);

/* }*/
}
double Undergraduate::getGrade() {
{
double allScore=0;
int allPoint=0;
for(std::vector<Class *>::iterator it=classes.begin();it!=classes.end();++it)
{
double score=(*it)->getStudentWrapper(id).getScore()/20;
allPoint+=(*it)->point;
allScore+=(*it)->point*score;
}
double Grade=allScore/allPoint;
return Grade;

}
}
double Graduate::getGrade() {
int allPoint=0;
double allScore=0;
double score;
for(std::vector<Class *>::iterator it=classes.begin();it!=classes.end();++it)
{
if((*it)->getStudentWrapper(id).getScore()<=100&&(*it)->getStudentWrapper(id).getScore()>=90)
score=4.0;
if((*it)->getStudentWrapper(id).getScore()<=89&&(*it)->getStudentWrapper(id).getScore()>=80)
score=3.5;
if((*it)->getStudentWrapper(id).getScore()<=79&&(*it)->getStudentWrapper(id).getScore()>=70)
score=3.0;
if((*it)->getStudentWrapper(id).getScore()<=60&&(*it)->getStudentWrapper(id).getScore()>=60)
score=2.5;
if((*it)->getStudentWrapper(id).getScore()<=60)
score=2.0;
allPoint+=(*it)->point;
allScore+=(*it)->point*score;
}
double Grade=allScore/allPoint;
return Grade;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//Student.h
#ifndef STUDENT_H_
#define STUDENT_H_

#include <string>
#include <vector>
#include "iostream"
using namespace std;

class Class;

enum Degree {
undergraduate,
graduate
};

class Student {
// TODO: implement class Student.
private:

protected:




public:
const std::string id;
const std::string name;
const std::string year;
Degree degree;
std::vector<Class*> classes;
std::string toString() const;
virtual double getGrade()=0;
void addClass(Class* c);
Student(std::string a,std::string b,std::string c):id(a),name(b),year(c)
{

}
};

// TODO: implement class Graduate.
class Graduate:public Student{
public:
/* Degree degree=graduate;*/
Graduate(std::string a,std::string b,std::string c): Student(a,b,c)
{
degree=graduate;
}
virtual double getGrade();


};

// TODO: implement class Undergraduate.
class Undergraduate:public Student{
public:
/*Degree degree=undergraduate;*/

Undergraduate(std::string a,std::string b,std::string c): Student(a,b,c)
{
degree=undergraduate;
}
virtual double getGrade();

};

class StudentWrapper {
private:

double score = 0.0;
public:
const Student &student;
const std::string id;
// TODO: fix error
//solved
StudentWrapper(const std::string &id, const Student &student) :student(student),id(id)
{
}

void setScore(double score)
{
try{
if (score < 0 || score > 100)
{
throw double(8);
//std::cout<<"Wrong score!"<<std::endl;
}
this->score = score;
}
catch (double)
{cout<<"Wrong score!"<<endl;}
}


double getScore() const
{
return this->score;
}

std::string toString() const
{
return student.toString();
}
};

#endif // STUDENT_H_

1
2
3
4
5
6
7
8
9
10
11
//Student.txt
# id;name;year;degree
F180370001;Apple;2019;U
F180370002;Boy;2019;U
F180370003;Cat;2019;U
F180370004;Dog;2019;U
F180370005;Egg;2019;U
B180370001;Fish;2018;G
B180370002;Girl;2018;G
B180370003;Hand;2018;G

1
2
3
4
//BugReport.txt
StudentWrapper类构造函数问题原因:

在StudentWrapper类中,student和id均被设置为const,所以在其构造函数中,不能直接对其进行赋值,而应该使用初始化列表对其进行初始化。

上面是代码,下面是可供测试的样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//input0.txt
i
ICS
F180370001
90
F180370002
60
F180370003
70
F180370004
45
F180370005
0
q
English
F180370001
71
F180370002
72
F180370003
70
B180370001
76
B180370002
-200
B180370003
78
q
ADS
B180370001
80
B180370002
-200
B180370003
90
q
q
a
ICS
ADS
English
q
g
B180370001
B180370002
B180370003
B190370004
F180370001
F180370002
F180370003
F180370004
F180370005
q
q
q


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//output0.txt
Please input the student id (or input q to quit): please input the score: Wrong score!
Please input the student id (or input q to quit): please input the score: Wrong score!
Please input the command: Please input the class name (or input q to quit): The average score is: 53.00
Please input the class name (or input q to quit): The average score is: 56.67
Please input the class name (or input q to quit): The average score is: 45.88
GPA = 3.20
GPA = 2.00
GPA = 3.40
Please input the student id (or input q to quit): No match student!
GPA = 4.14
GPA = 3.23
GPA = 3.50
GPA = 1.41
GPA = 0.00



上面就是lab1的所有内容,祝您阅读愉快,代码能力++!

有任何建议,欢迎+vx:w2386181363进行沟通!!!


文章作者: Wang Yixiao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Wang Yixiao !
  目录