课程管理系统设计(windows系统)

1. 介绍

本项目使用 C++ 实现一个课程管理系统,这个项目会学习C++的很多特性,同时可以熟悉Linux下的C++语言编译方法及简单的Makefile编写(以后会完善)。

2. 项目需求

编写一个课程管理程序,程序具备下述基本功能:

  1. 程序运行后可以循环输入操作命令
  2. 操作命令输入0,打印出程序帮助信息,即每个操作命令的作用
  3. 操作命令输入1,打印出程序中存储的所有课程ID和课程名
  4. 输入2,打印出课程数量
  5. 输入3,打印出名字最长的课程信息,如果有多个相同长度的课程名请都打印出
  6. 输入4,删除最后一个课程,如果没有课程需要返回错误信息
  7. 输入5,退出程序

在上述基本功能之外的附加功能:

  1. 课程包含基础课,项目课,评估课不同的类型
  2. 课程ID唯一,需要自动生成

需求很简单,我们完全不需要复杂的面向对象也可以实现,但为了尽可能多的应用C++的知识点,会进行“过度设计”,目的是让大家尽可能多的了解C++的知识如何应用到实际的代码场景中。

一、针对这个项目,我们首先需要知道我们要做什么,要达到什么样的效果。根据项目要求,我们要做的就是输出一系列帮助信息,每一条帮助信息对应一个功能,对于每个功能,我们需要编写函数实现。项目要求:默认输出全部帮助信息,根据帮助信息中显示的命令行,输入相应的命令后,根据命令判断以及相应的函数处理,然后输出对应的操作。这个项目的重点是实现基础课的相关操作,为了能够体现项目的可扩展性和锻炼C++编程的技能,又定义了扩展接口,即项目课和评估课等不同的类型(即为基础课的派生类)。同时由于要求课程id是唯一的,需要将课程id定义为static变量,并在类的外部初始化。

二、根据项目功能要求,可以进行模块划分,分成两个模块:命令输入及处理和课程存储及管理。既而得出类的划分,分为课程类、课程管理类和命令管理类。课程对象存储每个课程的信息,课程管理对象对课程列表进行维护和管理,命令管理对象对命令进行管理。具体来说:

1、课程类:类成员需要包括课程Id和课程名称,类成员函数至少包括构造函数(参数为课程名称)、拷贝构造函数、返回和设置课程名称、获得课程id和打印课程信息函数(需要重载operator<<)等。

2、课程管理类:类成员至少包含课程列表,类成员函数至少包括构造函数(参数为课程对象vector容器)、获取课程数目、添加课程(参数为课程名称或课程对象)、删除课程(删除最新课程、指定id或指定名称)、打印课程列表、打印课程(最长名称、指定id或指定名称)等。

3、命令管理类:类成员至少需要命令列表和课程管理对象,类成员函数至少包括初始化函数(课程及命令信息初始化)、打印帮助信息和命令处理函数。 现在根据现有的类的划分,每个类都有.cpp和.h,然后在定义一个Cmd.h,其中定义所有支持的命令数字,还需要主函数main.cpp和Makefile文件。说到这里,这个项目的整体架构已经成形,接下来就是如何实现。 这里附上每个类.cpp的具体实现,一句一句敲上的,记录一下。

 1 //------------------------------Course.cpp-------------------------------------
 2 #include<iostream>
 3 #include"Course.h"
 4 using namespace std;
 5 // Course 类成员函数
 6 //初始化静态成员,默认第一个课程Id为1
 7 int Course::currentId = 1;
 8 //课程类构造函数
 9 Course::Course()
