C++职工管理系统实现

2024-01-02 18:41:00

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言:需求

在这里插入图片描述

管理系统中需要实现的功能如下:

退出管理程序:退出当前管理系统

增加职工信息:实现批量添加职工功能,将信息录入到文件中,职工信息为:职工编号、姓名、部门编号

显示职工信息:显示公司内部所有职工的信息

删除离职职工:按照编号删除指定的职工

修改职工信息:按照编号修改职工个人信息

查找职工信息:按照职工的编号或者职工的姓名进行查找相关的人员信息

按照编号排序:按照职工编号,进行排序,排序规则由用户指定

清空所有文档:清空文件中记录的所有职工信息(清空前需要再次确认,防止误删)

一、创建一个管理者的类,面向管理者进行编程

1.建立.h文件

#pragma once//防止头文件重复包含,与下面C语言的ifndef差不多
#ifndef WORKERMANGER__H
#define WORKERMANGER__H

#include <iostream>

using namespace std;

class WorkerManger {
public:


	//构造函数
	WorkerManger();

	//析构函数
	~WorkerManger();



};



#endif // !1

2.建立.c文件

#include <iostream>
#include "workerManager.h"

WorkerManger::WorkerManger() {

}

WorkerManger::~WorkerManger() {

}

3.编写一个显示系统菜单的成员函数

没啥好说的,直接写就完事了。

void WorkerManger::showMenu() {
	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;
}

二、实现功能0:退出管理程序

代码如下:

void WorkerManger::exitSystem() {
	cout << "欢迎再次使用" << endl;
	system("pause");
	exit(0);
}

三、设计抽象类worker和三个职工的子类

1.思路:创建一个职工的抽象类,将员工、经理、老板用多态来构造

2.思路:多态的派生类中,成员变量是编号、姓名和等级。成员函数是岗位信息描述和获取岗位名称。

3.h文件声明抽象worker类成员变量和函数

这里要注意:纯虚函数根本不需要在.c文件去定义

#pragma once
#include <iostream>
#include <string>
using namespace std;

//一个抽象的worker类
class abstractWorker {
public:
	//打印岗位信息描述的虚函数
	virtual void showInfo() = 0;

	//获取岗位名称的虚函数
	virtual void getDeptname() = 0;

	//职工编号
	int worker_ID;

	//职工姓名
	string worker_name;

	//等级
	int Dept_ID;
};

4.单独实现一个员工employee的子类,重写父类的纯虚函数。

employee.h

#pragma once
#include <iostream>
#include <string>
#include "worker.h"
using namespace std;

//一个表示员工的子类,继承自抽象的worker类
class employee:public abstractWorker {
public:

	//初始化成员变量的构造函数
	employee(int mID, string name, int dID);

	//打印岗位信息描述的函数
	void showInfo();

	//获取岗位名称的函数
	string getDeptname();


};

employee.c

#include <iostream>
#include "worker.h"
#include "employee.h"


//构造函数,初始化员工信息
employee::employee(int mID,string name,int dID) {
	this->worker_ID = mID;
	this->worker_name = name;
	this->Dept_ID = dID;

}

//打印岗位信息描述的函数
void employee::showInfo() {
	cout << "职工编号为:" << this->worker_ID<<"\t"
		<< "职工姓名为:" << this->worker_name << "\t"
		<< "职工岗位编号为:" << this->getDeptname() << "\t"
		<<"岗位职责是完成经理交代的任务" << "\t"
		<< endl;
}

//获取岗位名称的函数
string employee::getDeptname() {
	return string("员工");

}

5.单独实现经理mannerr的子类并重写

manner.h

#pragma once
#include <iostream>
#include <string>
#include "worker.h"
using namespace std;

//一个表示员工的子类,继承自抽象的worker类
class manner :public abstractWorker {
public:

	//初始化成员变量的构造函数
	manner(int mID, string name, int dID);

	//打印岗位信息描述的函数
	void showInfo();

	//获取岗位名称的函数
	string getDeptname();


};

manner.c

