既然是谈继承,那我们就该进入主题了,昨天我们谈了一个关于人事管理的系统,虽然说我们只是在模拟,但是也应该弄得像一些,如果说用employ表示一个管理普通员工的类,那么对于管理员比如说主管又或者说是经理呢等等,这里有一个关于is-a和has-a的问题,今天,我们不会去和大家深入探讨什么是is-a什么又是has-a,不过有一点大家都能够明白,那就是不管是主管抑或是经理还是总监等等他们都是员工,都是employ(这里指类),所以简单点说,主管(我们今天要说的)和员工的关系其实就是is-a这种关系。
既然是is-a,那么我们是不是可以这么说,用employ这个类去抽象一个主管呢?我的回答是当然可以,不过有些地方可能得重新修改一下,就好比,一个主管的工资不应该和一个普通员工的属于同一级别,至少也得高出个50%吧,而且当我们在调用员工信息的时候要能够准确的知道这是一个主管还是一个普通员工,所以这时,我们昨天谈及的关键词virtual就起到了关键作用。
virtual是C++里面定义一个虚方法的唯一关键字,被他修饰的方法我们可以在他派生的类中重写,那么大家是不是想问,如果不用这个virtual修饰是不是就不能够覆盖了呢?这是一个很有技术性的话题,这里暂且不说,有兴趣的同学可以先去了解一下,当然如果大家不愿意动手自己去查阅的话可以继续等待,因为我们后面会让大明白为什么要重写一个函数就应该把他声明为virtual。
嗯,现在可能有人会说,virtual既然可以让其修饰的方法在派生类中重写,那么是不是应该把所有的方法都声明为virtual呢?想法当然是好的,而且通常的主张也是这样的啦,但是这里存在一个问题,只要一个class里声明得有virtual,那么系统就会给他分配一个虚函数表,这东西的存在不但占用资源还会影响性能,但是不管是什么东西,有功就有过,虚函数应用得当,带给我们的好处远比性能上的问题要多得多,所以就算是C++高级编程的两个作者都主张尽量把所有的方法都声明为virtual,如果打算让他作为基类的话。
好了,重点已经说得差不多了,哦,是吗?好像我们还没说重点,因为我们今天的主角应该是继承才对,是啊,因为是继承,所以我们的基础都说得差不多了,唯一剩下的就是怎么去继承了,其实很简单,我们主要说的共有继承,因为保护继承和私有继承不是那么有用,关于私有继承和保护继承留待后面再说,因为没什么好说的。好吧,我们来看看怎么实现共有继承:
——————————————-
class Supervisor :public employ
——————————————–
class 派生类名:public 基类名
———————————————
嗯,是时候说说类里面的三种属性了,一个类里面,我们通常会看到有些方法声明为public,又有些方法声明为protected,还有一些声明为private(通常我们会将数据都声明为private)。public如同其名,就是公有的,供对象访问的,而protected和private是对象不能访问的。看名字似乎这两个都是保护数据的,那么他们有什么区别呢?面对对象,protected和private都一样保护数据,但是在面对共有派生类时,protected里的方法就相当于public,所以,个人认为,protected就是为了继承和多态而生。
光说不练,没啥屁用,学习还是得从例子开始,我们现在可以来看看我们如何用上一讲中的employ类作为基类来派生出一个主管类。
——————————————-
//supervisor.cpp
#include "
employ.h"
namespace My_Code{
class Supervisor :public employ
{
public:
Supervisor(){ };
~Supervisor(){ };
void SetSalary(const double Salary);
void Show_Employy_Info();
};
}
——————————————
很简单是不是,不过有一点我们更改了,就是我们在上一讲里面把SetSalary的返回值设为employ的引用,当时目的是为了在使用的时候可以连续,但是这一讲里,为了实现重写,所以我们声明为void。
在这个主管类里面我们并没有添加新恭喜,我们只是简单的地重写了两个函数,一如开篇之时我们所说,主管的工资不该和普通员工的一个水平,所以我们应该重写这个函数,同样,员工信息这一栏,至少有一点不一样,那就是员工职位,所以重写Show_Employy_Info这个函数也是理所应当的了。
现在看来,只要我们有个合适的基类,想要再开发新东西其实会变得很轻松,有朋友可能在怀疑,就这点东西,真的行吗?好吧,我们来测试一下吧。
———————————————
//test.cpp
#include "
Supervisor.h"
using namespace My_Code;
int main()
{
employ m_employ[2];
Supervisor m_Sup[2];
string str1,str2;
double num,salary;
for(int i=0;
i<2;
i++)
{
cout<<"
请输入员工名字:n"
;
cin>>str1>>str2;
cout<<"
请输入员工工号:n"
;
cin>>num;
cout<<"
请输入员工工资:n"
;
cin>>salary;
m_employ[i].SetFirstName(str1).SetLastName(str2).SetNumberID(num).SetSalary(salary);
}
for(int i=0;
i<2;
i++)
{
cout<<"
请输入员工名字:n"
;
cin>>str1>>str2;
cout<<"
请输入员工工号:n"
;
cin>>num;
cout<<"
请输入员工工资:n"
;
cin>>salary;
m_Sup[i].SetFirstName(str1).SetLastName(str2).SetNumberID(num).SetSalary(salary);
}
cout<<"
员工信息:n"
;
cout<<"
———————————————"
<<endl;
cout<<"
员工姓名"
<<"
t职位"
<<"
tt工号"
<<"
t工资"
<<endl;
for(int i=0;
i<2;
i++)
m_employ[i].Show_Employy_Info();
for(int i=0;
i<2;
i++)
m_Sup[i].Show_Employy_Info();
employ m_em = m_Sup[0];
m_em.Show_Employy_Info();
employ&
m_em2 = m_Sup[0];
m_em2.Show_Employy_Info();
return 0;
}
——————————————–
不要在意上面这个程序,这个程序有很多瑕疵,等我们说到STL的时候大家可以把这个程序写得更漂亮一些,这里,我们只作测试使用,大家注意一下最后的一点:
————————————-
employ m_em = m_Sup[0];
m_em.Show_Employy_Info();
employ&
m_em2 = m_Sup[0];
m_em2.Show_Employy_Info();
—————————————-
好吧,我们来看看测试结果:
大家是不是看到有些奇怪的东西出来了呢?这就是为让大家注意最后那点的原因了,为什么会这样呢?留待大家去思考,明天我们再来细说。
===================
回复D直接查看目录
原文始发于微信公众号(
C/C++的编程教室
):第四十四讲 继承(2)
|