10 {
11     //将currentId当前值赋值给id,再将currentId自增
12     id = currentId++;
13     //默认课程名称为空字符串
14     name = "";
15 }
16 //课程类拷贝构造函数
17 Course::Course(const Course& course)
18 {
19     id = course.GetId();
20     name = course.GetName();
21 }
22 //打印课程信息
23 void Course::PrintInfo() const{
24     cout<<"Course: "<< id <<" : "<< name << endl;
25 }
26 //友元函数:读取输入创建新的课程
27 void read(istream& is, Course& item){
28     is >> item.name;
29 }
30 //友元函数:操作符<<重载函数,当cout<<输出课程信息时使用
31 ostream& operator<<(ostream& os, const Course& course)
32 {
33     os << "Course: "<< course.id <<" : " << course.name;
34     return os;
35 }
36 //ProjectCourse 类成员函数
37 //打印课程信息
38 void ProjectCourse::PrintInfo() const{
39     cout<<"ProjectCourse: "<< id <<" : "<<name<<" : "<<tag<< endl;
40 }
41 //JudgeCourse 类成员函数
42 //打印课程信息
43 void JudgeCourse::PrintInfo() const{
44     cout<<"JudgeCourse: "<< id <<" : "<<name<<" : "<<time<<endl;
45 }
  1 //---------------------------------------CourseManager.cpp--------------------------
  2 #include<stdexcept>
  3 #include<iostream>
  4 #include "CourseManager.h"
  5 
  6 using namespace std;
  7 
  8 //构造函数,参数为课程vector
  9 CourseManager::CourseManager(const vector<Course>& course){
 10     for(auto curs = course.begin();curs!=course.end();curs++)
 11         courseList.push_back(*curs);
 12 }
 13 //添加课程函数(参数为课程名称)
 14 void CourseManager::AddCourse(const string& courseName){
 15     Course course(courseName);
 16     courseList.push_back(course);
 17 }
 18 //添加课程函数(参数为课程对象)
 19 void CourseManager::AddCourse(const Course& course){
 20     courseList.push_back(course);
 21 }
 22 
 23 //删除最后一个课程
 24 void CourseManager::RemoveLast(){
 25     try
 26     {
 27         //如果课程非空,则删除最后一门课程
 28         if(!courseList.empty()){
 29             courseList.pop_back();
 30             cout<<"Deleted successfully!"<<endl;
 31         }
 32         //如果课程为空,则抛出异常被catch捕获
 33         else{
 34             throw runtime_error("Deleted error, there is no course!");
 35         }
 36     }
 37     catch(runtime_error err){
 38         cout<<err.what()<<endl;
 39     }
 40 }
 41 //删除课程:删除指定id的课程
 42 void CourseManager::RemoveById(int id){
 43     int index = FindCourse(id);
 44     if(index>0)
 45         courseList.erase(courseList.begin()+index);
 46     else
 47         cout<<"NOT FOUND"<<endl;
 48 }
 49 //删除课程:删除指定名称的课程
 50 void CourseManager::RemoveByName(const string& name){
 51     int index = FindCourse(name);
 52     if(index>0)
 53         courseList.erase(courseList.begin()+index);
 54     else
 55         cout<<"NOT FOUND"<<endl;
 56 }
 57 //打印课程列表
 58 void CourseManager::PrintAllCourse(){
 59     cout<<"CourseList: "<<endl;
 60     //遍历courseList,打印出所有course信息
 61     for(auto curs = courseList.begin();curs!=courseList.end();curs++)
 62         cout<<*curs<<endl;
 63 }
 64 //打印指定课程(指定id)
 65 void CourseManager::PrintCourse(int id){
 66     int index = FindCourse(id);
 67     if(index > 0)
 68         cout<<courseList[index]<<endl;
 69     else
 70         cout<<"NOT FOUND"<<endl;
 71 }
 72 //打印指定课程(指定名称)
 73 void CourseManager::PrintCourse(const string& name){
 74     int index = FindCourse(name);
 75     if(index>0)
 76         cout<<courseList[index]<<endl;
 77     else
 78         cout<<"NOT FOUND"<<endl;
 79 }
 80 //打印最长名称课程函数
 81 void CourseManager::PrintLongName(){
 82     int maxLen = 0;
 83     //遍历courseList,查找最长名称
 84     for(auto curs = courseList.begin();curs!=courseList.end();curs++){
 85         int currentLen = curs->GetName().size();
 86         if(currentLen>maxLen)
 87             maxLen = currentLen;
 88     }
 89     //遍历courseList,打印最长名称课程
 90     for(auto curs = courseList.begin();curs!=courseList.end();curs++){
 91         if(curs->GetName().size()==maxLen)
 92             cout<<*curs<<endl;
 93     }
 94 }
 95 //根据id查找课程,返回课程在vector的索引
 96 int CourseManager::FindCourse(int id){
 97     for(int i=0;i<courseList.size();i++){
 98         if(courseList[i].GetId()==id)
 99             return i;
100     }
101     return -1;
102 }
103 //根据名称查找课程,返回课程在vector的索引
104 int CourseManager::FindCourse(const string& name){
105     for(int i=0;i<courseList.size();i++){
106         if(courseList[i].GetName()==name)
107             return i;
108     }
109     return -1;
110 }
 1 //------------------------------------CmdManager.cpp-----------------------------
 2 #include<iostream>
 3 #include "CmdManager.h"
 4 
 5 using namespace std;
 6 
 7 //初始化函数
 8 void CmdManager::Init(){
 9     //初始化课程列表
10     manager.AddCourse("Linux");
11     manager.AddCourse("NodeJS");
12     manager.AddCourse("C++");
13     manager.AddCourse("Python");
14     manager.AddCourse("Spark");
15     manager.AddCourse("Hadoop");
16     manager.AddCourse("Ruby");
17     manager.AddCourse("Java");
18     //初始化命令列表
19     cmdMap.insert(pair<CourseCmd,string>(Cmd_PrintHelp,"Help Info"));
20     cmdMap.insert(pair<CourseCmd,string>(Cmd_PrintCourse,"Course List"));
21     cmdMap.insert(pair<CourseCmd,string>(Cmd_PrintCourseNum,"Course Number"));
22     cmdMap.insert(pair<CourseCmd,string>(Cmd_PrintLongName,"Longest Course Name"));
23     cmdMap.insert(pair<CourseCmd,string>(Cmd_RemoveLastCourse,"Remove Last Course"));
24     cmdMap.insert(pair<CourseCmd,string>(Cmd_exit,"Exit"));
25 }
26 //打印帮助信息
27 void CmdManager::PrintAllHelp() const{
28     cout<<"Cmd List: "<<endl;
29     for(auto iter = cmdMap.begin();iter!=cmdMap.end();iter++)
30         cout<<iter->first<<":"<<iter->second<<endl;
31 }
32 //根据命令查询帮助信息
33 void CmdManager::PrintCmdHelp(const CourseCmd cmd) const{
34     auto iter = cmdMap.find(cmd);
35     if(iter != cmdMap.end())
36         cout<<iter->first<<":"<<iter->second<<endl;
37     else
38         cout<<"NOT FOUND"<<endl;
39 }
40 //处理命令操作,如果返回false则表示退出程序,其他情况返回true
41 bool CmdManager::HandleCmd(const CourseCmd cmd){
42     auto iter = cmdMap.find(cmd);
43     if(iter == cmdMap.end()){
44         cout<<"NOT FOUND"<<endl;
45         return true;
46     }
47     switch(cmd){
48         case Cmd_PrintHelp: PrintAllHelp();break;
49         case Cmd_PrintCourse: manager.PrintAllCourse();break;
50         case Cmd_PrintCourseNum: cout<<manager.GetCourseNum()<<endl;break;
51         case Cmd_PrintLongName: manager.PrintLongName();break;
52         case Cmd_RemoveLastCourse: manager.RemoveLast();break;
53         case Cmd_exit:return false;
54         default: return true;
55     }
56     return true;
57 }
 1 //-----------------------------------------main.cpp---------------------------------
 2 #include "CmdManager.h"
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     //输入的命令
 8     int cmd;
 9     //创建命令管理对象
