面向对象编程技术第七章派生与继承_第1页
面向对象编程技术第七章派生与继承_第2页
面向对象编程技术第七章派生与继承_第3页
面向对象编程技术第七章派生与继承_第4页
面向对象编程技术第七章派生与继承_第5页
已阅读5页,还剩48页未读 继续免费阅读

下载本文档

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

文档简介

面向对象编程技术第七章派生与继承第一页,共五十三页,2022年,8月28日本章主要内容类的继承与派生的提出派生类的定义与相关概念三种基本继承方式派生类的构造与析构函数派生类的成员标示与访问虚基类赋值兼容规则第二页,共五十三页,2022年,8月28日类的继承与派生的提出问题:我会使用windows98,我需要重新学习XP操作系统吗?我定义了一个描述点的类,如何在定义一个描述矩形的类??现实思维模式..WH事物发展有其延续性!第三页,共五十三页,2022年,8月28日类的继承与派生的提出继承的目的:实现数据、代码的重用。派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有数据、代码进行改造。

返回第四页,共五十三页,2022年,8月28日派生类的定义与相关概念定义格式:class

派生类名:继承方式1基类名1,…,继承方式n基类名n{成员声明;}

注:继承方式公有继承public私有继承private保护继承protected保持已有类的特性而构造新类的过程称为继承。在已有类的基础上新增自己的特性而产生新类的过程称为派生。被继承的已有类称为基类(父类)。派生出的新类称为派生类(子类)。直接父类、直接子类;间接父类、间接子类第五页,共五十三页,2022年,8月28日派生类的定义与相关概念派生(继承)的内部实现过程:添加新成员吸收除构造、析构函数外基类成员改造基类成员第六页,共五十三页,2022年,8月28日派生类的定义与相关概念描述平面的一个点矩形定义简单实例:classpoint{public:point(inta,intb){x=a,y=b;}intgetx()…intgety()…voidmoveto(inta,intb)…private:intx,inty;}classrectangle:publicpoint{public:publicretangle(intx,inty,intwidth,intheigth):point(x,y){w=width;h=height;}privated:intw,h;}第七页,共五十三页,2022年,8月28日派生类的定义与相关概念基类与派生类的对应关系:单继承:派生类只从一个基类派生。多继承:派生类从多个基类派生。多重派生:由一个基类派生出多个不同的派生类。多层派生:派生类又作为基类,继续派生新的类。

第八页,共五十三页,2022年,8月28日简化的继承体系图返回第九页,共五十三页,2022年,8月28日三种基本继承方式1.公有继承(public)基类的public和protected成员的访问属性在派生类中保持不变;基类的private成员不可访问(类内)

派生类的对象只能访问基类的public成员(类外)

