C++项目实战之职工管理系统

职工管理系统

1. 管理系统需求

职工管理系统可以用来管理公司内所有员工的信息,利用C++来实现一个基于多态的职工管理系统

公司中职工分为三类:普通员工、经理、老板,显示信息时,需要显示职工编号、职工姓名、职工岗位、以及职责

  • 普通员工职责:完成经理交给的任务

  • 经理职责:完成老板交给的任务,并下发任务给员工

  • 老板职责:管理公司所有事务

管理系统中需要实现的功能如下:

  • 退出管理程序:退出当前管理系统
  • 增加职工信息:实现批量添加职工功能,将信息录入到文件中,职工信息为:职工编号、姓名、部门编号
  • 显示职工信息:显示公司内部所有职工的信息
  • 删除离职职工:按照编号删除指定的职工
  • 修改职工信息:按照编号修改职工个人信息
  • 查找职工信息:按照职工的编号或者职工的姓名进行查找相关的人员信息
  • 按照编号排序:按照职工编号,进行排序,排序规则由用户指定
  • 清空所有文档:清空文件中记录的所有职工信息 (清空前需要再次确认,防止误删)

2. 创建管理类

管理类负责的内容如下:

  • 与用户的沟通菜单界面
  • 对职工增删改查的操作
  • 与文件的读写交互

2.1 创建文件

在头文件和源文件的文件夹下分别创建 workerManager.hworkerManager.cpp 文件

2.2 头文件实现

workerManager.h 中设计管理类

代码如下:

#pragma once
#include <iostream>

class WorkerManager
{
public:
	WorkerManager();

	~WorkerManager();
};

2.3 源文件实现

workerManager.cpp 中将构造和析构函数空实现补全

#include "workerManager.h"

WorkerManager::WorkerManager()
{

}

WorkerManager::~WorkerManager()
{

}

至此职工管理类以创建完毕

3. 菜单功能

3.1 添加成员函数

在管理类 workerManager.h 中添加成员函数 void Show_Menu();

#pragma once
#include <iostream>

class WorkerManager
{
public:
	WorkerManager();

	void showMenu();

	~WorkerManager();
};

3.2 菜单功能实现

在管理类 workerManager.h 中添加成员函数 void Show_Menu();

void WorkerManager::showMenu()
{
	std::cout << "********************************************" << std::endl;
	std::cout << "*********  欢迎使用职工管理系统! **********" << std::endl;
	std::cout << "*************  0.退出管理程序  *************" << std::endl;
	std::cout << "*************  1.增加职工信息  *************" << std::endl;
	std::cout << "*************  2.显示职工信息  *************" << std::endl;
	std::cout << "*************  3.删除离职职工  *************" << std::endl;
	std::cout << "*************  4.修改职工信息  *************" << std::endl;
	std::cout << "*************  5.查找职工信息  *************" << std::endl;
	std::cout << "*************  6.按照编号排序  *************" << std::endl;
	std::cout << "*************  7.清空所有文档  *************" << std::endl;
	std::cout << "********************************************" << std::endl;
	std::cout << std::endl;
}

3.3 测试菜单功能

main.cpp 文件中中测试菜单功能

#include <iostream>
#include "workerManager.h"

int main()
{
	WorkerManager wm;
	wm.showMenu();

	return 0;
}
image-20230731154542863

4. 退出功能

4.1 提供功能接口

在main函数中提供分支选择,提供每个功能接口

int main()
{
	WorkerManager wm;

	int choise = 0;
	while (true)
	{
		wm.showMenu();

		std::cout << "请输入你的选择: " << std::endl;
		std::cin >> choise;
		
		switch (choise)
		{
		case 0: //退出系统
			break;
		case 1: //添加职工
			break;
		case 2: //显示职工
			break;
		case 3: //删除职工
			break;
		case 4: //修改职工
			break;
		case 5: //查找职工
			break;
		case 6: //排序职工
			break;
		case 7: //清空文件
			break;
		default:
			system("cls");
			break;
		}
	}
	return 0;
}

4.2 实现退出功能

workerManager.h 中提供退出系统的成员函数 void exitSystem();

workerManager.cpp 中提供具体的功能实现

void WorkerManager::exitSystem()
{
	cout << "欢迎下次使用" << endl;
	system("pause");
	exit(0);
}

4.3 测试功能

在main函数分支 0 选项中,调用退出程序的接口

image-20230731155904366

5. 创建职工类

5.1 创建职工抽象类

职工的分类为:普通员工、经理、老板

将三种职工抽象到一个类 (worker) 中,利用多态管理不同职工种类

职工的属性为:职工编号、职工姓名、职工所在部门编号

职工的行为为:岗位职责信息描述,获取岗位名称

头文件文件夹下 创建文件 worker.h 文件并且添加如下代码:

#pragma once
#include <iostream>

class Worker
{
public:
	int m_Id;
	std::string m_Name;
	int m_DeptId;

