您好,欢迎访问三七文档
2020/5/51第2章继承与派生本章学习重点掌握内容:继承的概念派生类的建立及继承的方式各种继承方式下基类成员的访问机制派生类的构造函数和析构函数多重继承虚基类2020/5/52第2章继承与派生2.1继承与派生的基础知识2.2类的继承方式2.3派生类的构造函数与析构函数2.4基类与派生类的转换2.5多重继承2.6虚基类2.7综合应用实例2020/5/532.1继承与派生的基础知识2.1.1继承与派生的基本概念现实世界中,许多事物之间的并不是孤立存在的,它们存在共同的特性,有细微的差别,可以使用层次结构描述它们之间的关系。例如交通工具的层次结构如图2.1所示:2020/5/542.1.1继承与派生的基本概念C++通过类派生(ClassDerivation)的机制支持继承(Inheritance)。允许程序员在保持原有类特性的基础上进行扩展,增加功能,派生出新类。继承是面向对象程序设计中的代码复用的最重要的手段之一。被继承的类称为基类(BaseClass)、父类或超类(Superclass),而新产生的类称为派生类(DerivedClass)或子类(Subclass)。基类和派生类的集合称作类继承层次结构(Hierarchy),继承呈现了面向对象程序设计的层次结构。2020/5/552.1.1继承与派生的基本概念一个新类从已有的类获得其已有的特性称为继承。通过继承,新类获得了父类的所有数据成员和成员函数,并可以添加自己的数据成员和成员函数。一个基类可以派生出很多的子类,一个子类也可以作为另一个新类的基类,因此基类和子类是相对而言的。继承的方式有以下2种:单一继承和多重继承。2020/5/562.1.1继承与派生的基本概念单一继承和多重继承请注意图中箭头的方向,本书约定,箭头表示继承的方向,由子类指向基类。2020/5/572.1.2派生类的定义定义派生类的一般格式为:class派生类名:继承方式基类名{private:成员表1;//派生类增加或重写的私有成员protected:成员表2;//派生类增加或重写的保护成员public:成员表3;//派生类增加或重写的公有成员};2020/5/582.1.2派生类的定义其中:基类名是已声明的类,派生类名是新生成的类名;继承方式规定了如何访问从基类继承的成员。继承的方式包括:私有继承(private)、保护继承(protected)、公有继承(public)。不同的继承方式下,派生类继承的父类成员的访问权限是不同的。继承方式可以省略不写,默认的继承方式为私有继承(private);派生类的定义中包括子类新增加的成员和继承父类需要重写的成员。新添加的成员是派生类对基类的发展,说明派生类新的属性和方法;派生类继承了父类的数据成员和成员函数,有时继承来的成员函数需要改进,以满足新类的实际需要。C++允许在派生类中重新声明和定义这些成员函数,使这些函数具有新的功能,称之为重写或覆盖。重写函数起屏蔽、更新作用,取代基类成员,完成新功能。2020/5/592.1.2派生类的定义【例2.1】已知盒子CBox类,用继承与非继承两种不同的方法定义彩色盒子CColorbox类。分析:盒子类(Cbox)具有长、宽和高,成员函数SetLength()、SetWidth()和SetHeight()分别设置盒子的长、宽和高,成员函数Volume()计算盒子的体积。彩色盒子除具有以上特性外,还有一个数据成员color表示盒子的颜色,相应的成员函数SetColor()用于设置彩色盒子的颜色。2020/5/5102.1.2派生类的定义非继承的方式,分别定义CBox类和CColorbox类盒子类的定义:代码见备注彩色盒子类的定义:代码见备注2020/5/5112.1.2派生类的定义使用派生类定义:classCColorbox:publicCBox//公有继承{//新增的私有数据成员public:voidSetColor(intc)//新增的成员函数{color=c;}private:intcolor;};利用继承机制产生类比第一种简单多了,但功能一样。派生类CColorbox公有继承Cbox类,它包括基类CBox类的全部数据成员(length,width,height)和成员函数(SetWidth、SetHeigh和SetWidth),但访问权限发生了变化。并且添加自己的新成员——数据成员color和成员函数SetColor()。2020/5/5122.1.3派生类的生成仔细分析派生新类这个过程,实际是经历了以下步骤:首先继承基类的成员,不论是数据成员,还是成员函数,除构造函数与析构函数外全部接收,全部成为派生类的成员。第二步是重写基类成员。当基类成员在派生类的应用中不合适时,可以对继承的成员加以重写。如果派生类声明了一个与基类成员函数相同的成员函数时,派生类中的新成员则屏蔽了基类同名成员,类似函数中的局部变量屏蔽全局变量。称为同名覆盖(Override)。第三步定义新成员。新成员必须与基类成员不同名,是派生类自己的新特性。派生类新成员的加入使得派生类在功能上有所发展。这一步是继承与派生的核心特征。第四步是重写构造函数与析构函数。因为派生类不继承基类的构造函数与析构函数,并且派生类的需要对新添加的数据成员进行必要的初始化,所以构造函数与析构函数需要重写。2020/5/5132.2类的继承方式派生类中包含基类的成员和派生类自己增加的成员,那么这两部分的成员关系和访问权限该如何确定呢?在继承机制中,并不是简单的把基类的私有成员直接作为派生类的私有成员,把基类的公有成员直接作为派生类的公有成员。派生类继承的基类成员访问权限由继承方式来控制。继承方式有三种:public(公有)继承、protected(保护)继承和private(私有)继承。不同的继承方式,决定了从基类继承来的成员的访问权限。下面分别介绍不同继承方式下,派生类成员的访问权限。2020/5/5142.2.1公有继承当定义一个派生类时,将基类前的继承方式指定为public,则称为公有派生(或公有继承)。采用公有继承方式时,基类的公有成员和保护成员的访问权限在派生类中不变。而基类的私有成员在派生类中是不可访问。但它仍然是基类的私有成员,如果需要在派生类中引用继承基类的私有成员,那么需要通过基类的公有或保护的成员函数访问。【例2.3】演示公有继承方式下,不同成员的访问权限。程序代码见备注:2020/5/5152.2.1公有继承【例2.4】公有派生方式下如何访问继承的基类原有私有数据成员。程序代码见备注:2020/5/5162.2.2私有继承当定义一个派生类时,将基类前的继承方式指定为private,则称为私有继承。用私有继承方式建立的派生类称为私有派生类,其基类成为私有基类。采用私有继承方式时,私有基类的公有成员和保护成员在私有派生类中成为私有成员。即派生类成员可访问它们,而派生类外不可访问它们。基类的私有成员在派生类中成为不可访问的成员。私有继承基类成员的访问权限如表2-2所示。私有继承的意义是将基类中原来能被外部访问的成员隐藏起来,不让外界引用。【例2.5】私有继承演示。2020/5/5172.2.2私有继承由上例可以看到私有继承方式:(1)不能通过派生类对象(box1)引用从私有继承过来的任何成员。如box1.set(3,5,6);或box1.length=100。(2)在派生类内部(如派生类的成员函数),不可以访问基类的私有成员(如length=len,length为基类的私有成员),但可以访问基类的公有和保护成员(如height=h,height为基类的保护成员)。(3)如果派生类需要访问基类的私有成员,可以通过派生类的成员函数调用基类的公有成员函数实现如:voidset_1(doublelen,doublew,doubleh,intc){set(len,w,h);//基类的公有成员函数……}由上可以看出,私有派生的限制太多,一般不经常使用。2020/5/5182.2.3保护继承当定义一个派生类时,将基类前的继承方式指定为protected,则称为保护继承。在保护继承中,基类的公有成员和保护成员成为派生类的保护成员,在派生类中可以直接访问,但在派生类外不能直接访问任何基类成员的。基类中的私有成员成为派生类的不可访问成员,在派生类中不可直接访问。保护继承基类成员的访问权限如表2-3所示。保护继承的意义是将基类的公有成员也保护起来,不让类外部任意访问。2020/5/519继承的方式有三种,使用不同继承方式,基类的成员在派生类中的访问权限也不同。不同继承方式下基类成员在派生类的访问权限总结如表2-4所示。2.2.4继承方式的总结和比较2020/5/5202.3派生类的构造函数与析构函数派生类的成员是由基类中的数据成员和派生类中新增的数据成员共同构成。而在继承机制下,构造函数不能够被继承。因此,对继承过来的基类成员的初始化工作也得由派生类的构造函数完成。也就是说在定义派生类的构造函数时,既要初始化派生类新增数据,又要初始化基类的成员。所以,在定义派生类的构造函数时,有两步需要做:编写代码完成自己的数据成员进行初始化调用基类构造函数使基类数据成员得以初始化。2020/5/5212.3.1简单派生类的构造函数单一继承的构造函数的定义形式为:派生类名:派生类构造函数名(参数总表):基类构造函数名(参数名表){派生类新增成员的初始化语句};定义派生类的构造函数时,在构造函数的参数总表中包括基类构造函数所需的参数和派生类新增的数据成员初始化所需的参数。冒号后面基类构造函数名(参数名表),表示要调用基类的构造函数。【例2.6】演示派生类的构造函数执行顺序。2020/5/5222.3.2析构函数析构函数的功能是做善后工作,析构函数无返回类型也没有参数,情况比较简单。在派生过程中,基类的析构函数不能继承,如果需要析构函数的话,要在派生类中重新定义。派生类析构函数定义格式与非派生类无任何差异,只要在函数体内把派生类新增一般成员处理好就可以了。而对基类成员的善后工作,系统会自己调用基类的析构函数来完成。如果没有显示的定义析构函数,系统会自动生成一个默认的析构函数,清理工作就是靠它们来完成的。析构函数各部分执行次序与构造函数相反,首先对派生类新增成员析构,然后对基类成员析构。2020/5/5232.3.3复杂派生类的构造函数和析构函数一个派生类中新增加的成员可以是简单的数据成员,也可以是类对象。派生类可以是单一继承,也可以是多重继承。假如派生类是多重继承,并且新增数据成员有一个或多个类对象,那么派生类需要初始化的数据有三部分:继承的成员、新增类对象的成员和新增普通成员。这种复杂派生类的构造函数定义如下:派生类名::派生类构造函数名(总参数表):基类构造函数名1(参数表1),基类构造函数名2(参数表2),……子对象名1(参数表n),子对象名2(数表n+1)……{派生类新增普通数据成员的初始化;}2020/5/5242.3.3复杂派生类的构造函数和析构函数派生类构造函数的调用顺序如下:1.基类构造函数。按它们在派生类定义中的先后顺序,依次调用。2.子对象的构造函数。按它们在派生类定义中的先后顺序,依次调用。3.派生类的构造函数。复杂派生类的析构函数,只需要编写对新增普通成员的善后处理,而对类对象和基类的善后工作是由类对象和基类的析构函数完成的。析构函数的调用顺序与构造函数相反。【例2.7】复杂继承举例。2020/5/5252.3.3复杂派生类的构造函数和析构函数【例2.7】复杂继承举例。2020/5/5262.3.3复杂派生类的构造函数和析构函数在派生类构造函数使用中应注意以下问题:(1)派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义构造函数。当然,基类中没有定义构造函数,派生类调用基类的缺省构造函数。(2)当基类的构造函数使用一个或多个参数时,则派生类必须定义构造函数,提供将参数传递给基类构
本文标题:C程序设计课件
链接地址:https://www.777doc.com/doc-5215405 .html