面向对象程序设计 ch7.ppt
《面向对象程序设计 ch7.ppt》由会员分享,可在线阅读,更多相关《面向对象程序设计 ch7.ppt(75页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第第7 7章章 继承和派生继承和派生 从已有的对象类型出发建立一种新的对象类型,使它从已有的对象类型出发建立一种新的对象类型,使它继承原对象类型的特点和功能,这种思想是面向对象设计继承原对象类型的特点和功能,这种思想是面向对象设计方法的主要贡献。方法的主要贡献。通过对已有类进行特殊化通过对已有类进行特殊化(派生派生)来建立新的数据类型,来建立新的数据类型,就使得面向对象语言具有极大的能力和丰富的表现力。从就使得面向对象语言具有极大的能力和丰富的表现力。从概念上讲,类的派生创建了一种软件结构,它真实地反映概念上讲,类的派生创建了一种软件结构,它真实地反映了实际问题。从软件角度来看,类的派生创建了
2、一种类族。了实际问题。从软件角度来看,类的派生创建了一种类族。派生类的对象也是基类的一种对象,它可以被用在基类对派生类的对象也是基类的一种对象,它可以被用在基类对象所使用的任何地方。可以用多态成员函数仔细调整这种象所使用的任何地方。可以用多态成员函数仔细调整这种关系,以便使派生类在某些地方与它的基类一致,而在别关系,以便使派生类在某些地方与它的基类一致,而在别的地方表现出它自身的行为特征。的地方表现出它自身的行为特征。本章主要讨论本章主要讨论C+C+语言继承方面的语法特征和一般的使语言继承方面的语法特征和一般的使用方法。用方法。主要内容7.1继承和派生的基本概念继承和派生的基本概念7.2单一继
3、承单一继承7.3多重继承多重继承7.4二义性及其支配规则二义性及其支配规则7.5设计实例设计实例7.1 继承和派生的基本概念继承和派生的基本概念 派生和继承的概念也来自于人们认识客观世界的过程。派生和继承的概念也来自于人们认识客观世界的过程。举个简单的例子:举个简单的例子:“狗狗”和和“黑狗黑狗”。当谈论。当谈论“狗狗”的时的时候,知道它是哺乳动物,有候,知道它是哺乳动物,有4 4条腿,条腿,1 1条尾巴,喜欢啃肉骨条尾巴,喜欢啃肉骨头,头,。现在谈论。现在谈论“黑狗黑狗”,人们会怎么说呢?当然可,人们会怎么说呢?当然可以说:以说:“黑狗是一种哺乳动物,有黑狗是一种哺乳动物,有4 4条腿,条腿
4、,1 1条尾巴,喜欢条尾巴,喜欢吃肉骨头,吃肉骨头,并且它的毛是黑色的,并且它的毛是黑色的”。但是人们一般。但是人们一般都不这么说,而是说:都不这么说,而是说:“黑狗就是黑毛的狗黑狗就是黑毛的狗”。比较一下。比较一下这两种说法,显然后一种说法更好。那么它好在哪里呢?这两种说法,显然后一种说法更好。那么它好在哪里呢?第一,它更简炼;第二,更重要的是它反映了第一,它更简炼;第二,更重要的是它反映了“狗狗”和和“黑狗黑狗”这两个概念的内在联系。这两个概念的内在联系。“狗狗”和和“黑狗黑狗”之间存之间存在一条重要的联系,那就是所有的在一条重要的联系,那就是所有的“黑狗黑狗”都是都是“狗狗”,或者说,或
5、者说,“黑狗黑狗”是一类特殊的是一类特殊的“狗狗”。根据这一条,。根据这一条,“狗狗”所具有的特征,例如所具有的特征,例如4 4条腿,条腿,1 1条尾巴等,条尾巴等,“黑狗黑狗”自自然都具有。也就是说,然都具有。也就是说,“黑狗黑狗”从从“狗狗”那里继承了那里继承了“狗狗”的全部特征。的全部特征。现在我们用现在我们用C+C+语言来描述这一问题。显然可以定义一个语言来描述这一问题。显然可以定义一个描述描述“狗狗”的类的类dog dog。但是描述但是描述“黑狗黑狗”的类的类blackdogblackdog怎怎么办?为了能准确地描述这两个类之间的关系,么办?为了能准确地描述这两个类之间的关系,C+C
6、+提供提供了一种机制,使得人们可以像了一种机制,使得人们可以像“黑狗就是黑毛的狗黑狗就是黑毛的狗”那样那样定义一个新类定义一个新类blackdogblackdog。在这种机制下,类在这种机制下,类blackdogblackdog自动自动拥有类拥有类dog dog 的所有成员,该类的每一个对象都是类的所有成员,该类的每一个对象都是类dog dog 的的对象,也就是说,对象,也就是说,“每一条黑狗都是狗每一条黑狗都是狗”。这种机制的具体实现留到下一节再说。这一节的主要任务这种机制的具体实现留到下一节再说。这一节的主要任务是弄清楚基本概念。现在先来看几个术语。是弄清楚基本概念。现在先来看几个术语。首
7、先,首先,“黑狗是黑毛的狗黑狗是黑毛的狗”是从一般的是从一般的dogdog类通过特殊化类通过特殊化而得到类而得到类blackdogblackdog的。这种通过特殊化已有的类来建立新的。这种通过特殊化已有的类来建立新类的过程,叫做类的过程,叫做“类的派生类的派生”,原有的类叫做,原有的类叫做“基类基类”,新建立的类则叫做新建立的类则叫做“派生类派生类”。这里类。这里类dog dog 就是基类,而就是基类,而blackdogblackdog是派生类。另一方面,从类的成员的角度看,派是派生类。另一方面,从类的成员的角度看,派生类自动地将基类的所有成员作为自己的成员,这叫做生类自动地将基类的所有成员作
8、为自己的成员,这叫做“继承继承”。基类和派生类又可以分别叫做。基类和派生类又可以分别叫做“父类父类”和和“子类子类”,有时也称为,有时也称为“一般类一般类”和和“特殊类特殊类”。类的派生和继承是面向对象程序设计方法和类的派生和继承是面向对象程序设计方法和C+C+语言最重语言最重要的特征之一。首先,客观世界本身是有层次的,人们认要的特征之一。首先,客观世界本身是有层次的,人们认识客观世界的过程中,由一般到特殊的演绎思维发挥着巨识客观世界的过程中,由一般到特殊的演绎思维发挥着巨大作用。演绎的过程在绝大多数情况下就表现为层次分类大作用。演绎的过程在绝大多数情况下就表现为层次分类的过程。继承使得程序员
9、可以在一个较一般的类的基础上的过程。继承使得程序员可以在一个较一般的类的基础上很快地建立一个新类,而不必从零开始设计每个类。很快地建立一个新类,而不必从零开始设计每个类。从一个或多个以前定义的类从一个或多个以前定义的类(基类基类)产生新类的过程称为产生新类的过程称为派生,这个新类称为派生类。派生的新类同时也可以增加派生,这个新类称为派生类。派生的新类同时也可以增加或重新定义数据和操作,这就产生了类的层次性。或重新定义数据和操作,这就产生了类的层次性。类的继承是指新类继承基类的成员。继承常用来表示类属类的继承是指新类继承基类的成员。继承常用来表示类属关系,不能将继承理解为构成关系。当从现存类中派
10、生出关系,不能将继承理解为构成关系。当从现存类中派生出新类时,可以对派生类做如下几种变化:新类时,可以对派生类做如下几种变化:可以增加新的数据成员;可以增加新的数据成员;可以增加新的成员函数;可以增加新的成员函数;可以重新定义已有的成员函数;可以重新定义已有的成员函数;可以改变现有成员的属性。可以改变现有成员的属性。如图如图7.17.1所示,所示,C+C+中有两种继承:单一继承和多重继承。中有两种继承:单一继承和多重继承。对于单一继承,派生类只能有一个基类;对于多重继承,对于单一继承,派生类只能有一个基类;对于多重继承,派生类可以有多个基类。派生类可以有多个基类。图图7.1类的单一继承和多重继
11、承的类的单一继承和多重继承的UML结构图结构图在图在图7.17.1中,箭头指向基类。单一继承形成一个倒挂的树。中,箭头指向基类。单一继承形成一个倒挂的树。派生类继承了基类所有的数据成员和成员函数,程序员派生类继承了基类所有的数据成员和成员函数,程序员也可以在派生类中添加新的数据成员和成员函数。也可以在派生类中添加新的数据成员和成员函数。这样,基类定义了对象的一个集合,派生类通过增添新这样,基类定义了对象的一个集合,派生类通过增添新的成员限制基类的定义,以便定义基类对象集合的一个的成员限制基类的定义,以便定义基类对象集合的一个子集。子集。由此可见,从编码角度讲,派生类从基类中以较低代价由此可见,
12、从编码角度讲,派生类从基类中以较低代价换来了大量的灵活性。一旦产生了可靠的基类,只需要换来了大量的灵活性。一旦产生了可靠的基类,只需要调试派生类中所做的修改即可。调试派生类中所做的修改即可。C+C+派生类从父类中继承性质时,可使派生类扩展它们,派生类从父类中继承性质时,可使派生类扩展它们,或者对其做些限制,也可改变或删除,甚至不作任何修或者对其做些限制,也可改变或删除,甚至不作任何修改。所有这些变化可归结为两类基本的面向对象技术。改。所有这些变化可归结为两类基本的面向对象技术。第一种称为性质约束,即对基类的性质加以限制或删除。第一种称为性质约束,即对基类的性质加以限制或删除。第二种称为性质扩展
13、,即增加派生类的性质。第二种称为性质扩展,即增加派生类的性质。7.2单一继承单一继承7.2.1单一继承的一般形式单一继承的一般形式在在C+中,声明单一继承的一般形式为:中,声明单一继承的一般形式为:class派生类名:访问控制派生类名:访问控制基类名基类名private:成员声明列表成员声明列表protected:成员声明列表成员声明列表public:成员声明列表成员声明列表;这里和一般的类的声明一样,用关键字这里和一般的类的声明一样,用关键字class class 声明声明一个新的类。一个新的类。冒号后面的部分指示这个新类是哪个基类的派生类。冒号后面的部分指示这个新类是哪个基类的派生类。所谓
14、所谓“访问控制访问控制”是指如何控制基类成员在派生类是指如何控制基类成员在派生类中的访问属性,它是中的访问属性,它是3 3个关键字个关键字public,protected和和private中的一个。中的一个。一对大括号一对大括号“”中是用来声明派生中是用来声明派生类自己的成类自己的成员的。这和类的声明一样,不再赘述。员的。这和类的声明一样,不再赘述。7.2.2派生类的构造函数和析构函数派生类的构造函数和析构函数如何初始化派生类的对象呢?当然也应在派生类中声明一如何初始化派生类的对象呢?当然也应在派生类中声明一个与派生类同名的函数。假设从基类个与派生类同名的函数。假设从基类Point派生一个描述
15、派生一个描述矩形的类矩形的类Rectangle。类类Rectangle继承继承Point类的两个数据类的两个数据成员作为矩形的一个顶点,再为成员作为矩形的一个顶点,再为Rectangle类增加两个数类增加两个数据成员据成员H和和W,分别描述它的高和宽。为类分别描述它的高和宽。为类Point设计一设计一个构造函数个构造函数Point(int,int)和显示数据的函数和显示数据的函数Showxy。为为Rectangle类也设计构造函数类也设计构造函数Rectangle(int,int,int,int)和显和显示函数示函数Show。由此可见,派生类增加了两个新的数据成由此可见,派生类增加了两个新的数
16、据成员以及相应的成员函数,同时继承员以及相应的成员函数,同时继承Point的全部成员。的全部成员。【例例7.1】是它们的程序实现。是它们的程序实现。【例【例7.1】使用默认内联函数实现单一继承。使用默认内联函数实现单一继承。#includeusingnamespacestd;classPointprivate:intx,y;public:Point(inta,intb)x=a;y=b;coutPoint.endl;voidShowxy()coutx=x,y=yendl;Point()coutDeletePointendl;classRectangle:publicPointprivate:in
17、tH,W;public:Rectangle(inta,intb,inth,intw):Point(a,b)/构造函构造函/数初始化列表数初始化列表H=h;W=w;coutRectangle.endl;voidShow()coutH=H,W=Wendl;Rectangle()coutDeleteRectangleendl;voidmain()Rectangler1(3,4,5,6);r1.Showxy();/派生类对象调用基类的成员函数派生类对象调用基类的成员函数r1.Show();/派生类对象调用派生类的成员函数派生类对象调用派生类的成员函数程序输出如下:程序输出如下:Point./调用基类构
18、造函数调用基类构造函数Rectangle./调用派生类构造函数调用派生类构造函数x=3,y=4/调用基类成员函数调用基类成员函数Showxy()H=5,W=6/调用派生类成员函数调用派生类成员函数Show()DeleteRectangle/调用派生类析构函数调用派生类析构函数DeletePoint/调用基类析构函数调用基类析构函数在派生类中继承的基类成员的初始化,需要由派生类的构在派生类中继承的基类成员的初始化,需要由派生类的构造函数调用基类的构造函数来完成,这和初始化对象成员造函数调用基类的构造函数来完成,这和初始化对象成员有类似之处。有类似之处。定义派生类的构造函数的一般形式为:定义派生类
19、的构造函数的一般形式为:派生类名派生类名 :派生类名派生类名(参数表参数表0):0):基类名基类名(参数表参数表)././函数体函数体 冒号后冒号后“基类名基类名(参数表参数表)”称为成员初始化列表,参数称为成员初始化列表,参数表给出所调用的基类构造函数所需要的实参。实参的值可表给出所调用的基类构造函数所需要的实参。实参的值可以来自以来自“参数表参数表0 0”,或由表达式给出。可以像,或由表达式给出。可以像RectangleRectangle那样,在类中直接定义为内联函数。下面是在类说明之外那样,在类中直接定义为内联函数。下面是在类说明之外定义的示范:定义的示范:Rectangle:Recta
20、ngle(inta,intb,inth,intw):Point(a,b)H=h;W=w;coutRectangle.endl;“参数表参数表0 0”有有4 4个参数,基类个参数,基类PointPoint的参数表是自己的的参数表是自己的2 2个数据成员。个数据成员。构造函数(包括析构函数)是不被继承的,所以一个派生构造函数(包括析构函数)是不被继承的,所以一个派生类只能调用它的直接基类的构造函数。当定义派生类的一类只能调用它的直接基类的构造函数。当定义派生类的一个对象时,首先调用基类的构造函数,对基类成员进行初个对象时,首先调用基类的构造函数,对基类成员进行初始化,然后执行派生类的构造函数,如果
21、某个基类仍是一始化,然后执行派生类的构造函数,如果某个基类仍是一个派生类,则这个过程递归进行。当该对象消失时,析构个派生类,则这个过程递归进行。当该对象消失时,析构函数的执行顺序和执行构造函数时的顺序正好相反。输出函数的执行顺序和执行构造函数时的顺序正好相反。输出结果也证实了这个结论。结果也证实了这个结论。7.2.3 类的保护成员类的保护成员现在修改现在修改Rectangle的的Show函数,使得它可以一次显示函数,使得它可以一次显示x、y、H和和W。怎样修改成员函数怎样修改成员函数Show呢?修改成下面呢?修改成下面的内容能实现这一目的吗?的内容能实现这一目的吗?voidRectangle:
22、show()coutx=x,y=y,H=H,W=Wendl;这段简单程序并不能通过编译。类这段简单程序并不能通过编译。类Rectangle有有4个私有成个私有成员员x、y、H和和W。这这4个私有成员的来源是不一样的。个私有成员的来源是不一样的。H和和W是是Rectangle自己定义的,而自己定义的,而x和和y是从是从Point那里继那里继承来的。承来的。换句话说,换句话说,x和和y是类是类Point的私有成员。类的私有成员是的私有成员。类的私有成员是只能被它自己的成员函数只能被它自己的成员函数(不讨论友元不讨论友元)访问的,而访问的,而Show函数是在类函数是在类Rectangle中定义的,它
23、是类中定义的,它是类Point子类的成员子类的成员函数,并不是类函数,并不是类Point的成员函数,因而不能访问的成员函数,因而不能访问x和和y。C+语言规定,公有派生类的成员函数可直接访问基类中语言规定,公有派生类的成员函数可直接访问基类中定义的或基类(从另一个基类)继承来的公有成员,但不定义的或基类(从另一个基类)继承来的公有成员,但不能访问基类的私有成员。这和私有成员的定义是一致的,能访问基类的私有成员。这和私有成员的定义是一致的,符合数据封装思想。但这样也有问题,就拿上面的程序来符合数据封装思想。但这样也有问题,就拿上面的程序来说,在类说,在类Rectangle看来,看来,x、y、H和
24、和W的地位是平等的地位是平等的,现在希望对它们的,现在希望对它们“一视同仁一视同仁”,但,但C+语言关于私有语言关于私有成员继承的规定却妨碍这样做。为解决这一矛盾,成员继承的规定却妨碍这样做。为解决这一矛盾,C+引引入了保护成员的概念。入了保护成员的概念。在类声明中,关键字在类声明中,关键字protected之后声明的是类的保护成员。之后声明的是类的保护成员。保护成员具有私有成员和公有成员的双重角色:对派生类保护成员具有私有成员和公有成员的双重角色:对派生类的成员函数而言,它是公有成员,可以被访问;而对其他的成员函数而言,它是公有成员,可以被访问;而对其他函数而言则仍是私有成员,不能被访问。因
25、此,要想在类函数而言则仍是私有成员,不能被访问。因此,要想在类Rectangle中使用统一的中使用统一的Show函数,只要把函数,只要把x和和y定义成定义成类类Point的保护成员就行了。的保护成员就行了。【例【例7.2】是修改过的程序。是修改过的程序。【例【例7.2】演示使用演示使用protected成员。成员。#includeusingnamespacestd;classPointprotected:intx,y;public:Point(inta,intb)x=a;y=b;voidShow()cout“x=”x“,y=”yendl;/基基类类/的的Show()函数函数;classRect
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 面向对象程序设计 ch7 面向 对象 程序设计
限制150内