	virtual void showInfo() = 0;
	virtual std::string getDeptName() = 0;
};

5.2 创建普通员工类

普通员工类继承职工抽象类,并重写父类中纯虚函数

在头文件和源文件的文件夹下分别创建 employee.hemployee.cpp 文件

employee.h 中代码如下:

#pragma once
#include <iostream>
#include "worker.h"

class Employee :public Worker
{
public:
	Employee(int id, std::string name, int deptId);

	void showInfo();
	std::string getDeptName();
};

employee.cpp 中代码如下:

#include "employee.h"

Employee::Employee(int id, std::string name, int deptId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = deptId;
}

void Employee::showInfo()
{
	std::cout
		<< "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位: " << this->getDeptName()
		<< " \t岗位职责: 完成经理交给的任务" << std::endl;
}

std::string Employee::getDeptName()
{
	return std::string("普通员工");
}

5.3 创建经理类

经理类继承职工抽象类,并重写父类中纯虚函数,和普通员工类似

在头文件和源文件的文件夹下分别创建 manager.hmanager.cpp 文件

manager.h 中代码如下:

#pragma once
#include <iostream>
#include "worker.h"

class Manager :public Worker
{
public:
	Manager(int id, std::string name, int deptId);

	void showInfo();
	std::string getDeptName();
};

manager.cpp 中代码如下:

#include "manager.h"

Manager::Manager(int id, std::string name, int deptId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = deptId;
}

void Manager::showInfo()
{
	std::cout
		<< "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位: " << this->getDeptName()
		<< " \t岗位职责: 完成老板交给的任务,并下发任务给员工" << std::endl;
}

std::string Manager::getDeptName()
{
	return std::string("经理");
}

5.4 创建老板类

老板类继承职工抽象类,并重写父类中纯虚函数,和普通员工类似

在头文件和源文件的文件夹下分别创建 boss.hboss.cpp 文件

boss.h 中代码如下:

#pragma once
#include <iostream>
#include "worker.h"

class Boss :public Worker
{
public:
	Boss(int id, std::string name, int deptId);

	void showInfo();
	std::string getDeptName();
};

boss.cpp 中代码如下:

#include "boss.h"

Boss::Boss(int id, std::string name, int deptId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = deptId;
}

void Boss::showInfo()
{
	std::cout
		<< "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位: " << this->getDeptName()
		<< " \t岗位职责: 管理公司所有事务" << std::endl;
}

std::string Boss::getDeptName()
{
	return std::string("老板");
}

5.5 测试多态

main.cpp 中添加测试函数,并且运行能够产生多态

测试代码如下:

void test1()
{
	Worker* 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;
}

image-20230731165904709

6. 添加职工

功能描述:批量添加职工,并且保存到文件中

6.1 功能分析

分析:

用户在批量创建时,可能会创建不同种类的职工

如果想将所有不同种类的员工都放入到一个数组中,可以将所有员工的指针维护到一个数组里

如果想在程序中维护这个不定长度的数组,可以将数组创建到堆区,并利用 Worker ** 的指针维护

6.2 功能实现

WorkerManager.h 头文件中添加成员属性代码:

	//职工人数
	int m_EmpNum;
	
	//职工数组
	Worker** m_EmpArray;

WorkerManager 构造函数中初始化属性

WorkerManager::WorkerManager()
{
	this->m_EmpNum = 0;
	this->m_EmpArray = NULL;
}

WorkerManager.h 中添加成员函数

	void add_Emp();

WorkerManager.cpp 中实现该函数

void WorkerManager::add_Emp()
{
	std::cout << "请输入添加职工的数量: " << std::endl;
	int addNum = 0;
	std::cin >> addNum;

	if (addNum > 0)
	{
		int newSize = this->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;
			std::string name;
			int deptId;

			std::cout << "请输入第[" << i + 1 << "]个职工编号: ";
			std::cin >> id;

			std::cout << "请输入第[" << i + 1 << "]个职工姓名: ";
			std::cin >> name;

			std::cout << "请选择该职工的岗位" << std::endl;
			std::cout << "1.普通员工" << std::endl;
			std::cout << "2.经理" << std::endl;
			std::cout << "3.老板" << std::endl;
			std::cin >> deptId;

			Worker* newWorker = NULL;
			switch (deptId)
			{
			case 1:
				newWorker = new Employee(id, name, 1);
				break;
			case 2:
				newWorker = new Manager(id, name, 2);
				break;
			case 3:
				newWorker = new Boss(id, name, 3);
				break;
			default:
				break;
			}
			newSpace[this->m_EmpNum + i] = newWorker;
		}

		delete[] this->m_EmpArray;
		this->m_EmpArray = newSpace;
		this->m_EmpNum = newSize;
		this->m_FileIsEmpty = false;

		std::cout << "成功添加" << addNum << "人" << std::endl;
		this->save();
	}
	else
	{
		std::cout << "输入有误,请重新输入!" << std::endl;
	}

	system("pause");
	system("cls");
}