#include <iostream>
#include "worker.h"
#include "manner.h"
//构造函数,初始化员工信息
manner::manner(int mID, string name, int dID) {
	this->worker_ID = mID;
	this->worker_name = name;
	this->Dept_ID = dID;

}

//打印岗位信息描述的函数
void manner::showInfo() {
	cout << "职工编号为:" << this->worker_ID << "\t"
		<< "职工姓名为:" << this->worker_name << "\t"
		<< "职工岗位编号为:" << this->getDeptname() << "\t"
		<< "岗位职责是完成老板交代的任务,并下发给员工" << "\t"
		<< endl;
}

//获取岗位名称的函数
string manner::getDeptname() {
	return string("经理");

}

6.实现老板boss的子类并重写

boss.h

#pragma once
#include <iostream>
#include <string>
#include "worker.h"
using namespace std;

//一个表示老板的子类,继承自抽象的worker类
class boss :public abstractWorker {
public:

	//初始化成员变量的构造函数
	boss(int mID, string name, int dID);

	//打印岗位信息描述的函数
	void showInfo();

	//获取岗位名称的函数
	string getDeptname();


};

boss.c

#include <iostream>
#include "worker.h"
#include "boss.h"


//构造函数,初始化员工信息
boss::boss(int mID, string name, int dID) {
	this->worker_ID = mID;
	this->worker_name = name;
	this->Dept_ID = dID;

}

//打印岗位信息描述的函数
void boss::showInfo() {
	cout << "职工编号为:" << this->worker_ID << "\t"
		<< "职工姓名为:" << this->worker_name << "\t"
		<< "职工岗位编号为:" << this->getDeptname() << "\t"
		<< "岗位职责是总管全局" << "\t"
		<< endl;
}

//获取岗位名称的函数
string boss::getDeptname() {
	return string("老板");

}

四.实现功能1:添加职工信息的功能

①思路分析:我们添加职工时,可能会创建各种各样不同的职工,需要将不同种类的职工放入一个不定长的数组保存。

面临的问题是:不同的职工类创建出来的对象类型不同,比如创建了三个employee对象、两个manner对象和一个boss对象,他们很难统一的管理和操作,没办法有序的排布在表中。

    employee e1(1, "小明", 2);
	employee e2(2, "小花", 3);
	manner m1(3, "李哥", 4);
	boss b1(4, "王总", 5);

像这样单纯实例化对象,但是他们都是分散的,没有办法很好的有序的建立其联系来。

②解决方法:父类的指针可以统一的访问不同子类对象,所以利用堆区建立一个指针数组来统一的管理不同的子类对象,使其类似数组似的有序排布。

abstractWorker* worker[max_count];

③一个一个的添加不同职员的信息的函数

//一个一个的增加职工信息的函数
void WorkerManger::addInformation(abstractWorker* worker[]) {
	int mId;
	string name;
	string dept;
	cout << "请输入职工的ID号:";
	cin >> mId;
	cout << "请输入职工的姓名:";
	cin >> name;
	cout << "请输入职工的职位:";
	cin >> dept;
	if (dept == "员工") {
		worker[person_index] = new employee(mId, name, 1);
	}
	else if (dept == "经理") {
		worker[person_index] = new manner(mId, name, 2);
	}
	else if (dept == "老板") {
		worker[person_index] = new boss(mId, name, 3);
	}
	else {
		cout << "无效的职位类型!" << endl;
		return;
	}
	cout << "职工信息添加成功!" << endl;

	person_index++;
}

代码很简单,也很清楚。这里最巧妙的就是用到了父类的指针数组来统一访问不同子类的属性,实现了多态。
但是问题又来了,一个公司一般有成百上千人,如果一个个添加,就非常浪费时间,那么能否优化代码,可以实现成批的大量的添加职员信息呢?

④成批的批量的添加职员信息的函数

