c艹入门->入土 ( 四 )
C++提高编程
本阶段主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层次的使用
1.模板
1.1 模板的概念
模板就是建立通用的模具,大大提高复用性
1.2 函数模板
C++另一种编程思想称为泛型编程,主要利用的技术就是模板
C++提供两种模板机制: 函数模板 和 类模板
1.2.1 函数模板语法
函数模板作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法:template
函数声明或定义
解释:template – 声明创建模板
typename – 表明其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母
#include
using namespace std;
//交换两个整型函数
void swapInt(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//交换两个浮点型函数
void swapDouble(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
//函数模板
template//声明一个模板,告诉编译器后面代码中的T不要报错,T是通用的数据类型
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
void test01() {
int a = 10;
int b = 20;
//swapInt(a, b);
//利用函数模板交换
//两种方式使用函数模板
//1.自动类型推导
mySwap(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;double c = 1.1;
double d = 2.2;//swapDouble(c, d);
//2.显示指定类型
mySwap(c, d);
cout << "c = " << c << endl;
cout << "d = " << d << endl;
}
int main() {
test01();system("pause");return 0;
}
总结:
1.函数模板利用关键字 template
2.使用函数有两种方式:自动类型推导,显示指定类型
3.模板的目的是为了提高复用性,将类型参数化
1.2.2 函数模板注意事项
注意事项:
1.自动类型推导,必须推导出一致的数据类型T,才可以使用
2.模板必须要确定出T的数据类型,才可以使用
#include
using namespace std;
//函数模板注意事项
template//typename可以替换成class
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
//1.自动类型推导,必须推导出一致的数据类型T才可以使用
void test01() {
int a = 10;
int b = 20;
char c = 'c';mySwap(a, b);
//mySwap(a, c); 错误! 推导不出一致的T类型cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
//2.模板必须要确定出T的数据类型,才可以使用
template
void func() {
cout << “func 调用” << endl;
}
void test02() {
//func(); 不指定类型则错误
func();
}
int main() {
test01();
test02();system("pause");return 0;
}
总结:
使用模板时必须确定出通用类型T,并且能够推导出一致的类型
1.2.3 函数模板案例
案例描述:
1.利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
2.排序规则从大到小,排序算法为选择排序
3.分别利用char数组和int数组进行测试
#include
using namespace std;
//实现通用的 对数组进行排序的函数
//规则 从大到小
//算法 选择
//测试 char 数组 , int 数组
//交换函数模板
template
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
//排序算法
template
void mySort(T arr[], int len) {
for (int i = 0;i < len;i++) {
int max = i;//认定最大值的下标
for (int j = i+1;j < len;j++) {
//认定的最大值 比 遍历出的数值要小,说明j下标的元素才是真正的最大值
if (arr[max] < arr[j]) {
max = j;//更新最大值下标
}
}
if (max != i) {
//交换max和i元素
mySwap(arr[max], arr[i]);
}
}
}
//提供打印数组模板
template
void printArray(T arr[], int len) {
for (int i = 0;i < len;i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void test01() {
//测试char数组
char charArr[] = “emmm”;
int num = sizeof(charArr) / sizeof(char);
mySort(charArr, num);
printArray(charArr, num);
}
void test02() {
//测试int数组
int intArr[] = { 7,5,1,3,9,2,4,6,8 };
int num = sizeof(intArr) / sizeof(int);
mySort(intArr, num);
printArray(intArr, num);
}
int main() {
cout << "test01 测试结果:" << endl;
test01();cout << "test02 测试结果:" << endl;
test02();system("pause");return 0;
}
1.2.4 普通函数与函数模板的区别
普通函数与函数模板区别:
1.普通函数调用时可以发生自动类型转换(隐式类型转换)
2.函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
3.如果利用显示指定类型的方式,可以发生隐式类型转换
#include
using namespace std;
//普通函数与函数模板的区别
//1.普通函数调用可以发生隐式类型转换
//2.函数模板 用自动类型推导,不可以发生隐式类型转换
//3.函数模板 用显示指定类型,可以发生隐式类型转换
//普通函数
int myAdd01(int a, int b) {
return a + b;
}
//函数模板
template
T myAdd02(T a, T b) {
return a + b;
}
void test01() {
int a = 10;
int b = 20;
char c = 'c';//字符转换成整形来运算cout << myAdd01(a, c) << endl;//自动类型推导 不会发生隐式类型转换
cout << myAdd02(a, b) << endl;
//cout << myAdd02(a, c) << endl;错误,无法转换//显示指定类型 会发生隐式类型转换
cout << myAdd02(a, c) << endl;
}
int main() {
test01();system("pause");return 0;
}
总结:
建议使用指定类型转换调用函数模板,因为可以自己确定通用类型T
1.2.5 普通函数与函数模板的调用规则
调用规则如下:
1,如果函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配机制,优先调用函数模板
#include
using namespace std;
// 普通函数与函数模板的调用规则
//1.如果函数模板和普通函数都可以实现,优先调用普通函数
//2.可以通过空模板参数列表来强制调用函数模板
//3.函数模板也可以发生重载
//4.如果函数模板可以产生更好的匹配, 优先调用函数模板
void myPrint(int a, int b) {
cout << “调用的普通函数” << endl;
}
template
void myPrint(T a, T b) {
cout << “调用的模板” << endl;
}
template
void myPrint(T a, T b, T c) {
cout << “调用重载的模板” << endl;
}
void test01() {
int a = 10;
int b = 20;
myPrint(a, b);//通过空模板参数列表,强制调用函数模板
myPrint<>(a, b);myPrint<>(a, b, 100);//如果函数模板产生更好的匹配,优先调用函数模板
char c1 = 'a';
char c2 = 'b';myPrint(c1, c2);
}
int main() {
test01();system("pause");return 0;
}
1.2.6 模板的局限性
局限性:模板的通用性不是万能的
template
void f(T a, T b) {
a = b;
}
上述代码中提供赋值操作,如果传入的a和b是一个数组,就无法实现
再例如:
template
void f(T a, T b) {
if (a > b) {
…
}
}
在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板
#include
#include
using namespace std;
//模板的局限性
//模板不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
class Person {
public:
Person(string name, int age) {this->m_Name = name;this->m_Age = age;
}string m_Name;
int m_Age;
};
//对比两个数据是否相等函数
template
bool myCompare(T& a, T& b) {
if (a == b) {
return true;
}
else {
return false;
}
}
//利用具体化的Person版本是实现代码,具体化优先调用
template<>bool myCompare(Person& p1, Person& p2) {
if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) {
return true;
}
else {
return false;
}
}
void test01() {
int a = 10;
int b = 20;
bool ret = myCompare(a, b);if (ret) {cout << "a == b" << endl;
}
else {cout << "a != b" << endl;
}
}
void test02() {
Person p1(“Tom”, 10);
Person p2(“Tom”, 10);
bool ret = myCompare(p1, p2);
if (ret) {cout << "p1 == p2" << endl;
}
else {cout << "p1 != p2" << endl;
}
}
int main() {
test01();test02();system("pause");return 0;
}
总结:
1.利用具体化的模板,可以解决自定义类型的通用化
2.学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
1.3 类模板
1.3.1 类模板语法
类模板作用:建立一个通用类,类中的成员,数据类型可以不具体指定,用一个虚拟的类型来代表
语法: template
类
解释:template — 声明创建模板
typename — 表明其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母
#include
#include
using namespace std;
//类模板
template
class Person {
public:
Person(NameType name, AgeType age) {
this->m_Name = name;
this->m_Age = age;
}
void showPerson() {cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;
}NameType m_Name;
AgeType m_Age;
};
void test01() {
Person
}
int main() {
test01();system("pause");return 0;
}
总结:
类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板
1.3.2 类模板和函数模板区别
类模板与函数模板主要有两点区别:
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数
#include
using namespace std;
//类模板与函数模板的区别
template
class Person {
public:
Person(NameType name, AgeType age) {this->m_Age = age;this->m_Name = name;
}void showPerson() {cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;
}NameType m_Name;
AgeType m_Age;
};
//1.类模板没有自动类型推导的使用方式
void test01() {
//Person p(“孙悟空”, 999);错误,无法用自动类型推导
Personp("孙悟空", 999);//正确,只能用显示指定类型p.showPerson();
}
//2.类模板在模板参数列表中可以有默认参数
void test02() {
Personp(“猪八戒”, 999);
p.showPerson();
}
int main() {
test01();test02();system("pause");return 0;
}
总结:
1.类模板使用只能用显示指定类型方式
2.类模板中的模板参数可以有默认参数
1.3.3 类模板中成员函数创建时机
类模板中成员函数和普通类中成员函数创建时机是有区别的:
1.普通类中的成员函数一开始就可以创建
2.类模板中的成员函数在调用时才创建
#include
using namespace std;
//类模板中成员函数创建时机
//类模板中成员函数在调用时才去创建
class Person1 {
public:
void showPerson1() {
cout << “Person1 show” << endl;
}
};
class Person2 {
public:
void showPerson2() {
cout << “Person2 show” << endl;
}
};
template
class MyClass {
public:
T obj;
//类模板中的成员函数
void func1() {obj.showPerson1();
}void func2() {obj.showPerson2();
}
};
void test01() {
MyClassm;
m.func1();
//m.func2();
}
int main() {
test01();system("pause");return 0;
}
总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建
1.3.4 类模板对象做函数参数
学习目标:类模板实例化出的对象,向函数传参
一共有三种传入方式:
1.指定传入的类型 — 直接显示对象的数据类型
2.参数模板化 — 将对象中的参数变为模板进行传递
3.整个类模板化 — 将这个对象类型模板化进行传递
#include
//#include
using namespace std;
//类模板对象做函数参数
template
class Person {
public:
Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
void showPerson() {cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}T1 m_Name;
T2 m_Age;
};
//1.指定传入类型
void printPerson1(Person
p.showPerson();
}
void test01() {
Person
printPerson1§;
}
//2.参数模板化
template
void printPerson2(Person
p.showPerson();
cout << "T1 的类型为: " << typeid(T1).name() << endl;
cout << "T2 的类型为: " << typeid(T2).name() << endl;
}
void test02() {
Person
printPerson2§;
}
//3.整个类模板化
template
void printPerson3(T& p) {
p.showPerson();
cout << “T的数据类型为:” << typeid(T).name() << endl;
}
void test03() {
Person
printPerson3§;
}
int main() {
test01();test02();test03();system("pause");return 0;
}
1.3.5 类模板与继承
当类模板遇到继承时,需要注意几点:
1.当子类继承的父类时一个类模板的时候,子类在声明的时候,要指定出父类中T的位置
2.如果不指定,编译器无法给子类分配内存
3.如果想灵活指定出父类中T的类型,子类也需要变为类模板
#include
using namespace std;
//类模板与继承
template
class Base {
T m;
};
//class Son:public Base{ — 错误,必须知道父类中的T类型,才能继承给子类
class Son:public Base {
};
void test01() {
Son s1;
}
//如果想灵活指定父类中T类型,子类也需要变类模板
template
class Son2 :public Base {
public:
Son2() {
cout << “T1的类型为:” << typeid(T1).name() << endl;
cout << “T2的类型为:” << typeid(T2).name() << endl;
}
T1 obj;
};
void test02() {
Son2
}
int main() {
//test01();
test02();system("pause");return 0;
}
总结:
如果父类是类模板,子类需要指定出父类中的T的数据类型
1.3.6 类模板成员代码类外实现
学习目标:能够掌握类模板中的成员函数类外实现
#include
using namespace std;
//类模板成员函数的类外实现
template
class Person {
public:
Person(T1 name, T2 age);
/{
this->m_Age = age;
this->m_Name = name;
}/
void showPerson();
/*{cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;
}*/T1 m_Name;
T2 m_Age;
};
//构造函数类外实现
template
Person
this->m_Age = age;
this->m_Name = name;
}
//成员函数类外实现
template
void Person
cout << “姓名:” << this->m_Name << “年龄:” << this->m_Age << endl;
}
void test01() {
Person
P.showPerson();
}
int main() {
test01();system("pause");return 0;
}
总结:
类模板中成员函数类外实现时,需要加上模板参数列表
1.3.7 类模板分文件编写
学习目标:掌握类模板成员函数分文件编写产生的问题以及解决方式
问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:
解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制
头文件:
#pragma once
#include
using namespace std;
//类模板分文件编写问题以及解决
template
class Person {
public:
Person(T1 name, T2 age);
void showPerson();T1 m_Name;
T2 m_Age;
};
template
Person
this->m_Name = name;
this->m_Age = age;
}
template
void Person
cout << “姓名:” << this->m_Name << " 年龄:" << this->m_Age << endl;
}
源文件:
#include
using namespace std;
//第一种解决方式,直接包含源文件
//#include"person.cpp"
//第二种解决方式,将.h和.cpp中的内容写到一起,将后缀名写成.hpp文件
#include"person.hpp"
//类模板分文件编写问题以及解决
//template
//class Person {
//public:
// Person(T1 name, T2 age);
//
// void showPerson();
//
// T1 m_Name;
// T2 m_Age;
//};
//template
//Person
//
//}
//
//template
//void Person
// cout << “姓名:” << this->m_Name << “年龄:” << this->m_Age << endl;
//}
void test01() {
Person
p.showPerson();
}
int main() {
test01();system("pause");return 0;
}
总结:
主流的解决方法是第二种,把类模板成员函数写到一起,并将后缀名改为.hpp
1.3.8 类模板与友元
学习目标:掌握类模板配合友元函数的类内和类外实现
全局函数类内实现 - 直接在类内声明友元即可
全局函数类外实现 - 需要提前让编译器知道全局函数的存在
#include
#include
using namespace std;
//通过全局函数 打印Person信息
//提前让编译器知道Person类存在
template
class Person;
//类外实现
template
void printPerson2(Person
cout << “类外实现 — 姓名:” << p.m_Name << " 年龄:" << p.m_Age << endl;
}
template
class Person {
//全局函数 类内实现
friend void printPerson(Person
cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}
//全局函数 类外实现
//加空模板参数列表
//如果成员是类外实现 需要让编译器提前知道这个函数的存在
friend void printPerson2<>(Personp);
public:
Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
//1.全局函数在类内实现
void test01() {
Person
printPerson(p);
}
//2.全局函数在类外实现
void test02() {
Person
printPerson2(p);
}
int main() {
test01();test02();system("pause");return 0;
}
总结:
建议全局函数做类内实现用法简单,而且编译器可以直接识别
职工管理系统
1.管理系统需求
职工管理系统可以用来管理所有员工的信息
主要利用C++实现一个基于多态的职工管理系统
公司中职工分为三类:普通员工,经理,老板,显示信息时,需要显示职工编号,职工姓名,职工岗位以及职责
普通员工职责:完成经理交给的任务
经理职责:完成老板交给的任务,并下发任务给员工
老板职责:管理公司所有事务
管理系统中需要实现的功能如下:
退出管理系统:退出当前管理系统
增加职工信息:实现批量增加职工功能,将信息录入到文件中,职工信息为:职工编号,姓名,部门编号
显示职工信息:显示公司内部所有职工的信息
删除离职职工:按照编号删除指定的员工
修改职工信息:按照编号修改职工个人信息
查找职工信息:按照职工的编号或者职工的姓名进行查找相关的人员信息
按照编号排序:按照职工编号,进行排序,排序规则由用户指定
清空所有文档:清空文件中记录的所有职工信息(清空前需要再次确认,防止误删)
2.创建项目
2.1 创建项目
2.2 添加文件
3.创建管理类
管理负责的内容如下:
1.与用户的沟通菜单界面
2.对职工删改改查的操作
3.与文件的读写交互
3.1 创建文件
在头文件和源文件的文件夹下分别创建workerManager.h和workerManager.cpp文件
3.2 头文件实现
在workerManager.h中设计管理类
3.3 源文件实现
在workerManager.cpp中将构造和析构函数空实现补全
4.菜单功能
功能描述 : 与用户的沟通界面
4.1 添加成员函数
在管理类workerManager.h中添加成员函数void show_Menu();
4.2 菜单功能实现
在管理类workerManager.cpp中实现Show_Menu()函数
4.3测试菜单功能
在职工管理系统.cpp中测试菜单功能
5.退出功能
5.1 提供功能接口
在main函数中提供分支选择,提供每个功能接口
5.2 实现退出功能
在workerManager.h中提供退出系统的成员函数 void exitSystem();
在WorkerManager.cpp中提供具体的功能实现
5.3 测试功能
在main函数分支0选项中,调用退出程序的接口
6.创建职工类
6.1 创建职工抽象类
职工的分类为:普通员工,经理,老板
将三种职业抽象到一个类(worker)中,利用多态管理不同职工种类
职工的属性为:职工编号,职工姓名,职工所在部门编号
职工的行为为:岗位职责信息描述,获得岗位名称
头文件文件夹下 创建文件worker.h文件并且添加代码
6.2 创建普通员工类
普通员工继承职工抽象类, 并重写父类中纯虚函数
在头文件和源文件的文件夹下分别创建employee.h和employee.cpp文件
6.3 创建经理类
经理类继承职工抽象类,并重写父类中纯虚函数,和普通员工类似
在头文件和源文件下分别创建manager.h和manager.cpp文件
6.4 创建老板类
老板类继承职工抽象类,并重写父类中纯虚函数,和普通员工类似
在头文件和源文件的文件夹下分别创建boss.h和boss.cpp文件
6.5 测试多态
在职工管理系统.cpp中添加测试函数,并且运行能够产生多态
- 添加职工
功能描述:批量添加职工,并且保存到文件中
7.1 功能分析
用户在批量创建时,可能会创建不同种类的职工
如果想将所有不同种类的员工都放入到一个数组中,可以将所有员工的指针维护到一个数组里
如果想在程序中维护这个不定长度的数组,可以将数组创建到堆区,并利用Worker*的指针维护
7.2 功能实现
在workerManager.h头文件中添加成员属性代码
在workerManager构造函数中初始化属性
在workerManager.h中添加成员函数
workerManager.cpp中实现该函数
8.文件交互 - 写文件
功能描述:对文件进行读写
在上一个添加功能中,我们只是将所有的数据添加到了内存中,一旦程序结束就无法保存了
因此文件管理类中需要一个与文件进行交互的功能,对于文件进行读写操作
8.1 设定文件路径
首先我们将文件路径在workerManager.h中添加宏常量,并且包含头文件fstream
8.2 成员函数声明
在workerManager.h中类里添加成员函数void save()
8.3 保存文件功能实现
8.4 保存文件功能测试
在添加职工功能中添加成功后添加保存文件函数
- 文件交互 - 读文件
功能描述:将文件中的内容读取到程序中
虽然我们实现了添加职工后保存早文件的操作,但是每次开始运行程序,并没有将文件中数据读取到程序中
而我们的程序功能中还有清空文件的需求
因此构造函数初始化数据的情况分为三种
1.第一次使用,文件未创建
2.文件存在,但是数据被用户清空
3.文件存在,并且保持职工的所有数据
9.1 文件未创建
在workerManager.h中添加新的成员属性m_FileIsEmpty标志文件是否为空
修改WorkerManager.cpp中构造函数代码
9.1 文件未创建
在workerManager.h中添加新的成员属性m_FileIsEmpty标志文件是否为空
修改WorkerManager.cpp中构造函数代码
删除文件后,测试文件不存在时初始化数据功能
9.2 文件存在且数据为空
在workerManager.cpp中的构造函数追加代码
将文件创建后清空文件内容,并测试该情况下初始化功能
我们发现文件不存在或者为空清空m_FileIsEmpty判断问价是否为空的标志都为真,那何时为假
成功添加职工后,应该更改文件不为空的标志
9.3 文件存在且保存职工数据
9.3.1 获取记录的职工人数
在workerManager.h中添加成员函数 int get_Empty();
workerManager.cpp中实现
9.3.2 初始化数组
根据职工的数据以及职工的数据, 初始化workerManager中的Worker** m_EmpArray指针
在workerManager.h中添加成员函数 void init_Emp();
在WorkerManager.cpp中实现
10.显示员工
功能描述 : 显示当前所有职工信息
10.1 显示职工声明
在workerManager.h中添加成员函数 void Show_Emp();
10.2 显示职工函数实现
在workerManager.cpp中实现成员函数 void Show_Emp();
11.删除职工
功能描述 : 按照职工的编号进行职工操作
11.1 删除职工函数声明
在workerManager.h中添加成员函数 void Del_Emp();
11.2 职工是否存在函数声明
很多功能都需要用到根据职工是否存在来进行操作如 : 删除职工, 修改职工, 查找职工
因此添加该公告函数, 以便后续调用
在workerManager.h中添加成员函数 int IsExist(int id);
11.3 职工是否存在函数实现
在workerManager.cpp中实现成员函数 int IsExist(int id);
11.4 删除职工函数实现
在workerManager.cpp中实现成员函数 void Del_Emp();
12.修改职工
功能描述 : 能够按照职工的编号对职工信息进行修改并保存
12.1 修改职工函数声明
在workerManager.h中添加成员函数 void Mod_Emp();
12.2 修改职工函数实现
在workerManager.cpp中实现成员函数 void Mod_Emp();
13.查找职工
功能描述 : 提供两种查找职工的方式, 一种按照职工编号, 一种按照职工姓名
13.1 查找职工函数声明
在workerManager.h中添加成员函数 void Find_Emp();
13.2 查找职工函数实现
在workManager.cpp中实现成员函数 void Find_Emp();
14.排序
功能描述 : 按照职工编号进行排序, 排序的顺序由用户指定
14.1 排序函数声明
在workerManager.h中添加成员函数 void Sort_Emp();
14.2 排序函数实现
在workerManager.cpp中实现成员函数 void Sort_Emp();
15.清空文件
功能描述 : 将文件中记录数据清空
15.1 清空函数声明
在workerManager.h中添加成员函数 void Clean_File();
15.2 清空函数实现
在workerManager.cpp中实现成员函数 void Clean_File();
头文件:
boss.h
#pragma once
#pragma once
#include
using namespace std;
#include"worker.h"
class Boss :public Worker {
public:
//构造函数
Boss(int id, string name, int dId);
//显示个人信息
virtual void showInfo();
//获取岗位名称
virtual string getDeptName();
};
employee.h
#pragma once
//普通员工文件
#include
#include"worker.h"
using namespace std;
class Employee :public Worker {
public:
//构造函数
Employee(int id,string name,int dId);
//显示个人信息
virtual void showInfo();
//获取岗位名称
virtual string getDeptName();
};
manager.h
#pragma once
#include
using namespace std;
#include"worker.h"
class Manager :public Worker {
public:
//构造函数
Manager(int id, string name, int dId);
//显示个人信息
virtual void showInfo();
//获取岗位名称
virtual string getDeptName();
};
worker.h
#pragma once
#include
#include
using namespace std;
//职工抽象类
class Worker {
public:
//显示个人信息
virtual void showInfo() = 0;
//获取岗位名称
virtual string getDeptName() = 0;
//职工编号
int m_Id;
//职工姓名
string m_Name;
//部门编号
int m_DeptId;
};
workManager.h
#pragma once//防止头文件重复包含
#include
#include
#include
#include"worker.h"
#include"worker.h"
#include"manager.h"
#include"boss.h"
#include"employee.h"
using namespace std;
#define FILENAME “empFile.txt”
class WorkerManager {
public:
//构造函数
WorkerManager();
//展示菜单
void show_Menu();//退出系统
void ExitSystem();//记录职工人数
int m_EmpNum;//职工数组指针
Worker** m_EmpArray;//添加职工
void Add_Emp();//保存文件
void save();//判断文件是否为空 标志
bool m_FileIsEmpty;//统计文件中人数
int get_Empty();//初始化员工
void init_Emp();//显示职工
void Show_Emp();//删除职工
void Del_Emp();//按照职工编号判断职工是否存在,若存在返回职工所在数组中的位置,不存在返回-1
int IsExist(int id);//修改职工
void Mod_Emp();//查找职工
void Find_Emp();//按照编号排序
void Sort_Emp();//清空文件
void Clean_File();//析构函数
~WorkerManager();
};
源文件
boss.cpp
#include"boss.h"
//构造函数
Boss::Boss(int id, string name, int dId) {
this->m_Id = id;
this->m_Name = name;
this->m_DeptId = dId;
}
//显示个人信息
void Boss::showInfo() {
cout << “职工编号:” << this->m_Id
<< “\t职工姓名:” << this->m_Name
<< “\t岗位:” << this->getDeptName()
<< “\t岗位职责: 管理公司所有事务” << endl;
}
//获取岗位名称
string Boss::getDeptName() {
return string(“总裁”);
}
employee.cpp
#include"employee.h"
//构造函数
Employee::Employee(int id, string name, int dId) {
this->m_Id = id;
this->m_Name = name;
this->m_DeptId = dId;
}
//显示个人信息
void Employee::showInfo() {
cout << “职工编号:” << this->m_Id
<< “\t职工姓名:” << this->m_Name
<< “\t岗位:” << this->getDeptName()
<< “\t岗位职责: 完成经理交给的任务” << endl;
}
//获取岗位名称
string Employee::getDeptName() {
return string(“员工”);
}
manager.cpp
#include"manager.h"
//构造函数
Manager::Manager(int id, string name, int dId) {
this->m_Id = id;
this->m_Name = name;
this->m_DeptId = dId;
}
//显示个人信息
void Manager::showInfo() {
cout << “职工编号:” << this->m_Id
<< “\t职工姓名:” << this->m_Name
<< “\t岗位:” << this->getDeptName()
<< “\t岗位职责: 完成老板交给的任务,并下发任务给员工” << endl;
}
//获取岗位名称
string Manager::getDeptName() {
return string(“经理”);
}
workerManager.cpp
#include"workerManager.h"
WorkerManager::WorkerManager() {
//文件不存在
ifstream ifs;
ifs.open(FILENAME, ios::in);//读文件
if (!ifs.is_open()) {cout << "文件不存在!" << endl;//初始化属性//初始化记录人数this->m_EmpNum = 0;//初始化数组指针this->m_EmpArray = NULL;//初始化文件是否为空this->m_FileIsEmpty = true;ifs.close();return;
}//2.文件存在,数据为空
char ch;
ifs >> ch;
if (ifs.eof()) {//文件为空cout << "文件为空!" << endl;//初始化记录人数this->m_EmpNum = 0;//初始化数组指针this->m_EmpArray = NULL;//初始化文件是否为空this->m_FileIsEmpty = true;ifs.close();return;
}//3.文件存在,并且记录数据
int num = this->get_Empty();
cout << "职工人数为:" << num << endl;
this->m_EmpNum = num;this->m_EmpArray = new Worker * [this->m_EmpNum];
//将文件中的数据 存入数组中
this->init_Emp();for (int i = 0;i < this->m_EmpNum;i++) {cout << "职工编号:" << this->m_EmpArray[i]->m_Id<< " 姓名:" << this->m_EmpArray[i]->m_Name<< " 部门编号:" << m_EmpArray[i]->m_DeptId << endl;
}
}
void WorkerManager::show_Menu() {
cout << “*******************************" << endl;
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;
cout << endl;
}
//退出系统
void WorkerManager::ExitSystem() {
cout << “欢迎下次使用” << endl;
system(“pause”);
exit(0);//退出程序
}
//添加职工
void WorkerManager::Add_Emp() {
cout << “请输入添加职工数量:” << endl;
int addNum = 0;//保存用户的输入数量
cin >> addNum;if (addNum > 0) {//添加//计算添加新空间大小int newSize = this->m_EmpNum + addNum;//新空间人数 = 原来人数 + 新增人数//开辟新空间Worker** newSpace = new Worker * [newSize];//将原来空间下数据拷贝到新空间下if (this->m_EmpNum != NULL) {for (int i = 0;i < this->m_EmpNum;i++) {newSpace[i] = this->m_EmpArray[i];}}//批量添加新数据for (int i = 0;i < addNum;i++) {int id;//string name;int dSelect;cout << "请输入第 " << i + 1 << " 个新职工编号" << endl;cin >> id;cout << "请输入第 " << i + 1 << " 个新职工姓名" << endl;cin >> name;cout << "请选择该职工岗位:" << endl;cout << "1.普通职工" << endl;cout << "2.经理" << endl;cout << "3.老板" << endl;cin >> dSelect;Worker* worker = NULL;switch (dSelect){case 1:worker = new Employee(id, name, 1);case 2:worker = new Manager(id, name, 2);case 3:worker = new Boss(id, name, 3);default:break;}//将创建的职工指针保存到数组中newSpace[this->m_EmpNum + i] = worker;}//释放原有的空间delete[] this->m_EmpArray;//更新新空间的指向this->m_EmpArray = newSpace;//更新新的职工人数this->m_EmpNum = newSize;//更新职工不为空this->m_FileIsEmpty = false;//成功添加后保存到文件中this->save();//提示添加成功cout << "成功添加" << addNum << "名新职工!" << endl;
}
else {cout << "输入数据有误" << endl;
}//按任意键后 清屏回到上级目录
system("pause");
system("cls");
}
//保存文件
void WorkerManager::save() {
ofstream ofs;
ofs.open(FILENAME,ios::out);//用输出方式打开文件 - 写文件
//将每个人数据写入到文件中
for (int i = 0;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();
}
//统计文件中人数
int WorkerManager::get_Empty() {
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int dId;int num = 0;while (ifs >> id && ifs >> name && ifs >> dId) {//统计人数num++;
}
return num;
}
//初始化员工
void WorkerManager::init_Emp() {
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int dId;int index = 0;while (ifs >> id && ifs >> name && ifs >> dId) {Worker* worker = NULL;if (dId == 1) {//普通员工worker = new Employee(id, name, dId);}if (dId == 2) {//经理worker = new Manager(id, name, dId);}if (dId == 3) {//老板worker = new Boss(id, name, dId);}this->m_EmpArray[index] = worker;index++;
}//关闭文件
ifs.close();
}
//显示函数
void WorkerManager::Show_Emp() {
//判断文件是否为空
if (this->m_FileIsEmpty) {
cout << “文件不存在或记录为空!” << endl;
}
else {
for (int i = 0;i < m_EmpNum;i++) {
//利用多态调用程序接口
this->m_EmpArray[i]->showInfo();
}
}
//按任意键清屏
system(“pause”);
system(“cls”);
}
//删除职工
void WorkerManager::Del_Emp() {
if (this->m_FileIsEmpty) {
cout << “文件不存在或记录为空!” << endl;
}
else {
//按照职工编号删除
cout << “请输入想要删除职工编号:” << endl;
int id = 0;
cin >> id;
int index = this->IsExist(id);if (index != -1) {//说明职工存在,并且要删除index位置的职工//数据前移for (int i = index;i < this->m_EmpNum - 1;i++) {this->m_EmpArray[i] = this->m_EmpArray[i + 1];}//更新数组中记录人员个数this->m_EmpNum--;//数据同步更新到文件中this->save();cout << "删除成功!" << endl;}else {cout << "删除失败,未找到该职工" << endl;}
}
//按任意键清屏
system("pause");
system("cls");
}
//按照职工编号判断职工是否存在,若存在返回职工所在数组中的位置,不存在返回-1
int WorkerManager::IsExist(int id) {
int index = -1;
for (int i = 0;i < this->m_EmpNum;i++) {if (this->m_EmpArray[i]->m_Id == id) {//找到职工index = i;break;}
}
return index;
}
//修改职工
void WorkerManager::Mod_Emp() {
if (this->m_FileIsEmpty) {
cout << “文件不存在或者记录为空!” << endl;
}
else {
cout << “请输入修改职工的编号:” << endl;
int id;
cin >> id;
int ret = this->IsExist(id);if (ret != -1) {//查找到编号的职工delete this->m_EmpArray[ret];int newId = 0;string newName = "";int dSelect = 0;cout << "查到: " << id << "号职工,请输入新职工号:" << endl;cin >> newId;cout << "请输入新姓名:" << endl;cin >> newName;cout << "请输入岗位:" << endl;cout << "1.普通职工" << endl;cout << "2.经理" << endl;cout << "3.老板" << endl;cin >> dSelect;Worker* worker = NULL;switch (dSelect){case 1:worker = new Employee(newId, newName, dSelect);case 2:worker = new Manager(newId, newName, dSelect);case 3:worker = new Boss(newId, newName, dSelect);default:break;}//更新数据到数组中this->m_EmpArray[ret] = worker;cout << "修改成功!" << endl;//保存到文件中this->save();}else{cout << "修改失败,查无此人!" << endl;}
}
//按任意键清屏
system("pause");
system("cls");
}
//查找职工
void WorkerManager::Find_Emp() {
if (this->m_FileIsEmpty) {
cout << “文件不存在或记录为空!” << endl;
}
else {
cout << “请输入查找的方式:” << endl;
cout << “1.按照职工的编号查找” << endl;
cout << “2.按职工姓名查找” << endl;
int select = 0;cin >> select;if (select == 1) {//按照编号查int id;cout << "请输入要查找的职工编号:" << endl;cin >> id;int ret = IsExist(id);if (ret != -1) {//找到职工cout << "查找成功!该职工信息如下:" << endl;this->m_EmpArray[ret]->showInfo();}else {cout << "查找失败!" << endl;}}else if (select == 2) {//按照姓名查string name;cout << "请输入查找的姓名:" << endl;cin >> name;//加入判断是否查到的标志bool flag = false;//默认未找到职工for (int i = 0;i < m_EmpNum;i++) {if (this->m_EmpArray[i]->m_Name == name) {cout << "查找成功,职工编号为: " << this->m_EmpArray[i]->m_Id << "号职工信息如下:" << endl;flag = true;//调用显示信息接口this->m_EmpArray[i]->showInfo();}}if (flag == false) {cout << "查找失败,查无此人!" << endl;}}else {cout << "输入选项有误!" << endl;}
}
//按任意键清屏
system("pause");
system("cls");
}
//按照编号排序
void WorkerManager::Sort_Emp() {
if (this->m_FileIsEmpty) {
cout << “文件不存在或记录为空!” << endl;
system(“pause”);
system(“cls”);
}
else {
cout << “请选择排序方法:” << endl;
cout << “1.按职工号进行升序” << endl;
cout << “2.按职工号进行降序” << endl;
int select = 0;cin >> select;for (int i = 0;i < m_EmpNum;i++) {int minOrMax = i;//声明最小值 或 最大值下标for (int j = i + 1;j < this->m_EmpNum;j++) {if (select == 1) {//升序if (this->m_EmpArray[minOrMax]->m_Id > this->m_EmpArray[j]->m_Id) {minOrMax = j;}}else {//降序if (this->m_EmpArray[minOrMax]->m_Id < this->m_EmpArray[j]->m_Id) {minOrMax = j;}}}//判断一开始认定 最小值或最大值 是不是计算的最小值或最大值,如果不是 交换数据if (i != minOrMax) {Worker* temp = this->m_EmpArray[i];this->m_EmpArray[i] = this->m_EmpArray[minOrMax];this->m_EmpArray[minOrMax] = temp;}}cout << "排序成功!排序后的结果为:" << endl;this->save();//排序后结果保存到文件中this->Show_Emp();//展示所有职工
}
}
//清空文件
void WorkerManager::Clean_File() {
cout << “确定清空?” << endl;
cout << “1.确定” << endl;
cout << “2.返回” << endl;
int select = 0;
cin >> select;
if (select == 1) {//清空文件ofstream ofs(FILENAME, ios::trunc);//删除文件后重新创建ofs.close();if (this->m_EmpArray != NULL) {//删除堆区的每个职工对象for (int i = 0;i < m_EmpNum;i++) {delete this->m_EmpArray[i];this->m_EmpArray[i] = NULL;}//删除堆区数组指针delete[] this->m_EmpArray;this->m_EmpArray = NULL;this->m_EmpNum = 0;this->m_FileIsEmpty = true;}cout << "清空成功!" << endl;system("pause");system("cls");
}
}
WorkerManager::~WorkerManager() {
/if (this->m_EmpArray != NULL) {
delete[] this->m_EmpArray;
this->m_EmpArray = NULL;
}/
if (this->m_EmpArray != NULL) {
for (int i = 0;i < m_EmpNum;i++) {
if (this->m_EmpArray[i] != NULL) {
delete this->m_EmpArray[i];
}
}
delete[] this->m_EmpArray;this->m_EmpArray = NULL;
}
}
职工管理系统.cpp
#include
#include"workerManager.h"
#include"worker.h"
#include"employee.h"
#include"manager.h"
#include"boss.h"
using namespace std;
int main() {
//实例化管理者对象
WorkerManager wm;int choice = 0;//用来存储用户的选项while (true) {//调用展示菜单成员函数wm.show_Menu();cout << "请输入您的选择:" << endl;cin >> choice;//接受用户的选项switch (choice){case 0://退出系统wm.ExitSystem();break;case 1://增加职工wm.Add_Emp();break;case 2://显示职工wm.Show_Emp();break;case 3://删除职工wm.Del_Emp();break;case 4://修改职工wm.Mod_Emp();break;case 5://查找职工wm.Find_Emp();break;case 6://排序职工wm.Sort_Emp();break;case 7://清空文档wm.Clean_File();break;default:system("cls");break;}
}//调用展示菜单成员函数
wm.show_Menu();测试代码
//Worker* worker = NULL;
//worker = new Employee(1,“张三”,1);
//worker->showInfo();
//delete worker;
//worker = new Manager(2, “李四”, 2);
//worker->showInfo();
//delete worker;
//worker = new Boss(3, “王五”, 3);
//worker->showInfo();
//delete worker;
system("pause");return 0;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