7. 文件交互——写文件

功能描述:对文件进行读写

在上一个添加功能中,我们只是将所有的数据添加到了内存中,一旦程序结束就无法保存了

因此文件管理类中需要一个与文件进行交互的功能,对于文件进行读写操作

7.1 设定文件路径

首先我们将文件路径,在 workerManager.h 中添加宏常量,并且包含头文件 fstream

#include <fstream>
#define  FILENAME "empFile.txt"

7.2 成员函数声明

workerManager.h 中类里添加成员函数 void save()

//保存文件
void save();

7.3 保存文件功能实现

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();
}

7.4 保存文件功能测试

在添加职工功能中添加成功后添加保存文件函数

8. 文件交互——读文件

功能描述:将文件中的内容读取到程序中

虽然我们实现了添加职工后保存到文件的操作,但是每次开始运行程序,并没有将文件中数据读取到程序中

而我们的程序功能中还有清空文件的需求

因此构造函数初始化数据的情况分为三种

  1. 第一次使用,文件未创建
  2. 文件存在,但是数据被用户清空
  3. 文件存在,并且保存职工的所有数据

8.1 文件未创建

workerManager.h 中添加新的成员属性 m_FileIsEmpty 标志文件是否为空

	//标志文件是否为空
	bool m_FileIsEmpty;

修改 WorkerManager.cpp 中构造函数代码

WorkerManager::WorkerManager()
{
	//文件不存在
	std::ifstream ifs(FILENAME, std::ios::in);
	if (!ifs.is_open())
	{
		std::cout << "文件不存在" << std::endl;
		this->m_EmpNum = 0;
		this->m_EmpArray = NULL;
		this->m_FileIsEmpty = true;
		ifs.close();
		return;
	}
}

删除文件后,测试文件不存在时初始化数据功能

8.2 文件存在且数据为空

workerManager.cpp 中的构造函数追加代码:

	//文件存在,但没有内容
	char buf;
	ifs >> buf;
	//只读文件里的第一个位置,看看是否是空的
	if (ifs.eof())
	{
		std::cout << "文件为空" << std::endl;
		this->m_EmpNum = 0;
		this->m_EmpArray = NULL;
		this->m_FileIsEmpty = true;
		ifs.close();
		return;
	}

8.3 文件存在且保存职工数据

8.3.1 获取记录的职工人数

workerManager.h 中添加成员函数 int get_EmpNum();

	//统计人数
	int get_EmpNum();

workerManager.cpp 中实现

int WorkerManager::get_EmpNum()
{
	std::ifstream ifs(FILENAME, std::ios::in);

	int id;
	std::string name;
	int deptId;

	int count = 0;
	//这种方法会使文件内容为空的情况下仍然返回1,造成缓冲区溢出
	/*
	char buf[1024] = { 0 };
	while (ifs.getline(buf, sizeof(buf)))
	{
		num++;
	}
	*/

	while (ifs >> id && ifs >> name && ifs >> deptId)
	{
		count++;
	}
	ifs.close();

	return count;
}

workerManager.cpp 构造函数中继续追加代码:

	int num =  this->get_EmpNum();
	cout << "职工个数为:" << num << endl;  //测试代码
	this->m_EmpNum = num;  //更新成员属性 

8.3.2 初始化数组

根据职工的数据以及职工数据,初始化 workerManager 中的 Worker ** m_EmpArray 指针

workerManager.h 中添加成员函数 void init_Emp();

	//初始化员工
	void init_Emp();

workerManager.cpp 中实现

void WorkerManager::init_Emp()
{
	std::ifstream ifs(FILENAME, std::ios::in);

	int id;
	std::string name;
	int deptId;

	int index = 0;
	while (ifs >> id && ifs >> name && ifs >> deptId)
	{
		Worker* worker = NULL;
		if (deptId == 1)
		{
			worker = new Employee(id, name, deptId);
		}
		else if (deptId == 2)
		{
			worker = new Manager(id, name, deptId);
		}
		else
		{
			worker = new Boss(id, name, deptId);
		}
		this->m_EmpArray[index] = worker;
		index++;
	}
	ifs.close();
}

workerManager.cpp 构造函数中追加代码

	//根据职工数创建数组
	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;
	}

9. 显示职工

功能描述:显示当前所有职工信息

9.1 显示职工函数声明

workerManager.h 中添加成员函数 void Show_Emp();

	//显示职工
	void show_Emp();

9.2 显示职工函数实现

workerManager.cpp 中实现成员函数 void Show_Emp();

//显示职工
void WorkerManager::show_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		for (int i = 0; i < m_EmpNum; i++)
		{
			//利用多态调用接口
			this->m_EmpArray[i]->showInfo();
		}
	}

	system("pause");
	system("cls");
}

