20240221
需求分析
- 本教程主要利用C++来实现一个基于多态的职工管理系统
员工信息
构成
- 普通员工
- 经理
- 老板
员工显示
- 需要显示职工编号、职工姓名、职工岗位以及职责
不同员工职责
- 责普通员工职责:完成经理交给的任务
- 经理职责:完成老板交给的任务,并下发任务给员工
- 老板职责:管理公司所有事务
主要功能
- 退出管理程序:退出当前管理系统
- 增加职工信息:实现批量添加职工功能,将信息录入到文件中,职工信息为:职工编号、姓名、部门编号
- 显示职工信息:显示公司内部所有职工的信息
- 删除离职职工:按照编号删除指定的职工
- 修改职工信息: 按照骗号修改职工个人信息
- 查找职工信息:按照职工的编号或者职工的姓名进行查找相关的人员信息
- 按照编号排序:按照职工编号,进行排序,排序规则由用户指定
- 清空所有文档:清空文件中记录的所有职工信息 (清空前需要再次确认,防止误删)
功能实现
创建管理类
创建管理类头文件
- 新建
workerManage.hpp
头文件 - 完成功能
- 包重复引用检查
- 引入对应头文件和响应的命名空间
- 声明对应的构造和析构函数
- 代码示例
#pragma once
#include <iostream>
using namespace std;
// 员工管理类
class WorkerManager {
public:
// 构造函数
WorkerManager();
// 析构函数
~WorkerManager();
};
创建管理类源文件
-
新建
workerManage.cpp
源文件 -
完成功能
-
引入
workerManage.hpp
头文件 -
实现两个空的析构和构造函数
-
-
代码示例
#include "workerManage.hpp"
WorkerManager::WorkerManager() {
}
WorkerManager::~WorkerManager() {
}
菜单功能实现
声明菜单功能
-
在
workerManage.hpp
头文件类中添加菜单声明函数 -
代码示例
// 展示菜单
void ShowMenu();
实现菜单功能
-
在
workerManage.cpp
源文件中实现菜单函数 -
代码示例
void WorkerManager::ShowMenu() {
cout << "****************************************" << endl;
cout << "******** 欢迎使用职工管理系统 ********" << endl;
cout << "********* 0.退出管理程序 *********" << endl;
cout << "********* 1.增加职工信息 *********" << endl;
cout << "********* 2.显示职工信息 *********" << endl;
cout << "********* 3.删除离职职工 *********" << endl;
cout << "********* 4.修改职工信息 *********" << endl;
cout << "********* 5.按照编号排序 *********" << endl;
cout << "********* 5.查找职工信息 *********" << endl;
cout << "********* 6.查找职工信息 *********" << endl;
cout << "********* 7.清空所有文档 *********" << endl;
cout << "****************************************" << endl;
cout << endl;
}
编写菜单功能测试
-
新建
main.cpp
文件 -
代码示例
#include "workerManage.hpp"
int main() {
WorkerManager wm;
wm.ShowMenu();
return 0;
}
测试结果
退出功能
- 编写功能框架,并在用户输入0时结束
int main() {
WorkerManager wm;
int choice;
while (true) {
wm.ShowMenu();
cout << "请输入你的选择:";
cin >> choice;
switch (choice) {
case 0: // 退出系统
exit(0);
break;
case 1: // 增加职工
break;
case 2: // 显示职工信息
break;
case 3: // 删除离职职工
break;
case 4: //修改职工信息
break;
case 5: //查找职工信息
break;
case 6: //按照编号排序
break;
case 7: //清空所有文档
break;
default: // 清屏
break;
}
}
return 0;
}
增加功能
功能分析
-
根据需求,员工有三类,且每个员工有共性也有区别,因此考虑用多态的方式
-
将共性的成员抽象在基类中,在不同员工实现类中进行不同特性的实现
-
首先给出员工的抽象类
worker.hpp
-
代码示例
#pragma once
#include <iostream>
#include <string>
using namespace std;
// 员工抽象类
class Worker {
public:
// 展示员工信息
virtual void ShowWorkerInfo() = 0;
// 获取部门名
virtual string getDeptName(int deptId) = 0;
// 获取岗位职责
virtual string getWorkerAbility() = 0;
// 员工编号
int m_id;
// 姓名
string m_name;
// 部门id
int m_deptId;
};
普通员工类实现
-
普通员工继承自抽象的worker类
-
首先在
employee.hpp
中声明抽象类中的方法
#include "worker.hpp"
// 普通员工类
class Employee : public Worker {
public:
// 构造函数
Employee(int id, string name, int deptId);
// 展示员工信息
virtual void ShowWorkerInfo();
// 获取部门名
virtual string getDeptName(int deptId);
// 获取岗位职责
virtual string getWorkerAbility();
};
- 在
employee.cpp
中实现头文件中声明的方法
#include "employee.hpp"
// 构造函数
Employee::Employee(int id, string name, int deptId) {
this->m_id = id;
this->m_name = name;
this->m_deptId = deptId;
}
// 展示员工信息
void Employee::ShowWorkerInfo() {
cout << "员工编号:" << this->m_id
<< "\t员工姓名:" << this->m_name
<< "\t员工部门:" << this->getDeptName()
<< "职责:" << this->getWorkerAbility() << endl;
}
// 获取部门名
string Employee::getDeptName(int deptId) {
return "普通员工";
}
// 获取岗位职责
string Employee::getWorkerAbility() {
return "完成经理交给的任务";
}
- 普通员工实现测试
#include "worker.hpp"
#include "employee.hpp"
int main() {
Worker* worker = Worker* worker = new Employee(1,"zs", 3);
worker->ShowWorkerInfo();
return 0;
}
- 测试结果
经理类实现
-
按照员工的思路实现经理类
-
经理类头文件
manager.hpp
#include "worker.hpp"
// 普通员工类
class Manager : public Worker {
public:
// 构造函数
Manager(int id, string name, int deptId);
// 展示员工信息
virtual void ShowWorkerInfo();
// 获取部门名
virtual string getDeptName(int deptId);
// 获取岗位职责
virtual string getWorkerAbility();
};
- 经理类具体实现
manager.cpp
#include "manager.hpp"
// 构造函数
Manager::Manager(int id, string name, int deptId) {
this->m_id = id;
this->m_name = name;
this->m_deptId = deptId;
}
// 展示员工信息
void Manager::ShowWorkerInfo() {
cout << "员工编号:" << this->m_id
<< "\t员工姓名:" << this->m_name
<< "\t员工部门:" << this->getDeptName()
<< "\t职责:" << this->getWorkerAbility() << endl;
}
// 获取部门名
string Manager::getDeptName(int deptId) {
return "经理";
}
// 获取岗位职责
string Manager::getWorkerAbility() {
return "完成老版交给的任务,并下发任务给普通员工";
}
老板类实现
-
按照员工的思路实现老板类
-
老板类头文件
boss.hpp
#include "worker.hpp"
// 普通员工类
class Boss : public Worker {
public:
// 构造函数
Boss(int id, string name, int deptId);
// 展示员工信息
virtual void ShowWorkerInfo();
// 获取部门名
virtual string getDeptName(int deptId);
// 获取岗位职责
virtual string getWorkerAbility();
};
- 老板类具体实现
boss.cpp
#include "boss.hpp"
// 构造函数
Boss::Boss(int id, string name, int deptId) {
this->m_id = id;
this->m_name = name;
this->m_deptId = deptId;
}
// 展示员工信息
void Boss::ShowWorkerInfo() {
cout << "员工编号:" << this->m_id
<< "\t员工姓名:" << this->m_name
<< "\t员工部门:" << this->getDeptName()
<< "\t职责:" << this->getWorkerAbility() << endl;
}
// 获取部门名
string Boss::getDeptName(int deptId) {
return "老板";
}
// 获取岗位职责
string Boss::getWorkerAbility() {
return "下发任务给经理";
}
测试多态
#include "worker.hpp"
#include "employee.hpp"
#include "manager.hpp"
#include "boss.hpp"
// TODO:delete 删除worker的时候在MAC下存在问题,待排查
int main() {
Worker *worker = NULL;
worker = new Employee(1, "zs", 1);
worker->ShowWorkerInfo();
worker = new Manager(2, "ls", 2);
worker->ShowWorkerInfo();
worker = new Boss(3, "ww", 3);
worker->ShowWorkerInfo();
return 0;
}
添加职工
- 批量添加职工,并且保存到文件中
功能分析
-
职工在创建的时候有不同的工种,如果想要将不同种类的员工都放在一个数组中,可以将所有员工的指针都维护到一个数组中
-
如果想要维护不定长的数组,可以将数组开辟到堆区,使用
worker**
的指针维护
功能实现
- 在员工管理头文件
workerManage.hpp
中添加员工数量和维护员工指针,并引入相应的头文件
#include "worker.hpp"
#include "employee.hpp"
#include "manager.hpp"
#include "boss.hpp"
// 批量添加职工
void AddEmp();
private:
// 员工数量
int memberSize;
// 员工数组指针
Worker **pWorker;
- 在员工管理源文件
workerManage.cpp
中实现构造函数、析构函数和批量添加员工逻辑
WorkerManager::WorkerManager() {
this->memberSize = 0;
this->pWorker = NULL;
}
WorkerManager::~WorkerManager() {
if (this->pWorker != NULL) {
delete[] this->pWorker;
this->pWorker = NULL;
}
}
void WorkerManager::AddEmp() {
// 要添加员工的数量
int addNum;
cout << "请输入要添加员工的数量: " << endl;
cin >> addNum;
if (addNum > 0) {
// 记录添加后的人数=当前已有人数+新增人数
int curSize = this->memberSize + addNum;
Worker **newArr = new Worker *[curSize];
// 如果之前已经存在职工,现将已有职工进行拷贝
if (this->memberSize > 0) {
for (int i = 0; i < this->memberSize; i++) {
newArr[i] = this->pWorker[i];
}
}
// 添加新职工
for (int i = 0; i < addNum; i++) {
Worker *worker = NULL;
int id;
string name;
int deptId;
cout << "请输入第" << i << "位新职工的编号" << endl;
cin >> id;
cout << "请输入第" << i << "位新职工的姓名" << endl;
cin >> name;
cout << "请输入第" << i << "位新职工的部门编号" << endl;
cout << "1.员工" << endl;
cout << "2.经理" << endl;
cout << "3.老板" << endl;
cin >> deptId;
switch (deptId) {
case 1:
worker = new Employee(id, name, deptId);
break;
case 2:
worker = new Manager(id, name, deptId);
break;
case 3:
worker = new Boss(id, name, deptId);
break;
}
// 将新员工加入到数组
newArr[this->memberSize + i] = worker;
}
// 释放旧空间
delete[]this->pWorker;
// 将员工数组指针指向新空间
this->pWorker = newArr;
// 更新现有员工数量
this->memberSize = curSize;
} else {
cout << "输入有误" << endl;
}
}
添加功能测试
- 在
main.cpp
添加职工的位置调用添加的函数
wm.AddEmp();
- 图示
文件交互–写文件文件
功能分析
- 上面虽然实现了添加员工操作,但是数据保存在堆区,程序结束后堆区的数据还是会被清空,因此将添加的员工持久化到文件中
功能实现
- 在
workerManager.hpp
中添加对应的头文件和成员函数
// 用于文件操作
#include <fstream>
// 定义写入文件
#define FILENAME "empFile.txt"
// 保存文件
void saveFile();
- 在
workerManager.cpp
中实现保存文件函数,并在添加员工成功后调用保存文件操作
void WorkerManager::saveFile() {
// 以写入的方式打开文件
ofstream ofs;
ofs.open(FILENAME, ios::out);
for (int i = 0; i < this->memberSize; i++) {
// 按行写入每一个员工信息
ofs << this->pWorker[i]->m_id << " "
<< this->pWorker[i]->m_name << " "
<< this->pWorker[i]->m_deptId << endl;
}
// 关闭文件
ofs.close();
}
// 调用保存文件
this->saveFile();
功能测试
- 录入新职工信息
- 文件查看
文件交互–读文件
功能分析
-
虽然录入员工信息已经写入了文件,但是每次程序重启时并没有将文件中的用户加载到程序中来,因此需要使用读文件的操作,在程序启动时将文件中的数据加载到程序中来
-
加载时存在以下三种情况
-
文件不存在,此时处于未录入任何员工状态
-
文件存在但没有数据,此时处于员工被清空状态
-
文件存在且有数据,此时处于员工被正常录入情况,需要将文件中的数据加载到程序中
-
功能实现
-
添加
bool isEmptyFile;
成员属性判断是否为空文件 -
加载时三种不同的情况对应构造函数三种不同的赋值方式
-
在
workerManager.hpp
中添加对应的成员函数声明
// 获取成员数量
int getEmpNum();
// 初始化员工
void initEmp();
- 在
workerManager.cpp
中实
int WorkerManager::getEmpNum() {
ifstream ifs;
ifs.open(FILENAME, ios::in);
if (!ifs.is_open()) {
cout << "open file fail" << endl;
}
char buf[1024] = {0};
int memberNum = 0;
// 判断文件中有多少行,就有多少个员工
while (ifs.getline(buf, sizeof(buf))) {
memberNum++;
}
ifs.close();
return memberNum;
}
WorkerManager::WorkerManager() {
ifstream ifs;
ifs.open(FILENAME, ios::in);
if (!ifs.is_open()) {
cout << "文件不存在" << endl;
// 1.文件不存在
// 初始化成员变量
this->memberSize = 0;
this->pWorker = NULL;
this->isEmptyFile = true;
// 关闭读文件流
ifs.close();
return;
}
// 文件存在
char ch;
ifs >> ch;
// C++中判断文件是否为空采用向右读一个字节,调用ifs.eof()判断是否为真
if (ifs.eof()) {
cout << "文件存在但为空" << endl;
// 2.文件不存在
// 初始化成员变量
this->memberSize = 0;
this->pWorker = NULL;
this->isEmptyFile = true;
// 关闭读文件流
ifs.close();
return;
}
// 文件存在且不为空
this->isEmptyFile = false;
// 获取职工数量
this->memberSize = this->getEmpNum();
// 根据职工数量现在堆上开辟空间
this->pWorker = new Worker *[this->memberSize];
// 调用初始化成员将文件中的数据加载到内存中
this->initEmp();
return;
}
void WorkerManager::initEmp() {
ifstream ifs;
ifs.open(FILENAME, ios::in);
if (!ifs.is_open()) {
cout << "open file fail" << endl;
return;
}
int id;
string name;
int deptId;
Worker *worker = NULL;
int index = 0;
while (ifs >> id && ifs >> name && ifs >> deptId) {
switch (deptId) {
case 1:
worker = new Employee(id, name, deptId);
break;
case 2:
worker = new Manager(id, name, deptId);
break;
case 3:
worker = new Boss(id, name, deptId);
break;
}
this->pWorker[index] = worker;
index++;
}
ifs.close();
}
显示职工信息
功能分析
-
显示职工信息时,根据职工数量和职工数组,挨个遍历
-
在遍历过程中判断
deptId
,根据多态的方式去调用不同职工的ShowWorkerInfo
函数
功能实现
-
在
workerManager.hpp
中添加成员函数声明 -
代码示例
// 显示职工信息
void ShowEmpInfo();
-
在
workerManager.cpp
中实现 -
代码示例
void WorkerManager::ShowEmpInfo() {
for (int i = 0; i < this->memberSize; i++) {
Worker *worker = NULL;
switch (this->pWorker[i]->m_deptId) {
case 1:
worker = new Employee(this->pWorker[i]->m_id, this->pWorker[i]->m_name, this->pWorker[i]->m_deptId);
break;
case 2:
worker = new Manager(this->pWorker[i]->m_id, this->pWorker[i]->m_name, this->pWorker[i]->m_deptId);
break;
case 3:
worker = new Boss(this->pWorker[i]->m_id, this->pWorker[i]->m_name, this->pWorker[i]->m_deptId);
break;
}
worker->ShowWorkerInfo();
}
}
删除职工
功能分析
- 首先使用用户交互让用户输入要删除的员工id
- 根据id查找员工是否存在,不存在直接返回,存在找到公所在位置,从内存中删除
- 将删除后内存中的数据重新写文件
功能实现
-
在
workerManager.hpp
中添加成员函数声明 -
代码示例
// 删除职工
void DelEmp();
// 根据id查找职工在数组中的位置
int findIndexById(int id);
-
在
workerManager.cpp
中实现 -
代码示例
void WorkerManager::DelEmp() {
int id;
cout << "请输入要删除的员工编号" << endl;
cin >> id;
int index = this->findIndexById(id);
if (index == -1) {
return;
}
// 从前往后依次往前移动一个
for (int i = index; i < this->memberSize - 1; i++) {
this->pWorker[i] = this->pWorker[i + 1];
}
// 职工数减1
this->memberSize--;
// 重新写文件
this->saveFile();
}
int WorkerManager::findIndexById(int id) {
int i = 0;
for (; i < this->memberSize; i++) {
if (this->pWorker[i]->m_id == id) {
break;
}
}
// 没找到
if (i == this->memberSize) {
return -1;
}
return i;
}
- 在添加职工的逻辑中添加判断职工编号是否已被占用逻辑
while (true) {
cin >> id;
if (this->findIndexById(id) != -1) {
cout << "编号已存在,请重新输入" << endl;
} else {
break;
}
}
修改职工
功能分析
- 首先使用用户交互让用户输入要修改的员工id
- 根据id查找员工是否存在,不存在直接返回,存在找到公所在位置
- 通过交互让用户传入要修改的名字和部门编号
- 将修改后内存中的数据重新写文件
功能实现
-
在
workerManager.hpp
中添加成员函数声明 -
代码示例
// 删除工
void UpdateEmp();
-
在
workerManager.cpp
中实现 -
代码示例
void WorkerManager::UpdateEmp() {
int id;
cout << "请输入要修改的员工编号" << endl;
cin >> id;
int index = this->findIndexById(id);
if (index == -1) {
cout << "员工不存在" << endl;
return;
}
string name;
int deptId;
cout << "请输入要修改的名字" << endl;
cin >> name;
this->pWorker[index]->m_name = name;
cout << "请输入要修改的部门编号" << endl;
cin >> deptId;
this->pWorker[index]->m_deptId = deptId;
// 将修改后的数据重写文件
this->saveFile();
cout << "修改成功" << endl;
}
查找职工信息
需求分析
-
查询方式
-
根据id查询
-
根据name查询
-
-
处理流程
-
用户交互让用户选择使用那种方式查询
-
根据不同的方式查询对应数据所在内存数组的下标
-
使用多态的方式判断员工类型
-
输出对应员工信息
-
功能实现
-
在
workerManager.hpp
中添加成员函数声明 -
代码示例
// 查找职工
void FindEmp();
// 根据名字查找职工在数组中的位置
int findIndexByName(string name);
-
在
workerManager.cpp
中实现 -
代码示例
// 查找职工
void WorkerManager::FindEmp() {
cout << "请选择查找方式" << endl;
cout << "1.根据id查找" << endl;
cout << "2.根据name查找" << endl;
int choice;
int index;
cin >> choice;
switch (choice) {
case 1:
cout << "请输入要查找的id: ";
int id;
cin >> id;
index = this->findIndexById(id);
break;
case 2:
cout << "请输入要查找的name: ";
string name;
cin >> name;
index = this->findIndexByName(name);
break;
}
if (index == -1) {
cout << "查无此人" << endl;
return;
}
Worker *worker = NULL;
switch (this->pWorker[index]->m_deptId) {
case 1:
worker = new Employee(this->pWorker[index]->m_id, this->pWorker[index]->m_name,
this->pWorker[index]->m_deptId);
break;
case 2:
worker = new Manager(this->pWorker[index]->m_id, this->pWorker[index]->m_name,
this->pWorker[index]->m_deptId);
break;
case 3:
worker = new Boss(this->pWorker[index]->m_id, this->pWorker[index]->m_name,
this->pWorker[index]->m_deptId);
break;
}
worker->ShowWorkerInfo();
return;
}
// 根据名字查找职工在数组中的位置
int WorkerManager::findIndexByName(string name) {
int i = 0;
for (; i < this->memberSize; i++) {
if (this->pWorker[i]->m_name == name) {
break;
}
}
// 没找到
if (i == this->memberSize) {
return -1;
}
return i;
}
排序
需求分析
-
排序方式
-
按照id升序排列
-
按照id降序排列
-
-
处理流程
-
用户交互让用户选择使用升序还是降序
-
按照用户输入排序内存数组
-
排序后展示保存文件
-
功能实现
// 按照编号排序
void WorkerManager::SortById() {
cout << "请选择排序方式:" << endl;
cout << "1.升序排序" << endl;
cout << "2.降序排序" << endl;
int select;
cin >> select;
for (int i = 0; i < this->memberSize; i++)
{
int minOrMax = i;
for (int j = i + 1; j < this->memberSize; j++)
{
if (select == 1) //升序
{
if (this->pWorker[minOrMax]->m_id > this->pWorker[j]->m_id)
{
minOrMax = j;
}
}
else //降序
{
if (this->pWorker[minOrMax]->m_id < this->pWorker[j]->m_id)
{
minOrMax = j;
}
}
}
if (i != minOrMax)
{
Worker * temp = this->pWorker[i];
this->pWorker[i] = this->pWorker[minOrMax];
this->pWorker[minOrMax] = temp;
}
}
cout << "排序成功,结果如下" << endl;
this->ShowEmpInfo();
this->saveFile();
}
清空文件
需求分析
-
直接将数量置空文章来源:https://www.toymoban.com/news/detail-835137.html
-
将内存中的数据加载到文件文章来源地址https://www.toymoban.com/news/detail-835137.html
功能实现
- 在
workerManger.hpp
中声明成员函数
void WorkerManager::ClearEmp();
- 在
workerManger.cpp
中实现成员函数
void WorkerManager::ClearEmp() {
this->memberSize = 0;
this->saveFile();
}
到了这里,关于【黑马程序员】C++核心功能项目实战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!