C++黑马 职工管理系统

分析及代码实现:

1. 首先创建一个职工父类,普通员工、经理、老板都属于它的子类;子类在.h文件中声明,在.cpp文件中实现;即创建了worker.h父类头文件,employee.h、manager.h、boss.h三个子类头文件,同时还有employee.cpp、manager.cpp、boss.cpp源文件实现。

worker.h父类头文件

#pragma once  
#include <iostream>
#include <string>
using namespace std;

//抽象职工类,Worker包含:普通员工,经理,老板
class Worker
{
public:

	//显示个人信息
	virtual void showInfo() = 0;

	//获取岗位名称
	virtual string getDeptName() = 0;

	int m_Id;//职工编号
	string m_Name;//职工姓名
	int m_DeptId;//部门编号: 1. 普通员工  2. 经理   3. 老板
};

employee.h

#pragma once  
#include <iostream>
#include <string>
using namespace std;
#include "worker.h" //子类 要包含 父类的头文件

//普通职工类,在头文件中只做 [声明]
class Employee :public Worker
{
public:

	//构造函数
	Employee(int id, string name, int dId);

	//显示个人信息
	virtual void showInfo();//子类重写父类中的虚函数,引发多态

	//获取岗位名称
	virtual string getDeptName();
};

manager.h

#pragma once  
#include <iostream>
#include <string>
using namespace std;
#include "worker.h"

//经理类
class Manager :public Worker
{
public:

	//构造函数
	Manager(int id, string name, int dId);

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

	//获取岗位名称
	virtual string getDeptName();
};

boss.h

#pragma once  
#include <iostream>
#include <string>
using namespace std;
#include "worker.h"

//老板类
class Boss :public Worker
{
public:

	//构造函数
	Boss(int id, string name, int dId);

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

	//获取岗位名称
	virtual string getDeptName();
};

employee.cpp

#include "employee.h"
#include <string>

//源文件中实现 头文件中的声明,三个具体函数

//构造函数
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_Id
		<< "\t职工姓名:" << this->m_Name
		<< "\t岗位:" << this->getDeptName()
		<< "\t岗位职责:完成经理交给的任务" << endl;
}

//获取岗位名称
string Employee::getDeptName()
{
	return string("员工");
}

manager.cpp

#include "manager.h"
#include <string>

//构造函数
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_Id
		<< "\t职工姓名:" << this->m_Name
		<< "\t岗位:" << this->getDeptName()
		<< "\t岗位职责:完成老板交给的任务,并下发任务给员工" << endl;
}

//获取岗位名称
string Manager::getDeptName()
{
	return string("经理");
}

boss.cpp

#include "boss.h"
#include <string>

//构造函数
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_Id
		<< "\t职工姓名:" << this->m_Name
		<< "\t岗位:" << this->getDeptName()
		<< "\t岗位职责:管理公司所有事务" << endl;
}

//获取岗位名称
string Boss::getDeptName()
{
	return string("总裁");
}

2. 职工管理头文件比较复杂,包含:构造与析构函数,8大功能实现,还有8个辅助功能实现(展示菜单、记录当前 职工人数 、职工数组指针、保存文件、标志文件是否为空、统计 文件中的人数、初始化职工信息、职工是否存在函数)。

workerManager.h

#pragma once  //防止同一个头文件被包含(include)多次
#include <iostream>
#include <string>
using namespace std;
#include "worker.h"
#include "employee.h"
#include "manager.h"
#include "boss.h"

#include <fstream>
#define FILENAME "empFile.txt"//把文件路径 宏定义

class WorkerManager
{
public:

	WorkerManager();//构造函数   .h中声明,在.cpp中实现初始化

	void Show_Menu();//展示菜单

	void ExitSystem();//0、退出系统

	int m_EmpNum;//记录当前 职工人数  

	Worker** m_EmpArray;//职工数组指针 

	void Add_Emp();//1、添加职工

	void save();//保存文件,将职工信息写进文件中

	bool m_FileIsEmpty;//标志文件是否为空,如果为空不再进行后面添加删除等操作,只返回 true 和 false

	int m_getEmpNum();//统计 文件中的人数

	void init_Emp();//初始化职工,读文件中的职工信息

	void Show_Emp();//2、显示职工

	void Del_Emp();//3、删除职工,按照编号删除职工

