C++使用模板类实现简单的人事管理系统

写在前面

这几天我一直在做我们《C++与数据结构》课程的大作业——c++人事管理系统。在写的过程中遇到了很多困难,也让我深刻地体会到“纸上得来终觉浅,绝知此事要躬行”。特别是编程,虽然我们看数据结构书感觉其中的很多数据结构很简单,但是实际写起来就会发现很多意想不到的问题,唯有不断地练习不断地思考才能取得长久的进步。

项目要求

编写一个简单的人事管理系统,要求功能如下
用链表存储、文件输入、输出。
具有建立、插入、删除、查询和打印功能。
平台不限、链表可用公共模板类。
管理的人员有:
本科生:姓名、性别、年龄、身份证号码、高考总分
脱产研究生:姓名、性别、年龄、身份证号码、专业
在职研究生:姓名、性别、年龄、身份证号码、学号、专业、工资
职工:姓名、性别、年龄、身份证号码、工资、岗位
教师:姓名、性别、年龄、身份证号码、工资、专业

项目思路

我最开始想的是:

  • 建立一个基类Person类,其中包含最基本的姓名、性别、年龄、身份证号码;
  • 从Person类中派生出本科生Student类,脱产研究生ReleasedUndergraduate类,在职研究生ServingUndergraduate类,职工Staff类以及教师Teacher类,其中每个类在继承了基类的成员基础上,各自添加自己特有的成员;
  • 在每一个类中定义getInfo函数,用来从获取从控制台输入的各种信息;
  • 为了更加熟悉链表这一数据类型,我没有使用STL中的list容器,而是自己写了一个LinkList链表类,包含了Node结点和链表LinkList,其中Node结点包含了data数据域和* next指针;Linklist包含了* head头结点和链表长度size
  • 为了能够一次性处理五种不同的人群(本科生、脱产、在职、职工、老师),所以我想把LinkList写成一个模板类,使用template< typename T>
  • 项目要求的建立、查找、删除、打印等功能在链表中实现

后来我发现一个很严峻的问题:不同于网上大部分涉及到链表结构的源码,我如果要用这个LinkList的模板的话,我传进去的参数本身是一个数据结构体,而不是单一的数据类型变量(如int,string);而且这些不同的数据结构体其本身包含的数据成员也是不同的。 换句话说,编译器是不知道我传进去的结构体具体有哪些成员。这样使得我不知道有些功能怎么通过类的成员函数来实现。比如我想写一个类的成员函数实现通过姓名查找的功能,我起初的写法是

void LinkList<T>::findByName(const string& name) {
   
	Node<T>* pcur = head->next;
	while (pcur != NULL) {
   
		if (name == pcur->data.name)
			……
	}	
}

很明显这样是非法的。
后来我采用的方法是在LinkList类外写一个查找函数,然后将链表和要查找的姓名字符串作为参数传入,再进行比较,比如

void findStudentName(LinkList<Student>& listForStudent, Student stu)
{
   
	Node<Student>* pcur = listForStudent.head->next;
	bool flag = false;	//查找成功标志
	while (pcur != NULL) {
   
		if (stu.name == pcur->data.name) {
   
			cout << "\t\t*-----------------------------------------------------*" << endl;
			cout << "查找到姓名为 " << stu.name << " 的相关信息: " << endl;
			cout << pcur->data;
			flag = true;
			break;
		}
		pcur = pcur->next;	//下一数据
	}
	if (flag == false) {
   
		cout << "没有找到相关人员信息!" << endl;
	}
}

但这样写的弊端,我自认为有以下几点:

  • 为了五种不同的数据类型,要写五个类似的函数;不够泛型化
  • 没有在数据结构类内部完成,不够简洁;在以后的调用中不够方便

通过这样在类外写函数的方法,我实现了查找删除两大功能。
其余功能的实现要点:

  • 数组长度:类成员函数,直接通过size成员可以得到
  • 末尾添加数据append:类成员函数,通过操作指针得到;
  • 在指定位置添加数据:类成员函数,先遍历至指定位置,再操作指针,改变相关结点的next指针得到;
  • 删除remove:先遍历判断,再设置相关操作指针并改变相关结点的next,注意要delete释放内存
  • 打印print: 类成员函数,data虽然有很多项,不能通过成员运算符进行逐个输出(和上述情况是一个原因),但是可以通过重载输出运算符<<直接print整个data数据域

除此之外,还要做一个菜单。一级菜单选定要处理的人员类型;二级菜单是针对链表的操作

感想心得

这是我到目前为止写的行数最长的一个demo,虽然难度比较小,网上相关的代码也比较多,但是“麻雀虽小,五脏俱全”。使我对c++的模板编程、链表数据结构有了更深的了解,实现功能的喜悦与成就感也愈发强烈。

