我们接下来写一个练习c++多态,文件,类的继承的小案例
首先我们定义有一个公司它有普通员工,经理,老板这样的3个职位,我们要将3个职位的信息放入一个信息表中。
类的继承:
由于普通员工,经理,老板这样的3个职位都是职工,所以我们可以定义一个叫职工的基类,让普通员工,经理,老板作为职工的派生类继承职工的属性和行为。
1.首先我们定义职员(基类)
创建职工的头文件Worker.h
//职工的抽象基类不需要具体实现所以不需要有.cpp文件
#pragma once
#include<iostream>
#include<string>
using namespace std;
class Worker//职工的抽象基类
{
public:
//显示个人信息
virtual void ShowInfo() = 0;
//获取岗位名称
virtual string getDeptName() = 0;
//岗位职责
virtual string DeptDuty() = 0;
//基类的属性要是定为private类型派生类是无法继承的
int m_Id;//职工的编号
string m_Name;//职工的姓名
int m_DeptId;//职工所在部门的编号
};
每个职工都有的行为有显示个人信息,获取岗位名称,岗位职责,都有的属性有编号,姓名,所在部门的编号,由于公司部门是固定且有限的,所以输入编号更加方便(后面也可以根据输入的编号判断创建什么类型的子类)
职工的抽象基类不需要具体实现所以不需要有.cpp文件(可以看到职工的行为函数都定义为了纯虚函数)
2.定义我们的3个子类
(1).普通员工
普通员工的头文件Employee.h
//普通员工类的定义
#pragma once
//普通员工要继承职工的抽象基类
#include"Worker.h"
#include<iostream>
#include<string>
class Employee:public Worker
{
//重写基类的虚函数
public:
//构造函数
Employee(int Id, string Name, int DeptId);
//显示个人信息
void ShowInfo();
//获取岗位名称
string getDeptName();
//岗位职责
string DeptDuty();
};
普通员工的源文件Employee.cpp
//普通员工类的具体实现
#include"Employee.h"
Employee::Employee(int Id, string Name, int DeptId)
{
this->m_Id = Id;
this->m_Name = Name;
this->m_DeptId = DeptId;
}
//获取岗位名称
string Employee::getDeptName()
{
return string("员工");
}
//岗位职责
string Employee::DeptDuty()
{
return string("完成经理交给的任务");
}
//显示个人信息
void Employee::ShowInfo()
{
cout << "职员编号:" << this->m_Id << endl;
cout << "姓名:" << this->m_Name << endl;
cout << "岗位:" << this->getDeptName() << endl;
cout << "职责:" << this->DeptDuty() << endl;
}
(2).经理
经理的头文件Manager.h
//经理的类定义
#include "Worker.h"
#pragma once
class Manager:public Worker
{
public:
//构造函数
Manager(int Id, string Name, int DeptId);
//显示个人信息
void ShowInfo();
//获取岗位名称
string getDeptName();
//岗位职责
string DeptDuty();
};
经理的源文件Manager.cpp
//经理类的具体实现
#include"Manager.h"
//构造函数
Manager::Manager(int Id, string Name, int DeptId)
{
this->m_Id = Id;
this->m_Name = Name;
this->m_DeptId = DeptId;
}
//显示个人信息
void Manager::ShowInfo()
{
cout << "职员编号:" << this->m_Id << endl;
cout << "姓名:" << this->m_Name << endl;
cout << "岗位:" << this->getDeptName() << endl;
cout << "职责:" << this->DeptDuty() << endl;
}
//获取岗位名称
string Manager::getDeptName()
{
return string("经理");
}
//岗位职责
string Manager::DeptDuty()
{
return string("完成老板交给的任务,给普通员工下达命令");
}
(3).老板
老板的头文件Boss.h
#pragma once
#include "Worker.h"
class Boss :public Worker
{
public:
//构造函数
Boss(int Id, string Name, int DeptId);
//显示个人信息
void ShowInfo();
//获取岗位名称
string getDeptName();
//岗位职责
string DeptDuty();
};
老板的源文件Boss.cpp
#include "boss.h"
//构造函数
Boss::Boss(int Id, string Name, int DeptId)
{
this->m_Id = Id;
this->m_Name = Name;
this->m_DeptId = DeptId;
}
//显示个人信息
void Boss::ShowInfo()
{
cout << "职员编号:" << this->m_Id << endl;
cout << "姓名:" << this->m_Name << endl;
cout << "岗位:" << this->getDeptName() << endl;
cout << "职责:" << this->DeptDuty() << endl;
}
//获取岗位名称
string Boss::getDeptName()
{
return string("老板");
}
//岗位职责
string Boss::DeptDuty()
{
return string("管理公司所有事务");
}
我们可以看出3个派生类的头文件和源文件都相差不大,我们在头文件中都重写了基类中的纯虚函数,这就是多态的实现
其实我们还可以在3个派生类中定义自己独特的行为和属性,而不只是继承基类的行为和属性,不过这样会很复杂,这里就只继承基类的行为和属性就行了
在派生类的源文件中对自己的行为进行实现
将职工的派生类创建完毕后,我们可以在程序中定义一个管理类,用来处理数据表的增删改查
管理类的头文件Workmanager.h
//管理类的定义(菜单的页面,职工信息的增删改查)
#pragma once//防止头文件重复包含
#include"Worker.h"
#include"Employee.h"
#include"Manager.h"
#include"boss.h"
#include<iostream>
#include<string>
#include<fstream>
//定义储存的文件名称
#define FILENAME "empFile.txt"
using namespace std;
class WorkerManager//管理类
{
public:
//行为
WorkerManager();//构造函数
void Show_Menu();//菜单
void Add_Emp();//添加职工
~WorkerManager();//析构函数
void save();//将数据保存到文件
void ExitSystem();//退出系统
//属性
int m_Empnum;//记录职工个数
Worker** m_EmpArray;//职工数组的指针
int m_addnum;//新增加的职工个数
int m_oldnum;//已经储存了数据的最后一位的后面的空位下标
};
由于我们要将3个派生类的信息都存入一个数组,而数组只能存相同类型的数据,所以我们肯定不能直接贮存数据到数组中,我们应该在数组中储存基类的指针,基类的指针能指向派生类对象,这样就能实现在数组中储存3个派生类的数据了(所以管理类中有基类的双重指针,这个指针就维护着储存基类指针的数组,相当于是数据表)
管理类的源文件Workmanager.cpp
//管理类的实现
#include "WorkerManager.h"
//初始化属性
WorkerManager::WorkerManager()
{
this->m_Empnum = 0;
this->m_EmpArray = NULL;
this->m_addnum = 0;
this->m_oldnum = 0;
}
WorkerManager::~WorkerManager()
{
if (this->m_EmpArray)
{
delete[]this->m_EmpArray;
this->m_EmpArray = NULL;
}
}
//菜单
void WorkerManager::Show_Menu()
{
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;
}
//退出系统
void WorkerManager::ExitSystem()
{
cout << "欢迎下次使用" << endl;
system("pause");
exit(0);//用exit(0)无论在哪个循环内都会直接退出系统
}
//添加职工
void WorkerManager::Add_Emp()
{
cout << "请输入添加员工的数量" << endl;
cin >> this->m_addnum;
if (this->m_addnum > 0)//判断用户输入的合法性
{
//计算添加后新空间的大小
//这是一个动态的储存,根据当前新添加的数据和以前的老数据一起再开辟一个新的储存空间,再把原来的空间释放掉(这里实现了数组的动态分配内存)
//新空间的人数=老空间的人数+新增加的人数
int NewSize = this->m_Empnum + this->m_addnum;
//要实现将职员的信息都放在一个数组里,首先肯定不能直接在数组里寸职员的信息,因为数组只能储存相同数据类型的信息,而职员分为了3个类
// 所以只能在数组里存入Worker类型的指针,Worker类型的指针能指向3个子类(员工,经理,老板)的对象
// 要用一个指针来维护这个数组,这个指针只能是Worker类型的双重指针
//开辟新空间
Worker**newspace= new Worker * [NewSize];
//如果原来空间里有信息,先将原来空间里的信息存入
if (this->m_EmpArray)
{
for (int i = 0; i < this->m_Empnum; i++)
{
newspace[i] = this->m_EmpArray[i];
}
//记录原来空间信息最后一位后面空位的下标
this->m_oldnum = this->m_Empnum;
}
//存入新增加的信息
for (int i = 0; i < this->m_addnum; i++)
{
int idd;//职工编号
string name;//名字
int deptid;//部门编号
cout << "请输入第"<<i+1<<"个职工的编号:" << endl;
cin >> idd;
cout << "请输入第" << i + 1 << "个职工的名字:" << endl;
cin >> name;
cout << "请输入第" << i + 1 << "个职工的部门编号:" << endl;
cout << "1.普通职工" << endl;
cout << "2.经理" << endl;
cout << "3.老板" << endl;
//创建基类的指针
Worker* worker = NULL;
int DBD = 1;
while (DBD)
{
//根据输入的部门编号,判断让基类的指针指向什么类型的派生类对象
cin >> deptid;
switch (deptid)
{
case 1:
worker = new Employee(idd, name, deptid);
DBD = 0;
break;
case 2:
worker = new Manager(idd, name, deptid);
DBD = 0;
break;
case 3:
worker = new Boss(idd, name, deptid);
DBD = 0;
break;
default:
cout << "输入有误" << endl;
break;
}
}
//把指向派生类对象的基类指针存入数组
//把新添加的数据放在以前数据的后面
newspace[this->m_oldnum + i] = worker;
}
//释放原来的空间
//删除指向一个变量空间的指针p是delete p,删除指向一个变量数组的指针p是delete[]p;
delete[]this->m_EmpArray;
//让职工数组的指针指向新空间
this->m_EmpArray = newspace;
//更新职工的数量
this->m_Empnum = NewSize;
//提示添加成功
cout << "成功添加" << this->m_addnum << "名职工";
}
}
//将数据保存到文件
void WorkerManager::save()
{
//将程序中的数据输出到文件中是输出流
ofstream ofs;
//用输出流对象ios以输出的方式打开文件
ofs.open(FILENAME, ios::app);
//通过for循环将数据保持到文件
for (int i = this->m_oldnum; i < this->m_Empnum; i++)
{
//输出流所以是左移运算符
ofs << this->m_EmpArray[i]->m_Id << " "
<< this->m_EmpArray[i]->m_Name << " "
<< this->m_EmpArray[i]->m_DeptId << endl;
}
//关闭文件
ofs.close();
}
附上文件打开方式的截图
c++写入文件操作模板
下篇读取文件中的信息到程序中