本文根据题目要求,通过实现了一个教务管理系统。在由于题目中给出的一些不合理要求,代码存在冗余结构。最终程序能实现基本的用户登录、查看学生列表、修改信息等功能。
教务管理系统完整代码
本课程设计以软件工程方法为指导,采用了多文件结构和面向对象的程序设计方法,以C++语言技术为基础,熟练面向对象程序设计(C++)实验指导和c++程序设计语言教科书的内容,使用Visual Stdio 2019为主要开发工具,对职工工资管理系统进行了需求分析,总体设计,详细设计,最终完成系统的实现与测试。
本软件的使用者有三个,首先需要进行登录和密码校验,然后才有资格查看和修改数据。三个用户分别是教务处工作人员、主修系教务员、辅修系教务员,程序需要满足他们对学生基本信息的查看和修改需要。
全部功能列表如下
0:教务处工作人员:
0:查看学生列表;
1:查看学生信息;
2:修改学生信息;
3:删除学生信息;
4:重新选择身份;
5:更改密码;
6:退出系统。
1:主修系教务员:
0:查看学生列表;
1:查看学生信息;
2:录入主修成绩;
3:查看成绩优秀的同学;
4:查看需要补考的同学;
5:重新选择身份;
6:更改密码;
7:退出系统。
2:辅修系教务员:
0:查看学生列表;
1:查看学生信息;
2:设置辅修专业;
3:录入辅修成绩;
4:查看需要补考的同学;
5:重新选择身份;
6:更改密码;
7:退出系统。
3:退出系统。
文件结构
程序文件
mian.cpp //整体流程控制
base.h //学生的基本信息、主修科目、辅修科目对应的Base,First,Fbase三个类的声明
base.cpp //上述三个类的具体实现
index.h //索引类
index.cpp //索引类的实现
dialog.h //对话界面的声明
dialog.cpp //对话界面的实现
tool.h //一些经常被调用的函数的声明
tool.cpp //函数的实现
数据文件
student.txt //为自然数,保存学生的基本信息的一系列文件
major.txt //为自然数,保存学生的主修科目信息的一系列文件
mimor.txt //为自然数,保存学生的辅修科目信息的一系列文件
password.txt //保存用户密码
index.txt //索引文件的备份
每个学生的信息分为三个部分,即基本信息、主修科目分数、辅修科目分数,分别用三个类来实现Base、First、Fbase来实现这三个对象的功能。类的声明如下:
#pragma once
#include
#include"tool.h"
#include
using namespace std;
constexpr auto MDEPT_NUM = 5; //主修科目有5个
constexpr auto FDEP_NUM = 4;//辅修科目有4个
class Base
{
public:
void InfoInput(); //输入基本信息
void Info(); //显示基本信息
void save(string); //读取信息
void read(string); //保存信息
private:
long num=0; //学号
char name[20] ="NULL"; //姓名
int sex; //性别,0表示男,1表示女
int age; //年龄
char addr[30]; //地址
char mdept[30]; //主修专业
};
class First: public Base
{
public:
void MscoreInput(); //录入成绩
void display(); //显示成绩
int getscore(int); //获取单科成绩
void save(string); //保存文件
void read(string ); //读取文件
bool outstand(); //是否三门课达到85分,并且其他两门分数不低于70
bool resit(); //有一门不及格则返回值为真
private:
float Mscore[60] = {0};//主修分数
};
class Fbase:public Base
{
public:
void FdepSet(); //设置辅修专业名称
void FscoreInput(); //输入辅修专业分数
bool resit(); //有一门不及格则返回值为真
int getscore(int); //获取某一个辅修专业科目的分数
void display(); //展示辅修专业分数
void save(string); //保存数据
void read(string a); //读取数据
char fdep[30] = {'\0'};//辅修专业
private:
float Fscore[35] = {0};//辅修分数
};
要处理大量数据,需要建立索引,来实现对信息的查找,所以建立Index类来实现索引的建立和查找。
#pragma once
#include
#include"tool.h"
constexpr auto MAX_INDEX = 100;
class Index
{
public:
Index(); //建立索引,供初始化时使用
void create(); //建立索引,供已经实例化之后重建索引使用
int search(int); //按学号检索,并返回索引位置
int search(string); //按姓名检索,并返回索引位置
int select(); //引导用户输入并按输入类型查找
void show(); //显示全部索引列表
void show(int n); //显示单个学生的学号和姓名
private:
int num[MAX_INDEX]{};
string name[MAX_INDEX]{};
};
由于在函数编写过程中,经常有一些重复的程序片段,把这些片段整合在tool.h
文件中,以便调用。
bool interval(int a, int min, int max); //判断变量是否在区间内
int inputnumber(int a= 2147483647); //输入一个数字,并确保不发生错误,a为数值上限
float inputfloat(int a); //参数为数字上限
void clear(string); //清除一个学生的数据
此外,为了进行用户与系统的交互,编写了一系列对话函数,并整合到类Dialog
中。
#pragma once
#include"tool.h"
#include"index.h"
class Dialog
{
public:
int select(Index m); //选择学生序号
bool KeyCheck(int n); //检查密码,n为不同用户的代号
void KeyReset(int n); //更改密码,n为不同用户的代号
int logon(); //登录界面
int AdmissionOpt(); //教务处工作人员的对话框
int M_teacherOpt(); //主修专业教务员的对话框
int F_teacherOpt(); //辅修专业教务员的对话框
};
学生的基本信息采用“student+序号+.txt”的格式命名,每名学生的信息存储在相应的文件中,例如序号为0的学生信息文件名为“student0.txt”;主修科目信息和辅修科目信息同样采用类似的方式命名。“student.txt”记录的变量有六个,对应Base类中的num、name、sex、 age、addr、mdept六个变量。
程序的流程控制由main()
函数实现,程序的简要流程如下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NMD3J4XR-1611562775956)(E:\Documents\MD文稿\流程控制.png)]
程序开始所声明的对象如下:
Base student; //处理学生基本信息的对象
First major; //处理主修专业的对象
Fbase minor; //处理辅修专业的对象
int n; //由于传递索引的变量
bool logoned = false; //用户登录状态变量
Index index; //建立索引
Dialog dialog; //供调用的对话框系列函数
程序的流程控制通过while()
循环和 switch()
的嵌套来实现,并将变量logoned
作为循环判断依据。简化后的代码如下:
while (!logoned)//如未登录则开始登录会话
{
switch (dialog.logon())//调用登录对话框,选择登录身份
{
case 0://以下是招生处的功能
logoned = true; //已登录
while (logoned) //如已登录则开始会话,在后面的程序运行中,如果用户选择登出,则跳出循环
{
switch (dialog.AdmissionOpt())//根据用户输入,选择相应功能
{
case 0://展示学生列表
case 1://检索并查看信息
case 2://修改信息
case 3://删除信息
case 4://重新选择登录身份
logoned = false; //用户登出,跳出循环
break;
case 5: //更改密码
dialog.KeyReset(0);
break;
case 6:
return 0; //程序结束
default:
break;
}
}
break;//招生处功能模块结束
case 1://以下是主修教务员的功能
logoned = true;
while (logoned)
{
switch (dialog.M_teacherOpt())
{
case 0://查看学生列表
case 1://查看学生信息,选择学生序号,显示基本信息和主修科目分数
case 2://修改成绩信息并保存
case 3://筛选出成绩优秀的学生
case 4://筛选出需要补考的学生
case 5://重新选择身份
logoned = false;
break;
case 6://更改密码
case 7://退出程序
return 0;
default:
break;
}
}
break;//主修教务员模块结束
case 2://以下是辅修教务员的功能
logoned = true;
while (logoned)
{
switch (dialog.F_teacherOpt())
{
case 0:
case 1://查看学生信息
case 2://设置辅修科目
case 3://录入辅修成绩
case 4://查看需要补考人员
case 5://重新选择身份
logoned = false;
break;
case 6://更改密码
dialog.KeyReset(2);
break;
case 7://退出程序
return 0;
default:
break;
}
}
break;//辅修教务员功能模块结束
case 3://用户选择退出系统
return 0;
case -1://密码校验失败,重新选择身份
logoned = false;
break;
default:
break;
}
}
}
索引的建立是的进行数据管理的关键,具体的建立方法如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBoWcPW1-1611562775962)(E:\Documents\MD文稿\建立索引.png)]
Index::Index()
{
create(); //在对象声明时即建立索引
}
void Index::create() //程序运行过程中需要更新索引,即可使用此函数
{
ifstream file;
ofstream outfile;
outfile.open("data\\index.txt");
for (int i = 0; i < MAX_INDEX; i++)
{
file.open("data\\student"+to_string(i)+".txt",ios::in);//按命名规则依次打开数据文件
if (file.is_open())
{
file >> num[i]>>name[i] ;//如果成功打开则读取数据保存至数组中相应的位置上
}
else
{
num[i] = 0; //未成功打开则相应的位置设置为默认值
name[i] ="NULL";
}
file.close();
outfile << "[id]\t" << i << "\n[num]\t" << num[i] << "\n[name]\t" <
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpLF0jT3-1611562775966)(E:\Documents\MD文稿\查找索引.png)]
索引建立之后,最基本的功能是查找数值在数组中的位置。Index
类提供了两种查找方式,可以查找姓名或学号所在的位置,通过对这两个函数的调用,还形成int Index::select()
方法,直接供用户查找,下面是程序代码。
int Index::search(int n)
{
for (int i = 0; i < MAX_INDEX; i++)
{
if (num[i] == n) return i;
}
return -1;
}
int Index::search(string n)
{
for (int i = 0; i < MAX_INDEX; i++)
{
if (name[i]==n) return i;
}
return -1;
}
int Index::select()
{
int n,i;
string str;
cout << "请输入要查看学生学号或姓名:" ;
if (!(cin>>n))//尝试按int型读取用户的输入
{
cin.clear(); //清除错误警告
cin >> str; //按字符串读取输入的内容
i = search(str);//调用姓名查找方法
}
else
{
i = search(n);//调用学号查找方法
}
return i;
}
此外,Index
类还提供展示索引列表的功能
void Index::show()
{
for (int i = 0; i < MAX_INDEX; i++)
{
if (num[i] == 0) continue;
cout << "序号:" <
Base
类提供了对学生基本信息的读取、保存、展示、录入的方法。
具体实现如下:
void Base::InfoInput() //引导用户输入信息
{
cout << "请输入该生的学号:" << endl;
num = inputnumber();
cout << "请输入该生的姓名:" << endl;
cin >> name;
cout << "请输入该生的性别(0表示男,1表示女):" << endl;
sex = inputnumber(1);
cout << "请输入该生的年龄:" << endl;
age = inputnumber(200);
cout << "请输入该生的地址:" << endl;
cin >> addr;
cout << "请输入该生的主修专业:" << endl;
cin >> mdept;
cout << "学生" << name << "的基本信息录入完成\n";
}
void Base::Info() //展示相关信息
{
if (num == 0)
{
cout << "信息尚未录入!" << endl;
}
else
{
cout << "学号:" << num << "\n姓名:" << name << "\n性别:";
if (sex) cout << "女";
else cout << "男";
cout << "\n年龄:" << age << "\n地址:" << addr << "\n主修专业:" << mdept << endl;
}
}
void Base::save(string a)
{
ofstream outfile;
outfile.open("data\\student" + a + ".txt", ios::out | ios::trunc);
outfile << num << endl << name << endl << sex << endl << age << endl << addr << endl << mdept << endl;
outfile.close();
}
void Base::read(string a)
{
ifstream infile;
infile.open("data\\student" + a + ".txt", ios::in);
if (infile.good())
{
infile >> num >> name >> sex >> age >> addr >> mdept;
}
infile.close();
}
First
类除了对主修分数的读取、保存、展示和录入功能,还提供了对学生是否成绩优秀、是否需要补考的判断方法bool First::outstand()
和bool First::resit()
。具体实现方法如下:
bool First::outstand()
{
int t;
int m = 0;
int n = 0;
for (int i = 0; i < MDEPT_NUM; i++)
{
t = getscore(i);
if (t >= 85) m++;
if (t < 70) n++;
}
if (m >= 3 && n <= 0) return true;
else return false;
}
bool First::resit()
{
bool record = false;//检查是否已经被记录
bool fail = false;//检查是否不及格
for (int i = 0; i < MDEPT_NUM; i++)
{
if (getscore(i) < 60) fail = true;
if (getscore(i) > 0) record = true;
}
return fail&&record;
}
学生辅修科目的处理由Fbase
类实现,实现方法与前两个类相似,这里不再赘述。
登录界面是用户打开程序之后的主界面,int Dialog::logon()
根据提示用户输入不同选项,并产生相应的返回值,决定主函数的跳转。当用户输入0
、1
、2
时,将以进行密码检查,密码正确即可进入相应功能界面,否则要重新登录。
int Dialog::logon()//登录系统
{
int a;
cout << "欢迎登录教务管理!" << endl;
cout << "请选择您的身份\n0:招生办工作人员\n1:主修系教务员\n2:辅修系教务员\n3:退出系统" << endl;
a = inputnumber(3);
if (a == 3) return 3;//3对应退出系统选项
else if (KeyCheck(a))
{
cout << "登录成功!" << endl;
return a;
}
else
{
cout << "密码错误请重新登录" << endl;
return -1;
}
}
用户密码是一个整数,进行密码检查时,会从文件读取已保存的密码,然后提示用户输入密码,当用户选择的身份与密码相对于时,则通过校验。
bool Dialog::KeyCheck(int n)//n为不同用户的代号
{
int password[3]{};
int key;
ifstream infile;
infile.open("data\\password.txt", ios::in);
if (infile.good())
{
infile >> password[0] >> password[1] >> password[2];
}
infile.close();
cout << "请输入密码:";
key = inputnumber();
if (password[n] == key) return true;
else return false;
}
当用户以某一身份登录成功后,将会进行引导用户进行功能选择,返回值将用于控制主程序的跳转。下面是主修系教务员的功能选择界面的代码。
int Dialog::M_teacherOpt()
{
int a;
cout << "请输入要进行的操作\n0:查看学生列表\n1:查看学生信息\n2:录入主修成绩\n3:查看成绩优秀的同学\n4:查看需要补考的同学\n5:重新选择身份\n6:更改密码\n7:退出系统" << endl;
a = inputnumber(7);
return a;
}
当用户选择查看学生列表时,直接调用Index
的 void Index::show()
功能,这里不再赘述。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WcOwFKRG-1611562775969)(E:\Documents\MD文稿\查看单个学生信息.png)]
case 1: //检索并查看信息
n = index.select(); //让用户通过输入学号或姓名来检索要展示的数据
if (n == -1) //返回值为“-1”代表未检索到相关信息
{
cout << "此信息不存在!" << endl;
break;
}
student.read(to_string(n)); //读取磁盘信息到对象
student.Info(); //展示读取到的信息
break;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SZoxgn3Y-1611562775971)(E:\Documents\MD文稿\修改信息.png)]
case 2: //修改信息
n = index.select();
if (n==-1)
{
cout << "信息不存在,请录入" << endl;
n=index.search(0); //如果学号不存在,则选择一个空位置。
}
else
{
cout << "信息已存在,是否修改?\n不修改请输入0,修改请输入1" << endl;
if(inputnumber(1)==0) break;
}
student.InfoInput(); //输入对象信息
student.save(to_string(n)); //保存相应信息
index.create(); //重新建立索引
break;
case 3: //删除信息
n = index.select();;
if (n==-1)
{
cout << "此人信息不存在!" << endl;
break;
}
else
{
clear(to_string(n)); //调用函数清空相应信息
index.create(); //重建索引
cout << "删除成功" << endl;
}
break;
case 2://修改成绩信息并保存
n = index.select(); //查找学生序号
if (n==-1) //如果基本信息尚未录入,则不能修改成绩
{
cout << "此人不存在!" << endl;
break;
}
major.MscoreInput(); //输入成绩
major.save(to_string(n)); //按命名规则保存
break;
case 3://筛选出成绩优秀的学生
for (int i = 0; i < MAX_INDEX; i++)
{
major.read(to_string(i)); //遍历文件
if (major.outstand()) //调用判断方法
{
index.show(i); //展示姓名和学号
major.display(); //展示分数
}
}
cout << "以上是成绩优秀的学生。\n" << endl;
break;
case 4://筛选出需要补考的学生
for (int i = 0; i < MAX_INDEX; i++)
{
major.read(to_string(i));
if (major.resit())
{
index.show(i);
major.display();
}
}
cout << "以上是需要补考的学生。\n" << endl;
break;
case 2://设置辅修科目
n = index.select();
if (n == -1)
{
cout << "此人不存在!" << endl;//如果基本信息尚未录入,则不能修改成绩
break;
}
minor.FdepSet();
minor.save(to_string(n));
break;
本软件可在windows X86/64平台上运行;
运行需保证同目录下存在名为“data”的文件夹,以保证数据文件的正常存储和读取;
用户密码是默认是“0”;