10. 删除职工

10.1 删除职工函数声明

workerManager.h 中添加成员函数 void del_Emp();

	//修改职工
	void del_Emp();

10.2 职工是否存在函数声明

很多功能都需要用到根据职工是否存在来进行操作如:删除职工、修改职工、查找职工

因此添加该公告函数,以便后续调用

workerManager.h 中添加成员函数 int isExist(int id);

	//按照职工编号判断职工是否存在,若存在返回职工在数组中位置,不存在返回-1
	int isExist(int id);

10.3 职工是否存在函数实现

workerManager.cpp 中实现成员函数 int isExist(int id);

int WorkerManager::isExist(int id)
{
	int count = -1;
	for (int i = 0; i < this->m_EmpNum; i++)
	{
		if (this->m_EmpArray[i]->m_Id == id)
		{
			count = i;
			break;
		}
	}
	return count;
}

10.4 删除职工函数实现

workerManager.cpp中实现成员函数 void Del_Emp();

void WorkerManager::del_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
	}
	else
	{
		int id = -1;
		std::cout << "请输入你要删除的职工编号: ";
		std::cin >> id;
		int result = isExist(id);

		if (result != -1)
		{
			for (int i = result; i < this->m_EmpNum - 1; i++)
			{
				this->m_EmpArray[i] = this->m_EmpArray[i + 1];
			}
			this->m_EmpNum--;
			this->save();
			std::cout << "删除成功" << std::endl;
		}
		else
		{
			std::cout << "没有找到职工编号为[" << id << "]的员工" << std::endl;
		}

	}

	system("pause");
	system("cls");
}

11. 修改职工

功能描述:能够按照职工的编号对职工信息进行修改并保存

11.1 修改职工函数声明

workerManager.h 中添加成员函数 void mod_Emp();

	//修改职工
	void mod_Emp();

11.2 修改职工函数实现

workerManager.cpp 中实现成员函数 void_mod_Emp();

void WorkerManager::mod_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
		return;
	}

	int id = -1;
	std::cout << "请输入你要修改的职工编号: ";
	std::cin >> id;
	int result = isExist(id);

	if (result != -1)
	{
		this->m_EmpArray[result]->showInfo();
		
		int id;
		std::string name;
		int deptId;

		std::cout << "请输入修改的职工编号: ";
		std::cin >> id;

		std::cout << "请输入修改的职工姓名: ";
		std::cin >> name;

		std::cout << "请选择该职工的岗位" << std::endl;
		std::cout << "1.普通员工" << std::endl;
		std::cout << "2.经理" << std::endl;
		std::cout << "3.老板" << std::endl;
		std::cin >> deptId;

		Worker* modWorker = NULL;
		switch (deptId)
		{
		case 1:
			modWorker = new Employee(id, name, 1);
			break;
		case 2:
			modWorker = new Manager(id, name, 2);
			break;
		case 3:
			modWorker = new Boss(id, name, 3);
			break;
		default:
			break;
		}
		this->m_EmpArray[result] = modWorker;
		this->save();
		std::cout << "修改成功,修改后的信息如下" << std::endl;
		this->m_EmpArray[result]->showInfo();
	}
	else
	{
		std::cout << "没有找到职工编号为[" << id << "]的员工" << std::endl;
	}

	system("pause");
	system("cls");
}

为什么不能直接覆盖?

没有真正改变子类对象,假如数组中是这样的

//直接操纵数组中存放的值
this->m_EmpArray[result].m_Id;
this->m_EmpArray[result].m_Name;
this->m_EmpArray[result].m_deptId;

类型没有变化,那么你就拥有了这个类型的所有函数。试想一下,假如一位普通员工升职成为经理了,但是它的类型仍然是Employee,而Manager中所有的权限他都没有,所以直接覆盖值是不对的

image-20230802214107033

12. 查找职工

功能描述:提供两种查找职工方式,一种按照职工编号,一种按照职工姓名

12.1 查找职工函数声明

workerManager.h 中添加成员函数 void find_Emp();

	//查找职工
	void find_Emp();

12.2 查找职工函数实现

workerManager.cpp 中实现成员函数 void find_Emp();

void WorkerManager::find_Emp()
{
	std::cout << "请输入查找的方式:" << std::endl;
	std::cout << "1.按员工编号查找" << std::endl;
	std::cout << "2.按员工姓名查找" << std::endl;
	int choise = 0;
	std::cin >> choise;

	if (choise == 1)
	{
		int id;
		std::cout << "请输入你要查找的员工编号: ";
		std::cin >> id;
		int result = isExist(id);

		if (result != -1)
		{
			std::cout << "查找成功,员工信息如下:" << std::endl;
			this->m_EmpArray[result]->showInfo();
		}
		else
		{
			std::cout << "没有找到职工编号为[" << id << "]的员工" << std::endl;
		}
	}
	else if (choise == 2)
	{
		std::string name;
		std::cout << "请输入你要查找的员工姓名: ";
		std::cin >> name;

		bool flag = false;
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			if (this->m_EmpArray[i]->m_Name == name)
			{
				std::cout << "查找成功,员工信息如下:" << std::endl;
				this->m_EmpArray[i]->showInfo();
				flag = true;
			}
		}
		if (flag == false)
		{
			std::cout << "没有找到职工姓名为[" << name << "]的员工" << std::endl;
		}
	}
	else
	{
		std::cout << "输入有误,请重新输入" << std::endl;
	}

	system("pause");
	system("cls");
}