//一个可以批量添加员工信息的函数
void WorkerManger::manyaddinformation(abstractWorker* worker[], ofstream& ofs) {
	// 检查文件是否为空
	bool fileIsEmpty = ofs.tellp() == 0;

	if (fileIsEmpty) {
		ofs << "ID\t姓名\t等级\t岗位" << endl;
	}

	cout << "请输入添加职工数量:" << endl;
	int addNum = 0;
	cin >> addNum;

	if (addNum > 0) {
		for (int i = 0; i < addNum; i++) {
			int type = 0;
			cout << "请输入第 " << i + 1 << " 个职工类型:" << endl;
			cout << "1、员工" << endl;
			cout << "2、经理" << endl;
			cout << "3、老板" << endl;
			cin >> type;

			string name;
			cout << "请输入职工姓名:" << endl;
			int id;
			int dSelect;
			cin >> name;

			switch (type) {
			case 1: // 普通职工
				worker[person_index] = new employee(person_index + 1, name, 1);
				break;
			case 2: // 经理
				worker[person_index] = new manner(person_index + 1, name, 2);
				break;
			case 3: // 老板
				worker[person_index] = new boss(person_index + 1, name, 3);
				break;
			default:
				break;
			}
			person_index++; // 每添加一个人员,人数增加1

			ofs << worker[person_index - 1]->worker_ID << "\t"
					<< worker[person_index - 1]->worker_name << "\t"
					<< worker[person_index - 1]->level << "\t"
					<< worker[person_index - 1]->getDeptname() << endl;
			
		}
		cout << "成功添加" << addNum << "名职工!" << endl;
	}
	else {
		cout << "输入数据有误!" << endl;
	}
	system("pause");
	system("cls");
}

在这里插入图片描述

这里我遇到一个大坑:ofs << “ID\t姓名\t等级\t岗位” << endl;

我想让表头永远有一个说明,但是出了问题,就是每次重新添加职员信息时,都会重新添加一次 “ID\t姓名\t等级\t岗位” ,我很不理解,明明自己做了文件为空和不为空的判断,但是无论怎样都会重新打印。

原因:文件流 ofs 是作为参数传递给函数的,每次调用函数时都会重新创建一个新的文件流对象。因此,每次调用 manyaddinformation 函数时,文件流 ofs 都是新创建的,并且文件是空的。这就导致了每次都会写入表头信息。

解决思路:void WorkerManger::manyaddinformation(abstractWorker* worker[], ofstream& ofs),将文件流 ofs 定义为 WorkerManger 类的成员变量。这样,文件流对象将在类的生命周期内保持打开状态,而不会在每次函数调用时重新创建。

首先,在 WorkerManger 类的头文件中声明文件流成员变量:

class WorkerManger {
private:
    ofstream ofs; // 文件流对象
    // 其他成员变量和函数声明
};

然后,在类的构造函数中打开文件流,并在析构函数中关闭文件流:

WorkerManger::WorkerManger() {
    ofs.open("worker.txt", ios::app); // 打开文件流,以追加模式写入
}

WorkerManger::~WorkerManger() {
    ofs.close(); // 关闭文件流
}

这样的话,调用manger.manyaddinformation(worker);就只用传一个参数了。
在这里插入图片描述

⑤将添加的职工信息保存到文件中

1.点h文件中引入文件头文件和宏定义

#include <fstream>
#define fliename "worker.txt"

2.代码实现

//保存职工信息到文件中
void WorkerManger::saveinfo(abstractWorker* worker[]) {
	ofstream ofs;
	ofs.open(filename, ios::out);
	ofs << "ID\t姓名\t等级\t岗位" << endl;
	for (int i = 0; i < person_index; i++) {
		
		ofs << worker[i]->worker_ID << "\t"
			<< worker[i]->worker_name << "\t"
			<< worker[i]->level << "\t"
			<< worker[i]->getDeptname() << endl;
	}
}

在这里插入图片描述

这里不建议用saveinfo这个函数,因为我尝试过,这样做,会导致每次重启程序时刷新文件,导致之前的信息丢失。最好还是在批量添加职员信息的函数里就直接完成文件的写入。

⑥读取文件内容并打印出来,还可以统计员工、经理、老板各自人数

string getPositionFromLine(const string& line) {
	// 假设岗位信息在第4列,以制表符分隔
	stringstream ss(line);
	string token;
	for (int i = 0; i < 3; i++) {
		getline(ss, token, '\t');
	}
	getline(ss, token, '\t');
	return token;
}

