我的第一个C++千行项目——职工管理系统,宣布完结!


项目介绍

这是一个面向C++学习者的一个小项目,很适合已经学习完C++核心编程的朋友来练手,它可以帮助你把之前学习的技能融会贯通。

它的主要功能为:

  • 增加职工信息
  • 显示职工信息
  • 删除离职职工
  • 修改职工信息
  • 查找职工信息
  • 按照编号排序
  • 清空所有文档

了解了需求之后,用你的方式去实现它吧!

以下是我的实现:

头文件

boss.h
#pragma once
#include "worker.h"

class Boss :public Worker
{
public:
	Boss(int workerId, string name);

	//显示个人所有信息
	void showInfo();

	//获取员工名字
	string getWorkerName();

	//获取岗位
	string getDepartmentName();

	//获取职责
	string getDepartmentDuty();
};
employee.h
#pragma once
#include "worker.h"

class Employee :public Worker
{
public:
	Employee(int workerId, string name);

	//显示个人所有信息
	void showInfo();

	//获取员工名字
	string getWorkerName();

	//获取岗位
	string getDepartmentName();

	//获取职责
	string getDepartmentDuty();
};
manager.h
#pragma once
#include "worker.h"

class Manager:public Worker
{
public:
	Manager(int workerId, string name);

	//显示个人所有信息
	void showInfo();

	//获取员工名字
	string getWorkerName();

	//获取岗位
	string getDepartmentName();

	//获取职责
	string getDepartmentDuty();
};
worker.h
#pragma once
#include <iostream>
using namespace std;
#include <string>

class Worker
{
public:
	//显示个人信息
	virtual void showInfo() = 0;

	//获取员工名字
	virtual string getWorkerName() = 0;

	//获取岗位
	virtual string getDepartmentName() = 0;

	//获取职责
	virtual string getDepartmentDuty() = 0;

	//职工编号
	int workerId;
	//职工名字
	string workerName;
	//岗位
	string departmentName;
	//职责
	string departmentDuty;
};
workerManager.h
#pragma once
#include <iostream>
#include <fstream>
#include "worker.h"
using namespace std;
#define FILENAME "workerFile.txt"

//适配开始菜单的enum
enum
{
	EXIT,
	ADD,
	DISPALY,
	DELETE,
	MODIFY,
	SEEK,
	SORT,
	EMPTY
};

//适配员工职务选择的enum
enum
{
	BOSS = 1,
	MANAGER,
	EMPLOYEE
};

//适配查找员工方式的enum
enum
{
	RETURN,
	BYID,
	BYNAME
};

//启动程序
void Start();

//管理与用户的交互,调用职工管理系统内核
class WorkerManager
{
public:
	WorkerManager();

	void showMenu();

	void exitSystem();

	~WorkerManager();

	void AddWorker();

	void saveToFile();

	//从程序外的文件中,展示职工信息
	void showFromFile();

	//从程序内的数组中,展示职工信息
	void showFromArray();

	//初始化数组
	void initArray();

	//判断员工是否存在
	// 1.存在   ->  返回其下标
	// 2.不存在 ->  返回 -1
	int isExist(int id);

	//删除员工
	void deleteWorker();

	//修改员工信息
	void modifyWorkerInfo();

	void seekWorker();

	int getWorkerNumber();

	void sortWorkerById();

	bool existInfo();

	void emptyInfo();

private:
	bool fileEmpty;
	int fileWorkerNumber;
	int workerNumber;
	Worker** workerArray;
};

源文件

boss.cpp
#include "boss.h"

Boss::Boss(int workerId, string name)
{
	this->workerId = workerId;
	this->workerName = name;
	this->departmentName = "老板";
	this->departmentDuty = "为公司指明发展方向";//因为所有boss的职责都一样,所以我们这里直接写死
}

//显示个人所有信息
void Boss::showInfo()
{
	cout << "职工编号: " << this->workerId
		<< " \t职工姓名: " << this->workerName
		<< " \t岗位:" << this->getDepartmentName()
		<< " \t岗位职责:" << this->getDepartmentDuty() << endl;
}

//获取员工名字
string Boss::getWorkerName()
{
	return this->workerName;
}

//获取岗位
string Boss::getDepartmentName()
{
	return this->departmentName;
}

//获取职责
string Boss::getDepartmentDuty()
{
	return this->departmentDuty;
}
employee.cpp
#include "workerManager.h"
#include "boss.h"
#include "employee.h"
#include "manager.h"

void Start()
{
	WorkerManager wm;
	int choice = 0;

	while (true)
	{
		wm.showMenu();
		cin >> choice;

		switch (choice)
		{
		case EXIT:
			wm.exitSystem();
			break;
		case ADD:
			wm.AddWorker();
			wm.saveToFile();
			break;
		case DISPALY:
			//wm.showFromFile();
			wm.showFromArray();
			break;
		case DELETE:
			wm.deleteWorker();
			break;
		case MODIFY:
			wm.modifyWorkerInfo();
			break;
		case SEEK:
			wm.seekWorker();
			break;
		case SORT:
			wm.sortWorkerById();
			break;
		case EMPTY:
			wm.emptyInfo();
			break;
		default:
			cout << "输入错误,请重新输入数字0~7:" << endl;
			cout << endl;
			break;
		}
	}
}

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 << "*************  6.按照编号排序  *************" << endl;
	cout << "*************  7.清空所有文档  *************" << endl;
	cout << "********************************************" << endl;
	cout << endl;
}

