C++程序设计基础教程 第2版 课件 第11章 继承与派生_第1页
C++程序设计基础教程 第2版 课件 第11章 继承与派生_第2页
C++程序设计基础教程 第2版 课件 第11章 继承与派生_第3页
C++程序设计基础教程 第2版 课件 第11章 继承与派生_第4页
C++程序设计基础教程 第2版 课件 第11章 继承与派生_第5页
已阅读5页,还剩74页未读 继续免费阅读

下载本文档

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

文档简介

第11章继承与派生主要内容11.1类的继承与派生11.2派的继承方式11.3派生类的构造函数和析构函数11.4多重继承11.5应用实例11.1类的继承与派生类的继承:新类从已有类(父类)那里获得其已有特性。类的派生:已有类(父类)产生新的子类。派生类继承了基类的所有数据成员和成员函数,并可对成员作必要的增加或调整。基类和派生类相对而言:一个基类可派生出多个派生类,每个派生类又可作为基类再派生出新的派生类。11.1.1继承与派生的实例设计的原则:公共的特性抽象封装成基类,独有的特性在派生类里实现。11.1.1继承与派生的实例学校人员管理:学生教师管理人员教师管理人员人员(姓名,性别,年龄,学院)(学号,姓名,性别,年龄,学院,专业,班级)(工号,姓名,性别,年龄,学院,职称)(工号,姓名,性别,年龄,学院,科室,职务)(工号,姓名,性别,年龄,学院,职称,科室,职务)人类教师类学生类管理人员类教师管理人员类多继承:派生类有多个基类单继承:派生类只有一个基类直接基类间接基类11.1.1继承与派生的实例单继承(singleinheritance):一个派生类只从一个基类派生。多重继承(multipleinheritance):一个派生类有两个或两个以上基类。11.1.2派生类的定义声明派生类的一般形式class派生类名:[继承方式]基类名{派生类新增的成员};继承方式:public,private和protected。默认继承方式:private。基类:人员类classPerson //定义Person类{ public:

Person(constchar*Name,intAge,charSex);

char*GetName(); intGetAge();

charGetSex();voidDisplay();private: charname[50]; charsex; intage;};classStudent:publicPerson//公有继承{public:

Student(char*pName,intAge,charSex,char*pId,floatscore):Person(pName,Age,Sex);

//派生类新增的成员函数 char*GetId();

floatGetScore();

voidDisplay(); private:

//派生类新增的数据成员charsid[9]; floatscore;};派生类:学生类派生类:教师类classTeacher:publicPerson{//公有继承public:

Teacher(char*pName,intAge,charSex,char*pId,char*pprof,floatSalary):Person(pName,Age,Sex);

char*GetId();

char*GetProf();

floatGetSalary();

voidDisplay();private: charid[9];charprof[12]; floatsalary;};11.1.3派生类的生成过程(1)继承基类成员(2)改造基类成员(3)增加新的成员11.2类的继承方式公用继承私有继承保护继承继承方式影响基类成员在派生类的访问属性(1)公用继承(publicinheritance)基类的公用和保护成员在派生类中保持原有访问属性,私有成员仍为基类私有。(2)私有继承(privateinheritance)基类的公用和保护成员在派生类中成了私有成员,私有成员仍为基类私有。(3)受保护的继承(protectedinheritance)基类的公用和保护成员在派生类中成了保护成员,私有成员仍为基类私有。11.2.1公用继承公有继承时,基类的公有成员和保护成员作为派生类的成员时,都保持原有状态,而私有成员仍是私有。公有继承时,派生类的对象只可访问基类中的公有成员,不能访问其它成员。派生类的成员函数可以访问基类中的公有成员和保护成员,不可访问其私有成员。11.2.1公用继承classstudent{private:intage;protected:charsex;public:intGetage(){returnage;}};classgraduatestudent:publicstudent{private:intstunum;

public:voiddisplay();};即:student::Getage()//

//不可访问基类的私有成员//派生类的私有成员//基类的公有成员公有继承voidgraduatestudent::display()//派生类成员函数定义{cout<<"age:"<<age<<endl;cout<<"stunum:"<<stunum<<endl;cout<<"age:"<<Getage()<<endl;cout<<"sex:"<<sex<<endl;//即:student::sex基类的保护成员}voidmain(){graduatestudentzh;//生成派生类对象

