清华大学出版社钱能课件_第1页
清华大学出版社钱能课件_第2页
清华大学出版社钱能课件_第3页
清华大学出版社钱能课件_第4页
清华大学出版社钱能课件_第5页
已阅读5页,还剩54页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

清华大学出版社钱能讲师:曹晓丽第十六章继承清华大学出版社钱能讲师:曹晓丽第十六章继承第十六章继承16.1继承的概念16.2继承的工作方式16.3派生类的构造16.4继承与组合16.5多态性16.6多态的思考方式16.7不恰当的虚函数16.8虚函数的限制16.9虚函数的限制第十六章继承16.1继承的概念第十六章继承16.10类的冗余16.11客服冗余带来的问题16.12类的分解16.13抽象类16.14有抽象类派生具体类16.15纯虚函数的需要小结第十六章继承16.10类的冗余第十六章继承教学目标:能利用继承现有的类建立新类理解继承如何提高软件的重用性理解多态性对于继承的意义掌握多态的工作原理理解抽象类和具体类的区别学会运用纯虚函数第十六章继承教学目标:16.1继承的概念交通工具汽车卡车小汽车旅行车工具车轿车面包车轮船飞机基类(父类)派生类(父类)祖先类16.1继承的概念交通工具汽车卡车小汽车旅行车工具车轿车面ShapeShape2DShape3DCircleTriangleRectangleSphereCubeTetrahedron16.1继承的概念ShapeShape2DShape3DCircleTrian继承是我们理解事物,解决问题的方法;通过继承,可以从已有的类派生出新类,新类继承父类的属性和操作,并在已有类的基础上新增自己的属性和操作,剔除那些不适合于其用途的继承下来的操作;被继承的已有类称为基类(父类),派生出的新类称为派生类(子类);继承可以减少代码的冗余性,实现代码的重用,并且通过作少量的修改,满足不断变化的具体应用要求,提高程序设计的灵活性;16.1继承的概念继承是我们理解事物,解决问题的方法;16.1继承的概念派生类的定义class派生类名:继承方式基类名1,…

{成员定义;

}基类与派生类的关系是相对的;

多继承:一个派生类有多个直接基类;

单继承:一个派生类只有一个直接基类;16.2继承的工作方式派生类的定义16.2继承的工作方式例如:现有一个学生类Student,要增加研究生类GraduateStudent。由于研究生除了他自己特有的性质外,具有学生的所有性质,所以我们用继承的方法来重用学生类。Ch16_1.cppclassStudent{//…};classGraduateStudent:publicStudent{//…};16.2继承的工作方式StudentGradusteStudent例如:现有一个学生类Student,要增加研究生类Gradu16.2继承的工作方式#include<iostream.h>#include<string.h>classAdvisor{intnoOfMeeting;};classStudent{public:Student(char*pName="noname"){strncpy(name,pName,sizeof(name));average=semesterHours=0;}16.2继承的工作方式#include<iostream.16.2继承的工作方式voidaddCourse(inthours,floatgrade){average=(semesterHours*average+grade);//总分

semesterHours+=hours;//总修学时

average/=semesterHours;//平均分

}intgetHours(){returnsemesterHours;}floatgetAverage(){returnaverage;}

