一、项目概述
编写一个有添加、删除、修改、显示、排序、查找功能的职工管理系统,对一些职工的信息进行处理,保存到文本文件中,便于后续使用。
二、创建项目
在本篇文章中我们使用vs2022版本编写程序。(为了使我们的代码结构严谨、减少冗余、便于修改我们分不同的头文件和不同的代码实现部分来写)。
三、代码实现
基础知识:在编写此系统时我们需要c++的大部分基础知识,包括(类的封装、继承、多态,还需要我们对qsort函数有一定的了解)。
项目总览:
在本次管理系统中我们需要编写三类职工(普通员工,经理,老板),我们构造三个类,并使用继承等一些类中的知识来对三个类进行封装。同时我们还需要有一个职工管理的类来对各种职工和各种构造函数进行实现。
我们需要写一个总体的代码的区域,记为“职工管理系统.cpp”在该代码区中实现对构造的各种函数的调用。
代码部分
我们首先创建“职工管理系统.cpp”文件和职工管理文件“workermanage.h”和“workermanage.cpp”
1.抽象职工管理类
在创建完职工管理文件之后我们创建一个职工管理类,负责宏观调控我们所有使用的函数和类。
class workmanager
{
public:
};
2.编写菜单函数
我们在职工管理类的头文件中声明一个菜单显示的函数,并在职工管理类的实现文件中对该函数进行实现。
接下来我们对菜单函数进行实现
void workermanage::showmenu()
{
cout << "**************************" << endl;
cout << "**************************" << endl;
cout << "**************************" << endl;
cout << "*******1.add、2.del*******" << endl;
cout << "*******3.show、4.mod*******" << endl;
cout << "*******5.sort、6.search*******" << endl;
cout << "*******7.clean、8.exit*******" << endl;
cout << "**************************" << endl;
cout << "**************************" << endl;
cout << "**************************" << endl;
}
在职工管理系统中我们使用一个test函数对所编写的函数进行测试。
在进行职工管理系统的实现时,我们先创建一个职工管理类,并调用其中的菜单显示函数。
我们使用一个死循环,确保我们可以在执行完一次操作之后可以继续进行其他操作。
3.完善职工管理系统的选项。
承接上文,接下来我们使用一个Switch-case函数对选项进行编写。在case的选项中我们使用枚举常量来代替数字。
while (ret)
{
w1.showmenu();
cout << "请做出你的选择" << endl;
int select = 0;
cin >> select;
switch (select)
{
case add:
break;
case del:
break;
case show:
break;
case mod:
break;
case search:
break;
case sort:
break;
case clean:
break;
case exit:
break;
default:
break;
}
}
4.对三种职工类进行抽象
思路:我们先写一个工人的基类,再使用继承,纯虚函数等技巧来实现对三种职工类的具体实现,在实现三种职工类的时候我们编写三个文件分别对应普通员工,经理,老板三类人。
接下来我们对工人这个基类的内容进行编写,以公共权限的方式要求类内要有工人的职工编号,工人的工作岗位,工人的姓名。同时我们在工人的基类内写两个纯虚函数,分别是展示信息和展示部门名称。
class worker
{
public:
virtual void showinfo() = 0;
virtual string getdeptname() = 0;
int m_id;
string m_name;
int deptnum;
};
紧接着我们对三种类型的职工进行编写,我们把三种类型的职工分三个文件来编写,这样条理清晰,也便于我们日后的修改工作。
对一系列的头文件引用完之后,我们使用公共继承的方式来继承上文中提到的基类。 (在.h文件中实现下面的两步)
#include"workermanage.h"
#include"worker.h"
#include<iostream>
class employee :public worker
{
};
class employee :public worker
{
public:
employee(int id, string name, int deptid);
void showinfo();
string getdeptname();
};
在员工类中,我们写一个有参构造函数,用来传入员工的信息,同时继承的一个关键点就是子类重要重写父类中的纯虚函数。
在.cpp文件中对具体的函数进行实现。
employee::employee(int id,string name,int deptid)
{
this->m_id = id;
this->m_name = name;
this->deptnum = deptid;
}
void employee::showinfo()
{
cout << this->m_id << endl;
cout << this->m_name << endl;
cout << this->deptnum << endl;
cout << "完成经理交给的工作" << endl;
}
string employee::getdeptname()
{
return "员工";
}
在cpp文件中包含头文件之后对employee类中的函数具体实现,对于经理类和老板类的实现基本一致,我们这里不再过度赘述,只提供代码供大家参考。
class manager :public worker
{
public:
manager(int id, string name, int deptid);
void showinfo();
string getdeptname();
};
5.保存函数实现
我们要把系统中的内容保存到文件中就需要我们实现一个保存函数,在c++中对文件的保存主要以ofstream函数为主。我们在职工管理基类中声明一个保存函数,并在职工管理.cpp文件中予以实现。
#include<fstream>
void workmanager::save()
{
ofstream ofs;
//规定文件打开的路径和打开的方式
ofs.open("text.txt", ios::out|ios::binary);
//遍历数组中的元素,使其都保存到文件中
for (int i = 0;i < this->m_capacity;i++)
{
ofs << this->m_worker[i]->m_id << endl;
ofs << this->m_worker[i]->m_name << endl;
ofs << this->m_worker[i]->deptnum << endl;
}
//关闭文件
ofs.close();
}
6.检查是否重复函数
因为防止用户在使用系统是对一个编号进行重复添加我们在workermanage类中声明一个检查函数,防止职工编号的重复出现
在cpp文件中实现对if_init函数的实现
int workermanage::if_init(int num)
{
for (int i = 0;i < this->m_capacity;i++)
//遍历数组中的元素,拿输入的职工编号和数组中存放的职工编号比较
{
if (this->worker[i]->m_id == num)
return i;
//如果有重复的返回职工所在的数组位置
//如果没有重复的返回-1
else
return -1;
}
}
7.类内元素的初始化
我们在workermanage的默认构造函数中对workermanage中的元素进行初始化赋值。
我们在workermanage基类中加入一个布尔数据类型,判断文件是否为空,便于我们后续的使用和操作。
workermanage::workermanage()
{
//初始化操作
ifstream ifs;
ifs.open("text.txt", ios::in);
//文件打开失败
if (!ifs.is_open())
{
cout << "文件不存在" << endl;
this->m_capacity = 0;
this->worker = NULL;
this->fileisempty = true;
}
//接下来是一种在c++中判断文件是否为空的办法,即文件存在,但是文件中没有内容
char ch;
ifs >> ch;//我们把文件中的第一个字符读到一个字符变量中。
if (ifs.eof())//判断读取到的第一个字符是不是'\0'即结束字符
{
cout << "文件为空" << endl;
this->m_capacity = 0;
this->worker = NULL;
this->fileisempty = true;
}
//如果打开成功,我们需要统计现在的文件中的职工个数,并把原本就有的职工进行分类存储
int id;
string name;
int deptnum;
int num = 0;//记录当前职工的个数
int index=0;//记录当前存储到哪个职工
if (ifs >> id && ifs >> name && ifs >> deptnum)//把文件中的内容写到暂存变量中,通过if函数来判断是否读取到有关的数据
{
num++;
class worker* worker = NULL;
//找到对应职工编号的职工,并对其进行归类
if (deptnum == 1)
worker = new employee(id, name, deptnum);
else if (deptnum == 2)
worker = new manager(id, name, deptnum);
else if (deptnum == 3)
worker = new boss(id, name, deptnum);
this->worker[index] = worker;
index++;
}
ifs.close();
//修改初始参数的值
this->m_capacity = num;
this->fileisempty = false;
this->worker = new class worker*[this->m_capacity];
}
8.添加职工
通过上文的叙述我们已经基本实现了职工管理系统的总体框架,接下来需要我们编写各类的函数。
职工添加函数
因为我们使用了继承的方式来编写三个职工类,而继承在调用的时候需要父类的指针指向子类,所以我们在职工管理类中添加工人指针数组,通过工人指针数组,对员工的信息进行统一的管理。
这里需要我们注意的就是这个指针数组,因为数组中存放的是指针,所以我们使用二级指针来维护这个指针数组。,再在职工管理类中添加一个参数用来记录当前系统中的职工数量。
#pragma once
#include<iostream>
#include"worker.h"
#include"employee.h"
#include"boss.h"
#include"manager.h"
using namespace std;
enum
{
add=1,
del,
show,
mod,
sort,
search,
clean,
exit_m
};
class workermanage
{
public:
void showmenu();
class worker** worker;
int m_capacity;
};
接下来我们在职工管理的cpp文件中实现添加函数。
在代码段中已经为大家进行了代码的详细讲解。不再进行赘述。
void workermanage::addworker()
{
int num;//记录要新增的职工个数
cout << "请输入要新增的职工数" << endl;
cin >> num;
if (num > 0)
{
int new_size = this->m_capacity + num;//修改当前的系统中职工的总个数
class worker** new_space = new class worker * [new_size];//修改职工管理指针数组的容量
//如果原来的系统中已经有职工了,我们需要把原来的职工信息保存到新的职工管理数组中
if (this->worker != NULL)
{
for (int i = 0;i < this->m_capacity;i++)
{
new_space[i] = this->worker[i];
}
}
//职工添加
for (int i = 0;i < num;i++)
{
int id;
string name;
int deptnum;
//添加三个变量用来记录职工的基本信息
cout << "请输入职工的职工号" << endl;
cin >> id;
if (this->if_init(id))
{
cout << "该职工编号已经存在" << endl;
}
cout << "请输入职工的姓名" << endl;
cin >> name;
cout << "请输入职工的部门编号" << endl;
cout << "1.普通员工" << endl;
cout << "2.经理" << endl;
cout << "3.老板" << endl;
cin >> deptnum;
class worker* worker = NULL;
//创建父类的指针,用来接受子类的对象。通过子类中的构造函数对子类中的信息进行初始化赋值。
switch (deptnum)
{
case 1:
worker = new employee(id, name, 1);
break;
case 2:
worker = new manager(id, name, 2);
break;
case 3:
worker = new boss(id, name, 3);
break;
default:
cout << "输入错误" << endl;
break;
}
//将创建的内容保存到指针数组中,进行以后的操作。
new_space[this->m_capacity + i] = worker;
}
//释放原有的空间
delete[]this->worker;
this->worker = new_space;
this->m_capacity = new_size;
cout << "添加成功" << endl;
}
system("pause");
system("cls");
}
下面是测试效果(因后续我们还要对添加职工的功能进行修改,此处只是暂时的一个职工添加的实现)
9.显示职工信息
在.h文件的职工管理类中声明显示函数,在cpp文件中实现显示函数
void workermanage::showworker()
{
if (this->fileisempty)
{
cout << "文件不存在或者文件打开失败" << endl;
}
else
{
for (int i = 0;i < this->m_capacity;i++)
{
this->worker[i]->showinfo();
//调用职工类中的信息显示函数
}
}
system("pause");
system("cls");
}
10.删除职工信息
在.h文件中声明一个删除函数,在.cpp文件对该函数进行实现
在注释中已经对内容进行了说明。
void workermanage::delworker()
{
if (this->fileisempty)
{
cout << "文件为空或者文件不存在" << endl;
}
else
{
cout << "请输入要删除的职工号" << endl;
int id = 0;
cin >> id;
if (int ret=this->if_init(id))//通过我们以前实现的判断函数来判断是否存在该职工号,如果存在则使用ret接受
{
for (int i = ret;i < this->m_capacity;i++)
{
//我们这里所说的删除实际上就是把该职工之后的所有职工信息向前移动,覆盖掉原来的信息
this->worker[i] = this->worker[i + 1];
this->m_capacity--;//删除职工之后改变职工数量。
this->save();//对现在的内容进行保存
cout << "删除成功" << endl;
}
}
else
{
cout << "找不到该员工" << endl;
}
}
}
11.查找职工
查找职工通过我们通过两种方式来实现,按照姓名查找和按照职工编号查找
我们先在职工管理的头文件中声明查找职工的函数,在.cpp文件中予以实现
void workermanage::searchmanager()
{
if (this->fileisempty)
{
//通过在职工管理类中的判断函数来判断文件是否成功打开
cout << "文件为空或者文件不存在" << endl;
return;
}
else
{
cout << "请输入查找方式" << endl;
cout << "1.按照职工编号查找" << endl;
cout << "2.按照职工姓名查找" << endl;
int select = 0;
cin >> select;
//这里可以实现的方式有多种,此处我们选择使用Switch-case语句实现
switch (select)
{
case 1:
{
cout << "请输入要查找的职工编号" << endl;
int num = 0;
cin >> num;
//通过我们上文中实现过的判断系统中湿粉扑存在着个编号的函数来判断是否存在这个职工的编号
if (int ret = this->if_init(num))
{
cout << "查找成功" << endl;
//调用我们在职工管理类中实现的信息显示函数来展示职工的信息
this->worker[ret]->showinfo();
}
}
break;
case 2:
{
cout << "请输入要查找的职工的姓名" << endl;
string name;
cin >> name;
int i;
//这里我们也可以通过实现一个姓名判断函数来判断姓名是否存在
//此处我们通过一个遍历系统中信息的方式来判断姓名是否存在
for (i = 0;i < this->m_capacity;i++)
{
if (this->worker[i]->m_name == name)
{
cout << "查找成功" << endl;
this->worker[i]->showinfo();
break;
}
}
if (i == this->m_capacity)
{
cout << "查找失败,查无此人" << endl;
}
}
break;
default:
break;
}
}
12.清空职工信息
当我们需要对文件中已存在的职工信息进行格式化的时候我们使用职工清理函数,对所有的职工信息进行删除
我们在职工管理的头文件中对函数进行声明,在.cpp文件中实现
void workermanage::cleanmanager()
{
//判断用户是否要格式化职工信息
cout << "确定要格式化你的职工信息吗" << endl;
cout << "1.确定" << endl;
cout << "2.不,我不确定" << endl;
int select = 0;
cin >> select;
if (select == 1)
return;
if (select == 2)
{
//遍历系统中的每一个职工并删除
for (int i = 0;i < this->m_capacity;i++)
{
delete this->worker[i];
this->worker[i] = NULL;
}
//删除整个数组,修改职工管理类中的总人数,把职工管理类中的文件置空。
delete[] this->worker;
this->m_capacity = 0;
this->fileisempty = true;
cout << "清空成功" << endl;
system("pause");
system("cls");
}
else
{
cout << "输入错误,重新输入" << endl;
}
}
13.修改职工信息
当我们需要对职工的信息进行修改的时候我们调用修改职工信息函数,
在职工管理类的头文件中声明,在.cpp文件中实现。
void workermanage::modmanager()
{
if (this->fileisempty)
{
cout << "文件为空或者文件不存在" << endl;
return;
}
else
{
cout << "请输入要修改的职工的编号" << endl;
int num = 0;
cin >> num;
if (int ret = this->if_init(num))
{
//删除原来职工的信息
delete this->worker[ret];
//此处同添加职工基本相同我们不再赘述
int newid;
string newname;
int newdeptid;
cout << "成功查找到编号为" << ret << "的员工" << endl;
cout << "请输入新的职工号" << endl;
cin >> newid;
cout << "请输入名字" << endl;
cin >> newname;
cout << "请输入新的岗位" << endl;
cout << "1.普通职工" << endl;
cout << "2.经理" << endl;
cout << "3.老板" << endl;
cin >> newdeptid;
class worker* woker = NULL;
switch (newdeptid)
{
//父类指针指向子类对象
case 1:
woker = new employee(newid, newname, newdeptid);
break;
case 2:
woker = new manager(newid, newname, newdeptid);
break;
case 3:
woker = new boss(newid, newname, newdeptid);
break;
default:
break;
}
this->worker[ret] = woker;
cout << "修改成功!" << endl;
//对修改的内容进行保存
this->save();
}
else
{
cout << "查找失败,该职工不存在" << endl;
}
}
//程序暂停
system("pause");
//清屏
//按任意键清屏
system("cls");
}
14.对职工进行排序
当我们添加了一定量的职工之后,我们需要对职工进行排序,使我们的整个系统条理有序。
在职工管理类的头文件中声明,在.cpp文件中实现。
在排序时可以使用的方法有很多,冒泡排序,选择排序等,此处我们直接使用qsort函数来对职工的内容进行排序。
首先我们回顾一下qsort函数
https://mp.csdn.net/mp_blog/creation/editor/128543580在这篇文章中我对qsort函数进行了详细的说明,大家如果有不明白的地方可以看看。
int cmp_1(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int cmp_2(const void* e1, const void* e2)
{
return *(int*)e2 - *(int*)e1;
}
void workermanage::sortmanager()
{
if (this->fileisempty)
{
cout << "文件为空或者文件不存在" << endl;
return;
}
else
{
cout << "请输入排序的方式" << endl;
cout << "1.按照职工编号升序" << endl;
cout << "2.按照职工编号降序" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
//qsort(要排序的数组,排序数组中的元素个数,每个元素的大小,插入自定义的比较函数
qsort(this->worker, this->m_capacity, sizeof(this->worker[1]), cmp_1);
for (int i = 0;i < this->m_capacity;i++)
{
this->worker[i]->showinfo();
}
cout << "排序完成" << endl;
}
if (select == 2)
{
qsort(this->worker, this->m_capacity, sizeof(this->worker[1]), cmp_2);
for (int i = 0;i < this->m_capacity;i++)
{
this->worker[i]->showinfo();
}
cout << "排序完成" << endl;
}
}
}
15.退出系统
退出系统的代码较为简单,我们直接在头文件中实现,.cpp中实现即可
void workmanager::exitsystem()
{
cout << "welcome next use" << endl;
system("pause");
exit(0);
}
四.总结
职工管理系统是我们在学习c++入门阶段很好的一个项目,他考察了c++中的各种基础的知识,适合初学者自己实现。
文章如果有不妥,错误或者有更好的实现方法欢迎大家及时指出,欢迎大家的批评指正。