学习c++后一直想写个学生管理系统,趁假期花了一天终于肝出了完整代码,让我对c++的理解更深了一层;写代码时真正体会到了内存操作的困难(想学java),但是还是通过几个巧妙的方法解决了内存问题,并在n次debug后终于调试出了完整代码,接下来我来介绍一下整个系统;
整个系统面向的对象是学生,所以就先写了一个学生类,并赋予了基本属性:学号,姓名,班级职责,还有显示个人信息的一个行为,又把学生分为三部分,普通学生,班干部,班长,当然这三类都具有学生的特性,所以我们可以通过继承学生类来获得相同的属性和行为;
想好了对象就要想一下具体实现的功能,该系统分为七大功能,分别是:
0.退出管理程序
1.增加学生信息
2.显示学生信息
3.删除学生信息
4.修改学生信息
5.查找学生信息
6.清空所有数据
为了实现这些功能,设计了一个管理员类StudentManager,将这些行为封装在一起,然后依次实现就行了;
这时就需要考虑一些细节了,在增加学生信息时,我们该如何增加呢?我在StudentManager这个类中增添了一个属性,一个vector的容器来存放增加的学生,这时就有问题了,学生既然分成了三大类,我们并不知道每次到底增加的是哪一类学生,那么vector到底该定位存放哪种学生类型呢?
这时面向对象三大特性之一的多态的优势就显现了出来,因为普通学生,班干部,班长这三类已经继承了学生类,所以我们只需要将学生类写为抽象类即可(把显示个人信息函数showinfo写为纯虚函数),这样我们vector容器只需要记录学生类的指针,通过多态的特性就可以实现同时存放普通学生,班干部,班长这三类的指针了;
构思完成后就可以写代码了,在写的过程中也遇到过很多问题,说几个主要的
1,因为我想要将学生信息每次更新后都可以存放到文件中,所以我不仅仅需要写一个save保存函数,还需要一个文件初始化函数init_std,因为一旦这次的代码运行成功后,学生信息就会存放到文件中,但是下一次运行就会将这次的学生信息覆盖,于是我们只要在程序开始运行时文件存在的情况下调用这个init函数,将文件原本的信息先读取到并存放到vector中,就可以实现对上一次信息的保存;这里都是些空间分配的问题,都是小细节,就不提了(闹心)
2,这个代码中的几个地方我一直避免使用delete释放内存,因为一旦delete就会出现一个warning警告,因为数据存放到了堆区,我猜测是抽象类Student和继承它的子类析构函数的问题,所以我先在Student中加了一个纯虚析构函数,又分别在下面几个类中重写了析构函数,虽然解决了warning,但是代码一走到delete就无法正常运行了;但是在最后还要清空所有数据,这当然包括分配的内存空间,还有什么办法?我突然想到了vector容器有一个swap函数,这个函数功能是交换两个vector容器的内容,但是我们可以用它的特点压缩内存,当然这需要用一个巧妙的方法实现,感兴趣的可以了解一下,我是在clean中使用了该功能
vector
(*this -> m_StdArray).swap(*this -> m_StdArray);
完成了内存的释放;
3,其他的问题还有很多,但是现在看来都也没有什么大不了的,只要在写代码时能够细心点,一定要可以熟练度的使用指针,在代码中我通过vector来存放增加的学生,这个相当于一个二级指针数组,所以再空间分配和调用时多多少少出现了很多小问题,浪费了我很多时间,尤其是加上this指针后,我很多时候就是蒙圈状态,但是最后还是调试出来了;
这是我第一次写这种对我来说稍稍大点的项目,让我感触最深的就是在完成整个代码中需要统筹全局,定义的每一个类都需要恰到好处,类与类之间的联系都需要严谨考虑,代码的每个函数都是非常好写的,但是又该如何整合起来?函数之间又有什么样的联系?每个函数又该放到哪个位置?我需要多定义那些变量?这些都是需要我考虑的;这比平时做题所需要考虑的方面多了好多好多,尤其是面向对象编程中封装起来就是一个整体,所以需要更全面的考虑和数次的调试;还有对内存的操控也更加困难,这就需要扎实的基本功了;我不能保证现在我代码的完美,但是对我来说这是一次非常好的历练,当然如果有代码方面的问题也欢迎在评论区提出来。
注:我是在vscode上编译运行的,所有功能正常,但是在dev上部分功能就会出现问题,所以要注意下编译环境;
代码如下:
#include#include #include #include using namespace std; #define FILENAME "stdFILE.txt" //定义生成文件名称 //学生类(抽象类) class Student { public: virtual void showInfo() = 0; //显示个人信息 // virtual ~Student() = 0; //定义纯虚析构函数保证释放堆区内存时不会发生内存泄漏 string StId; //学号 string m_name; //姓名 string m_Dept; //职责 }; //普通学生类 class Nomalstuden : public Student { public: Nomalstuden(string Id, string name, string dep); void showInfo(); //显示个人信息 // ~Nomalstuden() { // delete this; // } }; //班长类 class ClassPresident : public Student { public: ClassPresident(string Id, string name, string dep); void showInfo (); // ~ClassPresident() { // delete this; // } }; //班干部类 class Classleader : public Student { public: Classleader(string Id, string name, string dep); void showInfo (); // ~Classleader() { // delete this; // } }; //管理员类 class StudentManager { public: StudentManager();//构造函数 void Show_Menu(); //打印菜单界面 void Exit_System();//退出系统 void Addinfo(); //增加学生信息 void save(); //将学生信息保存到文件中 void init_Std(); //初始化学生 void show_Std(); //显示学生信息 void del_Std(); //删除学生信息 void mod_Std(); //修改学生信息 void find_Std(); //查找学生信息 void clean_File(); //清空文件 int IsExist(string id); //判断学号为id的学生信息是否存在,并返回该学生下标 ~StudentManager();//析构函数 vector *m_StdArray; //存放增加的学生信息 bool m_fileIsEmpty; //标记文件是否为空 }; //学生类纯虚析构的外部实现 // Student :: ~Student() { // delete this; // } //管理员函数实现 StudentManager :: StudentManager() { ifstream ifs; ifs.open(FILENAME, ios :: in); //如果文件不存在 if (!ifs.is_open()) { cout << "该文件不存在!" << endl; this -> m_fileIsEmpty = true; this -> m_StdArray = NULL; ifs.close(); return ; } //文件存在但是数据为空 char ch; ifs >> ch; //先读取一个字符 if (ifs.eof()) { cout << "该文件为空!" < m_fileIsEmpty = true; this -> m_StdArray = NULL; ifs.close(); return ; } //文件存在,并记录初始数据 this -> m_StdArray = new vector ; this -> init_Std(); } void StudentManager :: Show_Menu() { cout << "-------------------------------------------" << endl; cout << "------------ 欢迎使用学生管理系统! ----------" << endl; cout << "------------- 0.退出管理程序 -------------" << endl; cout << "------------- 1.增加学生信息 -------------" << endl; cout << "------------- 2.显示学生信息 -------------" << endl; cout << "------------- 3.删除学生信息 -------------" << endl; cout << "------------- 4.修改学生信息 -------------" << endl; cout << "------------- 5.查找学生信息 -------------" << endl; cout << "------------- 6.清空所有数据 -------------" << endl; cout << "-------------------------------------------" << endl; cout << endl; } void StudentManager :: Exit_System() { cout << "感谢您的使用!" << endl; // system("pause"); exit(-1); //退出系统 } void StudentManager :: Addinfo() { if (!this -> m_StdArray) this -> m_StdArray = new vector ; cout << "学生信息开始录入" << endl; int i = 1; while(true) { char flag; string id; string name; string dep; cout << "请输入第" << i << "个学生学号:" << endl; cin >> id; cout << "请输入第" << i << "个学生姓名:" << endl; cin >> name; cout << "请输入第" << i << "个学生职位:(班长or班干部or普通学生)" << endl; cin >> dep; Student *std = NULL; if (dep == "班长") { std = new ClassPresident(id, name, dep); } else if (dep == "班干部") { std = new Classleader(id, name, dep); } else if (dep == "普通学生") { std = new Nomalstuden(id, name, dep); } else { cout << "该学生职位不存在!信息录入结束!" < m_StdArray -> push_back(std); i++; this -> m_fileIsEmpty = false; //更新文件非空标记 cout << "是否继续录入信息?(y继续录入,n结束录入)" < > flag; if (flag == 'y') continue; else break; } cout << "成功添加了" << i - 1 << "名学生信息!" < save(); system("pause"); system("cls"); } void StudentManager :: save() { ofstream ofs; ofs.open(FILENAME, ios :: out); for (int i = 0; i < this -> m_StdArray -> size(); ++i) { ofs << this -> m_StdArray -> at(i) -> StId << " " << this -> m_StdArray -> at(i) -> m_name << " " << this -> m_StdArray -> at(i) -> m_Dept << endl; } ofs.close(); } void StudentManager :: init_Std() { ifstream ifs; ifs.open(FILENAME, ios :: in); string id; string name; string dep; while (ifs >> id && ifs >> name && ifs >> dep) { Student * std = NULL; if (dep == "班长") { std = new ClassPresident(id, name, dep); } else if (dep == "班干部") { std = new Classleader(id, name, dep); } else if (dep == "普通学生") { std = new Nomalstuden(id, name, dep); } this -> m_StdArray -> push_back(std); } this -> save(); } void StudentManager :: show_Std() { if (this -> m_fileIsEmpty) { cout << "文件不存在或者文件为空!" < for (int i = 0; i < this -> m_StdArray -> size(); ++i) { this -> m_StdArray -> at(i) -> showInfo(); } } system("pause"); system("cls"); } void StudentManager :: del_Std() { if (this -> m_fileIsEmpty) { cout << "文件不存在或者文件为空!" << endl; } else { cout << "请输入需要删除的学生学号:" << endl; string id; cin >>id; int index = this -> IsExist(id); if (index != -1) { this -> m_StdArray -> erase(this -> m_StdArray -> begin() + index); this -> save(); cout << "删除成功!" < cout << "删除失败,不存在该学号的学生!" < int len = this -> m_StdArray -> size(); int index = -1; for (int i = 0; i < len; ++i) { if (this -> m_StdArray -> at(i) -> StId == id) { index = i; break; } } return index; } void StudentManager :: mod_Std() { if (this -> m_fileIsEmpty) { cout << "文件不存在或者文件为空" < cout << "请输入需要修改的学生学号:" << endl; string id; cin >> id; int index = this -> IsExist(id); if (index != -1) { //delete this -> m_StdArray -> at(index); string newid; string newname; string newdep; Student *std = NULL; cout<< "搜索到学号为" << id << "的学生,请输入新学号:" << endl; cin >> newid; cout << "请输入新姓名:" < > newname; cout << "请输入新职责:" < > newdep; if (newdep == "班长") { std = new ClassPresident(newid, newname, newdep); } else if (newdep == "班干部") { std = new Classleader(newid, newname, newdep); } else if (newdep == "普通学生") { std = new Nomalstuden(newid, newname, newdep); } this -> m_StdArray -> at(index) = std; cout <<"修改成功!" << endl; this -> save(); } else { cout << "修改失败,不存在该学号的学生!" << endl; } } system("pause"); } void StudentManager :: find_Std() { if (this -> m_fileIsEmpty) { cout << "文件不存在或者文件为空" < cout << "请输入需要查找的学生学号:" << endl; string id; cin >> id; int index = this -> IsExist(id); if (index != -1) { cout<< "查找成功!该学生信息如下:" << endl; this -> m_StdArray -> at(index) ->showInfo(); } else { cout << "查找失败!该学生不存在!" < cout << "确定清空所有数据?" << endl; cout << "1,确定" < > selet; if (selet == 1) { ofstream ofs(FILENAME, ios :: trunc); ofs.close(); if (this -> m_StdArray) { this -> m_StdArray -> clear(); vector (*this -> m_StdArray).swap(*this -> m_StdArray); this -> m_fileIsEmpty = true; this -> m_StdArray = NULL; } cout << "清空成功!" << endl; } system("pause"); system("cls"); } StudentManager :: ~StudentManager() { if (this -> m_StdArray) { this -> m_StdArray -> clear(); delete[] this -> m_StdArray; this -> m_StdArray = NULL; } } //普通学生函数实现 Nomalstuden :: Nomalstuden(string Id, string name, string dep) { this -> StId = Id; this -> m_name = name; this -> m_Dept = dep; } void Nomalstuden :: showInfo() { cout << "学生学号:" << this -> StId << "t学生姓名:" << this -> m_name << "t学生职位:" << this -> m_Dept << "t学生任务:遵守班级纪律" << endl; } //班长函数实现 ClassPresident :: ClassPresident(string Id, string name, string dep) { this -> StId = Id; this -> m_name = name; this -> m_Dept = dep; } void ClassPresident :: showInfo () { cout << "学生学号:" << this -> StId << "t学生姓名:" << this -> m_name << "t学生职位:" << this -> m_Dept << "t学生任务:管理班干部,与辅导员对接,带领班级" << endl; } //班干部函数实现 Classleader :: Classleader(string Id, string name, string dep) { this -> StId = Id; this -> m_name = name; this -> m_Dept = dep; } void Classleader :: showInfo () { cout << "学生学号:" << this -> StId << "t学生姓名:" << this -> m_name << "t学生职位:" << this -> m_Dept << "t学生任务:履行自己的职责,和各科老师对接,管理班级学生" << endl; } //主函数 int main() { StudentManager stm; //实例化管理员 int choice; //存储用户选项 while(true) { stm.Show_Menu(); //调用打印界面成员函数 cout << "请输入您的选择:" << endl; cin >> choice; switch (choice) { case 0: //退出系统 stm.Exit_System(); break; case 1: //增加学生 stm.Addinfo(); break; case 2: //显示学生 stm.show_Std(); break; case 3: //删除学生 stm.del_Std(); break; case 4: //修改学生 stm.mod_Std(); break; case 5: //查找学生 stm.find_Std(); break; case 6: //清空文档 stm.clean_File(); break; default: system("cls"); //清屏操作 break; } } system("pause"); return 0; }