第十页,共五十三页,2022年,8月28日classA{public:intx;A(inta,intb){x=a;u=b;}voidprt(){cout<<"publicx=:"<<x<<endl;}private:intu;};举例第一步:定义基类:第十一页,共五十三页,2022年,8月28日举例第二步:定义派生类classB:publicA{public:B(inta,intb,intc):A(a,b){y=c;}inty;voidprt(){cout<<"A::x=:"<<A::x<<endl; A::prt();

//cout<<"privatebaseA::u="<<A::u<<endl; cout<<"B::y=:"<<y<<endl; }};此行错误!第十二页,共五十三页,2022年,8月28日举例第三步:使用派生类voidmain(){Bb(1,2,3);b.prt();//cout<<b.u<<endl;}运行结果:A::x=:1publicx=:1B::y=:31PressanykeytocontinueError!不可直接输出u.第十三页,共五十三页,2022年,8月28日派生类中:基类public和protected成员变成private成员;基类private成员不可访问。通过派生类的对象不能访问基类中的任何成员2.私有继承(private)

如何理解?类外的问题第十四页,共五十三页,2022年,8月28日classA{public:intx;A(inta,intb){x=a;u=b;}voidprt(){cout<<"publicx=:"<<x<<endl;}private:intu;};举例第一步:定义基类:第十五页,共五十三页,2022年,8月28日举例第二步:定义派生类classB:privateA{public:B(inta,intb,intc):A(a,b){y=c;}inty;voidprt(){cout<<"A::x=:"<<A::x<<endl; A::prt(); cout<<"B::y=:"<<y<<endl; }};第十六页,共五十三页,2022年,8月28日举例第三步:使用派生类voidmain(){Bb(1,2,3);b.prt();//cout<<b.x<<endl;}运行结果:A::x=:1publicx=:1B::y=:31Pressanykeytocontinue私有数据,不可直接输出b.第十七页,共五十三页,2022年,8月28日3.保护继承(public)派生类中:基类的public和protected成员变成protected成员;基类的private成员不可访问派生类的对象不能访问基类中的任何成员第十八页,共五十三页,2022年,8月28日protected成员举例classA{protected:intx;}intmain(){Aa;//a.X=5;错误}第十九页,共五十三页,2022年,8月28日protected继承classA{public:intxvoidshow_private(){cout<<"privateofA'sy="<<y;}voidshow_proteced(){cout<<"protectedofA'sz="<<z;}private:inty;protected:intz;};第二十页,共五十三页,2022年,8月28日classB:protectedA{public:voidout_base_public(){cout<<"x=:"<<x<<endl;}//voidout_base_private(){cout<<"y=:"<<y<<endl;}Error!voidout_base_proteced(){cout<<"z=:"<<z<<endl;}};voidmain(){Bb;//b.x=19;Errror//b.y=19;Error//b.z=19;Errorb.out_base_public();b.out_base_proteced();}如何访问A中的X、y、z?如何输出A中的私有成员?间接的方式第二十一页,共五十三页,2022年,8月28日三种继承方式之间的比较返回第二十二页,共五十三页,2022年,8月28日派生类的构造与析构函数一、构造函数基类的构造函数不被继承,需要在派生类中自行声明初始化完成:基类成员:基类构造函数完成内嵌对象成员新增成员顺序的思考:有它的现实原形么??第二十三页,共五十三页,2022年,8月28日格式:派生类名::派生类名(参数总表):基类名1(参数),基类名2(参数),...基类名n(参数),内嵌对象1(参数)…内嵌对象n(参数){本类成员初始化赋值语句;};派生类的构造函数注意:参数的顺序不重要对比组合类的构造函数第二十四页,共五十三页,2022年,8月28日构造函数的调用次序调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。调用成员对象的构造函数,调用顺序按照它们在类中声明的顺序。派生类的构造函数完成新增成员的初始化。注意:派生类的析构函数的调用次序与构造函数正好相反为什么?第二十五页,共五十三页,2022年,8月28日举例:讨论构造函数的调用次序问题classB1 //基类B1,构造函数有参数{public: B1(inti){cout<<"constructingB1"<<i<<endl;}};classB2 //基类B2,构造函数有参数{public: B2(intj){cout<<"constructingB2"<<j<<endl;}};classB3 //基类B3,构造函数无参数{public: B3(){cout<<"constructingB3*"<<endl;}};第二十六页,共五十三页,2022年,8月28日classC:publicB2,publicB1,publicB3{public: C(inta,intb,intc,intd):B1(a),memberB2(d),memberB1(c),B2(b){}private: B1memberB1; B2memberB2; B3memberB3;};voidmain(){Cobj(1,2,3,4);}认真思考并回答其输出结果?第二十七页,共五十三页,2022年,8月28日constructingB22constructingB11constructingB3*constructingB13constructingB24constructingB3*Pressanykeytocontinue第二十八页,共五十三页,2022年,8月28日对构造函数调用的讨论基类采用缺省构造函数时:派生类构造函数可以调用基类缺省构造函数。基类声明带形参的构造函数时,派生类传递参数给基类构造函数,完成基类成员的初始化自定义缺省构造函数:1.无参数2.带缺省值系统默认构造函数两种情形第二十九页,共五十三页,2022年,8月28日二、析构函数析构函数也不被继承,派生类自行声明声明方法与一般(无继承关系时)类的析构函数相同不需要显式地调用基类的析构函数,系统会自动隐式调用和组合类相似第三十页,共五十三页,2022年,8月28日二、析构函数析构函数的调用次序与构造函数相反自定义析构函数主要完成动态分配内存对象的释放第三十一页,共五十三页,2022年,8月28日举例:classB1 //基类B1声明{public:B1(inti){cout<<"constructingB1"<<i<<endl;}~B1(){cout<<"destructingB1"<<endl;}};classB2 //基类B2声明{public:B2(intj){cout<<"constructingB2"<<j<<endl;} ~B2(){cout<<"destructingB2"<<endl;} };第三十二页,共五十三页,2022年,8月28日classB3 //基类B3声明{public:B3(){cout<<"constructingB3*"<<endl;}~B3(){cout<<"destructingB3"<<endl;} };classC:publicB2,publicB1,publicB3 {public:C(inta,intb,intc,intd):B1(a),memberB2(d),memberB1(c),B2(b){}private:B1memberB1;B2memberB2;B3memberB3;};第三十三页,共五十三页,2022年,8月28日voidmain(){ Cobj(1,2,3,4);}输出结果:ConstuctingB22ConstuctingB11ConstuctingB3*ConstuctingB13ConstuctingB24ConstuctingB3*DestructingB3DestructingB2DestructingB1DestructingB3DestructingB1DestructingB2返回第三十四页,共五十三页,2022年,8月28日派生类的成员标示与访问

问题:1.当派生类与基类中有相同成员时,如何标示与访问不同类中定义的成员?第三十五页,共五十三页,2022年,8月28日举例:classB1 {public: intnV; voidfun(){…}};classD1:publicB1 {public:intnV; voidfun(){}}如何访问D1类中、对象中成员?看下页第三十六页,共五十三页,2022年,8月28日派生类的成员标示与访问

-同名覆盖原则当派生类与基类中有相同成员时:若未强行指名,则通过派生类对象使用的是派生类中的同名成员。如要通过派生类对象访问基类中被覆盖的同名成员,应使用基类名限定。第三十七页,共五十三页,2022年,8月28日voidmain(){ D1d1; d1.nV=1;//对象名.成员名标识,访问D1类成员,同名覆盖

d1.fun(); d1.B1::nV=2;//作用域分辨符标识,访问基类B1成员

d1.B1::fun(); }第三十八页,共五十三页,2022年,8月28日派生类的成员标示与访问

-消除二义性

2.当多个直接基类中都从某一间接基类继承共同成员时如何标示和访问?(参见下页图)问题:问题越来越复杂啦!看下页第三十九页,共五十三页,2022年,8月28日ClassB0{Public:IntnvVoidfun(){…}}classB1:publicB0{public: intnV1; voidfun1(){…}};classB2:publicB0{public: intnV2; voidfun2(){…}};classD1:publicB1,publicB2 {public:intnV; voidfun*(){}}第四十页,共五十三页,2022年,8月28日派生类的成员标示与访问

-解决二义性问题通过直接基类,使用作用域运算符来访问不同类中的成员-参照上页图示

D1.B1::nv=1;D1.B2::nv=2;声明虚基类(下节介绍)返回第四十一页,共五十三页,2022年,8月28日虚基类虚基类的引入:用于直接基类有共同基类的场合,防止多次初始化基类成员,实现维护一份拷贝声明:继承时以virtual修饰说明基类

例:classB1:virtualpublicB注意:在第一级继承时就要将共同基类设计为虚基类。下页举例第四十二页,共五十三页,2022年,8月28日虚基类举例:classB0 //声明基类B0{public: //外部接口

intnV; voidfun(){cout<<"MemberofB0"<<endl;}};classB1:virtualpublicB0//B0为虚基类{public: //新增外部接口

intnV1;};classB2:virtualpublicB0//B0为虚基类派生B2类{public: //新增外部接口

intnV2;};第四十三页,共五十三页,2022年,8月28日classD1:publicB1,publicB2 //派生类D1声明{public: //新增外部接口