	int IsExist(int id);//职工是否存在,存在 返回职工所在数组中的位置,不存在返回-1

	void Mod_Emp();//4、修改职工

	void Find_Emp();//5、查找职工

	void Sort_Emp();//6、排序职工

	void Clean_File();//7、清空文件

	~WorkerManager();//析构函数
};

1> 在构造函数中,主要为了初始化属性,如果文件中没有职工信息,属性都做初始化;如果有信息,则将原本就存在的职工信息读取到职工管理数组中。

2> 在添加新员工时,要重新开辟新空间,把原来的信息先存进来,然后再存新的信息,存好后释放原空间,并更改新空间的指向,更新数组人数和文件标志位,最重要的一步调用保存函数。

3> 使用 ofs.open(FILENAME, ios::out);  将信息写进文件中

4> 利用多态调用接口,显示已有的职工信息

5> 一个很重要的函数,查找职工是否存在函数:IsExist(int id),按编号查找,如果查找到就返回该职工的下标,否则返回 -1

6> 删除职工的本质是数据前移

7> 修改职工,将指定的职工信息先释放掉,然后再将新员工的信息放入

8> 职工排序,升序: 首先将 i 声明为 最小值或最大值(minORmax)的下标,如果第i个元素大于第i+1个元素,将i+1给给 minORmax。降序相反。

9> 清空文件时用 ofs.open(FILENAME, ios::trunc); 并且删除堆区的每个职工对象以及堆区数组指针

workerManager.cpp

#include "workerManager.h"


// WorkerManager 的构造函数,用于读取文件
WorkerManager::WorkerManager()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);

	//1、文件不存在
	if (!ifs.is_open())
	{
		//初始化属性
		this->m_EmpNum = 0;//初始化记录人数
		this->m_EmpArray = NULL;//初始化数组指针
		this->m_FileIsEmpty = true;//初始化文件标志是否为空
		ifs.close();
		return; //直接返回 main 函数
	}

	//2、文件存在,数据为空
	char ch;
	ifs >> ch;//先读一个字符,如果读到的字符是eof,说明文件已经读到头
	if (ifs.eof())  //文件结束符
	{
		//初始化属性
		this->m_EmpNum = 0;//初始化记录人数
		this->m_EmpArray = NULL;//初始化数组指针
		this->m_FileIsEmpty = true;//初始化文件标志是否为空
		ifs.close();
		return; //直接返回 main 函数
	}

	//3、文件存在,数据不为空
	int num = this->m_getEmpNum();//统计文件中的职工人数
	this->m_EmpNum = num;  //把文件中的人数传给数组的--当前职工人数

	//开辟一个 this->m_EmpNum 个大小的空间,将文件中的数据 存放在数组中
	this->m_EmpArray = new Worker * [this->m_EmpNum];// Worker * 返回一个 Worker **
	this->init_Emp();
}

//展示菜单****************************************************************************
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;
}

//0、退出系统*****************************************************************************
void WorkerManager::ExitSystem()
{
	//退出系统的常用套路
	cout << "欢迎下次使用!" << endl;
	system("pause");
	exit(0);//exit(0) 表示程序正常退出,exit⑴/exit(-1)表示程序异常退出。
}

//1、添加职工**********************************************************************************
void WorkerManager::Add_Emp()
{
	cout << "请输入添加职工的数量:" << endl;
	int addNum = 0;
	cin >> addNum;//用户要添加的人数

	if (addNum > 0)
	{
		//添加新人之前首先要 开辟新空间

		//先计算新空间大小
		int newSize = this->m_EmpNum + addNum;

		//在堆区开辟出新空间,用 newSpace 接收。如果开辟在栈区,数组用一次就完了,所以要开辟在堆区
		Worker ** newSpace = new Worker * [newSize];//用一个数组把父类指针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;//职工岗位

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

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

			cout << "请选择该职工岗位: " << 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:
				break;
			}
			//将创建的职工信息,保存到新空间中
			newSpace[this->m_EmpNum + i] = worker;
		}

		//释放原有空间  -------   原有空间中的信息前面已经拷贝到newSpace中,所以尽管释放旧空间
		delete [] this->m_EmpArray;
		//更改新空间的指向
		this->m_EmpArray = newSpace;
		//更新 新的职工人数
		this->m_EmpNum = newSize;
		//更新 职工不为空标志 ----  一旦添加职工后,标志就不为空
		this->m_FileIsEmpty = false;

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

		//调用保存文件函数,将职工信息保存到文件 empFile.txt 中
		this->save();
	}
	else
	{
		cout << "输入有误" << endl;
	}

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

