目前为止,C++的三大特性封装、继承、多态基本上都学习完了,现在用一个职工管理系统来结束和总结这一阶段的学习
项目
项目名称:职工信息管理系统
项目需求:
- 添加职工信息,并且支持批量添加,能保存添加进来职工信息
- 显示职工信息
- 删除职工信息
- 修改职工信息
- 查找职工信息,可以选择是根据名字查找还是根据编号查找,如果是根据名字查找则必须查找出所有名字符合的人的信息
- 给存贮的信息排序,可以是升序或者降序
- 清空所有信息
- 退出系统
项目思路:
- 职工的有很多职位,有普通员工,经理,老板等等,所以应该创建一个职工的抽象类,用多态来满足不同职位的信息显示和存储
- 对于职工信息的存贮可以创建一个专门用来存储信息的 data.txt 文件,用C++对文件进行读写和排序
- 整个系统由switch语句识别用户输入的指令并进行相应的操作
Code
依照惯例,先搭建出整个系统的大致框架
首先是将整个管理系统封装成一个类:labourManager ,有两个属性,一个是人员个数计数器(empNumber),一个是用于存贮人员信息数组的指针(empArry,是二阶指针) ,用于实现整个系统的功能(在main中实例化一个管理系统类即可);
其次是一个职工抽象类:worker , 三个属性:职工编号(id),职工姓名(name),职业编号(deptid);
最后是主函数,实例化系统类,switch控制系统功能选择与执行
下图是整个项目的结构
worker.h
是职工的抽象类声明
#pragma once
#include<iostream>
#include<string>
using namespace std;
//职工抽象类
class worker
{
public:
//职工编号
int id;
//职工姓名
string name;
//部门编号
int deptId;
//构造函数
worker(int i, string n, int d) :id(i), name(n), deptId(d) {};
//显示个人信息
virtual void showInfo() = 0;
//获取岗位名称
virtual string getDeptName() = 0;
};
尽管抽象类不能实例化,但是不妨碍有构造函数
employee.h
这是普通职工类
#pragma once
#include<iostream>
#include"worker.h"
#include<string>
using namespace std;
class employee : public worker
{
public:
//构造函数
employee(int i,string n,int d):worker(i,n,d){};
//重写worker抽象类的纯虚函数
void showInfo();
string getDeptName();
};
employee.cpp
#include "employee.h"
//纯虚函数的实现
void employee::showInfo() {
cout << "\tlabour's id:" << this->id;
cout << "\tlabour;s name:" << this->name;
cout << "\tlabour;s depatment:" << this->getDeptName();
cout << "\tlabour's task" << endl; //这表示职工的工作任务,统一简写了
}
string employee::getDeptName() {
return "employee";
}
经理类和老板类依葫芦画瓢实现即可,这里不再过多赘述
功能实现
所需的类创建好之后就要考虑系统功能的实现,由于对读写文件功能的设计,我们还需要在 labourManager 里面加入几个方便我们实现这一功能和系统初始化的函数和属性
首先需要一个简单的功能菜单界面
功能菜单
void labourManager:: showMeun() {
cout << "=======================================================" << endl;
cout << " LabourManager " << endl;
cout << "=======================================================" << endl;
cout << " 1-add labour information " << endl;
cout << " 2-show labour information " << endl;
cout << " 3-delete labour information " << endl;
cout << " 4-change labour information " << endl;
cout << " 5-find labour information " << endl;
cout << " 6-sort labour information " << endl;
cout << " 7-clear all information " << endl;
cout << " 0-exit system " << endl;
cout << "=======================================================" << endl;
cout << endl;
}
接着在写labourManager的构造函数时,我们要考虑到,在构造函数要应对几种情况
- 第一次初始化系统,则职工数据文件都不存在
- 文件存在但是是空文件
- 文件已经存在了,里面存有数据
因此,我们给系统类 labourManager 增加一个用于表示文件是否为空的属性:bool fileIsEmpty;若数据文件不存在或者是空文件则返回true,否则返回false;又因为在第三种情况下要将存贮在数据文件中的数据写到系统类中,所以又增加了一个初始化系统类数组的函数 void initEmp()以及专门用来获取文件中人数的函数int get_fileEmpNunmber();
void initEmp()
具体内容如下
//初始化数组
void labourManager::initEmp() {
//先把文件中的数据读出来
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int deptId;
int index = 0;
//把读出来的数据放入数组中
while (ifs >> id && ifs >> name&& ifs >> deptId)
{
worker* worker = NULL;
switch (deptId) {
case 1:
//读出来是普通员工
worker = new employee(id, name, deptId);
break;
case 2:
//读出来是经理
worker = new manager(id, name, deptId);
break;
case 3:
//读出来是老板
worker = new boss(id, name, deptId);
break;
}
this->empArray[index] = worker;
index++;
}
ifs.close();
}
注:在labourManager头文件中声明了了#define FILENAME “labourdata.txt”
int get_fileEmpNunmber()
int labourManager::get_fileEmpNunmber() {
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int deptId;
int count = 0; //人数计数器
while (ifs >> id&&ifs >> name&&ifs>>deptId) //读一行就自增一次,一直读完,就能计算出有多少行
{
count++;
}
ifs.close();
return count;
}
然后应对三种不同的情况使系统类初始化
labourManager::labourManager()
{
//对于构造函数,要分三种情况来进行构造
//1-第一次初始化系统,则职工数据文件都不存在
//先打开文件
ifstream ifs;
ifs.open(FILENAME, ios::in);
if (!ifs.is_open()) { //判断是否打开成功,若否,则没有数据文件,是第一次初始化系统
cout << "file isn't exist!" << endl;
//初始化属性
this->empArray = NULL;
this->empNumber = 0;
//标明数据文件不存在
this->fileIsEmpty = true;
//关闭文件
ifs.close();
return;
}
//2-若文件存在但是是空文件
char index;
ifs >> index; // 读一个字符s
if (ifs.eof()) { // eof()函数判断读到的字符是否是EOF,若是,则是空文件
cout << "the data is empty!" << endl;
//初始化属性
this->empArray = NULL;
this->empNumber = 0;
//标明数据文件不存在
this->fileIsEmpty = true;
//关闭文件
ifs.close();
return;
}
//3-文件已经存在了,则读出里面的人数
this->empNumber = get_fileEmpNunmber();
cout << "the file is exist,the quantity in file is: " << this->empNumber << endl;
//读入数据
this->empArray = new worker * [this->empNumber];
initEmp();
}
labourManager::~labourManager()
{
if (empArray != NULL)
{
delete empArray;
empArray = NULL;
}
}
除此之外,还需要一个每次改变都能如实将影响传输到数据文件中的函数save()
save()
//存储数据的函数
void labourManager::save() {
ofstream ofs;
ofs.open(FILENAME, ios::out); //用输出方式打开文件
for (int i = 0; i < this->empNumber; i++) { //录入数据
ofs << this->empArray[i]->id << " "
<< this->empArray[i]->name << " "
<< this->empArray[i]->deptId << endl;
}
ofs.close(); //关闭文件
}
然后开始写添加职工信息的功能
添加职工信息
void labourManager::addLabourInfo() {
int addNumber = 0;
cout << "the quantity you want to add:" << endl; //输入要添加的数目
cin >> addNumber;
if (addNumber > 0) {
//计算要新开辟的空间大小
int newSize = this->empNumber + addNumber;
//开辟新的空间
worker** newspace = new worker*[newSize];
//将原空间下的内容放到现有的新空间下
if (this->empArray != NULL) {
for (int i = 0; i < this->empNumber; i++) {
newspace[i] = this->empArray[i];
}
}
//往后添加新的数据
for (int i = 0; i < addNumber;i++) {
int id = 0;
string name;
int deptId = 0;
cout << "please enter NO." << i + 1 << "labour's id:" << endl;
cin >> id;
cout << "please enter NO." << i + 1 << "labour's name:" << endl;
cin >> name;
cout << "please enter NO." << i + 1 << "labour's department id:" << endl;
cout << "1-emplpyee" << endl;
cout << "2-manager" << endl;
cout << "3-boss" << endl;
cin >> deptId;
//利用多态给基类赋值
worker* worker = NULL;
switch (deptId)
{
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;
}
//将信息保存到数组中
newspace[this->empNumber + i] = worker;
}
//释放原有空间
delete[] this->empArray;
//更改新空间的指向
this->empArray = newspace;
//更新新员工人数
this->empNumber = newSize;
//将文件为空的表示符置否
this->fileIsEmpty = false;
//输入完毕保存数据
this->save();
//提示操作成功
cout << "add sucessful!" << endl;
}
else
{
//输入的无效数,报错
cout << "number is wrong!" << endl;
}
system("pause");
}
在写显示信息之前,我们要想到,可能有数据文件里面不存在这个人的情况
所以需要判断一下数据里面是否存贮了这个人的信息的函数,而且后面的其他功能也会用到这个判断
判断函数 isExist()
//判断是否存在所选的职工信息,是则返回对应的位置,不是则返回-1
int labourManager::isExist(int id) {
int index = -1; //默认不存在
for (int i = 0; i < this->empNumber; i++) {
if (this->empArray[i]->id == id) {
index = i;
break;
}
}
return index;
}
显示职工信息
//职工信息显示函数
void labourManager::showLabourInfo() {
//先判断文件是否存在或者是否为空
if (fileIsEmpty)
cout << "file dosen't exist or file is empty!" << endl;
else
{
//若文件内容不为空,则显示数据
for (int i = 0; i < this->empNumber; i++)
this->empArray[i]->showInfo();
}
system("pause");
}
删除职工信息
//删除职工信息
void labourManager::deleteLabourInfo() {
//先判断是否为空文件
if (this->fileIsEmpty) {
cout << "the file is empty!" << endl;
}
else
{
//接收想要删除的职工的编号
int id = 0;
cout << "the labour's id you want to delete" << endl;
cin >> id;
// 判断数据中是否存在这名员工
int index = this->isExist(id);
if (index == -1) {
cout << "delete fail" << endl;
}
else
{
for (int i = index; i < this->empNumber - 1; i++) {
this->empArray[i] = this->empArray[i + 1];
}
this->empNumber--; //更新数组
this->save(); //保存数据
cout << "delete sucessful!" << endl;
}
}
system("pause");
}
修改职工信息
//修改职工信息
void labourManager::changeLabourInfo() {
//先判断文件是否为空
if(this->fileIsEmpty)
cout << "file dosen't exist or file is empty!" << endl;
else
{ //不为空则查找想要修改的人的编号
int id = 0;
cout << "the labour's id you want to change: " << endl;
cin >> id;
int ret = this->isExist(id);
if (ret == -1)
//如果没找到,打出提示
cout << "this one doesn't exist!" << endl;
else
{
//找到了要修改的员工位置
delete this->empArray[ret]; //先删除掉节点信息
int newId = 0;
string newName = "";
int newDeptId = 0;
//开始重新录入信息
cout << "NO." << id << " labour's new id is: " << endl;
cin >> newId;
cout << "new name is: " << endl;
cin >> newName;
cout << "new department id is: " << endl;
cout << "1-employee" << endl;
cout << "2-manager" << endl;
cout << "3-boss" << endl;
cin >> newDeptId;
worker* worker = NULL;
switch (newDeptId)
{
case 1:
worker = new employee(newId, newName, newDeptId);
break;
case 2:
worker = new manager(newId, newName, newDeptId);
break;
case 3:
worker = new boss(newId, newName, newDeptId);
break;
default:
break;
}
//让原来的指针重新指向新的节点
this->empArray[ret] = worker;
//更新数据
this->save();
cout << "change sucessful!" << endl;
}
system("pause");
}
}
查找职工信息
//查找职工信息
void labourManager::findLabourInfo() {
//先判断文件是否存在
if (this->fileIsEmpty) {
cout << "file is empty!" << endl;
}
else
{
//若存在,选择查找的方式 1-按id号 2-按名字
int select = 0;
cout << "the way you find:" << endl;
cout << "1-by id" << endl;
cout << "2-by name" << endl;
cin >> select;
if (select == 1) { //如果按id查找
int id;
cout << "the labour;s id you want to find" << endl;
cin >> id; //输入目标职工id
int ret = this->isExist(id); //判断id在文件中是否存在
if (ret == -1) {
cout << "this one doesn't exist!" << endl;
}
else
{
// 找到存在则显示
cout << "find sucessful!" << endl;
this->empArray[ret]->showInfo();
}
}
//按名字查找
else if (select ==2) {
string name = "";
cout << "the labour's name you want to find" << endl;
cin >> name;
bool index = false; //用于判断是否找到,默认是false
for (int i = 0; i < this->empNumber; i++) {
if (this->empArray[i]->name == name) {
//cout << "find sucessful!" << endl;
this->empArray[i]->showInfo();
index = true; //找到了则true
}
}
if(index == false) //没找打则输出提示
cout << "this one doesn't exist!" << endl;
}
else
{
//输入的不是有数字
cout << "wrong number! pls try again" << endl;
}
}
//暂停,查看信息
system("pause");
}
给职工信息排序
//给文件中的内容排序
void labourManager::sortLabourInfo() {
//先判断文件是否存在
if (this->fileIsEmpty) {
cout << "file is empty!" << endl;
}
else
{
//选择方式
int select = 0;
cout << "the way you sort:" << endl;
cout << "1-ASC" << endl; //升序
cout << "2-DESC" << endl; //降序
cin >> select;
//利用选排给信息进行排序
for (int i = 0; i < this->empNumber;i++) {
int MIN = i;
for (int j = i + 1; j < this->empNumber; j++) {
if (select == 1) { //采取升序
if (this->empArray[MIN]->id > this->empArray[j]->id)
MIN = j;
}
else
{
//采取降序
if (this->empArray[MIN]->id < this->empArray[j]->id)
MIN = j;
}
}
//实行交换,保证是最小/最大的
if (MIN != i) {
worker* temp = this->empArray[i];
this->empArray[i] = this->empArray[MIN];
this->empArray[MIN] = temp;
}
}
cout << "sort sucessful!" << endl;
this->save(); //保存数据
this->showLabourInfo(); //显示数据
}
system("pause");
}
清空所有数据
void labourManager::clearAll() {
int select = 0;
cout << "Do you want to clear data?" << endl;
cout << "1-Yes" << endl;
cout << "2-No" << endl;
cin >> select;
if (select) {
ofstream ofs;
ofs.open(FILENAME, ios::trunc);
ofs.close();
if (this->empNumber != NULL) {
for (int i = 0; i < this->empNumber;i++) {
if (this->empArray[i] != NULL) {
delete this->empArray[i];
}
}
this->empNumber = 0;
delete[] this->empArray;
this->empArray = NULL;
this->fileIsEmpty = true;
}
cout << "clear sucessful!" << endl;
}
system("pause");
}
这样,整个管理系统就完结了
最后附上完整项目的代码
labourManager.zip
总结
这次是职工管理系统,用到了封装、多态、继承以及文件的读写,算是大部分所学知识都用上去了;但是感觉还能优化,比如这样的管理系统和数据库就很搭,给数据排序,查找,删除等操作都要简化不少,下次就朝这个方向改造