intnVd; voidfund(){cout<<"MemberofD1"<<endl;}};存储映象虚基类第四十四页,共五十三页,2022年,8月28日voidmain() //程序主函数{D1d1; //声明D1类对象d1 d1.nV=2; //使用直接基类数据成员

d1.fun();//使用直接基类函数成员}使之虚的思想第四十五页,共五十三页,2022年,8月28日虚基类及其派生类构造函数建立对象的类称为最远派生类虚基类成员由最远派生类构造函数通过虚基类构造函数进行初始化第四十六页,共五十三页,2022年,8月28日虚基类及其派生类构造函数派生类在构造函数的成员初始化表中调用虚基类的构造函数。否则调用该虚基类的缺省构造函数C++保证最远(当前)派生类的构造函数调用虚基类的构造函数,忽略其它父类对虚基类构造函数的调用避免多次构造第四十七页,共五十三页,2022年,8月28日classB0 //声明基类B0{public: //外部接口

B0(intn){nV=n;}intnV;voidfun(){…}};classB1:virtualpublicB0 {public: B1(inta):B0(a){} intnV1;};classB2:virtualpublicB0 {public: B2(inta):B0(a){} intnV2;};直接基类与间接基类定义第四十八页,共五十三页,2022年,8月28日classD1:publicB1,publicB2{public: D1(inta):B0(a),B1(a),B2(a){} intnVd; voidfund(){cout<<"MemberofD1"<<endl;}};voidmain() { D1d1(9); d1.nV=2; d1.fun();}派生类定义返回第四十九页,共五十三页,2022年,8月28日赋值兼容

温馨提示

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

评论

0/150

提交评论