cout<<zh.Getage();//即:student::Getage();基类中的公有成员

zh.display();//访问派生类中的公有成员

cout<<zh.sex;cout<<zh.stunum;cout<<zh.age;}//

//

error,访问基类中保护成员//

//

error,访问派生类中私有成员//

//

error,访问基类中私有成员公有继承11.2.2私有继承私有继承时,基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。私有继承classstudent{private:intage;protected:charsex;public:intGetage(){returnage;}};classgraduatestudent:privatestudent{private:intstunum;public:voiddisplay();};私有继承voidgraduatestudent::display()//派生类成员函数定义{

//cout<<"age:"<<age<<endl;//不可访问基类的私有成员

cout<<"stunum:"<<stunum<<endl;//派生类的私有成员

cout<<"age:"<<Getage()<<endl;//基类的公有成员

cout<<"sex:"<<sex<<endl;

//即:student::sex基类的保护成员

}私有继承voidmain(){graduatestudentzh;//生成派生类对象

//zh.Getage();//error,不能访问私有成员zh.display();//访问派生类中的公有成员//cout<<zh.sex;//error,不能访问私有成员

//cout<<zh.stunum;//error,不能访问私有成员

//cout<<zh.age;//error,不能访问私有成员}11.2.3保护继承保护继承时,基类的所有公有成员和保护成员都作为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍是私有的。保护继承时,派生类的成员函数可以直接访问从基类继承而来的成员,但在类外不能直接访问。保护继承classstudent{private:intage;protected:charsex;public:intGetage(){returnage;}};classgraduatestudent:protectedstudent{private:intstunum;public:voiddisplay();};保护继承voidgraduatestudent::display()//派生类成员函数定义{//cout<<"age:"<<age<<endl;//不可访问基类的私有成员cout<<"stunum:"<<stunum<<endl;//派生类的私有成员cout<<"age:"<<Getage()<<endl;//基类的公有成员cout<<"sex:"<<sex<<endl;//即:student::sex

基类的保护成员

}保护继承voidmain(){graduatestudentzh;//生成派生类对象

//zh.Getage();//error,不能访问保护成员zh.Getnum();//访问派生类中的公有成员//cout<<zh.sex;//

error,不能访问保护成员

//cout<<zh.stunum;//error,不能访问私有成员

//cout<<zh.age;//

error,不能访问保护成员}11.2类的继承方式派生类成员派生类中派生类外部下层派生类公用成员可以可以可以保护成员可以不可以可以私有成员可以不可以不可以不可访问成员不可以不可以不可以多级派生时的访问属性直接派生类、间接派生类直接基类、间接基类例多级派生的访问属性classA

//基类{public:inti;

protected:voidf2();intj;private:intk;};classB:public

A{public:voidf3();

protected:voidf4();

private:intm;};classC:protectedB{public:voidf5();private:intn;};例多级派生的访问属性各成员在不同类中的访问属性if2jkf3f4mf5n基类A公有保护保护私有公有派生类B公有保护保护不可访问公有保护私有保护派生类C保护保护保护不可访问保护保护不可访问公有私有多级派生时的访问属性派生类都不能访问基类的私有成员,私有成员只能被本类的成员函数访问。都采用公有继承的多级派生,则直到最后一级派生类都能访问基类的公有和保护成员。都采用私有继承方式,经过若干次派生之后,基类的所有成员变成不可访问。都采用保护继承方式,在派生类外无法访问派生类中的任何成员。公有继承:最常用。11.3派生类的构造函数和析构函数派生类的构造函数派生类的析构函数

