职工管理系统
在进一步深入学习C++的过程中,我们探索了面向对象编程的思想,并掌握了类和对象的核心概念。我们了解了如何使用封装来保护数据、对象的初始化和清理机制、C++对象模型和this
指针的作用。此外,我们还学习了友元、运算符重载、继承、多态以及文件操作。这些知识点将帮助我们构建更复杂的系统,提升编程的结构化和模块化。
为了实践这些新知识,本项目将基于多态性来实现一个常见的期末大作业项目——职工管理系统。这个管理系统可以帮助公司管理所有员工的信息,记录职工的基本情况并简化人事操作流程。
在本教程中,我们将利用C++的面向对象特性来设计和实现一个多态的职工管理系统。系统中,公司职工分为三类:普通员工、经理和老板,每类职工的职责各不相同,具体如下:
- 普通员工职责:完成经理分配的任务。
- 经理职责:执行老板布置的任务,同时将任务下发给普通员工。
- 老板职责:管理公司所有事务,确保公司正常运作。
在此管理系统中,我们需要实现以下核心功能:
- 增加职工信息:实现批量添加职工功能,将每个职工的编号、姓名和部门编号记录到文件中。
- 显示职工信息:展示公司所有职工的基本信息。
- 删除离职职工:根据职工编号删除指定的职工记录。
- 修改职工信息:根据编号修改职工的个人信息。
- 查找职工信息:支持根据职工编号或姓名进行查询,快速定位相关人员信息。
- 按照编号排序:对职工按照编号进行排序,用户可选择不同的排序规则。
- 清空所有文档:清空文件中记录的职工信息,删除前需确认,以防误删。
- 退出管理程序:结束当前的管理系统,退出程序。
系统的界面效果图如下所示:
用户可以通过不同的选项来操作系统,执行相应的功能。
1、创建管理类
在本项目中,我们将采用分文件的结构来构建整个职工管理系统,这种方式比将所有代码放在单一 .cpp
文件中更有优势。分文件法便于代码维护,每个文件专注于不同的功能模块,使项目结构更清晰、逻辑更分明。
管理类负责的内容如下:
- 展示菜单界面,与用户进行交互
- 实现对职工的增、删、改、查操作
- 处理文件的读写,保存和加载职工信息
首先,我们在项目中创建两个文件夹:一个用于存放头文件,另一个用于存放源文件。在头文件目录中,创建workerManager.h
,在源文件目录中创建workerManager.cpp
,分别定义和实现管理类。
以下是workerManager.h
中管理类的初始定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #pragma once #include<iostream> using namespace std;
class WorkerManager { public:
WorkerManager();
~WorkerManager();
};
|
此处,WorkerManager
类包含构造函数和析构函数的声明,用于初始化和清理管理类的实例。
源文件实现:
在workerManager.cpp
中,我们为构造函数和析构函数提供空实现,以便为后续功能扩展提供基础。
1 2 3 4 5 6 7 8 9 10
| #include "workerManager.h"
WorkerManager::WorkerManager() { }
WorkerManager::~WorkerManager() { }
|
至此,职工管理类的基本结构已完成。
2、菜单功能
功能描述:与用户的沟通界面,如图所示:
2.1 添加成员函数
在管理类workerManager.h中添加成员函数 void Show_Menu();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void WorkerManager::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 << "************* 7.清空所有文档 *************" << endl; cout << "********************************************" << endl; cout << endl; }
|
3、创建职工类
在职工管理系统中,职工分为三类:普通员工、经理和老板。我们将这三种类型的职工抽象成一个基类(Worker
),并通过多态来管理不同类型的职工。每种职工类型将拥有各自的岗位职责和工作描述,从而实现灵活的扩展性和可维护性。
3.1 创建职工抽象类
职工的分类为:普通员工、经理、老板
将三种职工抽象到一个类(worker)中,利用多态管理不同职工种类
职工的属性为:职工编号、职工姓名、职工所在部门编号
职工的行为为:岗位职责信息描述,获取岗位名称
我们将Worker
类作为抽象基类,定义职工的基本属性和行为:
- 属性:职工编号、职工姓名、职工所在部门编号
- 行为:显示个人信息、获取岗位名称(纯虚函数)
在头文件文件夹下创建worker.h
文件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #pragma once #include <iostream> #include <string> using namespace std;
class Worker { public: virtual void showInfo() = 0;
virtual string getDeptName() = 0;
int m_Id; string m_Name; int m_DeptId; };
|
该基类的纯虚函数showInfo
和getDeptName
要求子类必须实现具体的行为描述和岗位名称获取功能。
3.2 创建普通员工类
普通员工类继承自Worker
抽象类,并实现父类中的纯虚函数。普通员工的职责是完成经理分配的任务。
在头文件和源文件文件夹下分别创建employee.h
和employee.cpp
文件。
employee.h中代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #pragma once #include <iostream> #include <string> #include "worker.h"
class Employee : public Worker { public: Employee(int id, string name, int dId);
virtual void showInfo();
virtual string getDeptName(); };
|
employee.cpp
代码:
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
| #include "employee.h" #include <iostream> #include <string> using namespace std;
Employee::Employee(int id, string name, int dId) { this->m_Id = id; this->m_Name = name; this->m_DeptId = dId; }
void Employee::showInfo() { cout << "姓名:" << this->m_Name << "\t职工编号:" << this->m_Id << "\t岗位:" << this->getDeptName() << "\t\t职责:完成经理的任务" << endl; }
string Employee::getDeptName() { return string("员工"); }
|
3.3 创建经理类
经理类继承自Worker
抽象类,并实现父类中的纯虚函数。经理的职责是执行老板布置的任务,并将任务下发给普通员工。
在头文件和源文件文件夹下分别创建manager.h
和manager.cpp
文件。
manager.h
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #pragma once #include <iostream> #include <string> #include "worker.h"
class Manager : public Worker { public: Manager(int id, string name, int dId);
virtual void showInfo();
virtual string getDeptName(); };
|
manager.cpp
代码:
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
| #include "manager.h" #include <iostream> #include <string> using namespace std;
Manager::Manager(int id, string name, int dId) { this->m_Id = id; this->m_Name = name; this->m_DeptId = dId; }
void Manager::showInfo() { cout << "姓名:" << this->m_Name << "\t职工编号:" << this->m_Id << "\t岗位:" << this->getDeptName() << "\t\t职责:完成老板的任务并下发给员工" << endl; }
string Manager::getDeptName() { return string("经理"); }
|
3.4 创建老板类
老板类继承自Worker
抽象类,并实现父类中的纯虚函数。老板的职责是管理公司所有事务,确保公司运作顺利。
在头文件和源文件文件夹下分别创建boss.h
和boss.cpp
文件。
boss.h
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #pragma once #include <iostream> #include <string> #include "worker.h"
class Boss : public Worker { public: Boss(int id, string name, int dId);
virtual void showInfo();
virtual string getDeptName(); };
|
boss.cpp
代码:
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
| #include "boss.h" #include <iostream> #include <string> using namespace std;
Boss::Boss(int id, string name, int dId) { this->m_Id = id; this->m_Name = name; this->m_DeptId = dId; }
void Boss::showInfo() { cout << "姓名:" << this->m_Name << "\t职工编号:" << this->m_Id << "\t岗位:" << this->getDeptName() << "\t职责:管理公司的所有事务" << endl; }
string Boss::getDeptName() { return string("首席执行官"); }
|
至此,我们已经成功创建了包含普通员工、经理和老板的职工类体系,每个子类都继承了Worker
抽象类,并实现了岗位职责的描述方法。这种基于多态的设计使得管理系统可以灵活扩展,方便添加新的职工类型或调整现有类型的职责。
3.5 测试多态
在职工管理系统.cpp
中添加测试函数test()
,用于验证职工管理系统中的多态功能是否能够正常运行。通过创建不同类型的职工对象(普通员工、经理和老板)并调用各自的showInfo()
方法,我们可以观察到多态的效果。
测试代码如下:
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
| #include "worker.h" #include "employee.h" #include "manager.h" #include "boss.h"
void test() { Worker* worker = NULL;
worker = new Employee(1, "张员工", 1); worker->showInfo(); delete worker;
worker = new Manager(2, "李经理", 2); worker->showInfo(); delete worker;
worker = new Boss(3, "王老板", 3); worker->showInfo(); delete worker; }
|
在test()
函数中,我们通过将Worker*
指针指向不同类型的职工对象,并调用各自的showInfo()
方法,实现了多态调用。每个对象根据其具体类型展示了不同的岗位职责描述,验证了多态的功能。
运行该测试函数后,终端或控制台应输出每个职工的详细信息,包括姓名、职工编号、岗位和职责描述。运行效果如下图所示:
测试成功后,您可以选择将test()
函数的代码注释保留,方便日后测试或调试;或者选择删除该函数,以保持代码的简洁性。
4、添加职工
在本节中,我们实现一个批量添加职工的功能,并将新添加的职工数据保存到文件中。通过该功能,用户可以一次性添加多个职工,并将不同职工类别(普通员工、经理、老板)存储在统一的职工数组中。
4.1 功能分析
需求分析:
用户在批量创建职工时,可以选择不同类别的职工(普通员工、经理、老板)。为了方便管理和存储所有职工信息,我们将使用一个动态数组来存放职工对象的指针,动态扩展数组容量以适应新增数据。
技术实现:
为了实现动态管理不定长度的职工数组,我们将数组定义在堆区,并使用Worker**
类型的指针来维护该数组,以便在需要时动态调整数组的大小。
4.2 功能实现
在 WorkerManager.h
中添加成员属性
在WorkerManager
类中添加以下两个成员属性,用于记录当前职工人数和职工数组:
1 2 3 4 5 6
| int m_EmpNum;
Worker** m_EmpArray;
|
初始化成员属性
在 WorkerManager
的构造函数中,初始化职工人数和职工数组指针:
1 2 3 4 5 6 7 8 9
| WorkerManager::WorkerManager() { this->m_EmpNum = 0;
this->m_EmpArray = NULL; }
|
添加职工函数声明
在WorkerManager.h
头文件中声明Add_Emp()
成员函数,用于添加职工:
实现 Add_Emp()
函数
在 workerManager.cpp
中实现 Add_Emp()
函数,具体步骤如下:
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
| void WorkerManager::Add_Emp() { cout << "请输入需要增加的职工数量:" << endl; int addNum = 0; cin >> addNum;
if (addNum > 0) { int newSize = m_EmpNum + addNum;
Worker** newSpace = new Worker*[newSize];
if (this->m_EmpArray != NULL) { for (int i = 0; i < this->m_EmpNum; i++) { newSpace[i] = this->m_EmpArray[i]; } }
for (int i = 0; i < addNum; i++) { int id; string name; int dSelect;
while (true) { cout << "请输入第" << i + 1 << "名新职工的编号:" << endl; cin >> id; int index = this->isExist(id); if (index == -1) break; else cout << "该职工编号已存在,请重新输入:" << endl; }
cout << "请输入第" << i + 1 << "名新职工的姓名:" << endl; cin >> name; cout << "请选择第" << i + 1 << "名新职工的职工类型:" << endl; cout << "1、普通职工" << endl; cout << "2、经理" << endl; cout << "3、老板" << endl; cin >> dSelect;
Worker* worker = NULL; switch (dSelect) { case 1: worker = new Employee(id, name, dSelect); break; case 2: worker = new Manager(id, name, dSelect); break; case 3: worker = new Boss(id, name, dSelect); break; default: cout << "无效的职工类型" << endl; break; } newSpace[this->m_EmpNum + i] = worker; }
delete[] this->m_EmpArray;
this->m_EmpArray = newSpace; this->m_EmpNum = newSize;
cout << "成功添加" << addNum << "名新职工" << endl; this->m_FileEmpty = false; this->save(); } else { cout << "输入非法,添加失败" << endl; }
system("pause"); system("cls"); }
|
在 WorkerManager
析构函数中释放内存
为了避免内存泄漏,我们在析构函数中释放m_EmpArray
数组的内存:
1 2 3 4 5 6 7 8
| WorkerManager::~WorkerManager() { if (this->m_EmpArray != NULL) { delete[] this->m_EmpArray; } }
|
4.3 测试添加职工功能
在主程序的菜单选项中,调用 Add_Emp()
函数,并根据用户输入展示添加职工的结果。运行程序后,终端将显示添加的职工信息,如下图所示:
至此,职工添加功能已完成,实现了批量添加不同类别的职工并将信息保存至文件。
5、文件交互 - 写文件
在实现职工信息添加后,为了确保数据的持久化,我们需要将数据写入文件中,并在程序启动时从文件中读取这些数据。文件交互的流程可以分为两个步骤:文件写入和文件读取。
5.1 文件写入
在职工管理系统中,当新职工添加完成后,数据会写入文件以实现持久化。写文件的功能如下:
5.1.1 文件路径设定
在workerManager.h
文件中定义文件路径常量,并包含fstream
头文件:
1 2
| #include <fstream> #define FILENAME "empFile.txt"
|
5.1.2 成员函数声明
在 WorkerManager
类中声明 save()
函数,用于将职工数据写入文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void WorkerManager::save() { ofstream ofs; ofs.open(FILENAME, ios::out);
for (int i = 0; i < this->m_EmpNum; i++) { ofs << this->m_EmpArray[i]->m_Id << " " << this->m_EmpArray[i]->m_Name << " " << this->m_EmpArray[i]->m_DeptId << endl; }
ofs.close(); }
|
5.1.3 保存文件功能测试
在成功添加职工后,调用save()
函数,将职工信息写入文件:
测试程序:运行程序添加职工,验证生成的empFile.txt
文件中是否记录了新职工的信息。
5.2 文件读取
在程序启动时,从文件中加载职工数据到内存中,便于进行后续操作。文件读取功能将包括文件状态判断、数据读取和内存初始化。
5.2.1 文件状态判断
文件状态分为以下三种情况:
- 文件未创建:即文件不存在。
- 文件存在但无数据:文件存在但内容为空。
- 文件存在并包含数据:文件存在且包含职工数据。
在 workerManager.h
中添加标志属性 m_FileIsEmpty
,用于判断文件是否为空:
在构造函数 WorkerManager::WorkerManager
中,根据文件状态初始化数据:
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
| WorkerManager::WorkerManager() { ifstream ifs; ifs.open(FILENAME, ios::in);
if (!ifs.is_open()) { cout << "文件不存在" << endl; this->m_EmpNum = 0; this->m_FileIsEmpty = true; this->m_EmpArray = NULL; ifs.close(); return; }
char ch; ifs >> ch; if (ifs.eof()) { cout << "文件为空!" << endl; this->m_EmpNum = 0; this->m_FileIsEmpty = true; this->m_EmpArray = NULL; ifs.close(); return; }
this->m_FileIsEmpty = false; }
|
在成功添加职工后,将文件标志更新为非空:
1 2
| this->m_FileIsEmpty = false;
|
5.2.2 获取职工记录数
在文件读取前,需要获取文件中职工的数量以便初始化数组。定义get_EmpNum
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int WorkerManager::get_EmpNum() { ifstream ifs(FILENAME, ios::in); int id, dId, num = 0; string name;
while (ifs >> id && ifs >> name && ifs >> dId) { num++; } ifs.close();
return num; }
|
在构造函数中调用此函数,获取职工数量并初始化数组:
1 2 3 4
| int num = this->get_EmpNum(); this->m_EmpNum = num; cout << "文件中职工数量为:" << num << endl;
|
5.2.2 获取职工记录数
在文件读取前,需要获取文件中职工的数量以便初始化数组。定义get_EmpNum
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int WorkerManager::get_EmpNum() { ifstream ifs(FILENAME, ios::in); int id, dId, num = 0; string name;
while (ifs >> id && ifs >> name && ifs >> dId) { num++; } ifs.close();
return num; }
|
在构造函数中调用此函数,获取职工数量并初始化数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int num = this->get_EmpNum(); this->m_EmpNum = num; cout << "调试代码:文件中职工数量为:" << num << endl; this->m_EmpArry = new Worker * [num]; this->init_Emp();
for (int i = 0; i < num; i++) { cout << "调试代码:"; cout << "职工号:" << this->m_EmpArry[i]->m_Id << " 姓名:" << this->m_EmpArry[i]->m_Name << " 部门编号:" << this->m_EmpArry[i]->m_DeptId << endl; }
|
手动添加一些职工数据,测试获取职工数量函数
5.2.3 初始化职工数组
在WorkerManager
类中定义init_Emp()
函数,根据文件中的数据初始化m_EmpArray
数组:
1 2
| //初始化员工 void init_Emp();
|
在WorkerManager.cpp中实现
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
| void WorkerManager::init_Emp() { ifstream ifs(FILENAME, ios::in); int id, dId, index = 0; string name;
while (ifs >> id && ifs >> name && ifs >> dId) { Worker* worker = NULL; if (dId == 1) { worker = new Employee(id, name, dId); } else if (dId == 2) { worker = new Manager(id, name, dId); } else { worker = new Boss(id, name, dId); }
this->m_EmpArray[index++] = worker; } ifs.close(); }
|
在构造函数中调用init_Emp()
初始化数据:
//根据职工数创建数组
this->m_EmpArray = new Worker *[this->m_EmpNum];
//初始化职工
init_Emp();
//测试代码
for (int i = 0; i < m_EmpNum; i++)
{
cout << "职工号: " << this->m_EmpArray[i]->m_Id
<< " 职工姓名: " << this->m_EmpArray[i]->m_Name
<< " 部门编号: " << this->m_EmpArray[i]->m_DeptId << endl;
}
至此,实现了完整的文件交互功能,包括文件写入和文件读取。测试代码可注释或删除。
6、显示职工
功能描述:显示当前所有职工信息
6.1 显示职工函数声明
在 workerManager.h
中添加成员函数 void Show_Emp();
,用于显示所有职工信息。
6.2 显示职工函数实现
在 workerManager.cpp
中实现成员函数 void Show_Emp();
,该函数负责根据文件内容判断是否为空,并显示所有职工的详细信息。
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
| void WorkerManager::Show_Emp() { if (this->m_FileEmpty) { cout << "文件不存在或为空!" << endl; } else { for (int i = 0; i < this->m_EmpNum; i++) { this->m_EmpArray[i]->showInfo(); } } system("pause"); system("cls"); }
int WorkerManager::isExist(int id) { int index = -1; for (int i = 0; i < this->m_EmpNum; i++) { if (this->m_EmpArray[i]->m_Id == id) { index = i; break; } } return index; }
void WorkerManager::Del_Emp() { if (this->m_FileIsEmpty) { cout << "文件不存在或为空,删除失败!" << endl; } else { cout << "请输入要删除的职工编号:" << endl; int id; cin >> id;
int index = this->isExist(id); if (index == -1) { cout << "职工不存在,删除失败!" << endl; } else { for (int i = index; i < this->m_EmpNum - 1; i++) { this->m_EmpArray[i] = this->m_EmpArray[i + 1]; } this->m_EmpNum--; this->save(); cout << "删除成功!期待与ta的再次见面~" << endl; } } system("pause"); system("cls"); }
|
6.3 测试显示职工
在 main
函数中的分支 2 选项中,调用 Show_Emp()
接口进行显示职工功能测试。测试时分别考虑文件为空和文件不为空两种情况。
测试1 - 文件不存在或为空情况
测试效果:当文件为空或不存在时,程序会显示“文件不存在或为空”。
测试2 - 文件存在且有记录情况
测试效果:当文件存在并且有职工记录时,程序将显示职工的详细信息。
至此,显示所有职工信息功能已完整实现。测试代码可以在调试完成后进行注释或删除。
7、删除职工
功能描述:按照职工的编号进行删除职工操作
7.1 删除职工函数声明
在 workerManager.h
中添加成员函数 void Del_Emp();
,用于删除职工。
7.2 职工是否存在函数声明
为了支持删除职工、修改职工、查找职工等功能,添加一个判断职工是否存在的函数,以便后续调用。
在 workerManager.h
中添加成员函数 int IsExist(int id);
,用于判断职工是否存在。
7.3 职工是否存在函数实现
在 workerManager.cpp
中实现成员函数 int IsExist(int id);
,该函数负责判断职工是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int WorkerManager::isExist(int id) { int index = -1; for (int i = 0; i < this->m_EmpNum; i++) { if (this->m_EmpArray[i]->m_Id == id) { index = i; break; } } return index; }
|
7.4 删除职工函数实现
在 workerManager.cpp
中实现成员函数 void Del_Emp();
,该函数实现删除职工操作。
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
| void WorkerManager::Del_Emp() { if (this->m_FileIsEmpty) { cout << "文件不存在或为空,删除失败!" << endl; } else { cout << "请输入要删除的职工编号:" << endl; int id; cin >> id;
int index = this->isExist(id); if (index == -1) { cout << "职工不存在,删除失败!" << endl; } else { for (int i = index; i < this->m_EmpNum - 1; i++) { this->m_EmpArray[i] = this->m_EmpArray[i + 1]; } this->m_EmpNum--; this->save(); cout << "删除成功!期待与ta的再次见面~" << endl; } } system("pause"); system("cls"); }
|
7.5 测试删除职工
在 main
函数中的分支 3 选项中,调用 Del_Emp()
接口进行删除职工功能的测试。测试时分别考虑删除不存在职工和删除已存在职工两种情况。
测试1 - 删除不存在职工情况
测试效果:当输入不存在的职工编号时,程序会输出“职工不存在,删除失败”提示。
测试2 - 删除存在的职工情况
删除成功提示图:
测试效果:当输入存在的职工编号时,程序会成功删除该职工,并提示“删除成功!期待与ta的再次见面~”。
再次显示所有职工信息,确保已经删除
测试效果:删除职工后,调用显示职工信息接口,确认职工已被成功删除。
至此,删除职工功能已完整实现。测试代码可以在调试完成后进行注释或删除。
8、修改职工
功能描述:能够按照职工的编号对职工信息进行修改并保存。
8.1 修改职工函数声明
在 workerManager.h
中添加成员函数 void Mod_Emp();
,用于修改职工信息。
8.2 修改职工函数实现
在 workerManager.cpp
中实现成员函数 void Mod_Emp();
,该函数用于修改指定职工的个人信息。
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
| void WorkerManager::Mod_Emp() { if (this->m_FileEmpty) { cout << "文件不存在或者为空,无法修改!" << endl; return; } cout << "请输入需要修改的职工的编号:" << endl; int id; cin >> id;
int index = this->isExist(id); if (index == -1) { cout << "查无此人,修改失败!" << endl; } else { this->m_EmpArray[index]->showInfo(); delete this->m_EmpArray[index]; int NewId, NewSelect; string NewName;
while (true) { cout << "请输入新的职工号:" << endl; cin >> NewId; int index = this->isExist(NewId); if (index == -1) break; else cout << "此职工ID已存在,请重新输入:" << endl; } cout << "请输入新的职工姓名:" << endl; cin >> NewName;
cout << "请选择新的职工岗位:" << endl; cout << "1、普通职工" << endl; cout << "2、经理" << endl; cout << "3、老板" << endl; cin >> NewSelect;
Worker* worker = NULL; switch (NewSelect) { case 1: worker = new Employee(NewId, NewName, NewSelect); break; case 2: worker = new Manager(NewId, NewName, NewSelect); break; case 3: worker = new Boss(NewId, NewName, NewSelect); break; default: break; }
this->m_EmpArray[index] = worker; cout << "修改成功!" << endl;
this->save(); }
system("pause"); system("cls"); }
|
8.3 测试修改职工
在 main
函数的分支 4 选项中,调用 Mod_Emp()
接口进行修改职工功能的测试。测试时分别考虑修改不存在职工和修改已存在职工两种情况。
测试1 - 修改不存在职工情况
测试效果:当输入不存在的职工编号时,程序会输出“查无此人,修改失败”提示。
测试2 - 修改存在职工情况,例如将职工 “张三” 改为 “张新三”
测试效果:修改成功后,系统会显示“修改成功!”并保存修改后的职工信息。
改后再次查看所有职工信息,并确认修改成功
确认文件中的信息同步更新
测试效果:打开文件,确认修改后的职工信息已正确更新,保存的数据与程序中的显示一致。
至此,修改职工功能已完整实现。测试代码可以在调试完成后进行注释或删除。
9、查找职工
功能描述:提供两种查找职工方式,一种按照职工编号查找,一种按照职工姓名查找。
9.1 查找职工函数声明
在 workerManager.h
中添加成员函数 void Find_Emp();
,用于查找职工信息。
9.2 查找职工函数实现
在 workerManager.cpp
中实现成员函数 void Find_Emp();
,该函数根据用户选择的方式查找职工。
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
| void WorkerManager::Find_Emp() { if (this->m_FileEmpty) { cout << "文件不存在或者为空,查找失败!" << endl; return; } else { cout << "请选择你的查找方式:" << endl; cout << "1、按职工编号查找" << endl; cout << "2、按职工姓名查找" << endl; int select; cin >> select;
if (select == 1) { cout << "请输入需要查找的职工id:" << endl; int id; cin >> id; int index = this->isExist(id); if (index == -1) { cout << "查无此人!" << endl; } else { this->m_EmpArray[index]->showInfo(); } } else if (select == 2) { cout << "请输入需要查找的职工姓名:" << endl; string name; cin >> name;
int index = -1; for (int i = 0; i < this->m_EmpNum; i++) { if (this->m_EmpArray[i]->m_Name == name) { this->m_EmpArray[i]->showInfo(); index = 0; } } if (index == -1) { cout << "查无此人!" << endl; } } } system("pause"); system("cls"); }
|
9.3 测试查找职工
在 main
函数的分支 5 选项中,调用 Find_Emp()
接口进行查找职工功能的测试。测试时分别考虑按职工编号和按职工姓名查找的不同情况。
测试1 - 按照职工编号查找 - 查找不存在职工
测试效果:当输入不存在的职工编号时,程序会输出“查无此人!”的提示。
测试2 - 按照职工编号查找 - 查找存在职工
测试效果:当输入存在的职工编号时,程序会显示该职工的详细信息。
测试3 - 按照职工姓名查找 - 查找不存在职工
测试效果:当输入不存在的职工姓名时,程序会输出“查无此人!”的提示。
测试4 - 按照职工姓名查找 - 查找存在职工(如果出现重名,也一并显示,在文件中可以添加重名职工)
例如,添加两个名为“张三”的职工,并按照姓名查找“张三”。
测试效果:当存在重名职工时,程序会显示所有匹配的职工信息,确保用户能够看到所有与输入姓名匹配的职工。
至此,查找职工功能已完整实现。测试代码可以在调试完成后进行注释或删除。
10、排序
功能描述:根据职工编号进行排序,排序的顺序由用户指定。
10.1 排序函数声明
在 workerManager.cpp
中实现成员函数 void Sort_Emp();
,该函数将根据用户的选择对职工编号进行排序。
10.2 排序函数实现
在workerManager.cpp中实现成员函数 void Sort_Emp();
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
| void WorkerManger::Sort_Emp() { if (this->m_FileEmpty) { cout << "文件不存在或者为空,排序失败!" << endl; system("pause"); system("cls"); } else { int select; cout << "请选择需要的排序方式:" << endl; cout << "1、降序排序" << endl; cout << "2、升序排序" << endl; cin >> select;
for (int i = 0; i < this->m_EmpNum; i++) { int minOrMax = i; for (int j = i; j < this->m_EmpNum; j++) { if (select == 1) { if (this->m_EmpArry[j]->m_Id > this->m_EmpArry[minOrMax]->m_Id) minOrMax = j; } else { if (this->m_EmpArry[j]->m_Id < this->m_EmpArry[minOrMax]->m_Id) minOrMax = j; } } if (minOrMax != i) { Worker* temp = this->m_EmpArry[i]; this->m_EmpArry[i] = this->m_EmpArry[minOrMax]; this->m_EmpArry[minOrMax] = temp; } }
this->save(); this->Show_Emp(); } }
void WorkerManger::Clear_File() { if (this->m_FileEmpty) { cout << "文件为不存在或为空,无需操作!" << endl; system("pause"); system("cls"); } else { cout << "确认清空?此操作无法恢复!文件将会永久删除!" << endl; cout << "1、确认清空,文件永久删除" << endl; cout << "任意键取消" << endl; string select; cin >> select; if (select == "1") { cout << "确认清空操作请输入“清空”,输入任意内容取消" << endl; cin >> select; if (select == "清空") { ofstream ofs; ofs.open(FILENAME, ios::trunc); ofs.close();
if (this->m_EmpArry != NULL) { for (int i = 0; i < this->m_EmpNum; i++) { delete this->m_EmpArry[i]; } this->m_EmpNum = 0; this->m_FileEmpty = true; delete[] this->m_EmpArry; this->m_EmpArry = NULL; } cout << "已清空!" << endl; } else cout << "已取消!" << endl; } else cout << "已取消!" << endl;
system("pause"); system("cls"); } }
|
10.3 测试排序功能
在 main
函数的分支 6 选项中,调用排序职工接口进行排序功能的测试。
添加无序职工
首先我们添加一些职工,职工编号是无序的。例如:
测试 - 升序排序
选择升序排序后,职工会根据编号从小到大进行排序。
排序后的文件同步更新:
测试 - 降序排序
选择降序排序后,职工会根据编号从大到小进行排序。
文件同步更新
至此,职工编号排序功能已实现并经过测试,能够按照用户指定的顺序对职工进行升序或降序排序,并且排序结果会同步保存到文件中。
11、清空文件
功能描述:清空文件中记录的职工数据。
11.1 清空函数声明
在 workerManager.cpp
中实现 void Clean_File();
,该函数将删除文件中的所有数据,并清空职工记录。
11.2 清空函数实现
在 workerManager.cpp
中实现 void Clean_File();
,该函数将删除文件中的所有数据,并清空职工记录。
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
| void WorkerManger::Clear_File() { if (this->m_FileEmpty) { cout << "文件为不存在或为空,无需操作!" << endl; system("pause"); system("cls"); } else { cout << "确认清空?此操作无法恢复!文件将会永久删除!" << endl; cout << "1、确认清空,文件永久删除" << endl; cout << "任意键取消" << endl; string select; cin >> select; if (select == "1") { cout << "确认清空操作请输入“清空”,输入任意内容取消" << endl; cin >> select; if (select == "清空") { ofstream ofs; ofs.open(FILENAME, ios::trunc); ofs.close();
if (this->m_EmpArry != NULL) { for (int i = 0; i < this->m_EmpNum; i++) { delete this->m_EmpArry[i]; } this->m_EmpNum = 0; this->m_FileEmpty = true; delete[] this->m_EmpArry; this->m_EmpArry = NULL; } cout << "已清空!" << endl; } else cout << "已取消!" << endl; } else cout << "已取消!" << endl;
system("pause"); system("cls"); } }
|
11.3 测试清空文件
在 main
函数的分支 7 选项中,调用清空文件接口进行测试。
测试 - 确认清空文件
在执行清空文件操作时,系统会询问是否确认清空文件数据,并要求输入确认内容。
清空操作成功后,文件中的数据将被清除,可以通过打印文件内容来确认。
再次查看文件中数据,记录已为空
手动打开文件查看,文件内容已被完全清空:
随着清空文件功能的实现,本项目的基于多态的职工管理系统已经完整实现!至此,所有主要功能(增加、删除、修改、查找、排序、清空文件等)已经完成,可以满足基本的职工管理需求。
3、退出功能
在本节中,我们展示了完整的main
函数代码,该代码是整个职工管理系统的入口。main
函数通过循环和用户输入来控制系统的操作,支持添加、显示、删除、修改、查找、排序职工,以及清空文件等功能。代码中的各个功能通过switch
语句进行选择,并对应调用WorkerManger
类中的相应成员函数。
3.1 提供功能接口
在main函数中提供分支选择,提供每个功能接口
代码:
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
| #include <iostream> #include "workerManger.h" using namespace std;
enum choice { Exit, Add, Show, Del, Modify, Find, Sort, Clean };
int main() { WorkerManger wm;
while (true) { wm.Show_Menu(); int choice; cout << "请输入您的选择:" << endl; cin >> choice;
switch (choice) { case Exit: wm.EsixSystem(); break; case Add: wm.Add_Emp(); break; case Show: wm.Show_Emp(); break; case Del: wm.Del_Emp(); break; case Modify: wm.Mod_Emp(); break; case Find: wm.Find_Emp(); break; case Sort: wm.Sort_Emp(); break; case Clean: wm.Clear_File(); break; default: system("cls"); break; } } return 0; }
|
代码说明:
- 菜单选择与操作:通过
enum choice
定义了所有可能的菜单选项,并使用switch
语句根据用户输入的选择执行相应的功能。每个case
语句对应一个功能模块,如添加职工、显示职工、删除职工等。
- 循环运行:程序通过
while(true)
进入一个无限循环,用户输入选择后,系统根据选择执行操作,直到用户选择退出系统。
- 操作执行:每个功能模块调用
WorkerManger
类中的成员函数来实现具体操作。例如,wm.Add_Emp()
表示调用Add_Emp
函数来添加职工。
- 退出系统:当用户选择退出时,调用
wm.EsixSystem()
来终止程序。
通过这种结构,main
函数实现了职工管理系统的菜单化控制,使得程序的操作更加直观和易于扩展。
3.2 实现退出功能
在workerManager.h中提供退出系统的成员函数 void exitSystem();
在workerManager.cpp中提供具体的功能实现
1 2 3 4 5 6
| void WorkerManger::EsixSystem() { cout << "正在安全退出…… 欢迎下次使用!" << endl; system("pause"); exit(0); }
|
13、 总结
在本次职工管理系统的开发过程中,我们实现了基于C++的面向对象管理系统,通过类和多态的组合,实现了职工信息的管理。各个功能模块的实现使得职工的管理操作非常灵活,并且系统支持文件的持久化存储,能够在程序关闭后仍保留职工数据。
- 面向对象设计:我们通过继承和多态实现了不同职工类型的统一管理,使得系统结构更清晰,易于扩展。每个职工类型(如员工、经理、老板)都继承自一个基类
Worker
,并根据岗位需求修改或添加特有的行为。
- 模块化设计:各个功能如职工增加、删除、修改、查找等,都封装成独立的函数,并且与文件操作结合紧密,确保数据的一致性和持久性。这种模块化设计不仅保证了系统的可维护性,也便于后续功能的扩展。
- 灵活性与健壮性:在各个功能的实现中,我们考虑了不同的异常情况处理。例如,在删除职工时检查职工是否存在,在修改职工时避免重复编号,在排序职工时确保排序的准确性。这些细节保证了系统的稳定性和可靠性。
通过这次开发,我们实现了一个完整的职工管理系统,涵盖了职工的增、删、改、查、排序和文件管理等基本功能。这个系统不仅展示了如何使用C++中的面向对象编程(OOP)思想,还通过文件操作确保了数据的持久化存储。系统的实现为以后开发更复杂的管理系统奠定了基础。
致谢:
感谢ChatGPT对本文文本部分的指导与修改!这大大节省了本文的创作时间。
感谢ChatGPT对本文部分代码注释的补充!为代码的阅读提供了更佳的便利与体验。
代码原创,需要本项目源码请通过评论区、我的-留言板或邮箱联系免费获取。