void WorkerManger::readflie() {
	ifstream ifs(filename);
	if (ifs.is_open()) {
		string line;
		int totalEmployees = 0;
		int totalManagers = 0;
		int totalBosses = 0;

		while (getline(ifs, line)) {
			// 处理每行内容
			cout << line << endl;

			// 每行内容的格式为:ID\t姓名\t等级\t岗位
			
			// 假设岗位信息在第4列
			string position = getPositionFromLine(line);

			// 根据岗位信息进行计数
			if (position == "员工") {
				totalEmployees++;
			}
			else if (position == "经理") {
				totalManagers++;
			}
			else if (position == "老板") {
				totalBosses++;
			}
		}

		ifs.close();
		// 输出统计结果
		cout << "员工人数:" << totalEmployees << endl;
		cout << "经理人数:" << totalManagers << endl;
		cout << "老板人数:" << totalBosses << endl;
		cout << "总共人数:" << totalEmployees + totalManagers + totalBosses << endl;
	}
	else {
		cout << "无法打开文件:" << filename << endl;
	}

	system("pause");
	system("cls");
}

五、实现功能2:显示职工信息

没啥好说的,借助父类指针数组,打印就完了,注意可以使用水平制表符来统一格式。

//显示职工信息
void WorkerManger::showinfo(abstractWorker* worker[]) {
	cout << "当前共有 " << person_index << " 名职工" << endl;
	cout << "职工信息如下:" << endl;
	cout << "ID\t姓名\t等级\t岗位" << endl;
	for (int i = 0; i < person_index; i++) {
		cout << worker[i]->worker_ID << "\t" << worker[i]->worker_name << "\t" << worker[i]->level <<"\t"<<worker[i]->getDeptname() << endl;
	}

	system("pause");
	system("cls");

}

不过这里最好建议用上面的读取文件的方式来显示,因为这样的话,即使退出了程序,内容也不会丢失,可以随时读取。

六、实现功能3:删除离职职工

deleteWorker 函数的实现过程如下:
检查职工数组是否为空,如果为空则提示用户暂无职工记录并返回。
提示用户输入要删除的职工的ID号。
遍历职工数组,查找要删除的职工在数组中的下标。
如果未找到要删除的职工,则提示用户未找到该职工并返回。
如果找到要删除的职工,释放该职工对象的内存空间,将后面的职工对象向前移动,职工数量减一。
最后,将更新后的职工信息写入文件,并提示用户删除成功。


void WorkerManger::deleteworker(abstractWorker* worker[]) {
	if (person_index == 0) {
		cout << "暂无职工记录!" << endl;
		return;
	}

	cout << "请输入要删除的职工ID:" << endl;
	int id_num;
	cin >> id_num;

	int index = -1; // 要删除的职工在数组中的下标
	for (int i = 0; i < person_index; i++) {
		if (id_num==worker[i]->worker_ID) {
			index = i;
			break;
		}
	}

	if (index == -1) {
		cout << "未找到该职工!" << endl;
		return;
	}

	delete worker[index]; // 释放要删除的职工对象的内存空间
	for (int i = index; i < person_index - 1; i++) {
		worker[i] = worker[i + 1]; // 将后面的职工对象向前移动
	}
	person_index--; // 职工数量减一

	// 将更新后的职工信息写入文件
	for (int i = 0; i < person_index; i++) {
		ofs << worker[i]->worker_ID << "\t"
			<< worker[i]->worker_name << "\t"
			<< worker[i]->level << "\t"
			<< worker[i]->getDeptname() << endl;
	}
	ofs.close();
	cout << "删除成功!" << endl;
}

七、实现功能4:修改职工信息(目前仅姓名)

