版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第10章继承、多态和虚函数皮德常nuaacs@126.com110.1继承继承是OOP程序设计中很重要的一个方面。继承易于扩充现有类以满足新的应用。将已有的类称之为父类,也称基类,将新产生的类称为子类,也称为导出类或派生类。导出类不做任何改变地继承了基类中的所有变量和函数(构造函数和析构函数除外),并且还可以增加新的数据成员和函数,从而使导出类比基类更为特殊化。Example:例10-1.2//Contentsofgrade.hclassGrade{ charletter; floatscore; voidcalcGrade();public: voidsetScore(floats){score=s;calcGrade();} floatgetScore(){returnscore;} chargetLetter(){returnletter;}};3//Contentsofgrade.cpp
#include"grade.h"//DefinitionofmemberfunctionGrade::calcGradevoidGrade::calcGrade(){ if(score>89) letter='A'; elseif(score>79)letter='B'; elseif(score>69)letter='C'; elseif(score>59)letter='D'; elseletter='F';}4//Contentsoftest.h#include"grade.h"classTest:
publicGrade{
int
numQuestions; float pointsEach;
int
numMissed;public: Test(int,int);};5//Contentsoftest.cpp#include"test.h"//参数q代表问题的个数,m代表答错的题数.Test::Test(intq,intm){ floatnumericGrade;
numQuestions=q;
numMissed=m;
pointsEach=100.0f/numQuestions;
numericGrade=100.0f-numMissed*pointsEach;
setScore(numericGrade);}6#include"test.h"voidmain(){ intquestions,missed;
cout<<"Howmanyquestions?";
cin>>questions;
cout<<"Howmanyquestionsmissed?";
cin>>missed; Testexam(questions,missed); cout.precision(2);
cout<<"\nThescoreis"<<exam.getScore();
cout<<"\nThegradeis"<<exam.getLetter();}7上例中,父类中的公有成员在子类中仍是公有的,它们可以和子类中的公有成员一样被访问。但反过来是错误的,基类对象或基类中的某个函数不能调用子类中的函数。classBadBase
{ intx;public:
BadBase(){x=getVal();}//Error};classDerived:public
BadBase
{ inty;public: Derived(intz){y=z;}
int
getVal(){returny;}};810.2保护成员和类的访问基类中的保护成员和私有成员比较类似,唯一的区别是:子类不可访问基类中的私有成员,但可访问基类中的保护成员。在公有继承或保护继承的情况下,子类能访问基类的protected成员。Example:
例10-29//Contentsofgrade2.hclassGrade{protected:
charletter; floatscore; voidcalcGrade();public: voidsetScore(floats){score=s;calcGrade();} floatgetScore(){returnscore;} chargetLetter(){returnletter;}};10//Contentsoftest2.h#include"grade2.h"classTest:publicGrade{
int
numQuestions; float pointsEach;
int
numMissed;public: Test(int,int);
voidadjustScore();//新增加的函数};11//Contentsoftest2.cpp#include"test2.h"//构造函数略voidTest::adjustScore(){ if((score-int(score))>=0.5f){ score+=0.5;
calcGrade(); }}who12继承方式基类成员在子类中的表现private1.基类的私有成员在子类中不可访问;2.基类的保护成员变成了子类中的私有成员;3.基类的公有成员变成了子类中的私有成员。protected1.基类的私有成员在子类中不可访问;2.基类的保护成员变成了子类中的保护成员;3.基类的公有成员变成了子类中的保护成员。public1.基类的私有成员在子类中不可访问;2.基类的保护成员变成了子类中的保护成员;3.基类的公有成员变成了子类中的公有成员。13private:xprotected:ypublic:zprivate:xprotected:ypublic:zprivate:xprotected:ypublic:zxisinaccessibleprivate:yprivate:zxisinaccessibleprotected:yprotected:zxisinaccessibleprotected:ypublic:zprivatebaseclassprotectedbaseclasspublicbaseclassExample:14注意如果省略了继承修饰符,那么就是私有继承: classTest:Grade不要将继承修饰符与成员的访问修饰符相混淆:成员访问修饰符是规定类外语句能否访问类中的成员,而继承修饰符是为了限定基类成员在子类中的表现。1510.3构造函数和析构函数当基类和子类都有构造函数时,如果定义一个子类对象,那么首先要调用基类的构造函数,然后再调用子类的构造函数;析构函数的调用次序与此相反,即先调用子类的析构函数,然后再调用基类的析构函数。Example:
例10-3.16classBaseDemo{public:
BaseDemo() {cout<<"InBaseDemoconstructor.\n";} ~BaseDemo() {cout<<"InBaseDemodestructor.\n";}};classDeriDemo:publicBaseDemo{public:
DeriDemo() {cout<<"InDeriDemoconstructor.\n";} ~DeriDemo() {cout<<"InDeriDemodestructor.\n";}};17voidmain(){
cout<<"下面定义一个DerivedDemo
类对象\n";
DerivedDemoobject;//定义一个对象
cout<<"下面将要结束程序
\n";}Output:下面定义一个DerivedDemo
类对象调用基类BaseDemo的构造函数调用子类DerivedDemo
的构造函数下面将要结束程序调用子类DerivedDemo
的析构函数调用基类BaseDemo的析构函数1810.3.2向基类的构造函数传参数如果基类和子类都有缺省的构造函数,它们的调用是自动完成的,这是一种隐式调用。如果基类的构造函数带有参数,那么必须让子类的构造函数显式调用基类的构造函数,并且向基类构造函数传递适当的参数。
Example:例10-419classRectangle{protected: floatwidth,length,area;public: Rectangle(){width=length=area=0.0f;}
Rectangle(floatw,floatl)
{ width=w;length=l; area=width*length; } floatgetArea(){returnarea;} floatgetLen(){returnlength;} floatgetWidth(){returnwidth;}};20classCube:publicRectangle{protected: floatheight,volume;public:
Cube(float,float,float); floatgetHeight(){returnheight;} floatgetVol(){returnvolume;}};Cube::Cube(floatw,floatl,floath):Rectangle(w,l){ height=h;volume=area*height;}21Note如果基类没有缺省的构造函数,那么子类必须至少具有一个带参的构造函数,以便向基类构造函数传递参数。2210.3.3初始化列表的作用1.
如果类之间具有继承关系,子类必须在其初始化列表中调用基类的构造函数。例:classBase{ Base(intx);}; classDerived:publicBase{
Derived(intx,inty):Base(x)
{ /*…*/} };2310.3.3初始化列表的作用2.
类中的const常量只能在初始化列表中进行初始化,而不能在函数体内用赋值的方式来初始化。classBase{ constintSIZE;
Base(intsize):SIZE(size)
{/*…*/}};Baseone(100);2410.3.3初始化列表的作用3.
对象类型的成员的初始化放在初始化列表中,则效率较高,反之较低;基本类型变量的初始化可以在初始化列表中,也可在构造函数中,效率上没区别。classBase{ Base();
Base(constBase&other);};classDerived{ BaseB_Member;public:
Derived(constBase&a);};构造函数的实现:Derived::Derived(constBase&b):B_Member(b){/*…*/}也可这样实现,但效率较低。Derived::Derived(constBase&b){B_Member=b;}2510.4覆盖基类的函数成员重载的特点:(1)重载表现为有多个函数,它们的名字相同,但参数不全相同;(2)重载可以出现在同一个类中,也可出现在具有继承关系的父类与子类中;(3)重载也可表现为外部函数的形式。2610.4覆盖基类的函数成员覆盖的特点:(1)覆盖一定出现在具有继承关系的基类和子类之间;(2)覆盖除了要求函数名完全相同,还要求相应的参数个数和类型也完全相同;(3)当进行函数调用时,子类对象所调用的是子类中定义的函数;(4)覆盖是C++多态性的部分体现。27classMileDist
{protected:floatmiles;public: voidsetDist(floatd){miles=d;} floatgetDist(){returnmiles;}};classFeetDist:publicMileDist
{ protected:floatfeet;public: voidsetDist(float); floatgetDist(){returnfeet;} floatgetMiles(){returnmiles;}};28voidFeetDist::setDist(floatft){ feet=ft;
//Callbaseclassfunction
MileDist::setDist(feet/5280);}voidmain(){FeetDistfeet;floatft;
cout<<"Adistanceinfeetandconvertittomiles:";
cin>>ft;
feet.setDist(ft);
cout<<feet.getDist()<<"feetequals";
cout<<feet.getMiles()<<"miles.\n";}2910.5虚函数函数覆盖体现了一定的多态性。但是,简单的函数覆盖并不能称为真正的多态性。Example:例10-730classMileDist{protected: floatmiles;public: voidsetDist(floatd){miles=d;} floatgetDist(){returnmiles;} floatsquare(){returngetDist()*getDist();}};who31classFeetDist:publicMileDist
{protected: floatfeet;public: voidsetDist(float); floatgetDist(){returnfeet;} floatgetMiles(){returnmiles;}};voidFeetDist::setDist(floatft){ feet=ft;
MileDist::setDist(feet/5280);}32voidmain(){ FeetDistfeet; floatft;
cout<<"Adistanceinfeettomiles:";
cin>>ft;
feet.setDist(ft); cout.precision(1); cout.setf(ios::fixed);
cout<<feet.getDist()<<"feetequals";
cout<<feet.getMiles()<<"miles.\n";
cout<<feet.getDist()<<"squarefeetis";
cout<<feet.square()<<"totalfeet.\n";}33运行结果:
Adistanceinfeettomiles:52805280.0feetequals1.0miles.5280.0squarefeetis1.0totalfeet.错误的原因:C++编译器在缺省情况下,对函数成员的调用实施的是静态连编(也称静态绑定)。解决方法:将getDist设置为虚函数。对于虚函数,编译器完成的是动态连编(也称动态绑定),即对函数的调用是在运行时确定的。OOP:
覆盖和重载不能体现真正的多态性,只有虚函数才是多态性的表现。不支持多态性的语言,就不能称为OOP。3410.6纯虚函数和抽象类纯虚函数是在基类中声明的虚函数,没有函数体,要求继承基类的子类必须覆盖它。带有纯虚函数的类称为抽象类,不能定义抽象类的对象。派生类可以根据自己的需要,分别覆盖它,从而实现真正意义上的多态性。格式:virtualvoidshowInfo()=0;35classStudent//例10-9{protected: charname[51];
inthours;public: Student(){name[0]=hours=0; } voidsetName(char*n){strcpy(name,n);} //Purevirtualfunction
virtualvoidsetHours()=0; virtualvoidshowInfo()=0;};36classCsStudent:publicStudent{ int
mathHours,csHours;public: voidsetMathHours(int
mh){mathHours=mh;} voidsetCsHours(int
csh){csHours=csh;} voidsetHours() { hours=mathHours+csHours; } voidshowInfo();};37voidCsStudent::showInfo(){
cout<<"Name:"<<name<<endl;
cout<<"\tMath:"<<mathHours<<endl;
cout<<"\tCS:"<<csHours;
cout<<"\n\tTotalHours:"<<hours;}voidmain(){ CsStudentstudent1; charchInput[51];
int
intInput;38
cout<<"Enterthefollowinginformation:\n";
cout<<"Name:"; cin.getline(chInput,51); student1.setName(chInput);
cout<<"Numberofmathhourscompleted:";
cin>>intInput; student1.setMathHours(intInput);
cout<<"NumberofCShourscompleted:";
cin>>intInput; student1.setCsHours(intInput); student1.setHours();
cout<<"\nSTUDENTINFORMATION\n"; student1.showInfo();}39Rememberthefollowingpoints如果一个类包含有纯虚函数,那么它就是抽象类,必须让其它类继承它;基类中的纯虚函数没有代码;不能定义抽象类的对象,即抽象基类不能实例化;必须在子类中覆盖基类中的纯虚函数。4010.6.3指向基类的指针指向基类对象的指针可以指向其子类的对象;如果子类覆盖了基类中的成员,但通过基类指针所访问的成员仍是基类的成员,而不是子类成员。Example:例10-1041classBase{public:voidshow(){cout<<"InBaseclass.\n";}};classDerived:publicBase{public:voidshow(){cout<<"InDerivedclass.\n";}};voidmain(){ Base*bptr; Deriveddobject;
bptr=&dobject;
bptr->show();}思考:调用谁?什么原因?如何解决?4210.7多重继承classAclassBclassCClassCinheritsallofClassB'smembers,includingtheonesClassBinheritedfromClassA.4310.8多继承如果一个子类具有两个或多个直接父类,那么就称为多继承。
classAclassBclassCConstructorsarecalledintheordertheyarelistedinthefirstlineoftheclassdeclaration.44classDate //例10-12
{protected:
intday,month,year;public:
Date(intd,intm,inty) { day=d;month=m;year=y; }
int
getDay(){returnday;}
int
getMonth(){returnmonth;}
int
getYear(){returnyear;}};45classTime{protected:
inthour,min,sec;public:
Time(inth,intm,ints) { hour=h;min=m;sec=s; }
int
getHour(){returnhour;}
int
getMin(){returnmin;}
int
getSec(){returnsec;}};46classDateTime:publicDate,publicTime
{protected: chardTString[20];public:
DateTime(int,int,int,int,int,int); voidgetDateTime(char*str) {
strcpy(str,dTString); }};这个顺序很重要47DateTime::DateTime(int
yr,int
mon,int
dy,inthr,
int
mt,intsc):Time(hr,mt,sc),Date(dy,mon,yr)
{ chartemp[10];//IntheformYY/MM/DD
strcpy(dTString,itoa(getYear(),temp,10));
strcat(dTString,"/");
strcat(dTString,itoa(getMonth(),temp,10));
strcat(dTString,"/");
strcat(dTString,itoa(getDay(),temp,10));
strcat(dTString,"");
strcat(dTString,itoa(getHour(),temp,10));
strcat(dTString,":");
strcat(dTString,itoa(getMin(),temp,10));
strcat(dTString,":");
strcat(dTString,itoa(getSec(),temp,10));}48voidmain(){ charformatted[20];
DateTime
pastDay(2,4,60,5,32,27);
pastDay.getDateTime(formatted);
cout<<formatted<<endl;}输出结果:
4/2/605:32:2749#include<time.h>#include<iostream.h>voidmain(){chartmpbuf[128];//Displayoperatingsystem-styledateandtime_strtime(tmpbuf);
cout<<"time:\t"<<tmpbuf<<endl;_strdate(tmpbuf);
cout<<"date:\t"<<tmpbuf<<endl;}获取系统时间5010.9类模板类模板用于创建类属类和抽象数据类型,从而使程序员可以创建一般形式的类,而不必编写处理不同数据类型的类。
Example:Program10-13.51template<classT>classFreewillArray{ T*aptr;
int
arraySize; voidmemError(void); //allocationerrors
voidsubError(void); //outofrangepublic:
FreewillArray(){aptr=0;arraySize=0;}
FreewillArray(int);
FreewillArray(const
FreewillArray&); ~FreewillArray();
intsize() {returnarraySize;}
T&operator[](constint&);};52//ConstructorforFreewillArrayclass.
template<classT>FreewillArray<T>::FreewillArray(ints){
arraySize=s;
aptr=newT[s]; if(aptr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 安全教育在校园文化建设中的创新应用
- 教育装备的绿色节能型涂装实践
- Unit 1 Topic 2 I'll kick you the ball again. Section C 说课稿-2024-2025学年仁爱科普版英语八年级上册
- 七上第六单元大单元说课稿
- Two great teachers 说课稿2024-2025学年冀教版(2024)初中英语七年级上册001
- 浙教版信息技术七上 第11课《数据分析报告》说课稿
- 第八单元 20世纪下半叶世界的新变化-高中历史单元说课稿
- 第8课 浓郁的乡土气息淳朴的人性之美-《蒲柳人家(节选)》(说课稿)九年级语文下册同步高效课堂(统编版)
- 二手车买卖协议模板(2024年修订版)一
- 专用外接电源使用协议范本2024版版A版
- “简约与繁复”二元思辨【 审题立意+范文精评 】 语文高分写作 多元思辨
- 计算物理课件
- 初级养老护理员培训全套
- 集中供热管网系统一次网的调节方法
- MRP、MPS计划文档教材
- 甲状腺疾病护理查房课件
- 安全安全带检查记录表
- GB∕T 26520-2021 工业氯化钙-行业标准
- 2022年浙江省绍兴市中考数学试题及参考答案
- Listen-to-this-3-英语高级听力-(整理版)
- 生活垃圾焚烧处理建设项目评价导则(2022)
评论
0/150
提交评论