WorkerManager::WorkerManager()
{
	//文件打开有3种情况,我们要为其做3种不同的构造函数:
	// 1.没有文件
	// 2.有文件,但内容为空(上次使用时,最后一步操作是“清空所有文档”)
	// 3.有文件,且里面有内容
	//

	ifstream ifs;
	ifs.open(FILENAME, ios::in);
	char fileEnd;

	//1.没有文件
	if (!ifs.is_open())
	{
		//cout << "文件不存在" << endl;

		this->fileEmpty = true;
		this->workerNumber = 0;
		this->workerArray = NULL;
		this->fileWorkerNumber = 0;

		ifs.close();
		return;
	}

	//2.有文件,但内容为空
	//
	//文件中最少会有一个字符——EOF,现在我们从文件读走一个字符
	//如果文件因此为空了,那么说明我们刚刚读走的就是EOF,也就是说,现在文档里什么都没有了
	//然后,我们利用ifs.eof()去判断文件是否为空,
	// 若为空,则得出结论:该文件内容为空
	ifs >> fileEnd;

	if (ifs.eof())
	{
		//cout << "文件为空" << endl;

		this->fileEmpty = true;
		this->workerNumber = 0;
		this->workerArray = NULL;
		this->fileWorkerNumber = 0;

		ifs.close();
		return;
	}

	//3.有文件,且里面有内容
	//
	//当代码走到这,说明前2种情况都没有发生,所以此处不需要进行if判断

	//a.先求出文件中有几条数据
	this->fileWorkerNumber = this->getWorkerNumber();
	//cout << this->fileWorkerNumber;

	//b.在数据中开辟等量的空间,以便后续将文件中的数据存放至数组中
	this->workerArray = new Worker * [this->fileWorkerNumber];

	//c.将文件中的数据存放至数组中
	initArray();

	this->fileEmpty = false;//更新文件是否为空的标志

	//d.更新数组中当前的数据数量
	this->workerNumber = this->fileWorkerNumber;

	//测试代码
	//for (int i = 0; i < this->workerNumber; i++)
	//{
	//	cout << this->workerArray[i]->workerId << " "
	//		<< this->workerArray[i]->workerName << " "
	//		<< this->workerArray[i]->departmentName << " "
	//		<< this->workerArray[i]->departmentDuty << endl;
	//}
}

WorkerManager::~WorkerManager()
{
	int i = 0;

	//我们这里是2级指针,所有实质上我们需要释放2次,才可以释放干净空间

	//1.释放数组中,每个元素(实质上是一级指针)所指向的空间
	if (this->workerArray != NULL)
	{
		for (i = 0; i < this->workerNumber; i++)
		{
			if (*(this->workerArray + i) != NULL)
			{
				delete* (this->workerArray + i);
				*(this->workerArray + i) = NULL;
			}
		}
	}

	//2.释放数组(释放数组中的每一个一级指针)
	delete[] this->workerArray;
	this->workerArray = NULL;
}

int WorkerManager::getWorkerNumber()
{
	ifstream ifs;
	int count = 0;
	string buf;

	ifs.open(FILENAME, ios::in);

	if (!ifs.is_open())
	{
		cout << "getWorkerNumber::打开文件失败!" << endl;
		return -1;
	}

	//getline函数,可以一次读一行
	//而我们一行只放了一个职工,所以行数 == 职工数
	while (getline(ifs, buf))
	{
		count++;
	}

	ifs.close();

	return count;
}

void WorkerManager::initArray()
{
	ifstream ifs;
	int workerId = 0;
	string workerName;
	string departmentDuty;
	string departmentName;

	int i = 0;
	Worker* newWorker = NULL;

	//打开文件,以便进行后续读取数据操作
	ifs.open(FILENAME, ios::in);
	if (!ifs.is_open())
	{
		cout << "initArray::文件打开失败" << endl;
	}

	//把文件中的数据拿出来,存放入程序的数组中
	while (ifs >> workerId && ifs >> workerName && ifs >> departmentName && ifs >> departmentDuty)
	{
		if (departmentName == "老板")
		{
			newWorker = new Boss(workerId, workerName);
		}
		else if (departmentName == "经理")
		{
			newWorker = new Manager(workerId, workerName);
		}
		else//普通员工
		{
			newWorker = new Employee(workerId, workerName);
		}

		*(this->workerArray + i) = newWorker;
		i++;
	}

	//关闭文件
	ifs.close();
}