//保存文件  把职工信息写进文件中**************************************************************
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();
}


//统计文件中的人数*************************************************************************
int WorkerManager::m_getEmpNum()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);

	int id;
	string name;
	int dId;
	int num = 0;
	while (ifs >> id && ifs >> name && ifs >> dId)
	{
		//统计人数  读取到三个信息之后 num++
		num++;
	}
	return num;
}

//初始化员工 ,也就是读文件中的职工信息 *****************************************************
void WorkerManager::init_Emp()  //功能:在添加新数据时,将以前的数据先拷贝到数组中
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);

	int id;
	string name;
	int dId;
	int index = 0;
	while (ifs >> id && ifs >> name && ifs >> dId)
	{
		Worker* worker = NULL;
		//根据从文件中读取到的 不同的部门Id , 来创建不同的对象,
		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;
		index++;
	}
	ifs.close();
}


//2、显示职工***************************************************************************
void WorkerManager::Show_Emp()
{

	if (this->m_FileIsEmpty)//这是后面的功能实现 都要先进行的工作
	{
		cout << "文件不存在或文件为空!" << endl;
	}
	else
	{
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			//利用多态调用接口,显示已有的职工信息
			this->m_EmpArray[i]->showInfo();
		}
	}

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

//3、删除职工,按照编号删除职工***********************************************************************
void WorkerManager::Del_Emp()  
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		cout << "请输入要删除的职工编号: " << endl;
		int id = 0;
		cin >> id;
		           //IsExist(id) 返回职工所在数组中的位置
		int index = this->IsExist(id);//注意!假如要找第二个人,他在数组中的下标位置是 1 ,而不是 2,此时的 index=1

		if (index != -1)
		{
			//本质是 数据前移
			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 << "删除成功!" << endl;
		}
		else
		{
			cout << "删除失败,查无此人!" << endl;
		}
	}

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

//职工是否存在,存在 返回职工所在数组中的位置,不存在返回 -1  ****************************************
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;//i 就代表职工的编号
			break;//找到职工的编号,就不再寻找
		}
	}
	return index; //找到了 返回 i ,没找到(不存在) 返回 -1
}

//4、修改职工****************************************************************************************
void WorkerManager::Mod_Emp()
{
	if (this->m_FileIsEmpty)//1.先检查 文件是否存在
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		cout << "请输入要修改的职工编号: " << endl;
		int id;
		cin >> id;

		int ret = this->IsExist(id);  //2.再查职工 职工是否存在
		if (ret != -1)//职工存在,进行修改操作,赋予新的 id, name, 岗位
		{
			//先释放原来堆区的数据
			delete this->m_EmpArray[ret];

			int newId = 0;
			string newName = "";
			int dSelect = 0;

			cout << "查到:" << id << "号职工 " << "  请输入新职工编号: " << endl;
			cin >> newId;

			cout << "请输入新姓名:" << endl;
			cin >> newName;
			
			cout << "请选择该职工岗位: " << endl;
			cout << "1、普通职工" << endl;
			cout << "2、经理" << endl;
			cout << "3、老板" << endl;
			cin >> dSelect;

			Worker* worker = NULL;//由于有不同的职工,所以指针设置成空,用来指向不同的职工
			switch (dSelect)
			{
			case 1:
				worker = new Employee(newId, newName, dSelect);
				break;
			case 2:
				worker = new Manager(newId, newName, dSelect);
				break;
			case 3:
				worker = new Boss(newId, newName, dSelect);
				break;
			default:
				break;
			
			}
			
			//更新数据 到数组中
			this->m_EmpArray[ret] = worker;

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

			//同步更新到文件中
			this->save();
		}
		else
		{
			cout << "修改失败,查无此人!" << endl;
		}
	}

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