构造函数不能被继承,对派生类必须重新定义构造函数。在声明一个派生类对象时,系统首先要通过派生类的构造函数调用基类的构造函数,对基类成员初始化;然后对派生类中新增的成员初始化。派生类的对象的数据结构是由基类中说明的数据成员和派生类中说明的数据成员共同构成。将派生类的对象中由基类中说明的数据成员和操作所构成的封装体称为基类子对象,它由基类中的构造函数进行初始化。11.3.1派生类的构造函数派生类构造函数初始化对象基类的数据成员派生类新增的数据成员思路:在执行派生类的构造函数时,调用基类的构造函数。形式:派生类构造函数(参数):参数化列表{派生类新增成员的初始化语句}36派生类的构造函数带有子对象的派生类的构造函数形式:派生类构造函数(参数表):基类构造函数(参数表),对象成员1的构造函数(参数表)……,对象成员n的构造函数(参数表){派生类新增成员的初始化语句}37【例11-4】构造函数的调用顺序举例#include<iostream>usingnamespacestd;classBase{ inta; public: Base(intx):a(x){//基类的构造函数

cout<<"constructBaseclass"<<a<<endl; }};38classsubBase:publicBase{private:

intb,c;//类subBase中新增的普通成员

constintd;

Basex,y;//类subBase中新增的对象成员public:

subBase(intt):y(t+2),x(t+1),d(t+3),Base(t){

b=t;

c=t;

cout<<"constructsubBaseclass"<<b<<""<<c<<""<<d<<endl; }};intmain(){ subBases1(9); return0;//建立subBase类对象s1}constructBaseclass9constructBaseclass10constructBaseclass11constructsubBaseclass9912派生类构造函数的调用顺序

首先调用基类的构造函数;

其次执行参数化表中部分所列出的对象成员的构造函数;

最后执行派生类构造函数的函数体。即先祖先(基类),再客人(对象成员),后自己(派生类本身)。11.3.2派生类的析构函数派生类不能继承基类的析构函数。基类的清理工作仍由基类析构函数负责。执行派生类的析构函数时,系统自动调用基类和子对象的析构函数。调用顺序:先执行派生类的析构函数,然后调用子对象的析构函数,最后调用基类的析构函数。42【例11-5】析构函数的调用顺序举例。#include<iostream>usingnamespacestd;classBase{ inta; public: Base(intx):a(x){ //基类的构造函数

cout<<"constructBaseclass:"<<a<<endl; } ~Base(){ //基类Base的析构函数

cout<<"destructBase:"<<a<<endl; }};classsubBase:publicBase{private:

intb,c;

constintd;

Basex,y;public: subBase(intt):y(t+2),x(t+1),d(t+3),Base(t){

b=t;

c=t;

cout<<"constructsubBaseclass:"<<b<<""<<c<<""<<d<<endl; } ~subBase(){

cout<<"destructsubBase:"<<b<<""<<c<<""<<d<<endl; }};intmain(){ subBases1(9); return0;}constructBaseclass:9constructBaseclass:10constructBaseclass:11constructsubBaseclass:9912destructsubBase:9912destructBase:11destructBase:10destructBase:911.4多重继承多重继承概念多重继承的二义性虚基类4611.4.1多重继承概念多重继承:允许一个派生类同时继承多个基类。声明多重继承的方法class派生类名:继承方式基类名1,继承方式基类名2,...,继承方式基类名n{定义派生类自己的成员};47多继承的构造函数一般格式为:<派生类名>(<总参数表>):

<基类名1>(<参数表1>),<基类名2>(<参数表2>),…<子对象名>(<参数表n+1>){<派生类构造函数体>};它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。派生类构造函数的调用顺序是:先执行所有基类的构造函数再执行子对象类的构造函数(若有)再执行派生类本身的构造函数注意:同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化表的各项顺序无关。【例11-6】多重继承举例。#include<iostream>usingnamespacestd;classCBase1{ protected: intb; public: CBase1(intx=0){