//修改职工信息
void WorkerManger::modifyWorker(abstractWorker* worker[]) {
	if (person_index == 0) {
		cout << "暂无职工记录!" << endl;
		return;
	}

	cout << "请输入要修改的职工当前ID:" << endl;
	int id_num;
	cin >> id_num;

	int index = -1; // 要修改的职工在数组中的下标
	for (int i = 0; i < person_index; i++) {
		if (id_num == worker[i]->worker_ID) {
			index = i;
			break;
		}
	}

	if (index == -1) {
		cout << "未找到该职工!" << endl;
		return;
	}

	cout << "请输入修改后的职工姓名:" << endl;
	string name;
	cin >> name;
	worker[index]->worker_name = name;


	// 将更新后的职工信息写入文件
	for (int i = 0; i < person_index; i++) {
		ofs << worker[i]->worker_ID << "\t"
			<< worker[i]->worker_name << "\t"
			<< worker[i]->level << "\t"
			<< worker[i]->getDeptname() << endl;
	}
	ofs.close();

	cout << "修改成功!" << endl;
}

八、实现功能5:查找职工信息,根据ID号或姓名来查找职工信息的功能

首先,根据用户输入的查找方式(ID号或姓名),提示用户输入相应的信息。

根据用户输入的信息,在职工数组中查找匹配的职工对象。

如果找到匹配的职工对象,输出职工的详细信息;如果未找到匹配的职工对象,输出未找到的提示信息。

具体的代码实现如下:

void WorkerManger::searchWorker(abstractWorker* worker[]) {
    if (person_index == 0) {
        cout << "暂无职工记录!" << endl;
        return;
    }

    cout << "请选择查找方式:" << endl;
    cout << "1. 根据ID号查找" << endl;
    cout << "2. 根据姓名查找" << endl;
    int choice;
    cin >> choice;

    if (choice == 1) {
        cout << "请输入要查找的职工ID号:" << endl;
        int id_num;
        cin >> id_num;

        bool found = false;
        for (int i = 0; i < person_index; i++) {
            if (id_num == worker[i]->worker_ID) {
                found = true;
                cout << "职工ID号:" << worker[i]->worker_ID << endl;
                cout << "职工姓名:" << worker[i]->worker_name << endl;
                cout << "职工岗位:" << worker[i]->getDeptname() << endl;
                cout << "职工等级:" << worker[i]->worker_level << endl;
                break;
            }
        }

        if (!found) {
            cout << "未找到该职工!" << endl;
        }
    } else if (choice == 2) {
        cout << "请输入要查找的职工姓名:" << endl;
        string name;
        cin >> name;

        bool found = false;
        for (int i = 0; i < person_index; i++) {
            if (name == worker[i]->worker_name) {
                found = true;
                cout << "职工ID号:" << worker[i]->worker_ID << endl;
                cout << "职工姓名:" << worker[i]->worker_name << endl;
                cout << "职工岗位:" << worker[i]->getDeptname() << endl;
                cout << "职工等级:" << worker[i]->worker_level << endl;
                break;
            }
        }

        if (!found) {
            cout << "未找到该职工!" << endl;
        }
    } else {
        cout << "输入无效!" << endl;
    }
}

九、实现功能6:将员工、经理、老板三类分别打印其信息

思路:根据level等级来判断,1是员工,2是经理,3是老板

//实现功能:将员工、经理、老板三类分别打印其信息
void WorkerManger::printWorker(abstractWorker* worker[]) {
	if (person_index == 0) {
		cout << "暂无职工记录!" << endl;
		return;
	}

	cout << "请选择查找岗位:1-员工  2-经理  3-老板" << endl;
	
	int choice;
	cin >> choice;
	switch (choice) {
	case 1:
		cout << "员工信息:" << endl;
		for (int i = 0; i < person_index; i++) {
			//检索出level=1的各员工的下标,并将其信息进行打印
			if (worker[i]->level == 1) {
				cout << worker[i]->worker_ID << "\t" << worker[i]->worker_name << "\t" 
					<< worker[i]->level << "\t" << worker[i]->getDeptname() << endl;
			}
		}
		break;
	case 2:
		cout << "经理信息:" << endl;
		for (int i = 0; i < person_index; i++) {
			//检索出level=1的各员工的下标,并将其信息进行打印
			if (worker[i]->level == 2) {
				cout << worker[i]->worker_ID << "\t" << worker[i]->worker_name << "\t"
					<< worker[i]->level << "\t" << worker[i]->getDeptname() << endl;
			}
		}
		break;
	case 3:
		cout << "老板信息:" << endl;
		for (int i = 0; i < person_index; i++) {
			//检索出level=1的各员工的下标,并将其信息进行打印
			if (worker[i]->level == 3) {
				cout << worker[i]->worker_ID << "\t" << worker[i]->worker_name << "\t"
					<< worker[i]->level << "\t" << worker[i]->getDeptname() << endl;
			}
		}
		break;
	default:
		cout << "无效的选项!" << endl;
		break;
	}
}