16.2继承的工作方式voidaddCourse(int16.2继承的工作方式voiddisplay(){cout<<"name=\""<<name<<"\""<<",hours="<<semesterHours<<",average="<<average<<endl;}protected:charname[40];intsemesterHours;floataverage;};16.2继承的工作方式voiddisplay()16.2继承的工作方式classGraduateStudent:publicStudent{public:getQualifier(){returnqualifierGrade;}protected:Advisoradvisor;intqualifierGrade;};16.2继承的工作方式classGraduateStud16.2继承的工作方式voidmain(){Studentds("Loleeundergrade");GraduateStudentgs;ds.addCourse(3,2.5);ds.display();gs.addCourse(3,3.0);gs.display();}运行结果:name="Loleeundergrade",hours=3,average=0.833333name=“noname",hours=3,average=116.2继承的工作方式voidmain()name="继承方式继承方式指定了派生类成员以及类外对象对继承来的成员的访问权限。三种继承方式:公有继承(public);保护继承(protected);私有继承(private);16.2继承的工作方式继承方式16.2继承的工作方式16.3继承中的构造函数和析构函数派生类不继承基类的构造函数和析构函数,但是能调用基类的构造函数和析构函数;派生类的构造函数总是先调用基类的构造函数来初始化派生类中的基类成员,再进行派生类中成员的初始化;派生类构造函数的定义中,要提供基类构造函数所需要的参数。16.3继承中的构造函数和析构函数派生类不继承基类的构造函如果派生类没有用户自定义的构造函数,执行其默认构造函数时,首先调用基类的构造函数;析构函数的调用顺序和构造函数的调用顺序相反;子类的构造函数要有一个默认的父类的构造函数对应16.3继承中的构造函数和析构函数如果派生类没有用户自定义的构造函数,执行其默认构造函数时,首classBase{ public: Base(inti); ~Base(); voidprint();private: inta;};classDerive:publicBase{public: Derive(inti,intj); ~Derive(); voidprint();private:intb;};例116.3继承中的构造函数和析构函数classBaseclassDerive:publiBase::Base(inti){ a=i; cout<<"Baseconstructor"<<endl;}Base::~Base(){ cout<<"Basedestructor"<<endl;}voidBase::print(){ cout<<a<<endl;}16.3继承中的构造函数和析构函数Base::Base(inti)16.3继承中的构造函数Derive::Derive(inti,intj):Base(i){ b=j; cout<<"Deriveconstructor"<<endl;}Derive::~Derive(){ cout<<"Derivedestructor"<<endl;}voidDerive::print(){ Base::print(); cout<<b<<endl;}:a(i)

