资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,提纲,派生类的构造函数与析构函数,第三章 继承,1,3,2,继承方式,类的继承与派生,4,虚基类,5,聚合类,6,继承应用实例,1,3.1 类的继承与派生,需求,某公司需开发人事管理系统,每个员工都具有属性:工作编号、姓名、基本工资、月出勤率;企业需要为每个员工设置基本工资,员工可以查询基本工资,企业还要计算员工当月实际发放工资;行政员工的实际工资为基本工资加奖金,其中奖金与当月的考勤奖励;销售人员的工资为基本工资和按当月销售额的一定比例的提成;销售经理的工资为基本工资、当月考勤奖励和当月销售额的提成。,2,3.1 类的继承与派生,继承,是将自然界中存在的,普遍和特殊关系,用程序设计的方式进行分类描述;,是软件重用的一种形式。,继承在设计新类时,允许,重用某个原有类的所有特征,,并在此基础上,添加新类的新特征,。,被重用的原有类称为,基类(,base,class),而新创建的类称为,派生类(,derived class),。,派生类不会影响到原有类的结构。,企业员工,工作编号,姓名,基本工资,显示企业员工信息,设置基本工资,计算实际发放工资,行政人员,当月出勤率,出勤奖励,计算实际发放工资,销售经理,公司总销售额提成比例,个人销售额,计算实际发放工资,销售人员,当月出勤率,出勤奖励,个人销售额提成比例,个人销售额,计算实际发放工资,3,3.1 类的继承与派生,类设计,一个一般员工类,CCompanyStaff,,代表员工的共性;,三个新类,分别继承一般员工类,CCompanyStaff,然后根据各自的差异性,新类可以对继承来的内容进行改造,。,派生类的,定义,定义语法格式:,class,:,:,;,4,3.1 类的继承与派生,继承方式,public,private,protected,继承关系,单继承(只有一个基类名),多继承(继承多个父类),继承关系定义实例,A,B,C,5,3.1 类的继承与派生,基类与派生类的关系,基类不受派生类变化的影响;,类,CA,:,FunA();a,派生类,继承了基类的全部数据成员和除了构造函数析构函数之外的全部成员函数,类,CB,:,FunA(),FunB(),;,a,b,类,CC,:,FunA(),FunC();a,c,基类的对象无法使用派生类的成员,CA ca;,ca.FunB(1);(,),6,3.1 类的继承与派生,定义代码:,class CCompanyStaff;/,基类员工,class CAdminStaff:public CCompanyStaff,/,派生类行政人员继承员工,class CForeAdmin:public CAdminStaff;/,派生类行政主管继承行政人员,派生类内直接访问基类成员,可直接访问基类,public/protected,成员,不可访问基类,private,成员,例,3.3,smain3_3.cpp,protected,访问权限:,设计基类时,在隐藏成员的同时还要允许派生类的成员能访问到,这时,protected,就比,private,更合适;,9,3.1 类的继承与派生,类的继承方式,public,公有继承,private,私有继承,protected,保护继承,10,3.1 类的继承与派生,几个重要概念,基类类内,派生类类内,派生类类外,继承方式不改变派生类内访问基类成员的权限,只改变继承后,在派生类外通过派生类对象访问继承基类成员的权限。,11,3.1 类的继承与派生,public,公有继承,在公有继承下,基类中所有成员在派生类中的访问区分符都保持不变。,访问控制,被,public,继承后,基类,public,成员仍可在类外通过派生类对象访问;,基类,private,成员不能在类外通过派生类对象访问;,基类,protected,成员不能在类外(除派生类的派生类外)通过派生类对象访问。,例,3.1,一个公有继承的例子:,sclass3_3.dev,12,3.1 类的继承与派生,private,私有继承,在私有继承下,基类各成员无论是何种访问区分符在派生类中,一律是,private,。,访问控制,被,private,继承后,基类,public,成员不能在类外通过派生类对象访问;,基类,private,成员不能在类外通过派生类对象访问;,基类,protected,成员不能在类外通过派生类对象访问。,例,3.,2,一个私有继承的例子:,sclass3_3.dev,13,3.1 类的继承与派生,protected,保护继承,在保护继承下,基类,public,成员的访问区分符变成,protected,,其它维持不变。,访问控制,被,protected,继承后,基类,public,成员不能在类外(除派生类的派生类外)通过派生类对象访问;,基类,private,成员不能在类外通过派生类对象访问;,基类,protected,成员不能在类外(除派生类的派生类外)通过派生类对象访问。,例,3.,3,一个,protected,继承的例子:,sclass3_3.dev,14,3.1 类的继承与派生,访问区分符变化表,访问区分变化表,在派生类中,继承基类成员的访问区分符由基类成员访问区分符和继承方式共同决定,取两者中权限限制最高的访问区分符。,15,3.1 类的继承与派生,练习,1,class A,private:,int a;,protected:,int b;,public:,int c;,;,class B:protected A,public:,int d;,;,void main,(),A a1;,a1.a=1;/1,a1.c=1;/2,B b1;,b1.a=2;/3,b1.c=2;/4,;,问:,main,函数中哪些语句会因为访问权限限制而不可访问?,16,3.1 类的继承与派生,练习,2,class A,private:,int a;,protected:,int b;,public:,int c;,;,class B:public A,public:,int d;,;,void main,(),A a1;,a1.a=1;/1,a1.c=1;/2,B b1;,b1.a=2;/3,b1.c=2;/4,b1.d=2;/5,;,问:,main,函数中哪些语句会因为访问权限限制而不可访问?,17,3.2 继承方式,多继承(多个父类,):,声明,多继承,的语法如下:,class :,例:,D-B&D-C,Class CD:public CB,public CC,类,CD,:,FunA(),FunB(),FunC(),FunD();a,b,c,d,多继承举例:,在公司员工管理中有时会存在多继承关系,如图:,A,B,C,D,18,该关系的,C+,描述,:,经理,销售部经理,销售人员,类定义代码,企业员工类,相关派生类,19,3.3,派生类的构造函数和析构函数,构造函数:,派生类数据成员初始化,自身定义的数据成员,在自身的构造函数进行初始化,继承的数据成员,在派生类构造函数进行初始化,例:,classdemo,在,CB,类构造函数对,a,,,b,初始化。,在基类构造函数初始化基类成员,用基类构造函数初始化基类数据成员,用,不带参数,的基类构造函数初始化基类数据成员,在创建派生类的对象时,,会自动调用不带参数(或全是有缺省参数的基类构造函数,;,例:,classdemo,CB,类构造函数初始化,b,,,CA,类不带参数的构造函数初始化,a,。,20,3.3,派生类的构造函数和析构函数,用,带参数,的基类构造函数初始化基类数据成员,语法格式:,():()(),说明:派生类构造函数的形参表中必须包括自身的参数和基类构造函数的参数,例:,CB(int i,int j):CA(i)a=i;,演示:,classdemo,派生类构造函数的调用顺序为:,先基类构造函数后派生类构造函数,;,多重继承时按定义基类初始化的顺序,从左到右依次执行。,演示:,classdemo,创建,CD,类对象的调用顺序,21,3.3,派生类的构造函数和析构函数,例:,轿车具有交通工具的一般特征,比如轮胎数目,同时又具有轿车自身的特征,如载客人数,因此轿车继承交通工具,成为它的一个派生类。,例,3.4,smain3_4.cpp,22,3.3,派生类的构造函数和析构函数,析构函数,当派生类对象消亡时,系统会自动调用派生类的析构函数做一些必要的清理工作;,在执行派生类的析构函数,时基类的析构函数也将被自动调用;,析构函数调用的顺序是,先派生类的析构函数,然后是基类的析构函数(先调用的后析构),例,classdemo,23,3.3,派生类的构造函数和析构函数,(,练习,),class CA,public:,CA(int i=0),a=i;,coutCA a=aendl;,CA(),coutCA a=aendl;,int a;,;,class CB:public CA,public:,CB(int j,int i):CA(i)/(1),b=j;,coutCB b=bendl;,CB(),coutCB a=a b=bendl;,int b;,;,int main(),CB cb(2,1);,system(pause);,return 0;,显示结果?,CA a=1,CB b=2,CB a=1 b=2,CA a=1,如果将(1)改为:,CB(int j),结果如何?,24,3.4,虚基类,多继承中的多义性,如右图:,classdemo,分析:,CA,:,FunA();a,CB:FunA(),FunB();a,b,CC:FunA(),FunC();a,c,CD:,FunA()(,从,CB,中继承,),FunA()(,从,CC,中继承,),FunB(),FunC(),FunD();,a(,从,CB,中继承,),a(,从,CC,中继承,),b,c,d,A,B,C,D,25,3.4,虚基类,解决方法,作用域分辨符:,可以,通过作用域分辨符明确指定调用哪个类的接口;,其语法形式如下:,.:,/,访问数据成员,.:,/,访问成员函数,作用域分辨符举例:,classdemo,26,3.4,虚基类,定义虚基类,通过虚继承,使原来的基类变为虚基类,对于虚基类,则所有派生类成员变量共享,一个副本,,成员函数也,只有一个映射,虚继承声明语法:,class:,virtual,例,classdemo,27,3.4,虚基类,使用虚基类来定义公司员工管理系统中的多继承关系:,/,在继承路径“销售经理,销售人员,员工”中将基类,CCompanyStaff,设为虚基类,class CSaleman:virtual public CCompanyStaff;,/,在继承路径“销售经理,经理,员工”中将基类,CCompanyStaff,设为虚基类,class CManager:virtual public CCompanyStaff;,/,派生类,CSaleManager,成为两条继承路径的交汇点,class CSaleManager:public CSaleman,public Cmanager;,28,3.4,虚基类,比较使用作用域分辨符和虚基类技术:,使用作用域分辨符时基类的成员在内存中,存在多个副本,,通过指定基类名来唯一标识使用的是哪个副本,这样可以存放不同的数据进行不同的操作;,使用虚基类技术,使派生类共享基类的成员一个副本,(注:与基类不是同一空间),;,29,3.4,虚基类,虚基类的初始化,虚基类的初始化在语法上和处理一般基类一样只是,调用顺序略有不同,它遵循以下顺序:,虚基类,的构造函数在非虚基类之前调用;,若同一层次中包含多个虚基类则按它们的,声明顺序,调用;,若虚基类由非虚基类派生而来要先调用,更高级别基类,的构造函数再遵循上述,1,和,2,的顺序。,30,3.4,虚基类,虚基类初始化顺序的简单举例:,class A;,class B;,class C:,public A,virtual,B,;,将产生如下的调用次序,B(),A(),C(),31,3.5,聚合类,概念,问题:如何描述汽车与发动机的关系;员工与资历的关系?,对于整体与部分的关系,不能用继承来描述,聚合类:一个类中,内嵌其他类的对象作为成员,;,也是实现程序代码重用的另一有效手段,实例:,calssDemo,例,3.8,员工管理系统中的聚合关系:,smain3_8.cpp,32,3.5,聚合类,构造函数,聚合类对象在创建时作为其组成部件的,内嵌对象将首先被系统创建;,如果一个聚合类,同时又是一个派生类,那么它的构造函数初始化列表还应负责为基类构造函数的调用提供参数;,定义形式:,(,):,(,),(,),类的初始化,33,3.5,聚合类,例,3.8,公司的每一个员工都拥有不同的教育背景,其中记录着毕业学校、最高学历等基本数据。,分析:可以将教育背景抽象为一个类,CEducation,,拥有上述数据,并提供查询数据和显示数据等基本功能。企业员工类,CCompanyStaff,要使用教育背景类,CEducation,的功能,但是前者不能继承后者所具有的特征,因此可以把,CCompanyStaff,类处理成一个聚合类,在类中内嵌一个,Ceducation,类的对象。,实现代码,smain3_8.cpp,34,3.6,继承应用实例,问题描述:,假设一个作为某产品代理商的小型公司,它的员工组成很简单,主要分成经理、销售部门经理、销售人员和行政人员等几类。所有员工都具有姓名、工作编号、基本工资、奖金、当月出勤记录等数据,都拥有一定的教育背景;每个员工都存在录入和显示信息等操作,并且需要根据考勤等实际因素来发放工资。同时,不同类别的员工,计算工资的办法也各不相同,行政人员:基本工资奖金当月出勤率;经理:基本工资总销售额经理提出比例;销售人员:基本工资个人销售额销售人员提成比例;销售经理:基本工资个人销售额销售人员提成比例总销售额经理提出比例。具体员工数据要求过键盘录入方式进行初始化。,35,3.6,继承应用实例,问题分析:,每种员工定义为一类,给出类的属性和行为;,行政人员、销售人员、销售经理、经理,再从各类中抽象更高一层类;,销售经理销售人员、经理,销售人员、行政人员、经理员工,分析有没有整体与部分的类,员工教育背景,各类数据的初始化,通过键盘录入,对于各类中具有相同性质的行为,应定义相同的成员函数名。,设置、显示数据、计算工资,设定访问控制权限,36,3.6,继承应用实例,源程序,:,smain3_9.cpp,37,3.6,继承应用实例,练习:航空货物托运费用计算程序,航空公司记录旅客携带物品(包括:货物名、货物数量、货物重量、起点、终点),并计算费用,收费标准如下:,超过15公斤,但小于25公斤时,收费标准为:,(1)前15公斤的货物不收费;,(2)15公斤以后的货物,按每公斤12元收费;,超过25公斤,但小于45公斤时,收费标准为:,(1)前15公斤的货物不收费;,(2)15公斤25公斤之间的货物,按每公斤12元收费;,(3)25公斤以后的货物,按每公斤15元收费;,对于危险品货物,每公斤需要再附加收费5元,38,3.6,继承应用实例,练习:航空货物托运费用计算程序,航空公司记录旅客携带物品(包括:货物名、货物数量、货物重量、起点、终点),并计算费用,收费标准如下:,超过15公斤,但小于25公斤时,收费标准为:,(1)前15公斤的货物不收费;,(2)15公斤以后的货物,按每公斤12元收费;,超过25公斤,但小于45公斤时,收费标准为:,(1)前15公斤的货物不收费;,(2)15公斤25公斤之间的货物,按每公斤12元收费;,(3)25公斤以后的货物,按每公斤15元收费;,对于危险品货物,每公斤需要再附加收费5元,程序,s3_10smain3_10.dev,39,3.6,继承应用实例,练习:多项式(,polynomial),运算,实现功能选项至少有:输入多项式、输出多项式、合并同类项,求多项式的和、求多项式的差、求多项式的积、退出等。,Coefficient,,exponent,40,小节,类的继承是描述客观世界的继承关系,派生类继承了基类所有的成员变量和成员函数,继承方式不影响派生类内访问基类成员,与基类成员访问控制权限共同决定派生类对象在类外访问基类成员的访问控制权限。,派生类如果要调用基类带参数构造函数,则需在构造函数定义中显示调用;对象初时化时,先调用基类构造函数,然后再调用自身的构造函数;对象构造撤销时,按相反的顺序调用析构函数,如果一个派生类继承两个父基类,而这两个父基类又继承同一个父基类,则需在继承同一基类时,声明虚基类,聚合类描述客观世界中整体与部分的关系,严格上说不是继承关系。,41,Thanks!,The End,42,
展开阅读全文