void WorkerManager::AddWorker()
{
	//分配思想:有一个数据,分配一个空间

	int addNumber = 0;
	int newNumber = 0;
	Worker** newSpace = NULL;
	Worker* newWorker = NULL;

	int i = 0;
	int idCheck = 0;
	bool existSameId = false;

	string newName;
	int newDepartment = 0;
	int newWorkerId = 0;

	//录入需要的新空间数量
	while (true)
	{
		cout << "请输入增加职工的数量:" << endl;
		cin >> addNumber;

		//合法性判断:不可以是零或负数
		if (addNumber <= 0)
		{
			cout << "非法输入!请输入正整数" << endl;
		}
		else
		{
			break;
		}
	}


	newNumber = addNumber + this->workerNumber;

	//开始分配空间
	newSpace = new Worker * [newNumber];
	if (newSpace == NULL)
	{
		cout << "AddWorker::内存分配失败!" << endl;
		exit(1);
	}

	//开始往空间中存入数据
	//
	// 什么时候需要存数据?在有数据的时候。
	// 所以我们这里直接判断workerNumber是否有值
	//
	//先把之前的数据转移至新空间中
	if (this->workerNumber > 0)
	{
		for (i = 0; i < this->workerNumber; i++)
		{
			*(newSpace + i) = *(workerArray + i);
		}
	}

	//录入新数据
	for (i = 0; i < addNumber; i++)
	{
		cout << "请输入第" << i + 1 << "个新员工的姓名:" << endl;
		cin >> newName;

		//员工ID为主码,具有唯一性,所以我们必须检查是否有相同的ID录入
		//如果有,我们要求重新输入ID
		//
		//检查方法:遍历所有已存在的员工ID + 新增的员工ID(此ID还未拼接至程序的数组中),一一比对
		// (后续可以做先排序,再二分查找的优化,不过目前暂时不需要)
		cout << "请输入第" << i + 1 << "个新员工的工号:" << endl;
		do
		{
			existSameId = false;//每次进入循环时,重置标志为:不存在相同ID

			cin >> newWorkerId;

			//检查已存在的员工ID
			for (idCheck = 0; idCheck < this->workerNumber; idCheck++)
			{
				if ((*(this->workerArray + idCheck))->workerId == newWorkerId)
				{
					cout << "ID号" << newWorkerId << "已存在, 请重新输入员工ID:" << endl;
					existSameId = true;
					break;
				}
			}

			//检查本次新增的员工ID
			if (addNumber > 1)
			{
				for (idCheck = 0; idCheck < i; idCheck++)
				{
					if ((*(newSpace + idCheck))->workerId == newWorkerId)
					{
						cout << "ID号" << newWorkerId << "已存在, 请重新输入员工ID:" << endl;
						existSameId = true;
						break;
					}
				}
			}

		} while (existSameId);


		cout << "请输入第" << i + 1 << "个新员工的职务:" << endl;
		cout << "1.老板" << endl;
		cout << "2.经理" << endl;
		cout << "3.普通员工" << endl;
		cin >> newDepartment;

		switch (newDepartment)
		{
		case BOSS:
			newWorker = new Boss(newWorkerId, newName);
			break;
		case MANAGER:
			newWorker = new Manager(newWorkerId, newName);
			break;
		case EMPLOYEE:
			newWorker = new Employee(newWorkerId, newName);
			break;
		default:
			cout << "输入错误!请在职务选择处,输入数字 1~3 的闭区间:" << endl;
			i--;
			break;
		}
		*(newSpace + this->workerNumber + i) = newWorker;
	}

	//成功提示
	cout << "成功添加" << i << "名新职工" << endl;

	this->fileEmpty = false;//更新文件标志,表示文件不再为空

	//释放原来的空间
	//delete[] this->workerArray;
	for (i = 0; i < this->workerNumber; i++)
	{
		if (*(this->workerArray + i) != NULL)
		{
			delete* (this->workerArray + i);
			*(this->workerArray + i) = NULL;
		}
	}

	this->workerArray = newSpace;
	this->workerNumber = newNumber;

	system("pause");
	system("cls");
}
void WorkerManager::deleteWorker()
{
	//1.判断文件中是否有数据
	// 1.1 没有数据 -> 向屏幕输出报错信息(没有数据无法进行删除操作)
	// 1.2 有数据   -> 进行步骤2
	//2.要求用户输入ID
	// 2.1 没有此员工 -> 向屏幕输出报错信息:"没有该员工"
	// 2.2 有此员工   -> 在数组中删除此员工,并将数组的情况更新至文件中

	if (!this->existInfo())
	{
		return;
	}

	int i = 0;
	int id = 0;
	int index = 0;

	cout << "请输入要删除职工的ID:" << endl;
	cin >> id;

	index = this->isExist(id);

	if (index == -1)
	{
		cout << "没有ID为" << id << "的员工" << endl;
	}
	else
	{
		//删除数组中,下标为index的元素
		for (i = index; i < this->workerNumber - 1; i++)
		{
			//该数组中,本质上存放的是Worker类型的一级指针,所以可以直接赋值,而不需要重写等号运算符
			this->workerArray[i] = this->workerArray[i + 1];
		}

		//更新数组中的元素数量
		this->workerNumber--;

		//将数组中的情况,更新至文件中
		this->saveToFile();

		//向用户输出提示信息
		cout << "删除成功!" << endl;
	}

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


void WorkerManager::saveToFile()
{
	ofstream ofs;
	int i = 0;

	ofs.open(FILENAME, ios::out);

	for (i = 0; i < this->workerNumber; i++)
	{
		ofs << this->workerArray[i]->workerId << " "
			<< this->workerArray[i]->workerName << " "
			<< this->workerArray[i]->departmentName << "\t"
			<< this->workerArray[i]->departmentDuty << endl;
	}

	ofs.close();
}

void WorkerManager::showFromFile()
{
	ifstream ifs;
	string buf;

	//当我们尝试去打开一个文件时,有这几种情况:
	// 1.有这个文件   ->  打开成功
	// 2.没有这个文件 ->  打开失败
	//

	ifs.open(FILENAME, ios::in);

	if (!ifs.is_open())
	{
		cout << "showFromFile::文件打开失败" << endl;
		return;
	}

	//将文件的内容输出到屏幕上
	while (getline(ifs, buf))
	{
		cout << buf << endl;
	}

	ifs.close();

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

int WorkerManager::isExist(int id)
{
	//我们先不考虑id同名的情况,暂时认为每一个职工ID都是唯一的
	//在此前提的基础上,我们查找某一个ID的下标,则只需要遍历一遍数组即可

	int i = 0;

	for (i = 0; i < this->workerNumber; i++)
	{
		if (this->workerArray[i]->workerId == id)
		{
			//找到该员工,直接返回下标
			return i;
		}
	}

	//如果程序走到这儿,说明没有该员工。返回 -1
	return -1;
}

void WorkerManager::modifyWorkerInfo()
{
	//修改员工函数实现思想:
	// 1.合法性判断 -> 判断是否有该员工 || 文件里是否有数据  (这2种情况应该输出不同的提示)
	//		1.1 没有 ->  提示用户没有该用户,退出函数
	//		1.2 有   ->  进行步骤2
	// 2.将此员工delete掉
	// 3.把新数据存入该空间

	if (!this->existInfo())
	{
		return;
	}

	bool flag = true;
	int idWantModify = 0;
	int indexOfIdWantModify = 0;

	//员工的新信息
	Worker* newInfo = NULL;
	int newId = 0;
	string newName = "";
	int newDepartment = 0;

	cout << "请问你要修改的员工的ID是:" << endl;
	cin >> idWantModify;

	//判断是否存在此员工
	indexOfIdWantModify = isExist(idWantModify);

	if (indexOfIdWantModify == -1)
	{
		cout << "该用户不存在" << endl;

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

		return;
	}
	else
	{
		delete this->workerArray[indexOfIdWantModify];

		cout << "请输入原员工ID为" << idWantModify << "的新ID:" << endl;
		cin >> newId;

		cout << "请输入新名字:" << endl;
		cin >> newName;

		cout << "请输入新职务:" << endl;
		cout << "1.老板" << endl;
		cout << "2.经理" << endl;
		cout << "3.普通员工" << endl;
		cin >> newDepartment;

		while (flag)//在选择处添加一个循环,这样在错误输入时就可以重新输入
		{
			switch (newDepartment)
			{
			case BOSS:
				newInfo = new Boss(newId, newName);
				flag = false;
				break;
			case MANAGER:
				newInfo = new Manager(newId, newName);
				flag = false;
				break;
			case EMPLOYEE:
				newInfo = new Employee(newId, newName);
				flag = false;
				break;
			default:
				cout << "输入错误!请在职务选择处,输入数字 1~3 的闭区间:" << endl;
				break;
			}
		}

		cout << "修改成功!" << endl;


		*(this->workerArray + indexOfIdWantModify) = newInfo;//将新数据存入程序数组
		this->saveToFile();//更新文件信息

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

void WorkerManager::seekWorker()
{
	//实现思想:
	// 1.合法性判断
	// 2.提供两种查找方式
	//		2.1 按ID查找  -> 输出此ID的员工信息
	//		2.2 按姓名查找 -> 输出所有拥有该姓名的员工 (考虑到同名情况,我们应该遍历所有员工)
	//

	if (!this->existInfo())
	{
		return;
	}

	int seekBy = 0;
	int idWantSeek = 0;
	int i = 0;
	int indexIdWantSeek = 0;
	string nameWantSeek = "";
	bool ExistTheWorker = false;

	cout << "0.返回上一层" << endl;
	cout << "1.按员工ID查找" << endl;
	cout << "2.按员工姓名查找" << endl;

	while (true)
	{
		cin >> seekBy;

		//合法性判断
		if (seekBy != 1 && seekBy != 2 && seekBy != 0)
		{
			cout << "输入错误!请输入 1, 2 或 0:" << endl;
		}
		else
		{
			break;
		}
	}


	switch (seekBy)
	{
	case RETURN://退出修改函数
		cout << "按任意键返回上一菜单" << endl;
		break;
	case BYID:
	{
		//1.判断该员工是否存在
		//	1.1 存在 -> 输出该员工信息
		//	1.2 不存在 -> 退出函数,返回主菜单

		cout << "请输入要查找的员工ID:" << endl;
		cin >> idWantSeek;

		indexIdWantSeek = this->isExist(idWantSeek);

		if (indexIdWantSeek != -1)
		{
			//this->workerArray[indexIdWantSeek]->showInfo();
			(*(this->workerArray + indexIdWantSeek))->showInfo();
		}
		else
		{
			cout << "没有该员工" << endl;
		}
	}
	break;
	case BYNAME:
	{
		cout << "请输入要查找的员工姓名:" << endl;
		cin >> nameWantSeek;

		for (i = 0; i < this->workerNumber; i++)
		{
			if ((*(this->workerArray + i))->workerName == nameWantSeek)
			{
				(*(this->workerArray + i))->showInfo();
				ExistTheWorker = true;
			}
		}

		//遍历结束,没有该员工
		if (!ExistTheWorker)
		{
			cout << "没有姓名为 " << nameWantSeek << " 的员工" << endl;
		}
	}
	break;
	default:
		break;
	}
	system("pause");
	system("cls");
}

void WorkerManager::sortWorkerById()
{
	//实现思想:利用冒泡排序继续
	//

	if (!this->existInfo())
	{
		return;
	}

	int sortStyle = 0;
	int i = 0;
	int j = 0;
	Worker* temp = NULL;
	bool swapped = false;

	cout << "请选择排序方式:" << endl;
	cout << "1.升序" << endl;
	cout << "2.降序" << endl;

	while (true)
	{
		//录入用户的选择
		cin >> sortStyle;

		//合法性判断
		if (cin.fail() || sortStyle != 1 && sortStyle != 2)
		{
			cout << "输入错误,请重新输入 1 或 2 :" << endl;

			// 清除错误标志
			cin.clear();

			// 忽略掉剩余的输入(直到换行符)
			cin.ignore(numeric_limits < streamsize >::max(), '\n');
		}
		else
		{
			for (i = 0; i < this->workerNumber; i++)
			{
				for (j = 0; j < this->workerNumber - i - 1; j++)
				{
					if (sortStyle == 1)
					{
						//升序 (从小到大)
						if ((*(this->workerArray + j))->workerId > (*(this->workerArray + j + 1))->workerId)
						{
							temp = *(this->workerArray + j);
							*(this->workerArray + j) = *(this->workerArray + j + 1);
							*(this->workerArray + j + 1) = temp;

							swapped = true;
						}
					}
					else
					{
						//降序 (从大到小)
						if ((*(this->workerArray + j))->workerId < (*(this->workerArray + j + 1))->workerId)
						{
							temp = *(this->workerArray + j);
							*(this->workerArray + j) = *(this->workerArray + j + 1);
							*(this->workerArray + j + 1) = temp;

							swapped = true;
						}
					}
				}

				//本次循环没有发生排序行为,即表示当前数据已经有序,提前退出循环
				if (!swapped)
				{
					break;
				}
			}

			//走到这里,说明输入正确,且排序结束
			//
			// 最后收尾工作:
			// 1.输出排序成功提示,
			// 2.更新至文档
			// 3.跳出循环,结束函数

			cout << "排序成功!" << endl;

			this->saveToFile();

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

			break;
		}
	}
}

void WorkerManager::emptyInfo()
{
	if (!this->existInfo())
	{
		return;
	}

	//实现思想:
	// 1. 清空文件信息:删除文件,并创建同名空文件
	// 2. 清空程序中数组信息:delete所有workerArrat中的数据

	int i = 0;
	int doubleConfirmation = 0;
	ofstream ofs;

	//清空功能比较危险,所以要求用户进行二次确认
	cout << "确认清空所有数据吗?" << endl;
	cout << "1.确认" << endl;
	cout << "2.返回主菜单" << endl;
	cin >> doubleConfirmation;

	//如果用户输入的是字符或其他任何非 1 的数据,都会直接返回主菜单
	if (doubleConfirmation == 1)
	{
		//清空文件

		//这个命令会判断文件是否存在,如果存在,它将删除此文件,并新创建一个同名空文件
		//换句话说,它可以实现清空文件内容的功能
		ofs.open(FILENAME, ios::trunc);
		ofs.close();

		//清空数组
		if (this->workerArray != NULL)
		{
			for (i = 0; i < this->workerNumber; i++)
			{
				if (this->workerArray + i != NULL)
				{
					delete* (this->workerArray + i);
					*(this->workerArray + i) = NULL;
				}

			}

			delete[] this->workerArray;
			this->workerArray = NULL;

			this->fileEmpty = true;
			this->workerNumber = 0;
			this->fileWorkerNumber = 0;
		}
		cout << "清空成功!" << endl;
	}
	system("pause");
	system("cls");
}

void WorkerManager::exitSystem()
{
	cout << "已经退出系统,欢迎下次使用" << endl;
	exit(0);
}

bool  WorkerManager::existInfo()
{
	//为什么要设置2个条件?
	//因为在这样一种情况时,fileEmpty为false,但实质上却已经没有数据了:打开系统后,利用删除功能,把用户一个个删完
	if (this->workerNumber == 0 || this->fileEmpty == true)
	{
		cout << "文件不存在或文件为空" << endl;

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

		return false;
	}
	return true;
}

void WorkerManager::showFromArray()
{
	// 1.判断数组是否有值
	//  1.1 若数组不存在 -> 输出报错信息:“文件不存在或文件为空”
	//	1.2 若数组有值 -> 输出数组信息

	int i = 0;

	if (!this->existInfo())
	{
		return;
	}
	else
	{
		for (i = 0; i < this->workerNumber; i++)
		{
			this->workerArray[i]->showInfo();
		}
	}
	system("pause");
	system("cls");
}
manager.cpp
#include "manager.h"

Manager::Manager(int workerId, string name)
{
	this->workerId = workerId;
	this->workerName = name;
	this->departmentName = "经理";
	this->departmentDuty = "将任务合理分解给员工";//因为所有employee的职责都一样,所以我们这里直接写死
}

//显示个人所有信息
void Manager::showInfo()
{
	cout << "职工编号: " << this->workerId
		<< " \t职工姓名: " << this->workerName
		<< " \t岗位:" << this->getDepartmentName()
		<< " \t岗位职责:" << this->getDepartmentDuty() << endl;
}

//获取员工名字
string Manager::getWorkerName()
{
	return this->workerName;
}

//获取岗位
string Manager::getDepartmentName()
{
	return this->departmentName;
}

//获取职责
string Manager::getDepartmentDuty()
{
	return this->departmentDuty;
}
workerManager.cpp
#include "workerManager.h"
#include "boss.h"
#include "employee.h"
#include "manager.h"

void Start()
{
	WorkerManager wm;
	int choice = 0;

	while (true)
	{
		wm.showMenu();
		cin >> choice;

		switch (choice)
		{
		case EXIT:
			wm.exitSystem();
			break;
		case ADD:
			wm.AddWorker();
			wm.saveToFile();
			break;
		case DISPALY:
			//wm.showFromFile();
			wm.showFromArray();
			break;
		case DELETE:
			wm.deleteWorker();
			break;
		case MODIFY:
			wm.modifyWorkerInfo();
			break;
		case SEEK:
			wm.seekWorker();
			break;
		case SORT:
			wm.sortWorkerById();
			break;
		case EMPTY:
			wm.emptyInfo();
			break;
		default:
			cout << "输入错误,请重新输入数字0~7:" << endl;
			cout << endl;
			break;
		}
	}
}

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 << "*************  6.按照编号排序  *************" << endl;
	cout << "*************  7.清空所有文档  *************" << endl;
	cout << "********************************************" << endl;
	cout << endl;
}

WorkerManager::WorkerManager()
{
	//文件打开有3种情况,我们要为其做3种不同的构造函数:
	// 1.没有文件
	// 2.有文件,但内容为空(上次使用时,最后一步操作是“清空所有文档”)
	// 3.有文件,且里面有内容
	//

	ifstream ifs;
	ifs.open(FILENAME, ios::in);
	char fileEnd;

	//1.没有文件
	if (!ifs.is_open())
	{
		//cout << "文件不存在" << endl;
		
		this->fileEmpty = true;
		this->workerNumber = 0;
		this->workerArray = NULL;
		this->fileWorkerNumber = 0;

		ifs.close();
		return;
	}
	
	//2.有文件,但内容为空
	//
	//文件中最少会有一个字符——EOF,现在我们从文件读走一个字符
	//如果文件因此为空了,那么说明我们刚刚读走的就是EOF,也就是说,现在文档里什么都没有了
	//然后,我们利用ifs.eof()去判断文件是否为空,
	// 若为空,则得出结论:该文件内容为空
	ifs >> fileEnd;

	if (ifs.eof())
	{
		//cout << "文件为空" << endl;

		this->fileEmpty = true;
		this->workerNumber = 0;
		this->workerArray = NULL;
		this->fileWorkerNumber = 0;

		ifs.close();
		return;
	}

	//3.有文件,且里面有内容
	//
	//当代码走到这,说明前2种情况都没有发生,所以此处不需要进行if判断
	
	//a.先求出文件中有几条数据
	this->fileWorkerNumber = this->getWorkerNumber();
	//cout << this->fileWorkerNumber;

	//b.在数据中开辟等量的空间,以便后续将文件中的数据存放至数组中
	this->workerArray = new Worker * [this->fileWorkerNumber];
	
	//c.将文件中的数据存放至数组中
	initArray();

	this->fileEmpty = false;//更新文件是否为空的标志
	
	//d.更新数组中当前的数据数量
	this->workerNumber = this->fileWorkerNumber;

	//测试代码
	//for (int i = 0; i < this->workerNumber; i++)
	//{
	//	cout << this->workerArray[i]->workerId << " "
	//		<< this->workerArray[i]->workerName << " "
	//		<< this->workerArray[i]->departmentName << " "
	//		<< this->workerArray[i]->departmentDuty << endl;
	//}
}

WorkerManager::~WorkerManager()
{
	int i = 0;

	//我们这里是2级指针,所有实质上我们需要释放2次,才可以释放干净空间

	//1.释放数组中,每个元素(实质上是一级指针)所指向的空间
	if (this->workerArray != NULL)
	{
		for (i = 0; i < this->workerNumber; i++)
		{
			if (*(this->workerArray + i) != NULL)
			{
				delete* (this->workerArray + i);
				*(this->workerArray + i) = NULL;
			}
		}
	}

	//2.释放数组(释放数组中的每一个一级指针)
	delete[] this->workerArray;
	this->workerArray = NULL;
}

int WorkerManager::getWorkerNumber()
{
	ifstream ifs;
	int count = 0;
	string buf;

	ifs.open(FILENAME, ios::in);

	if (!ifs.is_open())
	{
		cout << "getWorkerNumber::打开文件失败!" << endl;
		return -1;
	}

	//getline函数,可以一次读一行
	//而我们一行只放了一个职工,所以行数 == 职工数
	while (getline(ifs, buf))
	{
		count++;
	}

	ifs.close();

	return count;
}

void WorkerManager::initArray()
{
	ifstream ifs;
	int workerId = 0;
	string workerName;
	string departmentDuty;
	string departmentName;

	int i = 0;
	Worker* newWorker = NULL;

	//打开文件,以便进行后续读取数据操作
	ifs.open(FILENAME, ios::in);
	if (!ifs.is_open())
	{
		cout << "initArray::文件打开失败" << endl;
	}

	//把文件中的数据拿出来,存放入程序的数组中
	while (ifs >> workerId && ifs >> workerName && ifs >> departmentName && ifs >> departmentDuty)
	{
		if (departmentName == "老板")
		{
			newWorker = new Boss(workerId, workerName);
		}
		else if (departmentName == "经理")
		{
			newWorker = new Manager(workerId, workerName);
		}
		else//普通员工
		{
			newWorker = new Employee(workerId, workerName);
		}

		*(this->workerArray + i) = newWorker;
		i++;
	}

	//关闭文件
	ifs.close();
}

void WorkerManager::updateArray(Worker** newArray)
{
	this->workerArray = newArray;
}

void WorkerManager::updateWorkerNumber(int newWorkerNumber)
{
	this->workerNumber = newWorkerNumber;
}

void WorkerManager::AddWorker()
{
	//有一个数据,分配一个空间

	int addNumber = 0;
	int newNumber = 0;
	Worker** newSpace = NULL;
	Worker* newWorker = NULL;

	int i = 0;
	int idCheck = 0;
	bool existSameId = false;

	string newName;
	int newDepartment = 0;
	int newWorkerId = 0;

	//录入需要的新空间数量
	while (true)
	{
		cout << "请输入增加职工的数量:" << endl;
		cin >> addNumber;

		//合法性判断:不可以是零或负数
		if (addNumber <= 0)
		{
			cout << "非法输入!请输入正整数" << endl;
		}
		else
		{
			break;
		}
	}
	

	newNumber = addNumber + this->workerNumber;

	//开始分配空间
	newSpace = new Worker * [newNumber];
	if (newSpace == NULL)
	{
		cout << "AddWorker::内存分配失败!" << endl;
		exit(1);
	}

	//开始往空间中存入数据
	//
	// 什么时候需要存数据?在有数据的时候。
	// 所以我们这里直接判断workerNumber是否有值
	//
	//先把之前的数据转移至新空间中
	if (this->workerNumber > 0)
	{
		for (i = 0; i < this->workerNumber; i++)
		{
			*(newSpace + i) = *(workerArray + i);
		}
	}

	//录入新数据
	for (i = 0; i < addNumber; i++)
	{
		cout << "请输入第" << i + 1 << "个新员工的姓名:" << endl;
		cin >> newName;

		//员工ID为主码,具有唯一性,所以我们必须检查是否有相同的ID录入
		//如果有,我们要求重新输入ID
		//
		//检查方法:遍历所有已存在的员工ID + 新增的员工ID(此ID还为拼接至程序的数组中),一一比对
		// (后续可以做先排序,再二分查找的优化,不过目前暂时不需要)
		cout << "请输入第" << i + 1 << "个新员工的工号:" << endl;
		do
		{
			existSameId = false;//每次进入循环时,重置标志为:不存在相同ID

			cin >> newWorkerId;

			//检查已存在的员工ID
			for (idCheck = 0; idCheck < this->workerNumber; idCheck++)
			{
				if ((*(this->workerArray + idCheck))->workerId == newWorkerId)
				{
					cout << "ID号" << newWorkerId << "已存在, 请重新输入员工ID:" << endl;
					existSameId = true;
					break;
				}
			}

			//检查本次新增的员工ID
			if (addNumber > 1)
			{
				for (idCheck = 0; idCheck < i; idCheck++)
				{
					if ((*(newSpace + idCheck))->workerId == newWorkerId)
					{
						cout << "ID号" << newWorkerId << "已存在, 请重新输入员工ID:" << endl;
						existSameId = true;
						break;
					}
				}
			}

		} while (existSameId);


		cout << "请输入第" << i + 1<< "个新员工的职务:" << endl;
		cout << "1.老板" << endl;
		cout << "2.经理" << endl;
		cout << "3.普通员工" << endl;
		cin >> newDepartment;

		switch (newDepartment)
		{
		case BOSS:
			newWorker = new Boss(newWorkerId, newName);
			break;
		case MANAGER:
			newWorker = new Manager(newWorkerId, newName);
			break;
		case EMPLOYEE:
			newWorker = new Employee(newWorkerId, newName);
			break;
		default:
			cout << "输入错误!请在职务选择处,输入数字 1~3 的闭区间:" << endl;
			i--;
			break;
		}
		*(newSpace + this->workerNumber + i)  = newWorker;
	}

	//成功提示
	cout << "成功添加" << i << "名新职工" << endl;

	this->fileEmpty = false;//更新文件标志,表示文件不再为空

	//释放原来的空间
	//delete[] this->workerArray;
	for (i = 0; i < this->workerNumber; i++)
	{
		if (*(this->workerArray + i) != NULL)
		{
			delete *(this->workerArray + i);
			*(this->workerArray + i) = NULL;
		}
	}

	this->workerArray = newSpace;
	this->workerNumber = newNumber;

	system("pause");
	system("cls");
}
void WorkerManager::deleteWorker()
{
	//1.判断文件中是否有数据
	// 1.1 没有数据 -> 向屏幕输出报错信息(没有数据无法进行删除操作)
	// 1.2 有数据   -> 进行步骤2
	//2.要求用户输入ID
	// 2.1 没有此员工 -> 向屏幕输出报错信息:"没有该员工"
	// 2.2 有此员工   -> 在数组中删除此员工,并将数组的情况更新至文件中

	if (!this->existInfo())
	{
		return;
	}

	int i = 0;
	int id = 0;
	int index = 0;

	cout << "请输入要删除职工的ID:" << endl;
	cin >> id;

	index = this->isExist(id);

	if (index == -1)
	{
		cout << "没有ID为" << id << "的员工" << endl;
	}
	else
	{
		//删除数组中,下标为index的元素
		for (i = index; i < this->workerNumber - 1; i++)
		{
			//该数组中,本质上存放的是Worker类型的一级指针,所以可以直接赋值,而不需要重写等号运算符
			this->workerArray[i] = this->workerArray[i + 1];
		}

		//更新数组中的元素数量
		this->workerNumber--;

		//将数组中的情况,更新至文件中
		this->saveToFile();

		//向用户输出提示信息
		cout << "删除成功!" << endl;
	}
	
	system("pause");
	system("cls");
}


void WorkerManager::saveToFile()
{
	ofstream ofs;
	int i = 0;

	ofs.open(FILENAME, ios::out);

	for (i = 0; i < this->workerNumber; i++)
	{
		ofs << this->workerArray[i]->workerId << " "
			<< this->workerArray[i]->workerName << " "
			<< this->workerArray[i]->departmentName << "\t"
			<< this->workerArray[i]->departmentDuty << endl;
	}

	ofs.close();
}

void WorkerManager::showFromFile()
{
	ifstream ifs;
	string buf;

	//当我们尝试去打开一个文件时,有这几种情况:
	// 1.有这个文件   ->  打开成功
	// 2.没有这个文件 ->  打开失败
	//

	ifs.open(FILENAME, ios::in);

	if (!ifs.is_open())
	{
		cout << "showFromFile::文件打开失败" << endl;
		return;
	}

	//将文件的内容输出到屏幕上
	while (getline(ifs, buf))
	{
		cout << buf << endl;
	}

	ifs.close();

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

int WorkerManager::isExist(int id)
{
	//我们先不考虑id同名的情况,暂时认为每一个职工ID都是唯一的
	//在此前提的基础上,我们查找某一个ID的下标,则只需要遍历一遍数组即可

	int i = 0;
	
	for (i = 0; i < this->workerNumber; i++)
	{
		if (this->workerArray[i]->workerId == id)
		{
			//找到该员工,直接返回下标
			return i;
		}
	}

	//如果程序走到这儿,说明没有该员工。返回 -1
	return -1;
}

void WorkerManager::modifyWorkerInfo()
{
	//修改员工函数实现思想:
	// 1.合法性判断 -> 判断是否有该员工 || 文件里是否有数据  (这2种情况应该输出不同的提示)
	//		1.1 没有 ->  提示用户没有该用户,退出函数
	//		1.2 有   ->  进行步骤2
	// 2.将此员工delete掉
	// 3.把新数据存入该空间
	
	if (!this->existInfo())
	{
		return;
	}

	bool flag = true;
	int idWantModify = 0;
	int indexOfIdWantModify = 0;

	//员工的新信息
	Worker* newInfo = NULL;
	int newId = 0;
	string newName = "";
	int newDepartment = 0;

	cout << "请问你要修改的员工的ID是:" << endl;
	cin >> idWantModify;

	//判断是否存在此员工
	indexOfIdWantModify = isExist(idWantModify);

	if (indexOfIdWantModify == -1)
	{
		cout << "该用户不存在" << endl;

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

		return;
	}
	else
	{
		delete this->workerArray[indexOfIdWantModify];

		cout << "请输入原员工ID为" << idWantModify << "的新ID:" << endl;
		cin >> newId;

		cout << "请输入新名字:" << endl;
		cin >> newName;
		
		cout << "请输入新职务:" << endl;
		cout << "1.老板" << endl;
		cout << "2.经理" << endl;
		cout << "3.普通员工" << endl;
		cin >> newDepartment;

		while (flag)//在选择处添加一个循环,这样在错误输入时就可以重新输入
		{
			switch (newDepartment)
			{
			case BOSS:
				newInfo = new Boss(newId, newName);
				flag = false;
				break;
			case MANAGER:
				newInfo = new Manager(newId, newName);
				flag = false;
				break;
			case EMPLOYEE:
				newInfo = new Employee(newId, newName);
				flag = false;
				break;
			default:
				cout << "输入错误!请在职务选择处,输入数字 1~3 的闭区间:" << endl;
				break;
			}
		}

		cout << "修改成功!" << endl;

		
		*(this->workerArray + indexOfIdWantModify) = newInfo;//将新数据存入程序数组
		this->saveToFile();//更新文件信息

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

void WorkerManager::seekWorker()
{
	//实现思想:
	// 1.合法性判断
	// 2.提供两种查找方式
	//		2.1 按ID查找(后续需完善程序,使其ID具有唯一性) -> 输出此ID的员工信息
	//		2.2 按姓名查找 -> 输出所有拥有该姓名的员工 (考虑到同名情况,我们应该遍历所有员工)
	//

	if (!this->existInfo())
	{
		return;
	}

	int seekBy = 0;
	int idWantSeek = 0;
	int i = 0;
	int indexIdWantSeek = 0;
	string nameWantSeek = "";
	bool ExistTheWorker = false;

	cout << "0.返回上一层" << endl;
	cout << "1.按员工ID查找" << endl;
	cout << "2.按员工姓名查找" << endl;

	while (true)
	{
		cin >> seekBy;

		//合法性判断
		if (seekBy != 1 && seekBy != 2 && seekBy != 0)
		{
			cout << "输入错误!请输入 1, 2 或 0:" << endl;
		}
		else
		{
			break;
		}
	}


	switch (seekBy)
	{
	case RETURN://退出修改函数
		cout << "按任意键返回上一菜单" << endl;
		break;
	case BYID:
	{
		//1.判断该员工是否存在
		//	1.1 存在 -> 输出该员工信息
		//	1.2 不存在 -> 询问用户是否继续查找
		//		1.2.1 继续 -> 循环switch语句
		//		1.2.2 不继续 -> 退出函数,返回主菜单

		cout << "请输入要查找的员工ID:" << endl;
		cin >> idWantSeek;

		indexIdWantSeek = this->isExist(idWantSeek);

		if (indexIdWantSeek != -1)
		{
			//this->workerArray[indexIdWantSeek]->showInfo();
			(*(this->workerArray + indexIdWantSeek))->showInfo();
		}
		else
		{
			cout << "没有该员工" << endl;

			//待实现:询问是否需要重新输入
			//.。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
		}
	}
		break;
	case BYNAME:
	{
		cout << "请输入要查找的员工姓名:" << endl;		
		cin >> nameWantSeek;

		for (i = 0; i < this->workerNumber; i++)
		{
			if ((*(this->workerArray + i))->workerName == nameWantSeek)
			{
				(*(this->workerArray + i))->showInfo();	
				ExistTheWorker = true;
			}
		}

		//遍历结束,没有该员工
		if (!ExistTheWorker)
		{
			cout << "没有姓名为 " << nameWantSeek << " 的员工" << endl;
		}
	}
		break;
	default:
		break;
	}
	system("pause");
	system("cls");
}

void WorkerManager::sortWorkerById()
{
	//实现思想:利用冒泡排序继续
	//

	if (!this->existInfo())
	{
		return;
	}

	int sortStyle = 0;
	int i = 0;
	int j = 0;
	Worker* temp = NULL;
	bool swapped = false;

	cout << "请选择排序方式:" << endl;
	cout << "1.升序" << endl;
	cout << "2.降序" << endl;

	while (true)
	{
		//录入用户的选择
		cin >> sortStyle;

		//合法性判断
		if (cin.fail() || sortStyle != 1 && sortStyle != 2)
		{
			cout << "输入错误,请重新输入 1 或 2 :" << endl;

			// 清除错误标志
			cin.clear();

			// 忽略掉剩余的输入(直到换行符)
			cin.ignore(numeric_limits < streamsize >::max(), '\n');
		}
		else
		{
			for (i = 0; i < this->workerNumber; i++)
			{
				for (j = 0; j < this->workerNumber - i - 1; j++)
				{
					if (sortStyle == 1)
					{
						//升序 (从小到大)
						if ((*(this->workerArray + j))->workerId > (*(this->workerArray + j + 1))->workerId)
						{
							temp = *(this->workerArray + j);
							*(this->workerArray + j) = *(this->workerArray + j + 1);
							*(this->workerArray + j + 1) = temp;

							swapped = true;
						}
					}
					else
					{
						//降序 (从大到小)
						if ((*(this->workerArray + j))->workerId < (*(this->workerArray + j + 1))->workerId)
						{
							temp = *(this->workerArray + j);
							*(this->workerArray + j) = *(this->workerArray + j + 1);
							*(this->workerArray + j + 1) = temp;

							swapped = true;
						}
					}
				}

				//本次循环没有发生排序行为,即表示当前数据已经有序,提前退出循环
				if (!swapped)
				{
					break;
				}
			}

			//走到这里,说明输入正确,且排序结束
			//
			// 最后收尾工作:
			// 1.输出排序成功提示,
			// 2.更新至文档
			// 3.跳出循环,结束函数

			cout << "排序成功!" << endl;

			this->saveToFile();

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

void WorkerManager::emptyInfo()
{
	if (!this->existInfo())
	{
		return;
	}

	//实现思想:
	// 1. 清空文件信息:删除文件,并创建同名空文件
	// 2. 清空程序中数组信息:delete所有workerArrat中的数据

	int i = 0;
	int doubleConfirmation = 0;
	ofstream ofs;

	//清空功能比较危险,所以要求用户进行二次确认
	cout << "确认清空所有数据吗?" << endl;
	cout << "1.确认" << endl;
	cout << "2.返回主菜单" << endl;
	cin >> doubleConfirmation;

	//如果用户输入的是字符或其他任何非 1 的数据,都会直接返回主菜单
	if (doubleConfirmation == 1)
	{
		//清空文件

		//这个命令会判断文件是否存在,如果存在,它将删除此文件,并新创建一个同名空文件
		//换句话说,它可以实现清空文件内容的功能
		ofs.open(FILENAME, ios::trunc);
		ofs.close();

		//清空数组
		if (this->workerArray != NULL)
		{
			for (i = 0; i < this->workerNumber; i++)
			{
				if (this->workerArray + i != NULL)
				{
					delete* (this->workerArray + i);
					*(this->workerArray + i) = NULL;
				}

			}

			delete [] this->workerArray;
			this->workerArray = NULL;

			this->fileEmpty = true;
			this->workerNumber = 0;
			this->fileWorkerNumber = 0;
		}
		cout << "清空成功!" << endl;
	}
	system("pause");
	system("cls");
}

void WorkerManager::exitSystem()
{
	cout << "已经退出系统,欢迎下次使用" << endl;
	exit(0);
}

bool  WorkerManager::existInfo()
{
	//为什么要设置2个条件?
	//因为在这样一种情况时,fileEmpty为false,但实质上却已经没有数据了:打开系统后,利用删除功能,把用户一个个删完
	if (this->workerNumber == 0 || this->fileEmpty == true)
	{
		cout << "文件不存在或文件为空" << endl;

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

		return false;
	}
	return true;
}

void WorkerManager::showFromArray()
{
	// 1.判断数组是否有值
	//  1.1 若数组不存在 -> 输出报错信息:“文件不存在或文件为空”
	//	1.2 若数组有值 -> 输出数组信息

	int i = 0;

	if (!this->existInfo())
	{
		return;
	}
	else
	{
		for (i = 0; i < this->workerNumber; i++)
		{
			this->workerArray[i]->showInfo();
		}
	}
	system("pause");
	system("cls");
}
mian.cpp
#include "workerManager.h"
#include "worker.h"
#include "employee.h"
#include "boss.h"
#include "manager.h"

int main()
{
	Start();
  
	return 0;
}

写在最后

在每天写bug,debug的过程中,我感受到了无穷的乐趣。

快乐尽在coding中,你也一起爽起来吧!

另外,如果你还有好的项目,欢迎评论或私信,让我也参与进来。