b=x; cout<<"ConstructCBase1!"<<b<<endl; } ~CBase1(){

cout<<"DestructCBase1!"<<b<<endl; }};classCBase2{protected:

intb;public:

CBase2(intx=0){

b=x;

cout<<"ConstructCBase2!"<<b<<endl;

}

~CBase2(){

cout<<"DestructCBase2!"<<b<<endl;

}};classCDerived:publicCBase1,privateCBase2{protected:

CBase1b1;

CBase2b2;

intd;public:

CDerived(intx,inty,intz):b1(y),CBase2(y),b2(z),CBase1(x){

d=z;

cout<<"ConstructCDerived!"<<d<<endl;

}

~CDerived(){

cout<<"DestructCDerived!"<<d<<endl;

}};intmain(){ CDerivedd1(1,2,3); return0;}ConstructCBase1!1ConstructCBase2!2ConstructCBase1!2ConstructCBase2!3ConstructCDerived!3DestructCDerived!3DestructCBase2!3DestructCBase1!2DestructCBase2!2DestructCBase1!111.4.2多重继承的二义性多重继承情况下的二义性问题可分为两种情况(1)从不同基类继承的同名成员,在引用时产生二义性。(2)当低层派生类从不同的路径上多次继承同一个基类时,也会产生二义性。(1)两个基类有同名成员classA{public:inta;voiddisplay();};classB{public:inta;voiddisplay();};classC:publicA,publicB{public:intb;voidshow();};voidmain(){Cc1;c1.a=3;c1.display();}编译后:errorC2385:'C::a'isambiguouserrorC2385:'C::display'isambiguous消除二义性有两种方法1、使用相应的类名来标识 c1.A::display();2、由派生类提供统一的接口 voidC::show() {

A::display();

B::display();

…… }(2)两个基类和派生类三者都有同名成员。将C类声明改为:classC:publicA,publicB{public:inta;voiddisplay();};voidmain(){Cc1;c1.a=3;c1.display();}会有问题么?规则:基类的同名成员在派生类中被屏蔽,成为“不可见”的,或者说,派生类新增加的同名成员覆盖了基类中的同名成员。因此如果在定义派生类对象的模块中通过对象名访问同名的成员,则访问的是派生类的成员。(3)如果C从类A和B派生,而它们又从同一个基类派生classN{public:inta;voiddisplay()

{cout<<"A::a="<<a<<endl;}};classA:publicN{public:inta1;};classB:publicN{public:inta2;};classC:publicA,publicB{public:inta3;voidshow(){cout<<"a3="<<a3<<endl;}};intmain(){Cc1;//定义C类对象c1……..}怎样才能访问类A中从基类N继承下来的成员呢?inta3;显然不能用c1.a=3;c1.display();或c1.N::a=3;c1.N::display();因为这样依然无法区别是类A中从基类N继承下来的成员,还是类B中从基类N继承下来的成员。应当通过类N的直接派生类名来指出要访问的是类N的哪一个派生类中的基类成员。如:c1.A::a=3;c1.A::display();11.4.3虚基类虚基类的作用:在继承间接共同基类时只保留一份成员。声明虚基类的一般形式注:不是在声明基类时声明,而是在声明派生类时,指定继承方式时声明。class派生类名:virtual

继承方式基类名classA//声明基类A{…};classB:virtualpublicA//声明A是B的虚基类{…};classC:virtualpublicA//声明A是C的虚基类{…};注:为保证虚基类在派生类中只继承一次,应把该基类的所有直接派生类声明为虚基类。67【例11-9】利用虚基类避免产生二义性。classFurniture{

public: Furniture(){ cout<<"constructFurniture"<<endl; } voidSetPrice(doubled){ price=d; } doubleGetPrice(){ returnprice; } protected: doubleprice;};classBed:virtualpublicFurniture{

public: Bed(){ cout<<"constructBed"<<endl; } voidSleep(){ cout<<"Sleeping..."; }};classSofa:virtualpublicFurniture{

public: Sofa(){ cout<<"constructSofa"<<endl; } voidWatchTV(){ cout<<"WatchingTV.\n"; }};classSleeperSofa:publicBed,publicSofa{ public: SleeperSofa():Sofa(),Bed(){ cout<<"constructSleeperSofa"<<endl; } voidFoldOut(){ cout<<"Foldoutthesofa.\n"; } voidFunction(){ Sleep(); WatchTV(); }};intmain(){ SleeperSofass; ss.SetPrice(2000); cout<<"PriceofSleeperSofa:"<<ss.GetPrice()<<endl; cout<<"FunctionofSleeperSofa:"; ss.Function(); return0;}constructFurnitureconstructBedconstructSofaconstructSleeperSofaPriceofSleeperSofa:2000FunctionofSleeperSofa:Sleep

温馨提示

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

评论

0/150

提交评论