ref:https://github.com/Blitzer207/C-Resource/blob/master/%E7%AC%AC4%E9%98%B6%E6%AE%B5%E5%AE%9E%E6%88%98-%E5%9F%BA%E4%BA%8E%E5%A4%9A%E6%80%81%E7%9A%84%E4%BC%81%E4%B8%9A%E8%81%8C%E5%B7%A5%E7%B3%BB%E7%BB%9F/%E8%AE%B2%E4%B9%89/%E8%81%8C%E5%B7%A5%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F.md
主要是为了联系C++的基础知识。
多态是很好理解的,这里主要是实现。
c++关于文件的操作部分复习,看这里:
ref:https://blog.csdn.net/weixin_73768906/article/details/131023454
能看懂,写出下面的代码,是学习这篇代码的前置知识。
#include
#include
#define FILENAME "./1.txt"
using namespace std;
struct Student{
int id;
string name;
int score;
};
int main(){
// ofstream 文件写操作 内存写入存储设备
// ifstream 文件读操作,存储设备读区到内存中
// fstream //读写操作,对打开的文件可进行读写操作
ifstream input(FILENAME);
//
if(!input.is_open()) exit(-1);
int a,c;
string b;
while(input >> a >> b >> c){
cout << "a = " << a << ",b=" << b << ",c=" << c << endl;
// 这里就能写自己的业务了
}
ofstream output(FILENAME,ios::out);
a = 1; c = 2;
b = "盖建明";
Student stu1 = {1,"建明盖",2};
if (!output.is_open()) exit(-1);
output << stu1.id <<"\t"<< stu1.name <<"\t"<< stu1.score << "\n";
Student * stu2 = &stu1;
Student **arr[10];
arr[0] = &stu2;
cout << "---" << (*arr[0])->id << endl;
cout << "hello world!" << endl;
return 1;
}
公司中职工分为三类:普通员工、经理、老板,显示信息时,需要显示职工编号、职工姓名、职工岗位、以及职责
普通员工职责:完成经理交给的任务
经理职责:完成老板交给的任务,并下发任务给员工
老板职责:管理公司所有事务
管理系统中需要实现的功能如下:
1.退出管理程序:退出当前管理系统
2.增加职工信息:实现批量添加职工功能,将信息录入到文件中,职工信息为:职工编号、姓名、部门编号
3.显示职工信息:显示公司内部所有职工的信息
4.删除离职职工:按照编号删除指定的职工
5.修改职工信息:按照编号修改职工个人信息
6.查找职工信息:按照职工的编号或者职工的姓名进行查找相关的人员信息
7.按照编号排序:按照职工编号,进行排序,排序规则由用户指定
8.清空所有文档:清空文件中记录的所有职工信息 (清空前需要再次确认,防止误删)
一共8个菜单。
主业务的方法:
因为是多态所以需要一个基类 Worker, 三个角色【Employee、Manager、Boss】分别继承Worker,实现自己的业务。
Worker 有三个属性:工号 id,姓名 name, 部门id dept_id
包含几个虚函数,因为要多态所以必须虚函数了。
virtual void showDeptName() =0
virtual void showInfo() = 0
worker的地址存入到WorkerManager类的一个数组中,维护一个worker * 类型的数组,每个worker 是一个实体员工(员工、经理或者老板)。
这里三类的声明和定义没有分离,偷个懒!
#include
using namespace std;
class Worker{
public:
Worker(int,string,int);
virtual void showInfo()=0;
virtual void showDeptName()=0;
int id;
string name;
int dept_id;
};
Worker::Worker(int m_id,string nam,int dep_id):id(m_id),name(nam),dept_id(dep_id){};
class Employee:public Worker{
public:
Employee(int,string,int);
void showInfo();
void showDeptName();
};
Employee::Employee(int m_id,string nam,int dep_id):Worker(m_id,nam,dep_id) {};
void Employee::showInfo(){
cout << "工号:" << id << ",姓名:" << name <<",部门id:" << dept_id << ",责任:完成任务,当牛马"<< endl;
}
void Employee::showDeptName(){
cout << "员工部门" << endl;
}
class Manager:public Worker{
public:
Manager(int,string,int);
void showInfo();
void showDeptName();
};
Manager::Manager(int m_id,string nam,int dep_id):Worker(m_id,nam,dep_id) {};
void Manager::showInfo(){
cout << "工号:" << id << ",姓名:" << name <<",部门id:" << dept_id << ",责任:完成boos的任务,本质也是当牛马"<< endl;
}
void Manager::showDeptName(){
cout << "经理部门" << endl;
}
class Boss:public Worker{
public:
Boss(int,string,int);
void showInfo();
void showDeptName();
};
Boss::Boss(int m_id,string nam,int dep_id):Worker(m_id,nam,dep_id) {};
void Boss::showInfo(){
cout << "工号:" << id << ",姓名:" << name <<",部门id:" << dept_id << ",责任:做老板,负责公司的整个运营!"<< endl;
}
void Boss::showDeptName(){
cout << "老板部门" << endl;
}
写个demo 测试一下:
#include
#include"worker.h"
using namespace std;
void test(){
Worker * worker = new Employee(1,"张三",1);
worker->showInfo();
worker->showDeptName();
delete worker;
worker = new Manager(2,"李四",2);
worker->showInfo();
worker->showDeptName();
delete worker;
worker = new Boss(3,"王五",3);
worker->showInfo();
worker->showDeptName();
delete worker;
}
int main(){
test();
return 1;
}
输出:
D:\code\cpp_project\C++hm> cmd /C "c:\Users\HP\.vscode\extensions\ms-vscode.cpptools-1.17.5-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-wia31uxc.psy --stdout=Microsoft-MIEngine-Out-vg4g05ne.nzi --stderr=Microsoft-MIEngine-Error-akxk3cuj.vxv --pid=Microsoft-MIEngine-Pid-ae4yr2df.5at --dbgExe=D:\programfile\mingw64\bin\gdb.exe --interpreter=mi "
工号:1,姓名:张三,部门id:1,责任:完成任务,当牛马
员工部门
工号:2,姓名:李四,部门id:2,责任:完成boos的任务,本质也是当牛马
经理部门
工号:3,姓名:王五,部门id:3,责任:做老板,负责公司的整个运营!
老板部门
因为这个WorkerManager 只能将员工列表维护在内存中,重启服务后数据就丢了,所以需要一个文件来存实例员工属性list. 这一部分要考文件来维护。
workermanager.h
所有的精髓都在这个文件下,它实现了所有的业务逻辑。我没搞懂的是,git库的写作方式似乎回避了empArr[1000]的这种写法。原因未知,还没搞明白,todo.
#pragma once
#define FILENAME "empList.txt"
#include
#include"worker.h"
#include
using namespace std;
class WorkerManager{
public:
WorkerManager();
~WorkerManager();
bool fileExist = false;
int empCout; // 员工数量
Worker * empArr[1000]; // 用数组的方式来做 这种方式实现不好 @todo
void initEmp(); // 初始化人员
void showMenu(); // 显示菜单
void exitSystem(); // 退出系统
void addEmp(); // 添加员工
void showEmp(); // 显示职工信息
void delEmp(); // 删除离职员工
void modEmp(); // 修改职工信息
int findEmp(int mid); // 根据职工的编号或者姓名进行查找人员,返回pos
void findEmpAndShow(); // 查找并显示员工
void sortEmp(); // 按照职工编号,进行排序,排序规则由用户指定
void clearDoc(); // 清空文件中记录的所有职工信息 (清空前需要再次确认,防止误删)
void save();
};
void WorkerManager::sortEmp(){
if(empCout == 0){
cout << "文件记录不存在或为空!" << endl;
return;
}else{
cout << "请选择排序方式:"<< endl;
cout << "1.按职工号升序"<< endl;
cout << "2.按职工号降序"<< endl;
int select = 0;
cin >> select;
for (int i = 0; i < empCout; i++)
{
int minOrMax = i;
for (int j = i+1; j < empCout; j++)
{
if(select==1){ // 升序
if(empArr[minOrMax]->id > empArr[j]->id){
minOrMax = j;
}
}else{
if (empArr[minOrMax]->id < empArr[j]->id)
{
minOrMax = j;
}
}
}
if(i!=minOrMax){
Worker * temp = empArr[i];
empArr[i] = empArr[minOrMax];
empArr[minOrMax] = temp;
}
}
cout << "排序完成,排序后结果为:" << endl;
save();
showEmp();
}
}
void WorkerManager::clearDoc(){
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(empArr!=NULL){
for (int i = 0; i < empCout; i++)
{
delete empArr[i];
}
empCout = 0;
}
cout << "清空成功!" << endl;
}
}
void WorkerManager::findEmpAndShow(){
cout << "请输入要查看的id" << endl;
int m_id = -1;
cin >> m_id;
int pos = findEmp(m_id);
if (pos < -1){
cout << "查无此人" << endl;
return;
}
empArr[pos]->showInfo();
}
void WorkerManager::modEmp(){
cout << "请输入要删除的id" << endl;
int m_id = -1;
cin >> m_id;
int pos = findEmp(m_id);
if (pos < -1){
cout << "查无此人" << endl;
return;
}
cout << "当前人信息:" << endl;
empArr[pos]->showInfo();
cout << "请分别输入要id,name,depid:" << endl;
string nam;
int did;
cin >> m_id >> nam >> did;
Worker * worker = empArr[pos];
worker->dept_id = did;
worker->name = nam;
worker->id = m_id;
save();
}
int WorkerManager::findEmp(int mid){
int pos = -1;
for (size_t i = 0; i < empCout; i++)
{
if(empArr[i]->id == mid) {
pos = i;
break;
}
}
return pos;
}
void WorkerManager::delEmp(){
cout << "请输入要删除的id" << endl;
int m_id = -1;
cin >> m_id;
int pos = findEmp(m_id);
if (pos < -1){
cout << "查无此人" << endl;
return;
}
for ( int i = pos; i < empCout; i++)
{
empArr[i] = empArr[i+1];
}
empCout--;
save();
}
void WorkerManager::save(){
// 打开文件,没有则创建,有则情况重新写入
ofstream input_file(FILENAME,ios::out);
if(!input_file.is_open()){
cout << "打开文件错误:" << endl;
exit(-1);
}
for (int i = 0; i < empCout; i++)
{
input_file << empArr[i]->id << " " << empArr[i]->name << " " << empArr[i]->dept_id << "\n";
}
input_file.close();
}
void WorkerManager::addEmp(){
cout << "请分别输入工号,姓名和部门id";
int mid,did;
string nam;
cin >> mid >> nam >> did;
Worker * worker = nullptr;
switch (did)
{
case 1:
worker = new Employee(mid,nam,did);
break;
case 2:
worker = new Manager(mid,nam,did);
break;
case 3:
worker = new Boss(mid,nam,did);
break;
default:
break;
}
empArr[empCout] = worker;
empCout+=1;
// 保存在文本文件
save();
}
void WorkerManager::showEmp(){
for (size_t i = 0; i < empCout; i++)
{
empArr[i]->showInfo();
}
}
void WorkerManager::showMenu(){
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;
}
void WorkerManager::exitSystem(){
cout << "欢迎再来!" << endl;
exit(0);
}
void WorkerManager::initEmp(){
// 构造函数
// 先看文件是否存在
ifstream readfile(FILENAME,ios::in);
// 文件不存在
if(!readfile.is_open()) {
empCout = 0;
return;
}
// 文件存在
fileExist = true;
int mId, mDeptId;
string mName;
empCout = 0;
while(readfile>>mId>>mName>>mDeptId){
Worker* worker = nullptr;
switch (mDeptId)
{
case 1:
worker = new Employee(mId,mName,mDeptId);
empArr[empCout] = worker;
break;
case 2:
worker = new Manager(mId,mName,mDeptId);
empArr[empCout] = worker;
break;
case 3:
worker = new Boss(mId,mName,mDeptId);
empArr[empCout] = worker;
break;
default:
break;
}
empCout++;
}
}
WorkerManager::WorkerManager(){
initEmp();
}
WorkerManager::~WorkerManager(){
// 析构函数
}
值得注意的是,清空文件的时候用了 trunc的方式打开,很巧妙!
···
//打开模式 ios::trunc 如果存在删除文件并重新创建
ofstream ofs(FILENAME, ios::trunc);
ofs.close();
···
worker.h 包含三个lei
#pragma once
#include
using namespace std;
class Worker{
public:
Worker(int,string,int);
virtual void showInfo()=0;
virtual void showDeptName()=0;
int id;
string name;
int dept_id;
};
Worker::Worker(int m_id,string nam,int dep_id):id(m_id),name(nam),dept_id(dep_id){};
class Employee:public Worker{
public:
Employee(int,string,int);
void showInfo();
void showDeptName();
};
Employee::Employee(int m_id,string nam,int dep_id):Worker(m_id,nam,dep_id) {};
void Employee::showInfo(){
cout << "工号:" << id << ",姓名:" << name <<",部门id:" << dept_id << ",责任:完成任务,当牛马"<< endl;
}
void Employee::showDeptName(){
cout << "员工部门" << endl;
}
class Manager:public Worker{
public:
Manager(int,string,int);
void showInfo();
void showDeptName();
};
Manager::Manager(int m_id,string nam,int dep_id):Worker(m_id,nam,dep_id) {};
void Manager::showInfo(){
cout << "工号:" << id << ",姓名:" << name <<",部门id:" << dept_id << ",责任:完成boos的任务,本质也是当牛马"<< endl;
}
void Manager::showDeptName(){
cout << "经理部门" << endl;
}
class Boss:public Worker{
public:
Boss(int,string,int);
void showInfo();
void showDeptName();
};
Boss::Boss(int m_id,string nam,int dep_id):Worker(m_id,nam,dep_id) {};
void Boss::showInfo(){
cout << "工号:" << id << ",姓名:" << name <<",部门id:" << dept_id << ",责任:做老板,负责公司的整个运营!"<< endl;
}
void Boss::showDeptName(){
cout << "老板部门" << endl;
}
main.cpp 是入口文件
#include
#include"worker.h"
#include"workermanager.h"
using namespace std;
void test(){
Worker * worker = new Employee(1,"张三",1);
worker->showInfo();
worker->showDeptName();
// delete worker;
// worker = new Manager(2,"李四",2);
// worker.showInfo();
// worker.showDeptName();
// delete worker;
// worker = new Boss(3,"王五",3);
// worker.showInfo();
// worker.showDeptName();
// //new Worker *[this->m_EmpNum] 对这里的理解有问题
Worker ** workerArr;
// workerArr = new Worker *[10];
workerArr[0] = worker;
workerArr[0]->showInfo();
//workerArr[1].worker;
//workerArr[1].showInfo();
//delete worker;
}
void init_test(WorkerManager wm){
cout << "wm.empCout = " << wm.empCout << endl;
for (int i = 0; i < wm.empCout; i++)
{
(wm.empArr[i])->showDeptName();
(wm.empArr[i])->showInfo();
cout << "--------------" << endl;
}
}
int main(){
// test();
WorkerManager wm;
init_test(wm);
int choice = 0;
while (true){
switch (choice)
{
case 0: // 菜单
wm.showMenu();
break;
case 1: // 退出
wm.exitSystem();
case 2: // 加人
wm.addEmp();
break;
case 3: // 看全部
wm.showEmp();
break;
case 4: // 删除1个
wm.delEmp();
break;
case 5: // 编辑员工
wm.modEmp();
break;
case 6:
wm.findEmpAndShow();
break;
case 7:
wm.sortEmp();
break;
case 8:
wm.clearDoc();
break;
default:
break;
}
cout << "请输入菜单编号:" << endl;
cin >> choice;
}
return 1;
}
因为循环引用的问题,需要#pragma once 来化解!
另外,基于双指针的正序,逆序排序问题,解决的也很好。