10     CmdManager cmdManager;
11     cmdManager.Init();
12     //打印帮助信息
13     cmdManager.PrintAllHelp();
14     cout<<"New Command: ";
15     //进入主循环并处理输入信息
16     while(cin>>cmd){
17         if(cin.good()){
18             bool exitCode = cmdManager.HandleCmd((CourseCmd)cmd);
19             if(!exitCode)
20                 return 0;
21         }
22         cout<<"---------------------------------"<<endl;
23         cout<<"New Command: ";
24 
25         //清理输入流,避免刚才流中的字符影响后续输入
26         cin.clear();
27         cin.ignore();
28     }
29     return 0;
30 }

这里需要说明几点:

(1)在CourseManager类中需要存储课程列表,即包含一个Course容器,这里使用的vector容器,因为我们需要根据id和名称查找课程,并且需要删除最后的课程操作,顺序容器是最好的选择。

(2)在CmdManager类中包含课程管理对象和命令行列表,在这里优先选择关联容器map,因为map中存储的对象既是key又是value,并且不允许有重复的key,map存储的对象是必须具有可排序性的,默认采用less排序行为。这里使用map既要存储命令值又要存储相应的提示信息。

转载请注明出处: C++博客园:godfrey_88 http://www.cnblogs.com/gaobaoru-articles/
原文地址:https://www.cnblogs.com/gaobaoru-articles/p/5273983.html