Day 9知识点:
1.基于多态的管理项目实现
需求:
一个小型公司的人员信息管理系统
某小型公司,主要有四类人员:经理、技术人员、销售经理和推销员。现在,需要存储这些人员的姓名、编号、级别、当月薪水.计算月薪总额并显示全部信息。
人员编号基数为 1000,每输入一个人员信息编号顺序加 1。
程序要有对所有人员提升级别的功能。本例中为简单起见,所有人员的初始级别均为 1级。然后进行升级,经理升为 4 级,技术人员和销售经理升为 3 级,推销员仍为 1 级。
月薪计算办法是: 经理拿固定月薪 8000 元;技术人员按每小时 100 元领取月薪; 推销员的月薪按该推销员当月销售额的 4%提成;销售经理既拿固定月薪也领取销售提成,固定月薪为 5000 元,销售提成为所管辖部门当月销售总额的 5%。
详细设计:
父类
属性:
string 姓名、int 编号、int 级别、float 当月薪水
static startNum;
行为:
void getPay()计算月薪总额
void disInfor()显示全部信息
若想实现每次输入名字时都规定输入员工工作种类,如 please input technician's name
假如把employee.cpp中的构造函数中的
cout<<"please input name:";
cin>>name;
删除并分别在子类的cpp文件的构造函数中加上相应的工种员工名字输入,如:
Manager::Manager()
{
cout<<"please input Manager's name:";
cin>>name;
fixSalary = 8000;
}
会出现重复输入无用数据的情况,文件名为Company2,实验结果如下:
这是因为SalesManager子类继承父类Manager和Salesman时把他们的构造函数一同继承来,导致SalesManager类构造函数的重复构造,解决方法是把初始化信息不放在构造函数中,这样继承父类的时候就可以用自己的初始化函数而不使用继承的构造函数,解决初始化过程中出现的重复构造问题。在父类中创建纯虚函数init,各个子类中创建新函数init,将子类中的构造函数内容都移至init()中,在main函数中利用指向子类地址的父类指针来调用init()函数。如:
#include "manager.h"
Manager::Manager()
{
}
void Manager::init()
{
cout<<"please input Manager's name:";
cin>>name;
fixSalary = 8000;
}
Employee *emp[] = {new Technician,new Manager,new SalesMan,new SalesManager};
for(int i = 0;i<sizeof(emp)/sizeof(emp[0]);i++)
{
emp[i]->init();
emp[i]->calcSalary();
emp[i]->promote();
emp[i]->disInfo();
cout<<"--------------------"<<endl;
}
文件名为company,最后实验结果为:
2.虚函数表(听得不是很懂。。此处不做笔记)
3.typeid()函数的使用
typeid()函数被包含在#include<typeinfo>头文件中,使用时直接将变量,类型或表达式当做函数参数,返回值为动态类型信息,如对引用使用typeid()函数,返回的是所引用的变量的类型,对指针解引用使用typeid使用,返回的是指针指向的类型,但如果对指针使用,只会返回指针本身的类型。一般只用在多态的父子类当中。
在项目1中,可以通过typeid()来对单一子类的某非继承成员函数进行调用,如提升Manager的工资操作,代码如下:
for(int i = 0;i<sizeof(emp)/sizeof(emp[0]);i++)
{
emp[i]->init();
if(typeid(*emp[i]) == typeid(Manager))
{
Manager *t = dynamic_cast<Manager*>(emp[i]);
t->addFixSalary(30000);
}
emp[i]->calcSalary();
emp[i]->promote();
emp[i]->disInfo();
cout<<"--------------------"<<endl;
}
最后实现代码为company文件
4.typecast
static_cast
在一个方向上可以做隐式转换,在另一个方向上可做静态转换,如子类地址可以赋给父类指针,则父类指针可以静态转换给子类,既可以向上转换,也可以向下转换。发生在编译阶段。
B b;
A *pa = &b;
B *pb = static_cast<B*>(pa); //成功,安全
cout<<pb<<endl;
C *pc = static_cast<C*>(pa); //成功,不安全,使得B类型b的地址可以访问C中的func
cout<<pc<<endl;
pc->func();
D *pd = static_cast<D*>(pa); //不成功
reinterpret_cast
安全性由程序员决定。既不在编译器阶段也不在运行期进行检查。
B b;
A *pa = &b;
B *pb = reinterpret_cast<B*>(pa); // 成功,返回其地址,不安全
cout<<pb<<endl;
C *pc = reinterpret_cast<C*>(pa); // 成功,返回其地址,不安全
cout<<pc<<endl;
pc->func();
D *pd = reinterpret_cast<D*>(pa); // 成功,返回其地址,不安全
cout<<pd<<endl;
dynamic_cast
dynamic_cast 一种运行时的类型转化方式,所以要在运行时作转换判断,只能在含有虚函数的父子类中才能使用,只能向下转换。
会自动判断是否得到其目标类型,如果是则返回其指针,如果不是,则返回NULL。
B b;
A *pa = &b;
B *pb = dynamic_cast<B*>(pa); //成功,返回其地址
cout<<pb<<endl;
C *pc = dynamic_cast<C*>(pa); //成功,返回NULL
if(pc != NULL)
cout<<pc<<endl;
D *pd = dynamic_cast<D*>(pa); //成功,返回NULL
if(pd != NULL)
cout<<pd<<endl;
5.模板
泛型:在多种数据类型上都可操作。
STL:标准模板库。
原理:把原本某个特定类型的算法或类中的类型信息提取出来,替换成模板参数T。
函数模板的定义方法:
实验代码:
#include <iostream>
using namespace std;
template <typename T>
void Swap(T &a,T &b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
int a = 1,b = 2;
cout << "a = "<<a<<" b = "<<b<< endl;
Swap(a,b);
cout << "a = "<<a<<" b = "<<b<< endl;
return 0;
}
类模板的定义方法:
对day3中定义的栈空间类进行模板化:
原始代码:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
class Stack
{
public:
Stack(int size=1024);
~Stack();
bool isEmpty();
bool isFull();
void push(int data);
int pop();
private:
int* space;
int top;
};
Stack::Stack(int size)
{
space = new int[size];
top = 0;
}
Stack::~Stack()
{
delete []space;
}
bool Stack::isEmpty()
{
return top == 0;
}
bool Stack::isFull()
{
return top == 1024;
}
void Stack::push(int data)
{
space[top++] = data;
}
int Stack::pop()
{
return space[--top];
}
int main()
{
Stack s(100);
if(!s.isFull())
s.push(10);
if(!s.isFull())
s.push(20);
if(!s.isFull())
s.push(30);
if(!s.isFull())
s.push(40);
if(!s.isFull())
s.push(50);
while(!s.isEmpty())
cout<<s.pop()<<endl;
return 0;
}
template <typename T>
T Stack<T>::pop()
{
return space[--top];
}
并且在利用类模板定义模板类对象时需要加上类型,如
Stack<int> s
修改后的代码
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
template <typename T>
class Stack
{
public:
Stack(T size = 1024);
~Stack();
bool isEmpty();
bool isFull();
void push(T data);
T pop();
private:
T* space;
int top;
};
template <typename T>
Stack<T>::Stack(T size)
{
space = new T[size];
top = 0;
}
template <typename T>
Stack<T>::~Stack()
{
delete []space;
}
template <typename T>
bool Stack<T>::isEmpty()
{
return top == 0;
}
template <typename T>
bool Stack<T>::isFull()
{
return top == 1024;
}
template <typename T>
void Stack<T>::push(T data)
{
space[top++] = data;
}
template <typename T>
T Stack<T>::pop()
{
return space[--top];
}
int main()
{
Stack<int> s(100);
if(!s.isFull())
s.push(10);
if(!s.isFull())
s.push(20);
if(!s.isFull())
s.push(30);
if(!s.isFull())
s.push(40);
if(!s.isFull())
s.push(50);
while(!s.isEmpty())
cout<<s.pop()<<endl;
return 0;
}