×16.3继承中的构造函数和析构函数Derive::Derive(inti,intj):voidmain(){ Derived(2,5); d.print();}BaseconstructorDeriveconstructor25DerivedestructorBasedestructor16.3继承中的构造函数和析构函数voidmain()Baseconstructor16.例2classBase{ public: Base(); Base(inti);......};classDerive:publicBase{public: Derive(inti,intj){}......};16.3继承中的构造函数和析构函数例2classBaseclassDerive:pub例3classBase{ public: Base(){cout<<"Baseconstructor"<<endl;} ~Base(){ cout<<"Basedestructor"<<endl;} voidprint();};16.3继承中的构造函数和析构函数例3classBase16.3继承中的构造函数和析构函数classDerive:publicBase{public: voidset(inti){b=i;} voidprint(){cout<<b<<endl;}private:intb;};voidmain(){ Derived; d.set(2); d.print();}Baseconstructor2Basedestructor16.3继承中的构造函数和析构函数classDerive:publicBaseBase16.4继承与组合组合:一个类的数据成员是另一个类的对象;继承和组合都利用了已经定义的类,但是类之间关系上有差别;继承时子类享有父类的一切待遇,父类能出现的地方,子类同样可以出现,如汽车是车辆的子类,继承了车辆所有属性;而组合说明一个类只是另一个类的成员,不能代表类本身,汽车包含有一个马达,但马达不是汽车,汽车也不是马达。16.4继承与组合组合:一个类的数据成员是另一个类的对象;16.4继承与组合构造函数的调用顺序:调用基类构造函数;调用各成员对象的构造函数,调用顺序按照它们在类中声明的顺序。执行派生类的构造函数体中的内容;16.4继承与组合构造函数的调用顺序:classBase{ inta;public: Base(inti) { a=i; cout<<"Baseconstructor"<<endl; } ~Base(){cout<<"Basedestructor"<<endl;} voidprint(){cout<<a<<endl;}};16.4继承与组合classBase16.4继承与组合classMember{ intb;public: Member(intj) { b=j; cout<<"Memberconstructor"<<endl; } ~Member(){cout<<"Memberdestructor"<<endl;} voidprint(){cout<<b<<endl;}};16.4继承与组合classMember16.4继承与组合classDerive:publicBase{ intc; Membermem;public: Derive(inti,intj,intk):mem(j),Base(i) { c=k; cout<<"Deriveconstructor"<<endl; } ~Derive(){cout<<"Derivedestructor"<<endl;} voidprint() {

Base::print(); mem.print(); cout<<c<<endl; }};classDerive:publicBasevoidmain(){ Derived(2,3,4); d.print();}BaseconstructorMemberconstructorDeriveconstructor234DerivedestructorMemberdestructorBasedestructor16.4继承与组合voidmain()Baseconstructor16.classBase{ inta; public: Base(inti):a(i){}};classDerive:publicBase{ intb;public: Derive(inti)

:b(i*15),Base(b){}};voidmain(){Derived(10);}16.4继承与组合classBaseclassDerive:publi16.5多态性(Polymorphism)在程序中同一符号或名字在不同情况下具有不同解释的现象称为多态性。是指同一函数的多种行为。Earlybinding(编译时多态性):在程序编译阶段即可确定下来的多态性,主要通过使用重载机制获得;函数名相同,参数类型不同、个数不同,或返回值类型不同。Latebinding(运行时多态性):必须等到程序动态运行时才可确定的多态性,主要通过虚函数实现;参数类型、个数、返回值类型必须相同。否则不能迟后联编。16.5多态性(Polymorphism)在程序中同一符号16.5多态性(Polymorphism运行时多态性的优点运行时根据实际对象的类型,动态地决定应该使用虚函数的哪个版本,符合人们的习惯,实现了更高级更自然的抽象;进一步减少了信息冗余;显著提高了程序的可重用性、可扩展性、可维护性;

16.5多态性(Polymorphism运行时多态性的优点16.5多态性(Polymorphism)我们通常说的多态性是指运行时多态性。有时候,会遇到对象所属的类不能确定的情况,C++继承机制用一种称为多态性的技术解决上面的问题,为了指明某个成员函数具有多态性,用关键字virtual来标志其为虚函数。编译看见虚函数时,将其作为迟后联编来处理,保证运行时确定调用哪个虚函数。虚函数可以继承,所以子类中的虚函数前的virtual可以省略。16.5多态性(Polymorphism)我们通常说的多态classBase{public:

virtualvoidview(){cout<<"InBase!"<<endl;}};classDerive:publicBase{public: voidview(){cout<<"InDerive!"<<endl;}};16.5多态性(Polymorphism)classBase16.5多态性(Polymorphisvoidfunc(Base&b){ b.view();}voidmain(){ Baseb1; func(b1); //调用Base的成员函数 Derived1; func(d1); //调用Derive的成员函数}InBase!InDerive!16.5多态性(Polymorphism)voidfunc(Base&b)InBase!16.5赋值兼容原则一个公有继承的派生类对象可以隐式转化为一个基类对象:用派生类的对象给基类对象赋值;用派生类的对象来初始化基类的引用;把派生类对象的地址赋值给指向基类的指针;把指向派生类对象的指针赋值给指向基类对象的指针;访问范围基类对象不能代替派生类对象;基类成员派生类成员16.5多态性(Polymorphism)赋值兼容原则基类成员派生类成员16.5多态性(Polymo16.8不恰当的虚函数如果虚函数在基类与子类中出现的仅仅是名字的相同,而参数类型不同,或返回值类型不同,即使写上了Virtual,也不进行迟后联编,按同名函数重载处理。16.8不恰当的虚函数如果虚函数在基类与子类中出现的仅仅是16.8不恰当的虚函数P360ch16_4#include<iostream.h>classBase{public:virtualvoidfn(intx){cout<<"InBaseclass,intx="<<x<<endl;}};classSubClass:publicBase{public:virtualvoidfn(floatx){cout<<"InSubClass,floatx="<<x<<endl;}};16.8不恰当的虚函数P360ch16_4voidtest(Base&b){inti=1;b.fn(i);floatf=2.0;b.fn(f);}voidmain(){Basebc;SubClasssc;cout<<"Callingtest(bc)\n";test(bc);cout<<"Callingtest(sc)\n";test(sc);}InBase!InBase!16.8不恰当的虚函数voidtest(Base&b)InBase!16.816.8不恰当的虚函数如果基类中的虚函数返回一个基类指针或返回一个基类的引用,子类中的虚函数返回一个子类指针或一个子类的引用,则C++将其视为同名虚函数而进行迟后联编。16.8不恰当的虚函数如果基类中的虚函数返回一个基类指针或16.8不恰当的虚函数Ch16_5.cpp#include<iostream.h>classBase{public:

virtualBase*afn(){cout<<"ThisisBaseclass.\n";returnthis;}};classSubClass:publicBase{public:SubClass*afn(){cout<<"ThisisSubClass.\n";returnthis;}};16.8不恰当的虚函数Ch16_5.cpp16.8不恰当的虚函数classSubClass:publicBase{public:

SubClass*afn(){cout<<"ThisisSubClass.\n";returnthis;}};16.8不恰当的虚函数classSubClass:pu16.8不恰当的虚函数voidtest(Base&x){Base*b;b=x.afn();}voidmain()ThisisBaseclass.{ThisisSubClass.Basebc;SubClasssc;test(bc);test(sc);}16.8不恰当的虚函数voidtest(Base&x)16.9关于虚函数的说明定义虚函数,在类定义中函数原型之前加virtual;virtual只用来说明类定义中的原型,不能用在函数实现时;

classBase {public: virtualvoiddisplay();};virtualvoidB0::display()//Error{cout<<“InBase!"<<endl;}16.9关于虚函数的说明定义虚函数,在类定义中函数原型之前虚函数在基类与派生类中的声明(包括函数名,返回值类型和参数表列)必须一样,才能实现运行时的多态;classBase{public: virtualvoidfn1(); virtualvoidfn2(); virtualvoidfn3();}classDerive:publicBase{public: voidfn1(); intfn2(); voidfn3(int);}16.9关于虚函数的说明虚函数在基类与派生类中的声明(包括函数名,返回值类型和参数表基类中定义了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数;只有类的非静态成员函数才能声明为虚函数;内联函数不能是虚函数;构造函数不能是虚函数;析构函数通常是虚函数;16.9关于虚函数的说明基类中定义了虚函数,派生类中无论是否说明,同原型函数都自动为16.9关于虚函数的说明动态绑定成员函数调用中代码地址的确定非虚成员函数是根据指向对象的指针的类型静态地(在编译时)选择虚成员函数是动态(在运行时)解析的。根据对象的类型而不是根据指向对象的指针的类型来动态地(在运行时)选择使用虚函数,系统将使用动态绑定在程序设计中提供更强的功能和灵活性处理过程中占用一些开销16.9关于虚函数的说明动态绑定16.10类的冗余两个类如果有很多相同的成员,可以将共同的特性分解到基类中。16.10类的冗余两个类如果有很多相同的成员,可以将共同的16.13纯虚函数和抽象类纯虚函数(purevirtualfunction):被标明为不具体实现的虚成员函数;纯虚函数的声明格式为:virtual函数类型函数名(参数表)=0;抽象类(abstractclass):不能有实例对象的类,唯一的用途是被继承,一个抽象类至少具有一个虚函数;16.13纯虚函数和抽象类纯虚函数(purevirtua16.13纯虚函数和抽象类抽象类的作用抽象类为抽象和设计的目的而建立,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。派生类实现纯虚函数的参数要与父类纯虚函数声明的参数相同16.13纯虚函数和抽象类抽象类的作用constdoublePI=3.1415926;classShape2D{protected: doubleBaseX,BaseY;public: Shape2D(doublex,doubley):BaseX(x),BaseY(y){}

virtualdoubleArea()=0;};16.13纯虚函数和抽象类constdoublePI=3.1415926;16.1classCircle:publicShape2D{ doubleradius;public: Circle(doublex,doubley,doubler):Shape2D(x,y),radius(r){}

doubleArea(){returnPI*radius*radius;}};16.13纯虚函数和抽象类classCircle:publicShape2D16.classRectangle:publicShape2D{ doubleRectangleX,RectangleY;public: Rectangle(doublex,doubley,doublel,doublew) :Shape2D(x,y),RectangleX(l),RectangleY(w){}

doubleA

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论