




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
派生类的构派生类成员的访问属派生类的构造函数和析构函多重继基类与派生类的转继承与组继承在软件开发中的重要意第11承与派面向对面向对象程序设计有4个主要特点承和多态性抽象、封装、要较好地进行面向对象程序设计,还必须了解面面向对象技术强调软件的可重用性reusability)。C++语言提供了类的继承机制,解决11.111.1继承与派生的概利用原来声明的类Studn作为基础,再加上新的内容即可,以减少重复的工作量。C++机制就是为了解决这个问题。在第8章已举了马的例子来说明继承的概念。见11.1示意在C++中,所谓“在C++中,所谓“继承”就是在一个已存在的类的础上建立一个新的类。已存在的类(例如“马”)称“基类(baseclass)”或“父类(fatherclass)”。新建的类(例如“公马”)称为“派生类“子类(sonclass)”。见图11.2示意class)”图图一一个新类从已有的类那里获得其已有特性,这种以上介绍的是最简单的情况:一个派生类只从一个基类派生,这称为单继承(singleinheritance),这种图请图请注意图中箭头的方向,在本书中约定,箭头表继承的方向,从派生类指向基类一个派一个派生类不仅可以从一个基类派生,也可以从多重继承(multipleinheritance),这种继承关系所图关于基类和关于基类和派生类的关系,可以表述为派生类基类的具体化,而基类则是派生类的抽象图11.2派生类的11.2派生类的声明方假设已经声明了一个基类Student,在此基础上过单继承建立一个派生类voiddisplay_1({cout<<″age:″<<age<<endl;intage;基类名基类名前面有public的称为“公用继承inheritance)”声明派生类的一般形式class派生类名[继承方式{派生类新增加的成}继承方式包括:public(公用的),private(私有的)和类11.311.3派生类的构派生类中的成员包括从基类继承过来的成员和自部分:一部分是从基类继承来的成员,另一部分是图图实实际上,并不是把基类的成员和派生类自己增加调整从基类接收的成员。接收基类成员是程在声在声明派生类时增加的成员。这部分内容是重要的,它体现了派生类对基类功能的扩展。要的功能,形成适用于某一特定应用的派生类。通的派生类。因此,派生类是抽象基类的具体实现11.411.4派生类成员的访问属既然派生类中包含基类成员和派生类自己增加的用成员直接作为派生类的公用成员。实际上,对具具体说,在讨论访问属性时,要考虑以下几种况基类的成员函数访问基类成员派生类的成员函数访问派生类自己增加的成员基类的成员函数访问派生类的成员派生类的成员函数访问基类的成员在派生类外访问派生类的成员在派生类外访问基类的成员对于第(1)和第(2)种情况,比较简单,按第8章介绍过的规则处理,即:基类的成员函数可以访问基类成员,派生类的成员函数可以访问派生类成员。第第(3)种情况也比较明确,基类的成员函数只能访况也比较明确,在派生类外可以访问派生类的公用前面已前面已提到在派生类中,对基类的继承方式可有public(公用的),private(私有的)和protected(简单地说公用继承(public私有继承(private保护成员的意思是不能被外界引用,但可以被派11.4.111.4.1派生类称为公用派生类(publicderivedclass),其基类称为公用基类(publicbaseclass)。例访问公有基类的成例访问公有基类的成员下面写出类的声明部分voidget_value(voiddisplay(){cout<<″num:cout<<″sex:″<<sex<<endl;}private:charsex;classStudent1:publicvoiddisplay_1(voiddisplay_1({cout<<″num:″<<num<<endl;cout<<″sex:″<<sex<<endl;cout<<″age:intage;由于基类的私有成员对派生类来说是不可访问的因此在派生类中的display_1函数中直接引用基类通过基类的公用成员函数来引用基类的私有数据员可以将派可以将派生类Student1的声明改voiddisplay_1({cout<<″age:″<<age<<endl;}intstring然后在main函数中分别调用基类的display函数和生类中的display_1函数,先后输出5个数据intmain({Student1stud;//定义派生类Student1的对象┆stud.display();┆stud.display();return}请根据上面的分析,写出完整的程序,程序中应括输入数据的函数实际上,程序还可以改进,在派生类的display_1函即可输出5个数据11.4.211.4.2派生类称为私有派生类(privatederivedclass),其基类称为私有基类(privatebaseclass)。图图图11.7表示了各成员在派生类中的访问属性对表11.2的对表11.2的规定不必死记,只需理解既然声明私有继承,就表示将原来能被外界引用的成员隐可以知道:一个成员在不同的派生层次中的访问属例将例11.1中的公用继承例将例11.1中的公用继承方式改为用私有继方式(基类Student不改)可以写出私有派生类如下voiddisplay_1(intage;};请分析下面的主函数:intmain{Student1stud1;//定义一个Student1类的对象return0;}可可以看到用私有基类的私有成员呢?有。应当注意到:虽然可将上面的私有派生可将上面的私有派生类的成员函数定义改写voiddisplay_1()//输出5个数据成员的//调用基类的公用成员函数,输出3个数据成员的cout<<″age://输出派生类的私有数据成cout<<″address:″<<addr<<endl;}//输出派生类的私有数据成main函数可改写intmain(stud1.display_1();//display_1函数是派生类Student1类的公用函数return0;}:①在main函数中调用派生类中的公用成员函②通过该公用成②通过该公用成员函数调用基类的公用成员函display(它在派生类中是私有函数,可以被派生中的任何成员函数调用③通过基类的公用成员函数display引用基类中数据成员请根据上面的要求,补充和完善上面的程序,使之成为完整、正确的程序。程序中应包括输入数据的11.4.311.4.3图如如果基类声明了私有成员,那么任何派生类都是的派生类称为保护派生类(protectedderivedclass),其基类称为受保护的基类(protectedbase保护继承的特点是:保护基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为将表将表11.1和表11.2综合起来,并增加保护继承的容,见书中表11.3际上是相同的:在类外不能访问任何成员,而在派例例如,如果以公用继承方式派生出一个新派生类从表11.3可知:基类的私有成员被派生类继承后变到数据共享与成员隐蔽之间的结合点。既可实现通过以上的介绍,可以通过以上的介绍,可以知道①②在派生类中,成员有4种不同的访问属性公用的,派生类内和派生类外都可以访问受保护的,派生类内可以访问,派生类外不能问,其下一层的派生类可以访问③④私有的,派生类内可以访问,派生类外不能访问不可访问的,派生类内和派生类外都不能访问可以用书中表11.4表示需要说明的是①这里所列出的成员的访问属性是指在派生类中获得的访问属性②块中,在②块中,在派生类范围之外③如果本派生类继续派生,则在不同的继承方下,成员所获得的访问属性是不同的,在本表中(2)类的成员在不同作用域中有不同的访问属性,下面通过一个例子说明怎样访问保护成员例在派生类中引用保护成例在派生类中引用保护成员#include<iostream>#include<string>protected:intnum;charsex;{cout<<″num:″<<num<<endl;cout<<″sex:″<<sex<<endl;}classStudent1:protectedvoiddisplay1(intstringintstring{cout<<″num:″<<num<<endl;cout<<″name:″<<name<<endl;cout<<″sex:″<<sex<<endl;cout<<″age:″<<age<<endl;}intmain({Student1stud1;stud1.display1();return0;}在在派生类的成员函数中引用基类的保护成员是合注意在程序中通过派生类Student1的对象stud1的11.4.4图11.4.4图如果有图11.9所示的派生关系:类A为基类,类B例多级派生的例多级派生的访问属性如果声明了以下的类classinti;voidf2();intj;intk;classB:publicvoidf3();voidf4();intm;classC:protectedintclassC:protectedintijkmn基类公不可访保不可访不可访无无论哪一种继承方式,在派生类中是不能访问基成员的。而且经过多次派生后,人们很难清楚地派生派生类的构造函数和析构函用户在声明类时可以不定义构造函数,系统会自被初始化。解决这个问题的思路是:在执行派生类的构造函数时,调用11.5.111.5.1例11.5简单的派生类的构造函数#include<iostream>sex=s;}~Student(){intnum;charsex;classStudent1:intnum;charsex;classStudent1:publicStudent1(intn,stringnam,chars,inta,string}voidshow({cout<<″num:″<<num<<endl;cout<<″name:″<<name<<endl;cout<<″sex:″<<sex<<endl;cout<<″age:″<<age<<endl;}intage;intintage;intmain({Student1stud1(10010,″Wang-li″,′f′,19,″115BeijingRoad,Shanghai″);return0;}运行结果address:115Beijingaddress:213Shanghai请注意派生类请注意派生类构造函数首行的写法Student1(intn,stringnam,chars,inta,string其一般形式派生类构造函数名(总参数表列(参数表列{派生类中新增数据成员初始化语句基类构造函数形参。见图11.10图通过Student(n,nam,通过Student(n,nam,s)把3个值再传给基类构函数的形参,见图11.11↓↓↓stringnam,chars)//这是基类构造函数的首图在上例中也可以将派生类构造函数在类外面定义而在类体中只写该函数的声明Student1(intn,stringnam,chars,inta,string在类的外面定义派生类构造函数}请注意请注意在类中对派生类构造函数作声明时,不包基类构造函数名及其参数表列(即nam,s))。只在定义函数时才将它列出Student1(stringnam,chars,inta,stringBox::Box(intBox::Box(inth,intw,int{Student1(intn,stringnam,chars,inta,string}可可以将对age和addr的初始化也用初始化表处理将构造函数改写为以下形式Student1(intn,stringnam,chars,inta,string这样函数体为空,更显得简单和方便:①派。在派生类对象释放时,先执行派生类析构函~Student1(),再执行其基类析构函数~Student()11.5.211.5.2Student是已声明的类名,s1是Student类的对这时,s1就是类对象中的内嵌对象,称为子对(subobject),即对象中的对象通过例子来说明问题例包含子对象的派生类例包含子对象的派生类的构造函数为了简化程序以易于阅读,这里设基类Student数据成员只有两个,即num和name#include<iostream>#include<string>Student(intn,stringnam}voiddisplay(intnum;stringclassStudent1:publicStudent1(intn,stringnam,intn1,stringnam1,intStudent1(intn,stringnam,intn1,stringnam1,inta,string}voidshow(cout<<″age:}}intage;stringintmain(intmain(stud1.show();return}运行时的输出如下Thisstudentnum:10010age:19Classmonitor派派生类构造函数的任务应该包括3个部分对基类数据成员初始化对子对象数据成员初始化Student1(intn,stringnam,intn1,stringnam1,inta,string图归纳图归纳起来,定义派生类构造函数的一般形式派生类构造函数名(总参数表列)基类构造函数{派生类中新增数成员据成员初始化语句执行派生类构造函数的顺序是①调用基类构造函数,对基类数据成员初始化②调用子对象构②调用子对象构造函数,对子对象数据成员初化③再执行派生类构造函数本身,对派生类数据初始化派生类构造函数的总参数表列中的参数,应当包括基类构造函数和子对象的参数表列中的参数。基类构造函数和子对象的次序可以是任意的,如上面的Student1(intn,stringnam,intn1,stringnam1,inta,stringad):编译系统是根据相同的参数名(而不是根据参数的顺序)来确立它们的传递关系的。但是习惯上一般如果有多个子对象,派生类构造函数的写法依此11.5.311.5.3例11.7多级派生情况下派生类的构造函数#include<iostream>Student(intn,stringnam}voiddisplay(}}intstringclassStudent1:public{age=a;}voidshow(cout<<″age:}intStudent2(intn,stringnam,intStudent2(intn,stringnam,inta,intvoidshow_all({show(}intintmain(stud.show_all();return}运行时的输出如下其派生其派生关系如图11.13所示图请注意请注意基类和两个派生类的构造函数的写法基类的构造函数首部Student(intn,string派生类Student1的构造函数首部Student1(intn,stringnam],int派生类Student2的构造函数首部Student2(intn,stringnam,inta,int①②③先初始化基类的数据成员num和name再初始化Student1的数据成员age最后再初始化Student2的数据成员score11.5.411.5.4在使用派生类构造函数时,有以下特殊的形式(1)当不需要对派生类新增的成员进行任何初始化Student1(intn,strinnam,intn1,strinnam1):Student(n,nam),monitor(n1,nam1){}类构造函数和子对象,并在执行派生类构造函数如果如果在基类中没有定义构造函数,或定义了有参数的构造函数,那么在定义派生类构造函数如如果在基类或子对象类型的声明中定义了带参数参的构造函数(构造函数重载),则在定义派生类构时,根据构造函数的内容决定调用基类的有参的11.5.511.5.5调用的顺序与构造函数正好相反:先执行派生类自11.611.6多重继前面讨论的是单继承,即一个类是从一个基类派而来的。实际上,常常有这样的情况:一个派生承所需的属性。C++为了适应这种情况,允许一个(multipleinheritance)。11.6.111.6.1classD:publicA,privateB,protected{类D新增加的成员D是多重继承的派生类,它以公用继承方式继承类,以私有继承方式继承B类,以保护继承方式继11.6.211.6.2派生类构造函数名(总参数表列):基类1构造函数(参数表列),基类2构造函数(参数表列),基类3构造函数{派生类中新增数成员据成员初始化语句序同样为:先调用基类的构造函数,再执行派生类例11.8声明一个教例11.8声明一个教师(Teacher)类和一个学括数据成员name1(姓名)、age(性别)、score(成绩)#include#include<string>Teacher(stringnam,inta,stringvoiddisplay(}}intage;stringtitle;class}charsex;floatfloatGraduate(stringnam,inta,chars,stringt,floatsco,floatw):Teacher(nam,a,t),Student(nam,s,sco),wage(w){}voidshow(}floatintmain(return0;}程序运行结果如下age:24wages:1234.5在两个基类中分别用name和name1来代表姓名,其实这是同一个人的名字,从Graduate类的构造函数解决这个问题解决这个问题有一个好方法在两个基类中可以使用同一个数据成员名name,而在show函数中用数据成员时指明其作用域,通过这个程序还可以发现一个问题在多重继时,从不同的基类中会继承一些重复的数据。如11.6.311.6.3两个基两个基类有同名成员。如图11.14所示图classclassintvoiddisplay(classintvoiddisplay(classC:publicA,public{publicintvoidCc1;Cc1;c1.A::a=3;//引用c1对象中的基类A的数据成员//调用c1对象中的基类A的成员函数如果是在派生类C中通过派生类成员函数show访基类A的display和a,可以不必写对象名而直接A::display();如同上一节最后所介绍的那样。为清楚起见,11.14应改用图11.15的形式表示图图两个基类两个基类和派生类三者都有同名成员。将上的C类声明改classC:publicA,public{intvoid如图11.16所示。即有3个a,3个display函数图如如果在main函数中定义C类对象c1,并调用数据员a和成员函数Cc1;c1.display(C中的成员。规则是:基类的同名成员在派生类中员,则访问的是派生类的成员。请注意:不同的成而参数不同,不会发生同名覆盖,而属于函数重载要在派生类外访问要在派生类外访问基类A中的成员,应指明作用A,写成以下形式c1.A::a=3;//表示是派生类对象c1中的基类A中的数据成员//表示是派生类对象c1中的基类A中的成员函数如果类A和类B是从同一个基类派生的,如11.18所示图classclassintvoidclassA:publicintclassB:publicintclassC:publicA,public{publicintvoidshow(intmain(┆}图11.19和图11.20表图11.19和图11.20表示了派生类C中成员的情况图图11.怎样才怎样才能访问类A中从基类N继承下来的成员呢显然不能c1.a=3;c1.display();或c1.N::a=3;的成员,还是类B中从基类N继承下来的成员。c1.A::display();//要访问的是类N的派生类A中的基类成11.6.411.6.41.虚基类的作从上面的介绍可知:如果一个派生类有多个直接基成员,如c1.A::display()。C++提供虚基类(virtualbaseclass)的方法,使得在图图图图现在,将类A声现在,将类A声明为虚基类,方法如下classA//声明基类classB:virtualpublicclassC:virtualpublic注意虚基类并不是在声明基类时声明的,而是声明派生类时,指定继承方式时声明的。因为一class派生类名:virtual继承方式类在在派生类B和C中作了上面的虚基类声明后,派类D中的成员如图11.23所示需要注意:为了保证虚基类在派生类中只继承一类,则在派生类E中,虽然从类B和C路径派生的图图int图图intintdata_b;intdata_cvoidfun(intfun_d();2.虚基类的初2.虚基类的初始classA//定义基类{A(inti){classB:virtualpublic{B(intn):A(n){classC:virtualpublic{C(intn):A(n){classD:publicB,public注意在注意在定义类D的构造函数时,与以往使用的法有所不同。规定:在最后的派生类中不仅要负C++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B类C)对虚基类的构造函数的调用,这就保证了虚3.虚基3.虚基类的简单应用举例11.9在例11.8的基础上,在Teacher类和图#include<iostream>#include<string>#include<iostream>#include<string>classPerson(stringnam,chars,inta)//charsex;intclassTeacher:virtualpublic}classStudent:virtualpublicclassStudent:virtualpublicStudent(stringnam,chars,inta,floatGraduate(stringnam,chars,inta,stringt,floatsco,floatw)//voidshow(}floatintmain(grad1.show();return}运行结果可以看可以看到使用多重继承时要十分小心,经常会现二义性问题。许多专业人员认为:不要提倡在11.711.7基类与派生类的转只有公用派生类才是基类真正的子类型,它完整继承了基类的功能派生类对象可以向派生类对象可以向基类对象赋值可以用子类(即公用派生类)对象对其基类对象赋值如Aa1;B//定义基类A对象//定义类A的公用派生类B的对象//用派生类B对象b1对基类对象a1赋在赋值时舍弃派生类自己的成员。如图11.26示意请注意赋值后不能企图通过对象a1去访问派生对象b1的成员,因为b1的成员与a1的成员是不同的图图a1.age=23;//错误,a1.age=23;//错误,a1中不包含派生类中增加的成//正确,b1中包含派生类中增加的成应当注意,子类型关系是单向的、不可逆的。B象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,因为基类对象不包含派生类对象可以替代基派生类对象可以替代基类对象向基类对象的用进行赋值或初始化如已定义了基类A对象a1,可以定义a1的引用变量Aa1;BA&//定义基类A对象//定义公用派生类B对象//定义基类A对象的引用变量r,并用a1对其初始这时,引用变量r是a1的别名,r和a1共享同一段储单元。也可以用子类对象初始化引用变量r,上面最后一行改r=b1;//定义基类A对象的引用变量r,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 小餐饮合作协议书范本
- 短途沙石材料运输合同书5篇
- 标书管理协议
- 学校文具采购协议
- 生态贷款合同范本
- 电子设备购销合同
- 工艺品供货协议
- 园林绿化安全施工方案
- 济南市高空作业施工方案
- 离职退休人员返聘协议7篇
- 安全生产教育培训制度管理办法
- 抽油井检泵作业课件
- 2022年06月2022年广东肇庆广宁县司法局招考聘用政府雇员名师点拨卷V答案详解版(3套版)
- 《HSK标准教程3》第5课课件
- HSK标准教程4上第1课课件
- 民俗学概论 第一章 概述课件
- 养老机构行政值班查房记录表格
- 干粉灭火器点检记录表(样表)
- 伍光和自然地理学4版知识点总结课后答案
- 110kv变电站电气主接线设计资料全
- 华中科技大学版五年级信息技术教案
评论
0/150
提交评论