【C++学习系列】3.基于多态的企业职工系统,手把手从0到1


前言

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


1.前置知识

能看懂,写出下面的代码,是学习这篇代码的前置知识。

#include<iostream>
#include<fstream>
#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;
}

2.开始写代码

2.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 是一个实体员工(员工、经理或者老板)。
这里三类的声明和定义没有分离,偷个懒!

扫描二维码关注公众号,回复: 16963535 查看本文章
#include<iostream>
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<iostream>
#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. 这一部分要考文件来维护。

2.2 代码骨架

workermanager.h
所有的精髓都在这个文件下,它实现了所有的业务逻辑。我没搞懂的是,git库的写作方式似乎回避了empArr[1000]的这种写法。原因未知,还没搞明白,todo.

#pragma once
#define FILENAME "empList.txt"
#include<iostream>
#include"worker.h"
#include<fstream>
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<iostream>
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<iostream>
#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 来化解!
另外,基于双指针的正序,逆序排序问题,解决的也很好。

猜你喜欢

转载自blog.csdn.net/weixin_40293999/article/details/132795829