//5、查找职工***********************************************************************************
void WorkerManager::Find_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		cout << "请输入查找的方式:" << endl;
		cout << "1、按职工编号查找" << endl;
		cout << "2、按职工姓名查找" << endl;

		int select = 0;
		cin >> select;

		if (select == 1)
		{
			//按编号查找
			int id;
			cout << "请输入查找的职工编号:" << endl;
			cin >> id;

			int ret = IsExist(id);
			if (ret != -1)
			{
				//找到该职工,显示一下
				cout << "查找成功!该职工信息如下:" << endl;
				this->m_EmpArray[ret]->showInfo();
			}
			else
			{
				cout << "查找失败,查无此人!" << endl;
			}

		}
		else if(select == 2)
		{
			//按姓名查找
			string name;
			cout << "请输入要查找的姓名:" << endl;
			cin >> name;

			//加入 判断是否查到 的标志
			bool flag = false;   // bool 只返回 true 和 false!

			for (int i = 0; i < this->m_EmpNum; i++)
			{
				if (this->m_EmpArray[i]->m_Name == name)
				{
					cout << "查找成功!该职工信息如下:" << endl;

					this->m_EmpArray[i]->showInfo();//显示信息

					flag = true;
				}
			}
			if(flag == false)
			{
				cout << "查找失败,查无此人!" << endl;
			}
		}
		else
		{
			cout << "输入选项有误!" << endl;
		}
	}

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


//6、排序职工***********************************************************************************
void WorkerManager::Sort_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
		system("pause");
		system("cls");
	}
	else
	{
		cout << "请选择排序方式:" << endl;
		cout << "1、按职工号进行升序" << endl;
		cout << "2、按职工号进行降序" << endl;

		int select = 0;
		cin >> select;

		for (int i = 0; i < this->m_EmpNum; i++)
		{
			int minORmax = i;//声明最小值 或 最大值 的下标

			for (int j = i + 1; j < this->m_EmpNum; j++)
			{
				if (select == 1)//升序排序
				{
					if (this->m_EmpArray[minORmax]->m_Id > this->m_EmpArray[j]->m_Id)
					{
						minORmax = j;//把最小值的下标给 minOrmax,让该下标的数与第i个数互换
					}
				}
				else  //降序
				{
					if (this->m_EmpArray[minORmax]->m_Id < this->m_EmpArray[j]->m_Id)
					{
						minORmax = j;//把最大值的下标给 minOrmax
					}
				}
			}

			//判断一开始认定的 最小值或最大值是不是计算的最小值或最大值,如果不是,交换数据。
			if (i != minORmax)
			{
				Worker* temp = this->m_EmpArray[i];
				this->m_EmpArray[i] = this->m_EmpArray[minORmax];
				this->m_EmpArray[minORmax] = temp;
			}
		}

		cout << "排序成功!排序后的结果为:" << endl;
		this->save(); //排序后的结果保存到文件中
		this->Show_Emp();//展示所有职工信息
	}
}


//7、清空文件*********************************************************************************
void WorkerManager::Clean_File()
{
	cout << "确认清空?" << endl;
	cout << "1、确认" << endl;
	cout << "2、返回" << endl;

	int select = 0;
	cin >> select;

	if (select == 1)
	{
		//清空文件  要在文件中清除 ios::trunc
		ofstream ofs;
		ofs.open(FILENAME, ios::trunc);// ios::trunc 如果文件已存在则先删除该文件
		ofs.clear();

		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;
		}
		cout << "清空成功!" << endl;
	}

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

WorkerManager::~WorkerManager()
{
	if (this->m_EmpArray != NULL)//经过添加职工步骤后,此时的 this->m_EmpArray 指向的是新空间。
	{
		//删除堆区的每个职工对象
		for (int i = 0; i < this->m_EmpNum; i++)
		{
			if (this->m_EmpArray[i] != NULL)
			{
				delete this->m_EmpArray[i];
			}
		}
		//最后把数组置空
		delete [] this->m_EmpArray;
		this->m_EmpArray = NULL;
	}
}

3. 最后是主函数:

#include <iostream>
using namespace std;
#include "workerManager.h"

int main()
{
	//实例化 管理者对象
	WorkerManager wm;

	int choice = 0;

	while (true)
	{
		wm.Show_Menu();	//调用展示菜单
		cout << "请输入您的选择:" << endl;
		cin >> choice;

		//用switch 实现选择分支
		switch (choice)
		{
		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_File();
			break;

		default:
			system("cls");//清屏
			break;
		}
	}

	system("pause");
	return 0;
}

结束语:用到了太多知识,还没有融会贯通,敲的时候有点晕,敲完之后又整体过了一遍。任重而道远啊~

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值