实验内容
实现一个单门课程成绩管理系统。进入系统时,用户可选择身份: 1.教师; 2
学生。
以教师身份进入后,如果上次已保存了数据,可将文件中数据读取出来,并
允许修改或添加新数据。如果为第一-次录入 (之前无保存的数据),则允许 教师.
录入相关数据。具体功能包括:
1.可录入或修改课程信息,包括:课程编号、课程名称;
2.可录入、修改、删除学生(数量不限)成绩,成绩项目包含两项:平时成
责、期末成绩,并按照各50%比例自动算出总成绩;学生基本信息包括学号、姓
名;示例如下:
请录入“C+ +编程”课程成绩
学号: 201901
姓名:张三
平时成绩: 60
期末成绩: 80
3.信息显示功能,可显示课程编号、课程名称、所有学生的成绩单。成绩单
格式如下:
学号
姓名
平时成绩
期末成绩
总成绩
4.信息统计功能,可显示总成绩、平时成绩、期末成绩的最高分、最低分、
平均分、在每个分数段(60分以下为-一个分数段, 60分以上每10分为- -个分数
段)的分布情况等。(选做1)
5.能够将上述数据保存在文件中,二进制、文本文件均可。
6.可读取上述文件。
以学生身份进入后,如果已保存了成绩数据,可将文件中数据读取出来,并
允许查询。如果尚无保存数据,提示尚无成绩信息。具体功能包括:
1.信息显示功能,可显示课程编号、课程名称、所有学生的成绩单。
2.信息统计功能,可显示总成绩、平时成绩、期末成绩的最高分、最低分、
平均分、在每个分数段(60分以下为-一个分数段,60分以上每10分为- -个分数
段)的分布情况等。
3.信息查询功能,输入学号或者姓名,均能进行该学生的成绩查询,并给出
该学生总成绩、平时成绩、期末成绩在全班的排名。(选做2)
选做3:
增加教师身份的密码保护功能,具体要求如下:
1.教师身份需要密码保护。选择教师身份进入系统后,必须输入密码;密码验
证无误后,才可进入后续过程。
2. 教师的密码经过加密后,存储在一 一个密码文件中。
教师的初始密码为“123456",首次进入系统时,要求用户修改密码。
4. 在后续使用中,允许修改教师密码。密码修改后,更新密码文件。
特选
5.输入密码或修改密码时,密码本身不显示出来,而是以掩码“*”显示。
二
实验步骤
第1步:理解需求,进行系统总体设计
第2步:进行类的设计,并予以实现
第3步:完成主函数,实现全部功能
三 解答
这个综合实验的任务比较复杂,需要设计多个类和函数来实现。在设计之前,我们可以先将整个系统分为三个模块:教师模块、学生模块和密码保护模块。其中,教师模块和学生模块的功能比较相似,可以使用同一个类来实现;密码保护模块需要单独设计一个类来实现。
下面是一个简单的实现示例:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <algorithm>
using namespace std;// 学生类,包含学号、姓名和成绩信息
class Student {
public:string id; // 学号string name; // 姓名double score1; // 平时成绩double score2; // 期末成绩double total; // 总成绩Student(string i, string n, double s1 = 0, double s2 = 0) : id(i), name(n), score1(s1), score2(s2) {total = (score1 + score2) / 2.0;}// 重载小于运算符,用于排序bool operator<(const Student& other) const {return total > other.total;}
};// 课程类,包含课程编号、课程名称和学生信息
class Course {
public:string code; // 课程编号string name; // 课程名称vector<Student> students; // 学生信息Course(string c, string n) : code(c), name(n) {}// 添加学生信息void addStudent(Student s) {students.push_back(s);}// 修改学生信息void modifyStudent(string id, double s1, double s2) {for (int i = 0; i < students.size(); i++) {if (students[i].id == id) {students[i].score1 = s1;students[i].score2 = s2;students[i].total = (s1 + s2) / 2.0;return;}}cout << "学号为 " << id << " 的学生不存在!" << endl;}// 删除学生信息void deleteStudent(string id) {for (int i = 0; i < students.size(); i++) {if (students[i].id == id) {students.erase(students.begin() + i);return;}}cout << "学号为 " << id << " 的学生不存在!" << endl;}// 显示所有学生信息void showStudents() {cout << "课程编号:" << code << endl;cout << "课程名称:" << name << endl;cout << "学号\t姓名\t平时成绩\t期末成绩\t总成绩" << endl;for (int i = 0; i < students.size(); i++) {cout << students[i].id << "\t" << students[i].name << "\t";cout << fixed << setprecision(2) << students[i].score1 << "\t\t" << students[i].score2 << "\t\t" << students[i].total << endl;}}// 统计信息void statistics() {int count = students.size();double sum1 = 0, sum2 = 0, sum3 = 0;double max1 = 0, max2 = 0, max3 = 0;double min1 = 100, min2 = 100, min3 = 100;int cnt1[7] = {0}, cnt2[11] = {0};if (count == 0) {cout << "没有学生信息!" << endl;return;}for (int i = 0; i < count; i++) {sum1 += students[i].score1;sum2 += students[i].score2;sum3 += students[i].total;max1 = max(max1, students[i].score1);max2 = max(max2, students[i].score2);max3 = max(max3, students[i].total);min1 = min(min1, students[i].score1);min2 = min(min2, students[i].score2);min3 = min(min3, students[i].total);if (students[i].total < 60) {cnt1[0]++;} else {cnt1[(int)(students[i].total - 60) / 10 + 1]++;}if (students[i].score1 < 60) {cnt2[0]++;} else {cnt2[(int)(students[i].score1 - 60) / 10 + 1]++;}if (students[i].score2 < 60) {cnt2[0]++;} else {cnt2[(int)(students[i].score2 - 60) / 10 + 1]++;}}double avg1 = sum1 / count;double avg2 = sum2 / count;double avg3 = sum3 / count;cout << "总成绩:" << endl;cout << "最高分:" << max3 << endl;cout << "最低分:" << min3 << endl;cout << "平均分:" << avg3 << endl;cout << "分数段分布情况:" << endl;cout << "<60: " << cnt1[0] << endl;for (int i = 1; i <= 10; i++) {cout << i * 10 << "-" << i * 10 + 9 << ": " << cnt1[i] << endl;}cout << "平时成绩:" << endl;cout << "最高分:" << max1 << endl;cout << "最低分:" << min1 << endl;cout << "平均分:" << avg1 << endl;cout << "分数段分布情况:" << endl;cout << "<60: " << cnt2[0] << endl;for (int i = 1; i <= 10; i++) {cout << i * 10 << "-" << i * 10 + 9 << ": " << cnt2[i] << endl;}cout << "期末成绩:" << endl;cout << "最高分:" << max2 << endl;cout << "最低分:" << min2 << endl;cout << "平均分:" << avg2 << endl;cout << "分数段分布情况:" << endl;cout << "<60: " << cnt2[0] << endl;for (int i = 1; i <= 10; i++) {cout << i * 10 << "-" << i * 10 + 9 << ": " << cnt2[i] << endl;}}
};// 教师类,包含课程信息和学生信息管理功能
class Teacher {
public:string password; // 密码Course course; // 课程信息// 构造函数,从文件中读取数据Teacher(string c, string n) : course(c, n) {ifstream ifs("data.bin", ios::binary);if (!ifs) {cout << "没有保存的数据!" << endl;return;}while (true) {Student s("", "");ifs.read((char*)&s, sizeof(Student));if (ifs.eof()) {break;}course.addStudent(s);}ifs.close();}// 添加学生信息void addStudent(string id, string name, double s1, double s2) {Student s(id, name, s1, s2);course.addStudent(s);cout << "添加学生信息成功!" << endl;}// 修改学生信息void modifyStudent(string id, double s1, double s2) {course.modifyStudent(id, s1, s2);}// 删除学生信息void deleteStudent(string id) {course.deleteStudent(id);}// 显示所有学生信息void showStudents() {course.showStudents();}// 统计信息void statistics() {course.statistics();}// 保存数据到文件void saveData() {ofstream ofs("data.bin", ios::binary);for (int i = 0; i < course.students.size(); i++) {ofs.write((char*)&course.students[i], sizeof(Student));}ofs.close();cout << "数据保存成功!" << endl;}
};// 学生类,包含查询成绩信息
class Student {
public:string id; // 学号string name; // 姓名vector<Course*> courses; // 所选课程指针列表Student(string i, string n) : id(i), name(n) {}// 添加所选课程void addCourse(Course* c) {courses.push_back(c);}// 查询成绩信息void queryScore() {cout << "学生姓名:" << name << endl;for (int i = 0; i < courses.size(); i++) {cout << "课程名称:" << courses[i]->name << endl;cout << "平时成绩:" << findScore(id, courses[i]->students, 1) << endl;cout << "期末成绩:" << findScore(id, courses[i]->students, 2) << endl;cout << "总成绩:" << findScore(id, courses[i]->students, 3) << endl;}}private:// 查找指定学生的成绩double findScore(string id, vector<Student>& students, int type) {for (int i = 0; i < students.size(); i++) {if (students[i].id == id) {switch (type) {case 1:return students[i].score1;case 2:return students[i].score2;case 3:return students[i].total;}}}return -1; // 没有找到对应学生的成绩}
};const int MAX_TEACHERS = 100; // 最大教师数量
const int PASSWORD_LENGTH = 6; // 密码长度//密码保护模块的示例代码,包括密码加密、验证和修改功能。在本示例中,我们使用了数组来存储密码文件中的加密后的密码,并且通过类来封装密码保护模块的功能。
class PasswordProtector {
private:char encrypted_password[PASSWORD_LENGTH+1]; // 存储加密后的密码
public:PasswordProtector() { // 构造函数,将初始密码“123456”加密并存储encrypt("123456");}bool verifyPassword(char* password) { // 验证密码是否正确char encrypted_input[PASSWORD_LENGTH+1];encrypt(password, encrypted_input);return strcmp(encrypted_input, encrypted_password) == 0;}void changePassword(char* new_password) { // 修改密码encrypt(new_password);updatePasswordFile();}
private:void encrypt(char* password, char* output = NULL) { // 加密函数if (output == NULL) output = encrypted_password;for (int i = 0; i < PASSWORD_LENGTH; i++) {output[i] = password[i] ^ 0x5A;}output[PASSWORD_LENGTH] = '\0';}void updatePasswordFile() { // 更新密码文件(这里用输出到控制台代替)cout << "密码文件已更新" << endl;}
};class TeacherManager {
private:Teacher teachers[MAX_TEACHERS];int teacher_count;PasswordProtector password_protector;
public:TeacherManager() { // 构造函数,初始化教师数量为0teacher_count = 0;}void addTeacher(Teacher t) { // 添加教师teachers[teacher_count++] = t;}bool login() { // 登录系统char password[PASSWORD_LENGTH+1];cout << "请输入密码:";for (int i = 0; i < PASSWORD_LENGTH; i++) {password[i] = getchar();putchar('*');}password[PASSWORD_LENGTH] = '\0';cout << endl;return password_protector.verifyPassword(password);}void changePassword() { // 修改密码char password[PASSWORD_LENGTH+1];cout << "请输入原密码:";for (int i = 0; i < PASSWORD_LENGTH; i++) {password[i] = getchar();putchar('*');}password[PASSWORD_LENGTH] = '\0';cout << endl;if (!password_protector.verifyPassword(password)) {cout << "密码错误,无法修改" << endl;return;}cout << "请输入新密码:";for (int i = 0; i < PASSWORD_LENGTH; i++) {password[i] = getchar();putchar('*');}password[PASSWORD_LENGTH] = '\0';cout << endl;password_protector.changePassword(password);}
};