面向对象程序设计ch7

上传人:j****9 文档编号:54812109 上传时间:2018-09-19 格式:PPT 页数:75 大小:659.50KB
返回 下载 相关 举报
面向对象程序设计ch7_第1页
第1页 / 共75页
面向对象程序设计ch7_第2页
第2页 / 共75页
面向对象程序设计ch7_第3页
第3页 / 共75页
面向对象程序设计ch7_第4页
第4页 / 共75页
面向对象程序设计ch7_第5页
第5页 / 共75页
点击查看更多>>
资源描述

《面向对象程序设计ch7》由会员分享,可在线阅读,更多相关《面向对象程序设计ch7(75页珍藏版)》请在金锄头文库上搜索。

1、第7章 继承和派生从已有的对象类型出发建立一种新的对象类型,使它继承原对象类型的特点和功能,这种思想是面向对象设计方法的主要贡献。通过对已有类进行特殊化(派生)来建立新的数据类型,就使得面向对象语言具有极大的能力和丰富的表现力。从概念上讲,类的派生创建了一种软件结构,它真实地反映了实际问题。从软件角度来看,类的派生创建了一种类族。派生类的对象也是基类的一种对象,它可以被用在基类对象所使用的任何地方。可以用多态成员函数仔细调整这种关系,以便使派生类在某些地方与它的基类一致,而在别的地方表现出它自身的行为特征。本章主要讨论C+语言继承方面的语法特征和一般的使用方法。,主要内容,7.1 继承和派生的

2、基本概念 7.2 单一继承 7.3 多重继承 7.4 二义性及其支配规则 7.5 设计实例,7.1 继承和派生的基本概念派生和继承的概念也来自于人们认识客观世界的过程。举个简单的例子:“狗”和“黑狗”。当谈论“狗”的时候,知道它是哺乳动物,有4条腿,1条尾巴,喜欢啃肉骨头,。现在谈论“黑狗”,人们会怎么说呢?当然可以说:“黑狗是一种哺乳动物,有4条腿,1条尾巴,喜欢吃肉骨头,并且它的毛是黑色的”。但是人们一般都不这么说,而是说:“黑狗就是黑毛的狗”。比较一下这两种说法,显然后一种说法更好。那么它好在哪里呢?第一,它更简炼;第二,更重要的是它反映了“狗”和“黑狗”这两个概念的内在联系。“狗”和“

3、黑狗”之间存在一条重要的联系,那就是所有的“黑狗”都是“狗”,或者说,“黑狗”是一类特殊的“狗”。根据这一条,“狗”所具有的特征,例如4条腿,1条尾巴等,“黑狗”自然都具有。也就是说,“黑狗”从“狗”那里继承了“狗”的全部特征。,现在我们用C+语言来描述这一问题。显然可以定义一个描述“狗”的类dog 。但是描述“黑狗”的类blackdog怎么办?为了能准确地描述这两个类之间的关系,C+提供了一种机制,使得人们可以像“黑狗就是黑毛的狗”那样定义一个新类blackdog。在这种机制下,类blackdog自动拥有类dog 的所有成员,该类的每一个对象都是类dog 的对象,也就是说,“每一条黑狗都是狗

4、”。 这种机制的具体实现留到下一节再说。这一节的主要任务是弄清楚基本概念。现在先来看几个术语。 首先,“黑狗是黑毛的狗”是从一般的dog类通过特殊化而得到类blackdog的。这种通过特殊化已有的类来建立新类的过程,叫做“类的派生”,原有的类叫做“基类”,新建立的类则叫做“派生类”。这里类dog 就是基类,而blackdog是派生类。另一方面,从类的成员的角度看,派生类自动地将基类的所有成员作为自己的成员,这叫做“继承”。基类和派生类又可以分别叫做“父类”和“子类”,有时也称为“一般类”和“特殊类”。,类的派生和继承是面向对象程序设计方法和C+语言最重要的特征之一。首先,客观世界本身是有层次的