13. 职工排序

功能描述:按照职工编号进行排序,排序的顺序由用户指定

13.1 排序函数声明

workerManager.h 中添加成员函数 void sort_Emp();

	//排序职工
	void sort_Emp();

13.2 排序函数实现

workerManager.cpp 中实现成员函数 void sort_Emp();

void WorkerManager::sort_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
		system("pause");
		system("cls");
	}
	else
	{
		std::cout << "请输入排序的方式:" << std::endl;
		std::cout << "1.按员工编号升序" << std::endl;
		std::cout << "2.按员工编号降序" << std::endl;
		
		int choise = 0;
		std::cin >> choise;
		
		//升序
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			int Min_Or_Max = i;
			for (int j = i + 1; j < this->m_EmpNum; j++)
			{
				if (choise == 1)
				{
					//前一个大于后一个,就移动min指针
					if (this->m_EmpArray[Min_Or_Max]->m_Id > this->m_EmpArray[j]->m_Id)
					{
						Min_Or_Max = j;
					}
					//前一个小于后一个,继续往后比较
				}
				else if (choise == 2)
				{
					//前一个小于后一个,就移动max指针
					if (this->m_EmpArray[Min_Or_Max]->m_Id < this->m_EmpArray[j]->m_Id)
					{
						Min_Or_Max = j;
					}
					//前一个大于后一个,继续往后比较
				}
			}
			//一轮比较后,如果标记位置变了,交换位置
			if (Min_Or_Max != i)
			{
				Worker* tempWorker = this->m_EmpArray[i];
				this->m_EmpArray[i] = this->m_EmpArray[Min_Or_Max];
				this->m_EmpArray[Min_Or_Max] = tempWorker;
			}
		}
		this->save();
		std::cout << "排序完成,排序后的结果如下:" << std::endl;
		this->show_Emp();
	}
}

该排序算法选用 选择排序 难度不大,如果没有算法基础可以去看算法可视化动画,没有基础的人看完一般在1个小时内能够写出来大致的思路

14. 清空文件

功能描述:将文件中记录数据清空

14.1 清空函数声明

workerManager.h 中声明函数 void clean_File();

	//清空文件
	void clean_File();

14.2 清空函数实现

workerManager.cpp 中实现成员函数 void clean_File();

void WorkerManager::clean_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
	}
	else
	{
		std::cout << "请确认是否需要清空?" << std::endl;
		std::cout << "1.清空" << std::endl;
		std::cout << "2.返回" << std::endl;

		int choise = 0;
		std::cin >> choise;

		if (choise == 1)
		{
			std::ofstream ofs(FILENAME, std::ios::trunc);
			ofs.close();
			if (this->m_EmpArray != NULL)
			{
				for (int i = 0; i < this->m_EmpNum; i++)
				{
					delete this->m_EmpArray[i];
					this->m_EmpArray[i] = NULL;

				}
				delete[] this->m_EmpArray;
				this->m_EmpArray = NULL;
				this->m_EmpNum = 0;
				this->m_FileIsEmpty = true;
			}
			std::cout << "清空成功" << std::endl;
		}
	}

	system("pause");
	system("cls");
}

源代码及文件结构

├─头文件
│      boss.h
│      employee.h
│      worker.h
│      workerManager.h
│
├─源文件
│      boss.cpp
│      employee.cpp
│      EmploySys.cpp
│      manager.cpp
│      workerManager.cpp

项目关系图:

image-20230803183739601

1. 员工类

1.1 员工抽象类 Worker — 基类

worker.h

#pragma once
#include <iostream>

class Worker
{
public:
	int m_Id;
	std::string m_Name;
	int m_DeptId;

	virtual void showInfo() = 0;
	virtual std::string getDeptName() = 0;
};

1.2 普通员工类 Employee — 派生类

Employee.h

#pragma once
#include <iostream>
#include "worker.h"

class Employee :public Worker
{
public:
	Employee(int id, std::string name, int deptId);

	void showInfo();
	std::string getDeptName();
};

Employee.cpp

#include "employee.h"

Employee::Employee(int id, std::string name, int deptId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = deptId;
}

void Employee::showInfo()
{
	std::cout
		<< "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位: " << this->getDeptName()
		<< " \t岗位职责: 完成经理交给的任务" << std::endl;
}