十:实现功能7:清空文件

函数首先以覆盖模式打开文件,然后写入一个空字符串来清空文件内容。

void WorkerManger::clearFile() {
	ofstream ofs(filename, ios::trunc); // 打开文件并以覆盖模式写入空字符串

	if (ofs.is_open()) {
		ofs << ""; // 写入空字符串

		ofs.close();

		cout << "文件已清空!" << endl;
	}
	else {
		cout << "无法打开文件:" << filename << endl;
	}
}

十一:出现BUG:删除、修改操作中的文件重新写入会导致文件内容重复一次。

在这里插入图片描述

解决思路:只知道肯定是deleteWorker和modifyWorker这两个函数有问题,但是不知道怎么修改写文件那一块的代码。

在这里插入图片描述

void WorkerManger::deleteworker(abstractWorker* worker[]) {
	if (person_index == 0) {
		cout << "暂无职工记录!" << endl;
		return;
	}

	cout << "请输入要删除的职工ID:" << endl;
	int id_num;
	cin >> id_num;

	int index = -1; // 要删除的职工在数组中的下标
	for (int i = 0; i < person_index; i++) {
		if (id_num==worker[i]->worker_ID) {
			index = i;
			break;
		}
	}

	if (index == -1) {
		cout << "未找到该职工!" << endl;
		return;
	}

	delete worker[index]; // 释放要删除的职工对象的内存空间
	for (int i = index; i < person_index - 1; i++) {
		worker[i] = worker[i + 1]; // 将后面的职工对象向前移动
	}
	person_index--; // 职工数量减一
	// 先清空文件内容
	ofs.open("worker.txt", ios::out | ios::trunc);
	ofs.close();
	// 将更新后的职工信息写入文件
	ofs.open("worker.txt", ios::out | ios::app);
	for (int i = 0; i < person_index; i++) {
		ofs << worker[i]->worker_ID << "\t"
			<< worker[i]->worker_name << "\t"
			<< worker[i]->level << "\t"
			<< worker[i]->getDeptname() << endl;
	}
	ofs.close();
	cout << "删除成功!" << endl;
}
//修改职工信息
void WorkerManger::modifyWorker(abstractWorker* worker[]) {
	if (person_index == 0) {
		cout << "暂无职工记录!" << endl;
		return;
	}

	cout << "请输入要修改的职工当前ID:" << endl;
	int id_num;
	cin >> id_num;

	int index = -1; // 要修改的职工在数组中的下标
	for (int i = 0; i < person_index; i++) {
		if (id_num == worker[i]->worker_ID) {
			index = i;
			break;
		}
	}

	if (index == -1) {
		cout << "未找到该职工!" << endl;
		return;
	}
	cout << "请输入修改后的职工姓名:" << endl;
	string name;
	cin >> name;
	worker[index]->worker_name = name;

	// 先清空文件内容
	ofs.open("worker.txt", ios::out | ios::trunc);
	ofs.close();
	// 将更新后的职工信息写入文件
	ofs.open("worker.txt", ios::app);
	for (int i = 0; i < person_index; i++) {
		ofs << worker[i]->worker_ID << "\t"
			<< worker[i]->worker_name << "\t"
			<< worker[i]->level << "\t"
			<< worker[i]->getDeptname() << endl;
	}
	cout << "修改成功!" << endl;
}

目前没有解决办法,暂时挂在这里。。。。。。

文章来源:https://blog.csdn.net/qq_53092944/article/details/135325919
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。