🎁个人主页:工藤新一¹
🔍系列专栏:C++面向对象(类和对象篇)
🌟心中的天空之城,终会照亮我前方的路
🎉欢迎大家点赞👍评论📝收藏⭐文章
文章目录
C++ 项目 — 职工管理系统
一、项目日志
职工管理系统可以用来管理公司内所有员工的信息
本教程主要利用 C++ 来实现一个基于 多态 的职工管理系统
公司中职工分为三类:普通员工,经理、老板,显示信息时,需要显示职工编号、职工姓名、职工岗位、以及职责。
-
普通员工职责: 完成经理交给的任务
-
经理的职责: 完成老板交给的任务,并下发任务给员工
-
老板的职责: 管理公司所有的事务
管理系统中需要实现的功能如下:
-
**退出管理程序:**退出当前管理系统
-
**增加职工信息:**实现批量添加职工功能,将信息录入文件中,职工信息为职工编号、姓名、部门编号
-
显示职工信息, 显示公司内部所有职工的信息
-
删除离职职工: 按照编号删除指定的职工
-
修改职工信息: 按照编号修改职工的个人信息
-
查找职工信息: 按照职工的编号或者职工的姓名进行查找相关的人员信息
-
按照编号排序: 按照职工编号进行排序,排序规则由用户指定
-
清空所有的文档: 清空文件中记录所有职工的信息,清空前需要再次确认,防止误删。
其中联系各项功能的纽带:我们称之为接口
二、创建管理类
2.1功能描述
管理类负责功能如下:
- 与用户直接沟通的菜单页面
- 提供对职工进行增删改查操作的接口
- 与文件进行交互
2.2头文件实现
在WorkerManager.h
设计管理类
C++
#pragma once
#include<iostream>
using namespace std;
class WorkerManager
{
public:
//构造函数
WorkerManager() {}
//析构函数
~WorkerManager() {}
};
2.3源文件实现
在WorkerManager.cpp
将构造函数、析构函数补全
C++
#include"WorkerManager.h"
WorkerManager::WorkerManager(){}
WorkerManager::~WorkerManager(){}
至此职工管理类创建完毕。
三、菜单功能
- 功能描述:与用户沟通、交互的界面
3.1添加成员函数
在管理类WorkerManager.h
中增添成员函数 void Shou_Menu();
3.2菜单功能的实现
在管理类WorkerManager.cpp
中实现成员函数 Shou_Menu()
C++
void WorkerManager::Shou_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;
}
3.3测试菜单功能
在职工管理系统 SMSystem.cpp
中测试菜单功能
C++
#include"WorkerManager.h"
int main()
{
//实例化一个工作管理对象
WorkerManager wm;
wm.Shou_Menu();
return 0;
}
运行效果如图:
四、退出功能
4.1提供功能接口
在 main函数
中提供分支选择,提供功能接口
C++
int main()
{
//实例化一个工作管理对象
WorkerManager wm;
int choice = 0;//接收用户的选项
while (true)
{
//展示菜单
wm.Shou_Menu();
cout<<"请输入您的选择: " << endl;
cin >> choice;
//使用 switch语句 去承接(处理)用户不同地选择
switch (choice)
{
case 0://退出系统
break;
case 1://添加职工
break;
case 2://显示职工
break;
case 3://删除职工
break;
case 4://修改职工
break;
case 5://查找职工
break;
case 6://排序职工
break;
case 7://清空文件
break;
default:
system("cls");
break;
}
}
system("pause");
return 0;
}
4.2实现退出功能
在WorkerManager.h
提供退出系统的成员函数 void ExitSystem();
在WorkerManager.cpp
提供具体功能的实现
C++
void WorkerManager::ExitSystem()
{
cout << "欢迎下次使用" << endl;
system("pause");
exit(1);
}
4.3测试功能
在 main函数
分支为 0
的选项中,调用退出程序地接口
五、职工类(抽象类)
5.1创建职工抽象类
- 抽象基类(多态),在其他文件中被继承
职工的分类为:普通员工、经理、老板
将三种职工抽象到一个类(work)中,利用多态管理不同职工种类(利用多态,显示不同职工内容)
职工的属性为:职工编号,职工姓名,职工所在的部门编号
职工的行为:岗位职责信息描述,获取岗位名称
头文件夹下创建 Worker.h
并添加如下代码:
#pragma once
#include<iostream>
using namespace std;
#include<string>
//职工抽象类 - 抽象基类,在其他文件中被继承
class Worker
{
public:
//显示个人信息 - 在抽象类中不做任何实现
virtual void ShowInfo() = 0;//直接在函数体内 cout 输出信息
//获取岗位名称 - 在抽象类中不做任何实现
virtual string GetDepName() = 0;//返回岗位名称(字符串)
int m_id;//职工编号
string m_Name;//职工姓名
int m_DeptId;//职工所处部门的编号
};
5.2创建普通职工类
- 普通员工类继承职工抽象类,并重写父类中的纯虚函数(子类重写父类中的纯虚函数)
在**头文件 **和 源文件中分别加入 Employee.h
,Employee.cpp
在Employee.h
头文件中:
#pragma once
#include"Worker.h"
//继承抽象类 Worker
class Employee : public Worker
{
public:
//构造函数 - 初始化成员变量
Employee(int id, string name, int did);
//子类中重写父类中的纯虚函数(virtual 在子类中可删可不删)
virtual void ShowInfo();
//子类中重写父类中的纯虚函数(virtual 在子类中可删可不删)
virtual string GetDepName();
};
在Employee.cpp
头文件中:
#pragma once
#include"Employee.h"
Employee::Employee(int id, string name, int did)
{
m_id = id;
m_Name = name;
m_DeptId = did;
}
void Employee::ShowInfo()
{
cout << "职工编号:" << this->m_id
<< "\t 职工姓名:" << this->m_Name
<< "\t 岗位职责:完成经理交给的任务。" << endl;
}
string Employee::GetDepName()
{
//强制转换为 C++ 字符串
return string("员工");
}
5.3创建经理类
同 员工类 类似,经理类继承职工抽象类,并重写父类中的纯虚函数
在**头文件 **和 源文件中分别加入 Manager.h
,Manager.cpp
Manager.h
中代码如下:
#pragma once
#include"Worker.h"
class Manager : public Worker
{
public:
Manager(int id, string name, int did);
virtual void ShowInfo();
virtual string GetDepName();
};
Manager.cpp
中代码如下:
#include"MAnager.h"
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 岗位职责:完成老板交给的任务,并下发任务给员工。" << endl;
}
string Manager::GetDepName()
{
//强制转换为 C++ 字符串
return string("经理");
}
5.4创建 Boss 类
Boss类继承职工抽象类,并重写父类中的纯虚函数
在**头文件 **和 源文件中分别加入 Boss.h
,Boss.cpp
Boss.h
#pragma once
#include"Worker.h"
class Boss : public Worker
{
Boss(int id, string name, int did);
virtual void ShowInfo() = 0;
virtual string GetDeptName() = 0;
};
Boss.cpp
#include"Boss.h"
Boss::Boss(int id, string name, int did)
{
m_id = id;
m_Name = name;
m_DeptId = did;
}
void Boss::ShowInfo()
{
cout << "职工编号:" << this->m_id
<< "\t 职工姓名:" << this->m_Name
<< "\t 岗位职责:发任务给所有职工" << endl;
}
string Boss::GetDeptName()
{
//强制转换为 C++ 字符串
return string("Boss");
}
5.5测试多态
在职工管理系统 SMSytem.cpp 中添加测试函数,并且运行能够产生多态
#include"WorkerManager.h"
#include"Worker.h"
#include"Manager.h"
#include"Employee.h"
#include"Boss.h"
void test()
{
//创建抽象类指针(父类指针/引用)指向子类对象
Worker* worker1 = NULL;
worker1 = new Boss(1, "啦啦啦", 1);
worker1->ShowInfo();
delete worker1;
//创建抽象类指针(父类指针/引用)指向子类对象
Worker* worker2 = NULL;
worker2 = new Manager(2, "呦呦呦", 2);
worker2->ShowInfo();
delete worker2;
//创建抽象类指针(父类指针/引用)指向子类对象
Worker* worker3 = NULL;
worker3 = new Employee(3, "Gont", 3);
worker3->ShowInfo();
delete worker3;
}
int main(){
//测试代码
test();
system("pause");
return 0;
}
六、添加职工
- 功能描述:批量添加职工,并且存放到文件中
6.1功能分析
分析:
用户在批量创建时,可能会创建不同种类的职工
如果想存放不同种类的职工,可以将所有职工的指针维护到一个数组中(指针数组)
其中,指针数组必定是一个不定长度的数组,因此可以将数组开辟到堆区,使用 Worker**
的指针维护
6.2功能实现
在 WorkerManager.h
头文件中,添加成员属性:
C++
//记录文件中的人员数量
int m_EmpNum;
//员工数组的指针 - 维护在堆区开辟的子类对象
Worker** m_EmpArr;
在 **WorkerManager ** 构造函数中初始化属性
C++
WorkerManager::WorkerManager()
{
//初始化人数
this->m_EmpNum = 0;
//初始化数组
this->m_EmpArr = NULL;
}
在 WorkerManager.h
头文件中添加成员函数
C++
//增加职工
void Add_Emp();
WorkerManager.cpp
a.在堆区开辟大小为 newSize 的新空间,并使用 Worker** 指针维护这段空间
C++
//添加 - 计算新添加后空间的大小(原来人数 + 添加人数)
int newSize = this->m_EmpNum + addNum;
//在堆区开辟大小为 newSize 的新空间,并使用 Worker** 指针维护这段空间
Worker** newSpace = new Worker* [newSize];
b.拷贝旧数据、存储新数据、释放旧空间
C++
// 将原来空间下的数据, 拷贝到新空间
if (this->m_EmpArr != NULL)
{
for (int i = 0; i < this->m_EmpNum; ++i)
{
newSpace[i] = this->m_EmpArr[i];
}
}
c.父类指针指向子类对象
C++
//根据用户不同的创建,我们需要 new 出不同的对象 - 父类指针指向子类对象
Worker* worker = NULL;
switch (DeSelect)
{
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:
break;
}
//将创建的职工指针,存储到数组中 - 以 m_EmpNum 位置为起始点,开始存放 worker 指针
newSpace[this->m_EmpNum + i] = worker;
//释放原有的空间(释放旧空间)
delete[] this->m_EmpArr;
d.更新职工数组指针的指向 + 更新员工人数
C++
//将新空间的地址赋值给成员(指针)变量 - 更改员工数组指针的指向
this->m_EmpArr = newSpace;
//更新员工人数
this->m_EmpNum = newSize;
e.调用析构函数,回收、释放堆区数据
C++
//析构函数中释放堆区数据
WorkerManager::~WorkerManager()
{
if (this->m_EmpArr != NULL)
{
delete[] this->m_EmpArr;
this->m_EmpArr = NULL;
}
}
//添加职工
void WorkerManager::Add_Emp()
{
cout<< "请输入添加职工数量: " << endl;
int addNum = 0;cin >> addNum;
if (addNum > 0)
{
//添加 - 计算新添加后空间的大小(原来人数 + 添加人数)
int newSize = this->m_EmpNum + addNum;
//在堆区开辟大小为 newSize 的新空间,并使用 Worker** 指针维护这段空间
Worker** newSpace = new Worker* [newSize];
// 将原来空间下的数据, 拷贝到新空间
if (this->m_EmpArr != NULL)
{
for (int i = 0; i < this->m_EmpNum; ++i)
{
newSpace[i] = this->m_EmpArr[i];
}
}
/*
copy(this->m_EmpArr, this->m_EmpArr + this->m_EmpNum, newSpace);
模板函数 copy - 复制数组中的元素
this->m_EmpArr:这是源数组的起始指针,指向要复制的数组的第一个元素。
this->m_EmpArr + this->m_EmpNum:这是源数组的结束指针,指向要复制的数组的最后一个元素之后的位置。m_EmpNum 是数组中的元素数量。
newSpace:这是目标数组的起始指针,指向新分配的数组的第一个元素。
std::copy 函数会从 m_EmpArr 开始,复制 m_EmpNum 个元素到 newSpace 中。
它会逐个复制元素,直到达到 m_EmpArr + m_EmpNum。
示例
假设 m_EmpArr 是一个包含三个元素的数组:
m_EmpArr: [Worker1, Worker2, Worker3]
newSpace 是一个新分配的数组,大小为 newSize:
newSpace: [nullptr, nullptr, nullptr, ...]
执行 std::copy 后,newSpace 将包含从 m_EmpArr 复制的元素:
newSpace: [Worker1, Worker2, Worker3, ...]
*/
//批量添加新数据
for (int i = 0; i < addNum; i++)
{
int id;//职工编号
string name;//职工姓名
int DeSelect;//部门选择
cout << "请输入第 " << i + 1 << " 位员工的职工编号:" << endl;
cin >> id;
cout << "请输入第 " << i + 1 << " 位员工的姓名:" << endl;
cin >> name;
cout << "请选择该职工岗位:" << endl;
cout << " 1、普通职工 " << endl;
cout << " 2、经理 " << endl;
cout << " 3、Boss " << endl;
cin >> DeSelect;
//根据用户不同的创建,我们需要 new 出不同的对象 - 父类指针指向子类对象
Worker* worker = NULL;
switch (DeSelect)
{
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:
break;
}
//将创建的职工指针,存储到数组中 - 以 m_EmpNum 位置为起始点,开始存放 worker 指针
newSpace[this->m_EmpNum + i] = worker;
}
//释放原有的空间(释放旧空间)
delete[] this->m_EmpArr;
//将新空间的地址赋值给成员(指针)变量 - 更改员工数组指针的指向
this->m_EmpArr = newSpace;
//更新员工人数
this->m_EmpNum = newSize;
//提示添加成功
cout << "成功添加" << addNum << "位职工" << endl;
}
else
{
cout << "输入数据有误" << endl;
}
//按任意键后,清屏回到上级目录
system("pause");//等待用户输入任意键
system("cls");//清屏
}
//析构函数中释放堆区数据
WorkerManager::~WorkerManager()
{
if (this->m_EmpArr != NULL)
{
delete[] this->m_EmpArr;
this->m_EmpArr = NULL;
}
}
🌟 各位看官好,我是工藤新一¹呀~
🌈 愿各位心中所想,终有所致!