std::string Employee::getDeptName()
{
	return std::string("普通员工");
}

1.3 经理类 Manager — 派生类

Manager.h

#pragma once
#include <iostream>
#include "worker.h"

class Manager :public Worker
{
public:
	Manager(int id, std::string name, int deptId);

	void showInfo();
	std::string getDeptName();
};

Manager.cpp

#include "manager.h"

Manager::Manager(int id, std::string name, int deptId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = deptId;
}

void Manager::showInfo()
{
	std::cout
		<< "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位: " << this->getDeptName()
		<< " \t岗位职责: 完成老板交给的任务,并下发任务给员工" << std::endl;
}

std::string Manager::getDeptName()
{
	return std::string("经理");
}

1.4 老板类 Boss — 派生类

Boss.h

#pragma once
#include <iostream>
#include "worker.h"

class Boss :public Worker
{
public:
	Boss(int id, std::string name, int deptId);

	void showInfo();
	std::string getDeptName();
};

Boss.cpp

#include "boss.h"

Boss::Boss(int id, std::string name, int deptId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = deptId;
}

void Boss::showInfo()
{
	std::cout
		<< "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位: " << this->getDeptName()
		<< " \t岗位职责: 管理公司所有事务" << std::endl;
}

std::string Boss::getDeptName()
{
	return std::string("老板");
}

2. 员工管理类

该类用于声明和实现主界面的所有操作

workerManager.h

#pragma once
#include <iostream>
#include <fstream>
#include "worker.h"
#include "employee.h"
#include "manager.h"
#include "boss.h"

#define FILENAME "empFile.txt"

class WorkerManager
{
public:
	int m_EmpNum;
	Worker** m_EmpArray;
	bool m_FileIsEmpty;

	WorkerManager();

	void showMenu();
	void exitSystem();
	void add_Emp();
	void save();
	int get_EmpNum();
	void init_Emp();
	void show_Emp();
	int isExist(int id);
	void del_Emp();
	void mod_Emp();
	void find_Emp();
	void sort_Emp();
	void clean_Emp();

	~WorkerManager();
};

workerManager.cpp

#include "workerManager.h"

WorkerManager::WorkerManager()
{
	//文件不存在
	std::ifstream ifs(FILENAME, std::ios::in);
	if (!ifs.is_open())
	{
		//std::cout << "文件不存在" << std::endl;
		this->m_EmpNum = 0;
		this->m_EmpArray = NULL;
		this->m_FileIsEmpty = true;
		ifs.close();
		return;
	}

	//文件存在,但没有内容
	char buf;
	ifs >> buf;
	//只读文件里的第一个位置,看看是否是空的
	if (ifs.eof())
	{
		//std::cout << "文件为空" << std::endl;
		this->m_EmpNum = 0;
		this->m_EmpArray = NULL;
		this->m_FileIsEmpty = true;
		ifs.close();
		return;
	}

	//文件存在,并且记录数据
	int num = this->get_EmpNum();
	this->m_EmpNum = num;
	this->m_EmpArray = new Worker * [this->m_EmpNum];
	this->init_Emp();
}

void WorkerManager::showMenu()
{
	std::cout << "********************************************" << std::endl;
	std::cout << "*********  欢迎使用职工管理系统! **********" << std::endl;
	std::cout << "*************  0.退出管理程序  *************" << std::endl;
	std::cout << "*************  1.增加职工信息  *************" << std::endl;
	std::cout << "*************  2.显示职工信息  *************" << std::endl;
	std::cout << "*************  3.删除离职职工  *************" << std::endl;
	std::cout << "*************  4.修改职工信息  *************" << std::endl;
	std::cout << "*************  5.查找职工信息  *************" << std::endl;
	std::cout << "*************  6.按照编号排序  *************" << std::endl;
	std::cout << "*************  7.清空所有文档  *************" << std::endl;
	std::cout << "********************************************" << std::endl;
	std::cout << std::endl;
}

void WorkerManager::exitSystem()
{
	std::cout << "欢迎下次使用" << std::endl;
	exit(0);
}

void WorkerManager::add_Emp()
{
	std::cout << "请输入添加职工的数量: " << std::endl;
	int addNum = 0;
	std::cin >> addNum;

	if (addNum > 0)
	{
		int newSize = this->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;
			std::string name;
			int deptId;

			std::cout << "请输入第[" << i + 1 << "]个职工编号: ";
			std::cin >> id;

			std::cout << "请输入第[" << i + 1 << "]个职工姓名: ";
			std::cin >> name;

			std::cout << "请选择该职工的岗位" << std::endl;
			std::cout << "1.普通员工" << std::endl;
			std::cout << "2.经理" << std::endl;
			std::cout << "3.老板" << std::endl;
			std::cin >> deptId;

			Worker* newWorker = NULL;
			switch (deptId)
			{
			case 1:
				newWorker = new Employee(id, name, 1);
				break;
			case 2:
				newWorker = new Manager(id, name, 2);
				break;
			case 3:
				newWorker = new Boss(id, name, 3);
				break;
			default:
				break;
			}
			newSpace[this->m_EmpNum + i] = newWorker;
		}

		delete[] this->m_EmpArray;
		this->m_EmpArray = newSpace;
		this->m_EmpNum = newSize;
		this->m_FileIsEmpty = false;

		std::cout << "成功添加" << addNum << "人" << std::endl;
		this->save();
	}
	else
	{
		std::cout << "输入有误,请重新输入!" << std::endl;
	}

	system("pause");
	system("cls");
}

