目录
(4)创建"manager.h"头文件(与上面的员工内容很相似)
一.基本介绍
本文没有涉及到C++中的STL库,只是使用了C++中的基础知识,是入门级别的编程
其中涉及到:继承,纯虚函数(不会的同志可以先去了解一下)
上面有C++职工管理系统的全部代码,可以自行下载
二.职工管理系统的要求
公司中职工分为三类:普通员工,经理,老板
显示信息时,需要显示职工编号,职工姓名,职工岗位,以及职责
普通员工职责:完成经理交给的任务
经理职责:完成老板给的任务,并下发任务给员工
老板职责:管理公司所有事务
管理系统中需要实现的功能入下:
- 退出管理程序:退出当前管理系统
- 增加职工信息:实现批量添加职工功能,将信息录入到文件中
- 显示职工信息:显示公司内部所有职工的信息
- 删除离职职工:按照编号删除指定的职工
- 修改职工信息:按照编号修改职工个人信息
- 查找职工信息:按照职工的编号或者职工的姓名进行查找相关人员信息
- 按照编号排序:按照职工编号,进行排序,排序规则由用户指定
- 清空所有文档:清空文件中记录的所有员工的信息(要再次确认,防止误删)
三.菜单和退出管理程序
这两个的写法都很简单,我就写在一起了(首先创建一个"职工管理系统.cpp"来放主函数)
首先先创建一个头文件("workeManager.h")去放我们写的接口
class workManager
{
public:
//展示菜单
void Show_Menu();
//退出系统
void ExitSystem();
};
然后再创建一个源文件("workManager.cpp")去实现我们写的接口(注意引用头文件)
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;
}
void workManager::ExitSystem()
{
cout << "退出系统成功!!" << endl;
cout << "欢迎下次使用" << endl;
system("pause"); //请按任意键继续
system("cls"); //清屏
exit(-1); //退出系统
}
最后通过刚开始创建的"职工管理系统.cpp"去调用菜单接口 (注意引用头文件,后面不再提醒)
int main()
{
while (1)
{
workManager wm;
wm.Show_Menu(); //调用菜单
cout << "请输入要选择的程序:";
int n = 0;
cin >> n;
switch (n) //通过switch去调用接口
{
case 1: //增加职工信息
break;
case 2: //显示职工信息
break;
case 3: //删除离职职工
break;
case 4: //修改职工信息
break;
case 5: //查找职工信息
break;
case 6: //按照编号排序
break;
case 7: //清楚所有文档
break;
case 0: //退出系统
wm.ExitSystem(); //调用退出接口
break;
}
}
return 0;
}
四.增加职工信息
- 因为每类员工都有姓名,职工编号,所在部门编号,所以再增加一个"worker.h"头文件,去抽象出一个职工类,作为父类继承给子类员工
- 职工有三类员工,经理,老板。 创建头文件和源文件: 员工:"employee.cpp"和"employee.h" 经理:"manager.cpp"和"manager.h" 老板:"boss.cpp"和"boss.h" 这些头文件写接口,源文件写实现 (这样写可能很麻烦,但是,可以使我们的逻辑清晰,并且回头看这些代码时很清晰)
(1)创建"worker.h"头文件
class Worker
{
public:
//显示个人信息
virtual void showInfo() = 0; //纯虚函数
//获取岗位名称
virtual string getDeptName() = 0; //纯虚函数
string m_Name; //姓名
int m_Id; //职工编号
int m_DeptId; //职工所在部门编号
};
(2)创建"employee.h"头文件
class Employee :public Worker //继承
{
public:
//构造函数
Employee(int id, string name, int did);
//显示个人信息
virtual void showInfo();
//获取岗位名称
virtual string getDeptName();
};
(3)创建"employee.cpp"源文件
//构造函数
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是水平制表符
<< "\t岗位:" << this->getDeptName()
<< "\t岗位职责:" << "完成经理交给的任务" << endl;
}
//获取岗位名称
string Employee::getDeptName()
{
return string("员工");
}
(4)创建"manager.h"头文件(与上面的员工内容很相似)
class Manager :public Worker
{
public:
//构造函数
Manager(int id, string name, int did);
//显示个人信息
virtual void showInfo();
//获取岗位名称
virtual string getDeptName();
};
(5)创建"manager.cpp"源文件(同上)
//构造函数
Manager::Manager(int id, string name, int did)
{
this->m_Id = id;
this->m_DeptId = did;
this->m_Name = name;
}
//显示个人信息
void Manager::showInfo()
{
cout << "职工编号:" << this->m_Id
<< "\t职工姓名:" << this->m_Name
<< "\t岗位:" << this->getDeptName()
<< "\t岗位职责:" << "完成老板给的任务,并下发任务给员工" << endl;
}
//获取岗位名称
string Manager::getDeptName()
{
return string("经理");
}
(6)创建"boss.h"头文件(同上)
class Boss :public Worker
{
public:
//构造函数
Boss(int id, string name, int did);
//显示个人信息
virtual void showInfo();
//获取岗位名称
virtual string getDeptName();
};
(7)创建"boss.cpp"源文件(同上)
//构造函数
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("老板");
}
写到这里我们可以测试一下,看程序能不能正常运行(在"职工管理系统.cpp"里测试)
把原来main函数里的东西注释掉,写下面的代码进行测试
int main()
{
Worker* worker = NULL;
worker = new Employee(1, "张三", 1);
worker->showInfo();
delete worker;
worker = new Manager(2, "李四", 2);
worker->showInfo();
delete worker;
worker = new Boss(3, "王五", 3);
worker->showInfo();
delete worker;
return 0;
}
我的测试结果:(说明程序没有错误,测试完就可以删掉或注释掉了)
上面已经实现了员工,经理,老板的类了,下面实现在控制面板手动输入员工
在"workManager.h"头文件中的类中添加五个个接口
//构造函数
workManager();
//增加职工
void Add_Emp();
//记录文件中职工个数
int m_EmpNum; //后续要写文件操作的内容,来获取文件中的人数,以至于能更好的开辟空间
//员工数组指针
Worker** m_EmpArray; //这里使用两个*,因为:我们在录入员工时,使用new在堆区开放空间,也是一个指针,存放一级指针,使用二级指针
//判断文件是否为空
bool m_fileIsEmpty;
在"workManager.cpp"中去实现
//增加职工
void workManager::Add_Emp()
{
cout << "请输入加入的职工个数:";
int n = 0;
cin >> n;
if (n > 0)
{
//更新人数
int NewSize = this->m_EmpNum + n;
//开辟空间
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 < n; i++)
{
int id;
string name;
int did;
cout << "请输入第" << i + 1 << "个员工的编号:";
cin >> id;
cout << "请输入第" << i + 1 << "个员工的姓名:";
cin >> name;
cout << "请选择员工的岗位:" << endl;
cout << "1.员工" << endl;
cout << "2.经理" << endl;
cout << "3.老板" << endl;
cin >> did;
Worker* worker = NULL;
switch (did)
{
case 1: //员工
{
worker = new Employee(id, name, did);
break;
}
case 2: //经理
{
worker = new Manager(id, name, did);
break;
}
case 3: //老板
{
worker = new Boss(id, name, did);
break;
}
}
NewSpace[this->m_EmpNum + i] = worker;
}
//释放原来的空间
delete[] this->m_EmpArray;
this->m_EmpArray = NULL;
//更新空间内容
this->m_EmpArray = NewSpace;
//更新文件不为空
this->m_fileIsEmpty = false;
//更新数组大小
cout << "成功添加" << n << "个职工" << endl;
//保存到文件中
this->save();//这个函数下面将会说明
}
else
{
cout << "输入有误" << endl;
}
system("pause");
system("cls");
}
配合下面的显示职工信息的操作,我们可以测试一下我们写的代码(把Add_Emp()写道case2中)
五.显示职工信息
显示职工信息就比较简单了,可以调用我们之前写的Worker类中的showInfo()接口
在workManager.cpp中去使用workManager的构造函数去初始化一些变量(后期还会再更改)
//构造函数
workManager::workManager()
{
//初始化人数
this->m_EmpNum = 0;
//初始化数组指针
this->m_EmpArray = NULL;
//初始化为空
this->m_fileIsEmpty = true;
}
显示职工信息的操作:
在"workManager.h"头文件中添加接口
//显示职工信息
void Show_Emp();
在"workManager.cpp"中实现接口(在员工类中有直接写showInfo()的实现,可以直接调用)
//显示职工
void workManager::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");
}
实现到这,就可以在主函数中去测试了:(我这里是没有问题的,可以显示出来员工)
六.文件交互操作
上面,我们只是把信息存到了内存中,当程序结束后,内存释放,信息也就没了
所以需要一个与文件交互的功能,对文件进行读写操作
(1)设定文件路径
首先我们将文件路径,在"workManager.h"中添加宏常量,并且包含头文件fstream
#include<fstream>
#define FILENAME "test.txt"
(2)实现保存文件功能
在"workManager.h"中添加接口
//将数据保存到文件
void save();
在"workManager.cpp"中去实现接口
//保存文件
void workManager::save()
{
ofstream ofs;
ofs.open(FILENAME, ios::out); //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(); //关闭文件
}
注意: save()接口是将数据保存到文件中,所以应该在添加职工中的Add_Emp()接口中调用
在Add_Emp()中已经写到,下面就 不再写了
我们去测试一下(先在程序中录入数据,打开文件的地址就可以看到多出来一个txt文件):
(3)文件的读取
我们先考虑一下情况
- txt文件不存在
- txt文件存在,但是数据为空
- txt文件存在,数据不为空
一共就这三种情况,需要进行判断,我们将在workManager类的构造函数中进行更改
被注释掉的代码是测试代码,可以自行删除去测试
下面的代码中的一些接口我会慢慢说明
//构造函数
workManager::workManager()
{
ifstream ifs;
ifs.open(FILENAME, ios::in); //ios::in为读文件而打开文件
//文件不存在的情况
if (!ifs.is_open())
{
//cout << "文件不存在!" << endl;
this->m_fileIsEmpty = true; //初始化文件为空
this->m_EmpNum = 0; //初始化人数
this->m_EmpArray = NULL; //初始化指针
ifs.close(); //关闭文件
return;
}
//文件存在,数据为空
char c;
ifs >> c;
if (ifs.eof())
{
//cout << "文件为空!" << endl;
this->m_fileIsEmpty = true; //初始化文件为空
this->m_EmpNum = 0; //初始化人数
this->m_EmpArray = NULL; //初始化指针
ifs.close();
return;
}
//文件存在,并且有数据
int num = this->m_getEmpNum();
//cout << "职工人数为:" << num << endl;
this->m_EmpNum = num;
//更新职工数创建数组
this->m_EmpArray = new Worker * [this->m_EmpNum];
//初始化职工
Init_Emp();
测试代码
//for (int i = 0; i < this->m_EmpNum; i++)
//{
// cout << "职工号:" << this->m_EmpArray[i]->m_Id
// << "\t职工姓名:" << this->m_EmpArray[i]->m_Name
// << "\t部门编号:" << this->m_EmpArray[i]->m_DeptId << endl;
//}
}
int m_getEmpNum();接口 获取txt文件中员工的个数
注意:将接口写到"workManager.h"中
//职工个数
int workManager::m_getEmpNum()
{
ifstream ifs;
ifs.open(FILENAME, ios::in); //打开文件 读取
int id;
string name;
int did = 0;
int num = 0;
while (ifs >> id && ifs >> name && ifs >> did) //一行一行的遍历
{
num++;
}
ifs.close();//关闭文件
return num;
}
void Init_Emp();接口 是将文件中的数据录入到程序中(能在程序中显示)
注意:将接口写到"workManager.h"中
//初始化职工(将文件中的数据录入到程序中)
void workManager::Init_Emp()
{
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int did;
int n = 0;
while (ifs >> id && ifs >> name && ifs >> did)
{
Worker* worker = NULL;
if (did == 1) //普通员工
{
worker = new Employee(id, name, did);
}
else if (did == 2) //经理
{
worker = new Manager(id, name, did);
}
else
{
worker = new Boss(id, name, did);
}
this->m_EmpArray[n] = worker;
n++;
}
}
文件操作在这里就结束了,可以进行多次不同的测试,看程序是否能运行成功
七.删除离职职工
在"wokeManager.h"中写接口
//删除职工
void Del_Emp();
在"workManager.cpp"中实现接口
//删除职工
void workManager::Del_Emp()
{
if (this->m_fileIsEmpty)
{
cout << "文件不存在或记录为空" << endl;
}
else
{
int m = 0;
cout << "请输入要删除的职工号:";
cin >> m;
int ret = IsExist(m); //这个接口是判断员工是否存在
if (ret == -1)
{
cout << "删除失败,职工不存在!" << endl;
}
else
{
for (int i = ret; i < this->m_EmpNum - 1; i++)
{
this->m_EmpArray[i] = this->m_EmpArray[i + 1];
}
//更新人数
this->m_EmpNum--;
//保存到文件
this->save();
cout << "删除员工成功" << endl;
}
}
system("pause");
system("cls");
}
int IsExist(int id);的实现 判断职工是否存在
//判断职工是否存在
int workManager::IsExist(int id)
{
for (int i = 0; i < this->m_EmpNum; i++)
{
if (this->m_EmpArray[i]->m_Id == id)
{
return i;
}
}
return -1;
}
接着就是测试,如果没有成功,在认真分析代码,再进行调试
八.修改职工信息
修改职工信息:通过职工编号找到职工,然后进行修改
注意:将接口写到"workManager.h"中
//修改职工信息
void workManager::Mod_Emp()
{
if (this->m_fileIsEmpty)
{
cout << "文件不存在或记录为空" << endl;
}
else
{
int n = 0;
cout << "请输入要修改的职工编号:";
cin >> n;
int ret = IsExist(n); //判断职工是否存在
if (ret == -1)
{
cout << "修改失败,职工不存在!" << endl;
}
else
{
delete this->m_EmpArray[ret];
cout << "查找到:" << n << "号职工,请输入新的职工信息" << endl;
int id;
string name;
int did;
cout << "请输入新的职工号:";
cin >> id;
cout << "请输入新名字:";
cin >> name;
cout << "请输入岗位" << endl;
cout << "1.员工" << endl;
cout << "2.经理" << endl;
cout << "3.老板" << endl;
cin >> did;
Worker* worker = NULL;
switch (did)
{
case 1:
worker = new Employee(id, name, did);
break;
case 2:
worker = new Manager(id, name, did);
break;
case 3:
worker = new Boss(id, name, did);
break;
}
this->m_EmpArray[ret] = worker; //将新信息保存
}
}
system("pause");
system("cls");
}
测试一下
九. 查找职工信息
查找职工信息:这里分为两种查法 (1)按照职工编号查找 (2)按照职工姓名查找
注意:将接口写到"workManager.h"中
//查找职工
void workManager::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 = 0;
cout << "请输入要查找的职工号:";
cin >> id;
int ret = this->IsExist(id);
if (ret == -1)
{
cout << "查找失败,查无此人" << endl;
}
else
{
cout << "查找成功,具体信息如下:" << endl;
this->m_EmpArray[ret]->showInfo();
}
}
else if (select == 2) //按照姓名查找
{
bool flag = false;
cout << "请输入要查找人的姓名:" << endl;
string name;
cin >> name;
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;
break;
}
}
if (flag == false)
{
cout << "查找失败,查无此人" << endl;
}
}
else
{
cout << "输入有误" << endl;
}
}
system("pause");
system("cls");
}
测试一下
十. 按照编号排序
在这里使用一个非常简单的排序方法(选择排序)
注意:将接口写到"workManager.h"中
//按照职工号排序
void workManager::Sort_Emp()
{
if (this->m_fileIsEmpty)
{
cout << "文件不存在或记录为空" << endl;
}
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;
}
}
else //降序
{
if (this->m_EmpArray[minOrMax]->m_Id < this->m_EmpArray[j]->m_Id)
{
minOrMax = j;
}
}
}
if (minOrMax != i)
{
int tmp = this->m_EmpArray[i]->m_Id;
this->m_EmpArray[i]->m_Id = this->m_EmpArray[minOrMax]->m_Id;
this->m_EmpArray[minOrMax]->m_Id = tmp;
}
}
this->save();
cout << "排序成功" << endl;
}
system("pause");
system("cls");
}
测试一下
十一.清空所有文档
清空所有文档:将txt文件中的所有数据删除(防止错误操作,增加一层确认删除操作)
注意:将接口写到"workManager.h"中
//清空文件
void workManager::Clean_File()
{
cout << "确认清空?" << endl;
cout << "1.确认" << endl;
cout << "2.返回" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
//打开模式ios::trunc
ofstream ofs(FILENAME, 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_EmpNum = 0;
delete[] this->m_EmpArray;
this->m_EmpArray = NULL;
this->m_fileIsEmpty = true;
cout << "清空成功" << endl;
}
system("pause");
system("cls");
}
测试代码
到这里还没结束:我们是在堆区开放的空间,最后需要我们手动释放
十二.释放堆区空间
释放堆区空间:在workManager类的析构函数中去释放空间
注意:将接口写到"workManager.h"中
//析构函数
~workManager();
实现:
//析构函数
workManager::~workManager()
{
if (this->m_EmpArray != NULL)
{
delete[] this->m_EmpArray;
this->m_EmpArray = NULL;
}
}
总结
职工管理系统没有使用很难的算法,只是逻辑比较复杂,只要逻辑清晰,还是很好写出来的
本文也使用了C++中的一些基本的语法,可以更好的帮助我们学习C++