5、,人们认识客观世界的过程中,由一般到特殊的演绎思维发挥着巨大作用。演绎的过程在绝大多数情况下就表现为层次分类的过程。继承使得程序员可以在一个较一般的类的基础上很快地建立一个新类,而不必从零开始设计每个类。 从一个或多个以前定义的类(基类) 产生新类的过程称为派生,这个新类称为派生类。派生的新类同时也可以增加或重新定义数据和操作,这就产生了类的层次性。 类的继承是指新类继承基类的成员。继承常用来表示类属关系,不能将继承理解为构成关系。当从现存类中派生出新类时,可以对派生类做如下几种变化: 可以增加新的数据成员; 可以增加新的成员函数; 可以重新定义已有的成员函数; 可以改变现有成员的属性。,如图

6、7.1所示,C+中有两种继承:单一继承和多重继承。对于单一继承,派生类只能有一个基类;对于多重继承,派生类可以有多个基类。,图7.1 类的单一继承和多重继承的UML结构图,在图7.1中,箭头指向基类。单一继承形成一个倒挂的树。派生类继承了基类所有的数据成员和成员函数,程序员也可以在派生类中添加新的数据成员和成员函数。 这样,基类定义了对象的一个集合,派生类通过增添新的成员限制基类的定义,以便定义基类对象集合的一个子集。 由此可见,从编码角度讲,派生类从基类中以较低代价换来了大量的灵活性。一旦产生了可靠的基类,只需要调试派生类中所做的修改即可。 C+派生类从父类中继承性质时,可使派生类扩展它们,

7、或者对其做些限制,也可改变或删除,甚至不作任何修改。所有这些变化可归结为两类基本的面向对象技术。 第一种称为性质约束,即对基类的性质加以限制或删除。第二种称为性质扩展,即增加派生类的性质。,7.2 单一继承 7.2.1 单一继承的一般形式 在 C+中,声明单一继承的一般形式为:class 派生类名:访问控制 基类名private:成员声明列表protected:成员声明列表public:成员声明列表 ;,这里和一般的类的声明一样,用关键字class 声明一个新的类。 冒号后面的部分指示这个新类是哪个基类的派生类。所谓“访问控制”是指如何控制基类成员在派生类中的访问属性,它是3个关键字publi

8、c, protected和private 中的一个。一对大括号“ ”中是用来声明派生类自己的成员的。这和类的声明一样,不再赘述。,7.2.2 派生类的构造函数和析构函数 如何初始化派生类的对象呢?当然也应在派生类中声明一个与派生类同名的函数。假设从基类Point派生一个描述矩形的类Rectangle 。类Rectangle继承Point类的两个数据成员作为矩形的一个顶点,再为Rectangle类增加两个数据成员H 和W,分别描述它的高和宽。为类Point设计一个构造函数Point(int,int)和显示数据的函数Showxy。为Rectangle类也设计构造函数Rectangle(int,in

9、t, int, int)和显示函数Show。由此可见,派生类增加了两个新的数据成员以及相应的成员函数,同时继承Point的全部成员。 【例7.1】是它们的程序实现。 【例7.1】使用默认内联函数实现单一继承。 #include using namespace std;,class Point private:int x,y;public:Point(int a, int b)x=a; y=b; cout“Point.“endl;void Showxy()cout“x=“x“,y=“yendl;Point()cout“Delete Point“endl; ; class Rectangle :

10、public Point private:int H, W;,public:Rectangle(int a, int b, int h, int w):Point(a,b) /构造函/数初始化列表H=h; W=w; cout“Rectangle.“endl;void Show()cout“H=“H“,W=“Wendl;Rectangle()cout“Delete Rectangle“endl; ; void main() Rectangle r1(3,4,5,6);r1.Showxy(); /派生类对象调用基类的成员函数r1.Show(); /派生类对象调用派生类的成员函数 ,程序输出如下:

11、Point. /调用基类构造函数 Rectangle. /调用派生类构造函数 x=3,y=4 /调用基类成员函数Showxy() H=5,W=6 /调用派生类成员函数Show() Delete Rectangle /调用派生类析构函数 Delete Point /调用基类析构函数 在派生类中继承的基类成员的初始化,需要由派生类的构造函数调用基类的构造函数来完成,这和初始化对象成员有类似之处。 定义派生类的构造函数的一般形式为:派生类名 : 派生类名(参数表0) : 基类名(参数表)./函数体 ,冒号后“基类名(参数表)”称为成员初始化列表,参数表给出所调用的基类构造函数所需要的实参。实参的值可

12、以来自“参数表0”,或由表达式给出。可以像Rectangle那样,在类中直接定义为内联函数。下面是在类说明之外定义的示范: Rectangle:Rectangle(int a, int b, int h, int w):Point(a,b) H=h; W=w; cout“Rectangle.“endl;“参数表0”有4个参数,基类Point的参数表是自己的2个数据成员。 构造函数(包括析构函数)是不被继承的,所以一个派生类只能调用它的直接基类的构造函数。当定义派生类的一个对象时,首先调用基类的构造函数,对基类成员进行初始化,然后执行派生类的构造函数,如果某个基类仍是一个派生类,则这个过程递归进

13、行。当该对象消失时,析构函数的执行顺序和执行构造函数时的顺序正好相反。输出结果也证实了这个结论。,7.2.3 类的保护成员 现在修改Rectangle 的Show函数,使得它可以一次显示x 、y 、H 和W 。怎样修改成员函数Show呢?修改成下面的内容能实现这一目的吗?void Rectangle:show()cout “x=“ x “,y=“y “,H=“ H “,W=“Wendl; 这段简单程序并不能通过编译。类Rectangle有4个私有成员x 、y 、H 和W 。这4个私有成员的来源是不一样的。H 和 W是Rectangle 自己定义的,而x 和y 是从Point那里继承来的。 换句

14、话说,x和y是类Point的私有成员。类的私有成员是只能被它自己的成员函数(不讨论友元)访问的,而Show函数是在类Rectangle 中定义的,它是类Point子类的成员函数,并不是类Point的成员函数,因而不能访问x 和y 。,C+语言规定,公有派生类的成员函数可直接访问基类中定义的或基类(从另一个基类)继承来的公有成员,但不能访问基类的私有成员。这和私有成员的定义是一致的,符合数据封装思想。但这样也有问题,就拿上面的程序来说,在类Rectangle 看来,x 、y 、H 和W 的地位是平等的,现在希望对它们“一视同仁”,但C+语言关于私有成员继承的规定却妨碍这样做。为解决这一矛盾,C+

15、引入了保护成员的概念。 在类声明中,关键字protected之后声明的是类的保护成员。保护成员具有私有成员和公有成员的双重角色:对派生类的成员函数而言,它是公有成员,可以被访问;而对其他函数而言则仍是私有成员,不能被访问。因此,要想在类Rectangle 中使用统一的Show函数,只要把x 和y 定义成类Point的保护成员就行了。【例7.2】是修改过的程序。,【例7.2】演示使用protected成员。 #include using namespace std; class Point protected:int x,y;public:Point(int a, int b)x=a; y=b;

16、void Show()cout“x=”x“,y=”yendl; /基类/的Show()函数 ;,class Rectangle : public Point private:int H, W;public:Rectangle(int, int, int, int); /构造函数原型void Show()cout“x=“x“,y=“y“,H=“H“,W=“Wendl;,/定义构造函数 Rectangle:Rectangle(int a, int b, int h, int w):Point(a,b) H=h; W=w; void main() Point a(3,4);Rectangle r1(3,4,5,6);a.Show(); /基类对象调用基类Show()函数r1.Show(); /派生类对象调用派生类Show()函数 程序还演示了在类体内声明Rectangle构造函数原型,类体外定义它。派生类虽然继承了基类的成员函数Show,但它改造了这个函数,使它能显示所有数据。这并不会影响,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号