项目源码

/*用所学过的知识编写一个简单的人事管理系统,要求功能如下
用链表存储、文件输入、输出。
具有建立、插入、删除、查询和打印功能。
平台不限、链表可用公共模板类。
管理的人员有:
本科生:姓名、性别、年龄、身份证号码、高考总分
脱产研究生:姓名、性别、年龄、身份证号码、专业
在职研究生:姓名、性别、年龄、身份证号码、学号、专业、工资
职工:姓名、性别、年龄、身份证号码、工资、岗位
教师:姓名、性别、年龄、身份证号码、工资、专业
*/
#include <iostream>
#include <string>
#include <fstream>

using namespace std;
int first, second;	//一、二级菜单选项

//Person基类
class Person {
   
public:
	string name;
	char sex;
	int age;
	string idNum;
public:
	Person() = default;
	Person(const string& nam, char s, int ag, const string& id) : name(nam), sex(s), age(ag), idNum(id) {
   }

	void getInfo();	//获取相关信息
};

//Person类获取相关信息getInfo
void Person::getInfo()
{
   
	cout << "请输入姓名:";
	cin >> name;
	cout << "性别(m/f):";
	cin >> sex;
	cout << "年龄: ";
	cin >> age;
	cout << "身份证号码: ";
	cin >> idNum;
}

//本科生类
class Student : public Person{
   
private:
	int score;
public:
	Student() = default;
	Student(const string& nam, char s, int ag, const string& id, int sc):Person(nam, s, ag, id), score(sc) {
   }

	void getInfo();	//获取相关信息
	friend ostream & operator<<(ostream &, Student &);	//重载<<
};

//Student类重载<<
ostream & operator<<(ostream &os, Student &stu)
{
   
	os << "姓名: " << stu.name << endl;
	os << "性别: " << stu.sex << endl;
	os << "年龄: " << stu.age << endl;
	os << "身份证号码: " << stu.idNum << endl;
	os << "高考总分: " << stu.score << endl;
	return os;
}

//Student类获取相关信息getInfo
void Student::getInfo()
{
   
	Person::getInfo();
	cout << "高考总分: ";
	cin >> score;
}

//脱产研究生类
class ReleasedUndergraduate : public Person{
   
private:
	string major;
public:
	ReleasedUndergraduate() = default;
	ReleasedUndergraduate(const string& nam, char s, int ag, const string& id, const string& maj) : Person(nam, s, ag, id), major(maj) {
   }

	void getInfo();	//获取相关信息
	friend ostream & operator<<(ostream &, ReleasedUndergraduate &);	//重载<<
};

//ReleasedUndergraduate类重载<<
ostream & operator<<(ostream &os, ReleasedUndergraduate &ru)
{
   
	os << "姓名: " << ru.name << endl;
	os << "性别: " << ru.sex << endl;
	os << "年龄: " << ru.age << endl;
	os << "身份证号码: " << ru.idNum << endl;
	os << "专业: " << ru.major << endl;
	return os;
}

//ReleasedUndergraduate类获取相关信息getInfo
void ReleasedUndergraduate::getInfo()
{
   
	Person::getInfo();
	cout << "专业: ";
	cin >> major;
}

//在职研究生类
class ServingUndergraduate : public Person {
   
private:
	string major;
	int studentNum;
	int wage;
public:
	ServingUndergraduate() = default;
	ServingUndergraduate(const string& nam, char s, int ag, const string& id, const string& maj, int stuNum, int wag) : Person(nam, s, ag, id), major(maj), studentNum(stuNum), wage(wag) {
   }

	void getInfo();
	friend ostream & operator<<(ostream &, ServingUndergraduate &);	//重载<<
};

//ServingUndergraduate类重载<<
ostream & operator<<(ostream &os, ServingUndergraduate &su)
{
   
	os << "姓名: " << su.name << endl;
	os << "性别: " << su.sex << endl;
	os << "年龄: " << su.age << endl;
	os << "身份证号码: " << su.idNum << endl;
	os << "学号: " << su.sex << endl;
	os << "专业: " << su.major << endl;
	os << "工资: " << su.wage << endl;
	return os;
}

//ServingUndergraduate类获取相关信息
void ServingUndergraduate::getInfo()
{
   
	Person::getInfo();
	cout << "学号: ";
	cin >> studentNum;
	cout << "专业: ";
	cin >> major;
	cout << "工资: ";
	cin >> wage;
}

//职工类
class Staff : public Person{
   
private:
	int wage;
	string job;
public:
	Staff() = default;
	Staff(const string& nam, char s, int ag, const
  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值