void WorkerManager::save()
{
	std::ofstream ofs(FILENAME, std::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 << std::endl;
	}

	ofs.close();
}

int WorkerManager::get_EmpNum()
{
	std::ifstream ifs(FILENAME, std::ios::in);

	int id;
	std::string name;
	int deptId;

	int count = 0;
	//这种方法会使文件内容为空的情况下仍然返回1,造成缓冲区溢出
	/*
	char buf[1024] = { 0 };
	while (ifs.getline(buf, sizeof(buf)))
	{
		num++;
	}
	*/

	while (ifs >> id && ifs >> name && ifs >> deptId)
	{
		count++;
	}
	ifs.close();

	return count;
}

void WorkerManager::init_Emp()
{
	std::ifstream ifs(FILENAME, std::ios::in);

	int id;
	std::string name;
	int deptId;

	int index = 0;
	while (ifs >> id && ifs >> name && ifs >> deptId)
	{
		Worker* worker = NULL;
		if (deptId == 1)
		{
			worker = new Employee(id, name, deptId);
		}
		else if (deptId == 2)
		{
			worker = new Manager(id, name, deptId);
		}
		else
		{
			worker = new Boss(id, name, deptId);
		}
		this->m_EmpArray[index] = worker;
		index++;
	}
	ifs.close();
}

void WorkerManager::show_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
	}
	else
	{
		for (int i = 0; i < m_EmpNum; i++)
		{
			this->m_EmpArray[i]->showInfo();
		}
	}

	system("pause");
	system("cls");
}

int WorkerManager::isExist(int id)
{
	int count = -1;
	for (int i = 0; i < this->m_EmpNum; i++)
	{
		if (this->m_EmpArray[i]->m_Id == id)
		{
			count = i;
			break;
		}
	}
	return count;
}

void WorkerManager::del_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
	}
	else
	{
		int id = -1;
		std::cout << "请输入你要删除的职工编号: ";
		std::cin >> id;
		int result = isExist(id);

		if (result != -1)
		{
			for (int i = result; i < this->m_EmpNum - 1; i++)
			{
				this->m_EmpArray[i] = this->m_EmpArray[i + 1];
			}
			this->m_EmpNum--;
			this->save();
			std::cout << "删除成功" << std::endl;
		}
		else
		{
			std::cout << "没有找到职工编号为[" << result << "]的员工" << std::endl;
		}
	}

	system("pause");
	system("cls");
}

void WorkerManager::mod_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
	}
	else
	{
		int id = -1;
		std::cout << "请输入你要修改的职工编号: ";
		std::cin >> id;
		int result = isExist(id);

		if (result != -1)
		{
			this->m_EmpArray[result]->showInfo();

			int id;
			std::string name;
			int deptId;

			std::cout << "请输入修改的职工编号: ";
			std::cin >> id;

			std::cout << "请输入修改的职工姓名: ";
			std::cin >> name;

			std::cout << "请选择该职工的岗位" << std::endl;
			std::cout << "1.普通员工" << std::endl;
			std::cout << "2.经理" << std::endl;
			std::cout << "3.老板" << std::endl;
			std::cin >> deptId;

			Worker* modWorker = NULL;
			switch (deptId)
			{
			case 1:
				modWorker = new Employee(id, name, 1);
				break;
			case 2:
				modWorker = new Manager(id, name, 2);
				break;
			case 3:
				modWorker = new Boss(id, name, 3);
				break;
			default:
				break;
			}
			this->m_EmpArray[result] = modWorker;
			this->save();
			std::cout << "修改成功,修改后的信息如下" << std::endl;
			this->m_EmpArray[result]->showInfo();
		}
		else
		{
			std::cout << "没有找到职工编号为[" << id << "]的员工" << std::endl;
		}
	}

	system("pause");
	system("cls");
}

