目录
一、管理系统需求
作用:管理公司内所有员工的信息
分类:要显示每位员工的编号、姓名、岗位与职责
具体实现的功能:
二、创建管理 类
三、各个接口函数
1、菜单展示功能
2、 选择功能
3、创建员工功能
①普通员工employee
②经理manager
③老板boss
4、添加功能
4.1 添加员工
4.2将添加的员工保存到文件中
4.2.1写文件
4.2.2读文件
5、显示员工
6、删除员工
6、修改员工
7、查找员工
8、排序员工
9、清空文件
一、管理系统需求
作用:管理公司内所有员工的信息
分类:要显示每位员工的编号、姓名、岗位与职责
普通员工:完成经理交给的任务
经理:完成老板交给的任务,并下发给员工
老板:管理公司所有事务
具体实现的功能:
①添加:实现批量添加职工功能,将职工信息(编号、姓名、职位)录入到文件中
②显示:显示当前公司内所有员工的信息
③删除:按照编号删除指定的员工
④修改:按照编号修改指定员工的信息
⑤查找:按照员工的姓名或编号
查找员工并显示其信息
⑥排序:按照员工编号进行升序或降序排列
⑦清空:清空文件中所有员工信息(需二次确认)
⑧退出:退出当前管理系统
二、创建管理 类
管理 类的作用:
①供用户选择的菜单界面
②对员工增删查改等的操作
③与数据文件的读写交互
首先需要头文件与源文件
并在头文件中写入管理 类,并加上空的构造/析构函数
#pragma once
#include<iostream>
using namespace std;
class WorkerManager
{
public:
// 构造函数
WorkerManager();
// 析构函数
~WorkerManager();
};
并在源文件中空实现
#include<iostream>
using namespace std;
#include"workerManager.h"
// 构造函数
WorkerManager::WorkerManager()
{
}
// 析构函数
WorkerManager::~WorkerManager()
{
}
三、各个接口函数
1、菜单展示功能
先在头文件的类中声明函数
void Show_Menu();
再在源文件中实现
void WorkerManager:: Show_Menu()
{
cout << "***************************************" << endl;
cout << "******** 欢迎使用教工管理系统!********" << endl;
cout << "************ 1、添加员工 **************" << endl;
cout << "************ 2、删除员工 **************" << endl;
cout << "************ 3、显示员工 **************" << endl;
cout << "************ 4、修改员工 **************" << endl;
cout << "************ 5、查找员工 **************" << endl;
cout << "************ 6、排序员工 **************" << endl;
cout << "************ 7、清空员工 **************" << endl;
cout << "************ 8、退出系统 **************" << endl;
cout << "***************************************" << endl;
}
接下来我们回到主函数的源文件创建系统并尝试菜单功能
int main()
{
WorkerManager WM;
WM.Show_Menu();
return 0;
}
2、 选择功能
在主函数中我们使用switch语句使得系统实现选择功能,并加上退出功能
int main()
{
WorkerManager WM;
int choice = 0;
while (true)
{
WM.Show_Menu();
cout << "请选择" << endl;
cin >> choice;
switch (choice)
{
case 1: // 添加
break;
case 2: // 删除
break;
case 3: // 显示
break;
case 4: // 修改
break;
case 5: // 查找
break;
case 6: // 排序
break;
case 7: // 清空
break;
case 0: // 退出
WM.Exit_System();
break;
default:
system("cls");
break;
}
}
return 0;
}
void WorkerManager:: Exit_System()
{
cout << "退出系统!" << endl;
exit(0);
}
3、创建员工功能
首先创建worker.h头文件,其内创建职工Worker基类,包含员工编号、姓名与岗位编号
// 员工抽象类_基类
class Worker
{
public:
// 展示个人信息
virtual void showInfo() = 0;
// 获取个人岗位
virtual string getDeptName() = 0;
int m_id; // 员工编号
string m_name;// 员工姓名
int m_Did; // 所属部门编号
};
不需要具体实现,接下来,实现普通员工:
①普通员工employee
创建员工头文件employee.h与源文件employee.cpp,并包含worker.h
头文件:子类employee继承父类Worker
class employee :public Worker
{
public:
// 构造函数
employee(int id, string name, int Did);
// 展示个人信息
virtual void showInfo();
// 获取个人岗位
virtual string getDeptName();
};
源文件:
// 构造函数
employee::employee(int id, string name, int Did)
{
this->m_id = id;
this->m_name = name;
this->m_Did = Did;
}
// 展示个人信息
void employee:: showInfo()
{
cout << "员工编号:" << this->m_id
<< "\t员工姓名:" << this->m_name
<< "\t员工岗位:" << this->getDeptName()
<< "\t员工职责:完成经理安排的任务" << endl;
}
// 获取个人岗位
string employee::getDeptName()
{
return "普通员工";
}
main中测试:(先包含头文件和源文件)
int main()
{
// test:
Worker* worker = NULL;
worker = new employee(22,"Joyce",1);
worker->showInfo();
return 0;
}
②经理manager
同理:创建子类manager类,并继承父类Worker
头文件:
// 经理—子类
class manager :public Worker
{
public:
// 构造函数
manager(int id, string name, int Did);
// 展示个人信息
virtual void showInfo();
// 获取个人岗位
virtual string getDeptName();
};
源文件:
// 构造函数
manager::manager(int id, string name, int Did)
{
this->m_id = id;
this->m_name = name;
this->m_Did = Did;
}
// 展示个人信息
void manager::showInfo()
{
cout << "员工编号:" << this->m_id
<< "\t员工姓名:" << this->m_name
<< "\t员工岗位:" << this->getDeptName()
<< "\t员工职责:完成老板安排的任务" << endl;
}
// 获取个人岗位
string manager::getDeptName()
{
return "经理";
}
③老板boss
同理:创建子类boss类,并继承父类Worker
头文件:
// 老板—子类
class boss :public Worker
{
public:
// 构造函数
boss(int id, string name, int Did);
// 展示个人信息
virtual void showInfo();
// 获取个人岗位
virtual string getDeptName();
};
源文件:
// 构造函数
boss::boss(int id, string name, int Did)
{
this->m_id = id;
this->m_name = name;
this->m_Did = Did;
}
// 展示个人信息
void boss::showInfo()
{
cout << "员工编号:" << this->m_id
<< "\t员工姓名:" << this->m_name
<< "\t员工岗位:" << this->getDeptName()
<< "\t员工职责:安排所有任务" << endl;
}
// 获取个人岗位
string boss::getDeptName()
{
return "老板";
}
创建测试案例:(记得包含各个职位头文件)
int main()
{
// test:
Worker* worker1 = NULL;
worker1 = new employee(1,"Joyce",1);
worker1->showInfo();
delete worker1;
Worker* worker2 = NULL;
worker2 = new manager(2, "Nana", 2);
worker2->showInfo();
delete worker2;
Worker* worker3 = NULL;
worker3 = new boss(3, "Baby",3);
worker3->showInfo();
delete worker3;
return 0;
}
4、添加功能
作用:批量添加员工,并保存到文件中
4.1 添加员工
首先,用户在添加员工时,会有不同的职位,如果我们把所有种类员工信息直接塞进一个数组中,存储将会困难,也可能会占用大量内存
因此,我们创建一个员工接着就创建一个指针,使该指针指向该员工的信息数据,并保存指针到一个数组中,这样我们在数组中就只有指针
而且,想要在程序中维护这个不定长度的指针,我们将数组创建到堆区,并使用Worker**的指针维护
代码:
首先在workerManager头文件的WorkerManager类中添加记录员工数量和储存员工信息的指针这两个属性,并加入Add添加员工的接口函数
// 记录员工数量
int worker_num;
// 储存员工的数组
Worker** worker_array;
// 添加员工功能
void Add();
接着在workerManager的源文件中的构造函数中初始化这两个属性
// 构造函数
WorkerManager::WorkerManager()
{
// 初始化属性
this->worker_num = 0;
this->worker_array = NULL;
}
并实现Add添加员工函数
void WorkerManager::Add()
{
cout << "请输入要添加员工的个数:"<< endl;
int Add_num = 0;
cin >> Add_num;
if (Add_num > 0)
{
// 计算添加后员工的总数
int newSize = this->worker_num + Add_num;
// 开辟新空间
Worker** newSpace = new Worker * [newSize];
// 将原来空间的数据拷贝到新空间
if (this->worker_array != NULL)
{
for (int i = 0; i < this->worker_num; i++)
{
newSpace[i] = this->worker_array[i];
}
}
// 将新数据添加至新空间的后面
for (int j = 0; j < Add_num; j++)
{
int id;
string name;
int Did;
cout << "请输入第" << j + 1 << "个新员工的编号" << endl;
while (true)
{
cin >> id;
int ret = this->worker_isExit(id);
if (ret != -1)
{
cout << "用户编号已存在!请重新输入:" << endl;
}
else
{
break;
}
}
cout << "请输入第" << j + 1 << "个新员工的姓名" << endl;
cin >> name;
cout << "请输入第" << j + 1 << "个新员工的部门:" <<
"1、普通员工 "
"2、经理 "
"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;
default:
cout << "输入错误" << endl;
break;
}
// 将创建的员工指针,保存至数组中
newSpace[this->worker_num + j] = worker;
}
// 释放原有数组的空间
delete[] this->worker_array;
// 更新新空间的指向
this->worker_array = newSpace;
// 更新新空间的人数
this->worker_num = newSize;
cout << "成功添加" << Add_num << "名新员工!" << endl;
Sleep(1000); // 暂停1000毫秒
system("pause");// 按任意键继续
system("cls"); // 清屏
}
else
{
cout << "输入错误!" << endl;
}
}
然后,记得堆区手动开辟的数据要手动释放,析构函数
// 析构函数
WorkerManager::~WorkerManager()
{
if (this->worker_array != NULL)
{
delete[]this->worker_array;
this->worker_array = NULL;
}
}
最后在main函数中加入Add函数后进行测试
4.2将添加的员工保存到文件中
添加头文件<fstream>后就可以直接开始
4.2.1写文件
首先在主体函数中添加保存数据到文件的save函数
然后在源文件中实现:
void WorkerManager::save()
{
ofstream ofs;
ofs.open("WorkerFile.txt", ios::out);
for (int i = 0; i < this->worker_num; i++)
{
ofs << this->worker_array[i]->m_id<<" "
<< this->worker_array[i]->m_name << " "
<< this->worker_array[i]->m_Did << endl;
}
ofs.close();
}
最后在Add函数中调用即可
4.2.2读文件
作用:将文件中的内容读取到程序中
上面实现了将添加的员工保存到文件中,但是文件中的员工信息我们还不能读取到程序中
而文件实际有3种状态:
①第一次使用程序,文件未创建不存在
②文件存在,但数据被用户清空
③文件存在,保存有员工的数据
我们在workerManager头文件中添加新的变量:bool m_FileIsEmpty;来判断文件是否为空
然后修改源文件中构造函数
①文件不存在
// 构造函数
WorkerManager::WorkerManager()
{
// 1、文件不存在
ifstream ifs;
ifs.open("FILENAME", ios::in);
if (!ifs.is_open())
{
cout << "文件不存在!" << endl;
// 初始化属性
this->worker_num = 0;
this->worker_array = NULL;
this->m_FileIsEmpty = true;// 初始为空
}
}
②文件存在,但无数据
我们将文件取1个字符到一个字符变量里,然后使用函数eof()判断文件是否为空,若函数为真则为空(若无数据,文件里最后一个字符将是EOF文件结束标志,上面提取了就没了为空)
// 2、文件存在,无数据
char ch = 0;
ifs >> ch; // 取1个字符
if (ifs.eof())
{
cout << "文件为空!" << endl;
// 初始化属性
this->worker_num = 0;
this->worker_array = NULL;
this->m_FileIsEmpty = true;// 初始为空
ifs.close();
}
③文件存在有数据
首先我们增加一个统计文件中有多少人的函数get_WorkerNum();
在源文件中实现
int WorkerManager::get_WorkerNum()
{
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int Did;
int number = 0;
while (ifs >> id && ifs >> name && ifs >> Did)// 读取一行
{
number++;
}
return number;
}
然后实现一个初始化员工的函数Init();
void WorkerManager::Init()
{
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int Did;
int number = 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->worker_array[number] = worker;// 将对象放在数组中维护
number++;
}
ifs.close();
}
最后补全③
首先获取员工的个数,然后根据个数创建空间,然后初始化空间
// 3、文件存在,有数据
// 先获取员工的个数
int num = get_WorkerNum();
cout << "共有" << num << "个员工" << endl;
this->worker_num = num;
// 根据个数创建空间
this->worker_array = new Worker * [this->worker_num];
// 初始化员工
this->Init();
加上测试
// 测试:
for (int i=0; i < this->worker_num; i++)
{
cout << "员工编号:" << this->worker_array[i]->m_id <<
"\t员工名字:" << this->worker_array[i]->m_name <<
"\t部门为" << this->worker_array[i]->m_Did << endl;
}
5、显示员工
直接调用showInfo()函数即可
分为3种情况:
①文件为空,没有员工②文件存在,没有员工③文件存在,有员工
①和②可以合并
首先在workerManager头文件中创建show_worker()函数
然后在源文件中实现
void WorkerManager::show_worker()
{
if (this->m_FileIsEmpty)
{
cout << "文件为空或不存在!" << endl;
Sleep(1000);
}
else
{
for (int i = 0; i < this->get_WorkerNum(); i++)
{
this->worker_array[i]->showInfo();
Sleep(50);
}
}
system("pause");// 按任意键继续
system("cls"); // 清屏
}
6、删除员工
分为3步,首先判断员工是否存在,存在返回员工编号,然后删除员工编号的数据
首先创建判断员工是否存在worker_isExit()函数与删除员工函数del_worker();
先实现worker_isExit()函数
int WorkerManager::worker_isExit(int id)
{
for (int i = 0; i < this->worker_num; i++)
{
if (this->worker_array[i]->m_id == id)
return i;
}
return -1;
}
然后实现del_worker()函数:从要删除的数据开始从后往前覆盖数据即可
void WorkerManager::del_worker()
{
if (this->m_FileIsEmpty)
{
cout << "文件为空!" << endl;
}
else
{
cout << "请输入要删除的员工id:" << endl;
int input = 0;
cin >> input;
int ret = worker_isExit(input);
if (ret == -1)
{
cout << "删除失败,员工不存在!" << endl;
}
else
{
if (input == this->worker_num) // 如果输入的是末尾员工的id,数组直接 - 1即可
{
this->worker_num--;
}
else
{
// 数据前移,数组中后一个数据覆盖到前一个
for (int i = ret; i < this->worker_num - 1; i++)
{
this->worker_array[i] = this->worker_array[i + 1];
}
this->worker_num--;
}
this->save();
cout << "删除成功!" << endl;
}
}
Sleep(1000);
system("pause");// 按任意键继续
system("cls"); // 清屏
}
6、修改员工
worker_Manager头文件创建修改员工函数mod_worker();
输入要修改的员工编号,存在则先delete掉那个位置的员工数据,然后重新new一个worker,再写入其编号姓名与部门,最后把worker赋值给刚才delete掉的那个位置
void WorkerManager::mod_worker()
{
if (this->m_FileIsEmpty)
{
cout << "文件不存在或为空!" << endl;
}
else
{
cout << "请输入要修改的员工id:" << endl;
int input = 0;
cin >> input;
int ret = worker_isExit(input);
if (ret == -1)
{
cout << "修改失败,员工不存在!" << endl;
}
else
{
delete this->worker_array[ret];
int id = 1;
string name;
int Did;
cout << "已查找到,请输入员工新的编号" << endl;
while (true)
{
cin >> id;
int ret = this->worker_isExit(id);
if (ret != -1)
{
cout << "用户编号已存在!请重新输入:" << endl;
}
else
{
break;
}
}
cout << "请输入员工新的姓名" << endl;
cin >> name;
cout << "请输入员工新的部门:" <<
"1、普通员工 "
"2、经理 "
"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;
default:
cout << "输入错误" << endl;
break;
}
this->worker_array[ret] = worker;
cout << "修改成功!" << endl;
this->save();
}
}
Sleep(1000);
system("pause");
system("cls");
}
7、查找员工
有2种方式:①编号查找②姓名查找
也就是分别对比编号和姓名是否相等即可
首先创建查找员工函数find_worker();
然后在源文件中实现:
比对信息很简单,只要将输入的内容遍历与文件中的信息对比即可,有则输出信息,没有则输出查无此人。
同时,我们创建是否找到员工变量woreker_isFind;初始值即为false,找到员工改为true,遍历完后再根据true或者false确定是否输出查无此人。
void WorkerManager::find_worker()
{
cout << "请输入查找模式:" << endl;
cout << "1、编号查找 2、姓名查找 " << endl;
int input = 0;
cin >> input;
// 1、编号查找
if (input == 1)
{
cout << "请输入要查找人的编号:" << endl;
int id = 0;
cin >> id;
int ret = this->worker_isExit(id);
if (ret == -1)
{
cout << "查无此人!" << endl;
}
else
{
cout << "已查到编号为 " << id << " 的员工,信息如下:" << endl;
this->worker_array[ret]->showInfo();
}
}
// 2、姓名查找
else if (input == 2)
{
cout << "请输入要查找人的姓名:" << endl;
string name;
// 创建是否找到员工的变量,找到返回true,否则一直是false
bool worker_isFind = false;
cin >> name;
for (int i = 0; i < this->worker_num; i++)
{
if (name == this->worker_array[i]->m_name)
{
cout << "已查到姓名为 " << name << " 的员工,信息如下:" << endl;
this->worker_array[i]->showInfo();
worker_isFind = true;
}
}
if (worker_isFind == false)// 根据是否找到员工(即是否是false),输出查无此人
{
cout << "查无此人!" << endl;
}
}
else
{
cout << "输入错误!" << endl;
return;
}
Sleep(1000);
system("pause");
system("cls");
}
8、排序员工
2种方法:升序排列or降序排列
我们使用选择排序
void WorkerManager::sort_worker()
{
if (this->m_FileIsEmpty)
{
cout << "文件不存在或为空!" << endl;
system("pause");
system("cls");
}
else
{
cout << "请输入排序方式:" << endl;
cout << "1、升序排序 2、降序排序 " << endl;
int input = 0;
cin >> input;
int minORmax = 0;
for (int i = 0; i < this->worker_num; i++)
{
int minORmax = i; // 设定最小值或最大值
for (int j = i + 1; j < this->worker_num; j++)
{
if (input == 1) // 升序
{
if (this->worker_array[minORmax]->m_id > this->worker_array[j]->m_id)
{ // 如果我们设定的最小值比数组中某个数还小
minORmax = j; //交换下标
}
}
else // 降序
{
if (this->worker_array[minORmax]->m_id < this->worker_array[j]->m_id)
{ // 如果我们设定的最小值比数组中某个数还大
minORmax = j;
}
}
}
if (i != minORmax) // 下标有交换,则和原来的i不同,就可以进行数据的交换
{
swap(this->worker_array[minORmax], this->worker_array[i]);
}
}
this->save();
cout << "排序成功!" << endl;
cout << "排序后结果为:" << endl;
this->show_worker();
}
}
9、清空文件
先创建销毁函数
源文件中实现:
先清空文件,再销毁数组。
销毁数组时,先销毁每个元素,再销毁整个数组。
void WorkerManager::cleam_worker()
{
if (this->m_FileIsEmpty)
{
cout << "文件不存在或为空!" << endl;
system("pause");
system("cls");
}
else
{
cout << "确认清空文件?" << endl;
cout << "1、确定 2、返回" << endl;
int input = 0;
cin >> input;
if (input == 1)
{
// 1、先清空文件
// 直接使用文件打开方式的 trunc:文件存在先删除再创建
ofstream ofs(FILENAME, ios::trunc);
ofs.close();
// 2、再清空数组
if (this->worker_array != NULL)
{
// 2.1先删除堆区每个员工对象(数组每个元素)
for (int i = 0; i < this->worker_num; i++)
{
delete this->worker_array[i];
this->worker_array[i] = NULL;
}
}
// 2.2再清空数组
delete[]this->worker_array;
this->worker_array = NULL;
this->worker_num = 0;
this->m_FileIsEmpty = true; // 文件为空的标志
}
cout << "清空成功!" << endl;
system("pause");
system("cls");
}
}