void WorkerManager::find_Emp()
{
	std::cout << "请输入查找的方式:" << std::endl;
	std::cout << "1.按员工编号查找" << std::endl;
	std::cout << "2.按员工姓名查找" << std::endl;
	int choise = 0;
	std::cin >> choise;

	if (choise == 1)
	{
		int id;
		std::cout << "请输入你要查找的员工编号: ";
		std::cin >> id;
		int result = isExist(id);

		if (result != -1)
		{
			std::cout << "查找成功,员工信息如下:" << std::endl;
			this->m_EmpArray[result]->showInfo();
		}
		else
		{
			std::cout << "没有找到职工编号为[" << id << "]的员工" << std::endl;
		}
	}
	else if (choise == 2)
	{
		std::string name;
		std::cout << "请输入你要查找的员工姓名: ";
		std::cin >> name;

		bool flag = false;
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			if (this->m_EmpArray[i]->m_Name == name)
			{
				std::cout << "查找成功,员工信息如下:" << std::endl;
				this->m_EmpArray[i]->showInfo();
				flag = true;
			}
		}
		if (flag == false)
		{
			std::cout << "没有找到职工姓名为[" << name << "]的员工" << std::endl;
		}
	}
	else
	{
		std::cout << "输入有误,请重新输入" << std::endl;
	}

	system("pause");
	system("cls");
}

void WorkerManager::sort_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
		system("pause");
		system("cls");
	}
	else
	{
		std::cout << "请输入排序的方式:" << std::endl;
		std::cout << "1.按员工编号升序" << std::endl;
		std::cout << "2.按员工编号降序" << std::endl;

		int choise = 0;
		std::cin >> choise;

		//升序
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			int Min_Or_Max = i;
			for (int j = i + 1; j < this->m_EmpNum; j++)
			{
				if (choise == 1)
				{
					//前一个大于后一个,就移动min指针
					if (this->m_EmpArray[Min_Or_Max]->m_Id > this->m_EmpArray[j]->m_Id)
					{
						Min_Or_Max = j;
					}
					//前一个小于后一个,继续往后比较
				}
				else if (choise == 2)
				{
					//前一个小于后一个,就移动max指针
					if (this->m_EmpArray[Min_Or_Max]->m_Id < this->m_EmpArray[j]->m_Id)
					{
						Min_Or_Max = j;
					}
					//前一个大于后一个,继续往后比较
				}
			}
			//一轮比较后,如果标记位置变了,交换位置
			if (Min_Or_Max != i)
			{
				Worker* tempWorker = this->m_EmpArray[i];
				this->m_EmpArray[i] = this->m_EmpArray[Min_Or_Max];
				this->m_EmpArray[Min_Or_Max] = tempWorker;
			}
		}
		this->save();
		std::cout << "排序完成,排序后的结果如下:" << std::endl;
		this->show_Emp();
	}
}

void WorkerManager::clean_Emp()
{
	if (this->m_FileIsEmpty)
	{
		std::cout << "文件不存在或记录为空" << std::endl;
	}
	else
	{
		std::cout << "请确认是否需要清空?" << std::endl;
		std::cout << "1.清空" << std::endl;
		std::cout << "2.返回" << std::endl;

		int choise = 0;
		std::cin >> choise;

		if (choise == 1)
		{
			std::ofstream ofs(FILENAME, std::ios::trunc);
			ofs.close();
			if (this->m_EmpArray != NULL)
			{
				for (int i = 0; i < this->m_EmpNum; i++)
				{
					delete this->m_EmpArray[i];
					this->m_EmpArray[i] = NULL;

				}
				delete[] this->m_EmpArray;
				this->m_EmpArray = NULL;
				this->m_EmpNum = 0;
				this->m_FileIsEmpty = true;
			}
			std::cout << "清空成功" << std::endl;
		}
	}

	system("pause");
	system("cls");
}

WorkerManager::~WorkerManager()
{
	if (this->m_EmpArray != NULL)
	{
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			delete this->m_EmpArray[i];
		}
		delete[] this->m_EmpArray;
		this->m_EmpArray = NULL;
	}
}

3. Main函数主体

负责调用我们写好的函数

main.cpp

#include <iostream>
#include "workerManager.h"
#include "worker.h"
#include "employee.h"
#include "manager.h"
#include "boss.h"

int main()
{
	WorkerManager wm;

	int choise = 0;
	while (true)
	{
		wm.showMenu();

		std::cout << "请输入你的选择: " << std::endl;
		std::cin >> choise;
		
		switch (choise)
		{
		case 0: //退出系统
			wm.exitSystem();
			break;
		case 1: //添加职工
			wm.add_Emp();
			break;
		case 2: //显示职工
			wm.show_Emp();
			break;
		case 3: //删除职工
			wm.del_Emp();
			break;
		case 4: //修改职工
			wm.mod_Emp();
			break;
		case 5: //查找职工
			wm.find_Emp();
			break;
		case 6: //排序职工
			wm.sort_Emp();
			break;
		case 7: //清空文件
			wm.clean_Emp();
			break;
		default:
			system("cls");
			break;
		}
	}
	
	return 0;
}
posted @ 2023-08-03 21:05  sarexpine  阅读(419)  评论(1编辑  收藏  举报