C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用

上传人:E**** 文档编号:89155586 上传时间:2019-05-19 格式:PPT 页数:84 大小:890.01KB
返回 下载 相关 举报
C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用_第1页
第1页 / 共84页
C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用_第2页
第2页 / 共84页
C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用_第3页
第3页 / 共84页
C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用_第4页
第4页 / 共84页
C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用_第5页
第5页 / 共84页
点击查看更多>>
资源描述

《C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用》由会员分享,可在线阅读,更多相关《C++程序设计 教学课件 ppt 作者 郑莉 第10章_类的重用(84页珍藏版)》请在金锄头文库上搜索。

1、1,第 10 章 类的重用,清华大学 郑 莉,2,目录,10.1 类的组合 10.2 继承与派生 10.3 虚继承,3,10.1类的组合,类的组合 一个类的对象作为另一个类的数据成员的情况,他们之间的关系是一种包含与被包含的关系 例如,一个三角形包含三个顶点,三角形和顶点之间的关系是包含与被包含的关系。我们在对三角形抽象时,得到的属性就是三个顶点。在对顶点抽象时,得到的属性是x和y坐标。因此,对顶点可以定义一个Point类,其数据成员包含x和y坐标 ,对三角形可以定义Triangle类,其数据成员是三个Point类的对象。这样,类Triangle就使用了类Point。,4,10.1.1 对象成

2、员的初始化,当创建类的对象(称为复杂对象)时,如果这个类具有其他类的对象(称为内嵌对象)成员,那么先创建这些内嵌对象,然后再创建复杂对象 在创建对象时,既要对本类的基本类型数据成员进行初始化,也要对内嵌对象成员初始化,10.1 类的组合,5,10.1.1 对象成员的初始化,组合类构造函数的一般定义格式如下: 类名:类名(形参表):内嵌对象(形参表),内嵌对象(形参表),. 类的初始化 这里,“内嵌对象(形参表),内嵌对象(形参表),.”称为初始化列表。使用初始化列表的特点是效率要比赋值语句高。如果通过初始化列表对内嵌对象初始化,则实质是通过调用内嵌对象的构造函数对内嵌对象初始化 对基本数据类型

3、也可以使用初始化列表初始化 如果在构造组合类的对象时,不使用初始化列表对内嵌对象初始化,则会自动调用内嵌对象类的默认构造函数,10.1 类的组合,6,10.1.1 对象成员的初始化,通过初始化列表对内嵌对象初始化时,构造函数的调用顺序是: 调用内嵌对象的构造函数,调用顺序为内嵌对象在组合类的定义中出现的顺序 执行组合类的构造函数 当不使用初始化列表对内嵌对象时,构造函数的调用顺序是: 调用内嵌对象的默认构造函数,调用顺序为内嵌对象在组合类的定义中出现的顺序 执行组合类的构造函数 析构函数的调用执行顺序与构造函数相反,10.1 类的组合,7,10.1.1 对象成员的初始化,组合类的拷贝构造函数,

4、如果程序员没有编写组合类的拷贝构造函数,则会调用组合类的默认拷贝构造函数,而且会自动调用内嵌对象的默认拷贝构造函数 例如,假设类C包含类B的对象为数据成员,则类C的拷贝构造函数可以这样写: C:C(C & c1):b(c1.b) .,10.1 类的组合,8,10.1.1 对象成员的初始化,例10-1 组合类的构造函数,10.1 类的组合,class Point /Point类定义 public: /外部接口 Point(float x1 = 0.0f,float y1 = 0.0f) x = x1; y = y1; cout“Point类的构造函数被调用,x=“xendl; Point(Poi

5、nt ,9,10.1.1 对象成员的初始化,Point:Point(Point ,10.1 类的组合,10,10.1.1 对象成员的初始化,class Triangle public: Triangle(Point xp1,Point xp2,Point xp3); Triangle(Triangle ,10.1 类的组合,11,10.1.1 对象成员的初始化,/组合类的构造函数 Triangle:Triangle(Point xp1,Point xp2,Point xp3) p1.Init(xp1); p2.Init(xp2); p3.Init(xp3); float d1 = dis(p1

6、,p2); float d2 = dis(p2,p3); float d3 = dis(p3,p1); /利用S2 = p(p-a)(p-b)(p-c),p为周长的一半计算 float p = (d1 + d2 + d3) / 2; float area2 = p * (p-d1) * (p-d2) * (p-d3); area = sqrt(area2); cout“Triangle的构造函数被调用“endl; ,10.1 类的组合,12,10.1.1 对象成员的初始化,/组合类的拷贝构造函数,使用初始化列表对内嵌对象初始化 Triangle:Triangle(Triangle ,10.1

7、类的组合,10.1.1 对象成员的初始化,例10-1 组合类的构造函数 输出结果:,Point类的拷贝构造函数被调用,x=1 Point类的拷贝构造函数被调用,x=2 Point类的拷贝构造函数被调用,x=3 Triangle的构造函数被调用 Point类的构造函数被调用,x=1 Point类的拷贝构造函数被调用,x=2 Point类的拷贝构造函数被调用,x=3 Triangle的拷贝构造函数被调用 The area of t1 is:0.5 The area of t2 is:0.5,13,10.1 类的组合,Point类的构造函数被调用,x=1 Point类的构造函数被调用,x=2 Poi

8、nt类的构造函数被调用,x=3 Point类的拷贝构造函数被调用,x=3 Point类的拷贝构造函数被调用,x=2 Point类的拷贝构造函数被调用,x=1 Point类的构造函数被调用,x=0 Point类的构造函数被调用,x=0 Point类的构造函数被调用,x=0,14,10.1.1 对象成员的初始化,例10-1 组合类的构造函数 程序分析: 在main函数的刚开始,调用Point的普通构造函数对p1,p2,p3初始化。之后,调用Triangle的普通构造函数初始化t1,这时,首先调用的是Point的拷贝构造函数进行参数的形实结合,然后调用Point类的默认构造函数对Triangle的三

9、个Point对象p1,p2,p3初始化(因此此时输出的x值全为0)。此时对p1,p2,p3的初始化是通过Point类的Init函数进行的,Init函数的形实参数结合时也调用了拷贝构造函数。这个构造函数的最后输出“Triangle的构造函数被调用”。,10.1 类的组合,15,10.1.1 对象成员的初始化,例10-1 组合类的构造函数 程序分析: 之后调用Triangle的拷贝构造函数对t2初始化,此时t2的内嵌对象p1是在初始化列表中传递的参数是x和y的值,因此调用Point的普通构造函数对p1进行初始化。而p2,p3在初始化列表中传递的参数是Point的对象,因此调用拷贝构造函数对p1,p

10、2,p3初始化,然后输出“Triangle的拷贝构造函数被调用”。,10.1 类的组合,16,10.1.2 向前引用声明,在类的组合中,我们经常会碰到循环依赖的问题。所谓循环依赖,就是两个类互相引用的情况 例如: class A /定义类A public: void funA(B b); /类A的函数成员,以类B的对象为参数 /这样是非法的,因为在之前还没有定义类B ; class B /定义类B public: void funB(A a); /类B的函数成员,以类A的对象为参数 /因为在前面定义了类A,所以是合法的 ; 类A的成员函数funA的形参是类B的对象,而类B的成员函数funB的形

11、参是类A的对象。由于使用一个类之前,必须先定义该类,所以不管将哪一个类放在前面,都会引起编译错误,10.1 类的组合,17,10.1.2 向前引用声明,解决这个问题的办法,就是使用前向引用声明 前向引用声明,是指在引用未定义的类之前,将该类的名字告诉编译器,而完整的类定义可以放在程序的其他地方。例如: class B; /前向引用声明 class A /定义类A public: void funA(B b); /类A的函数成员,以类B的对象为参数 /这样合法 ; class B /定义类B public: void funB(A a); /类B的函数成员,以类A的对象为参数 /因为在前面定义了

12、类A,所以是合法的 ;,10.1 类的组合,18,10.1.2 向前引用声明,使用前向引用声明并不是万能的。尽管使用了前向引用声明,但是必须在完整的类定义之后,才能定义类的对象,也不能在内联函数中使用该类的对象 例如: class B; /前向引用声明 class A /定义类A public: void funA(B b) /非法,以类B的对象为参数,不能使用内联函数 public: B b; /非法,在类B的完整定义之前,不能使用B的对象 ; class B /定义类B public: void funB(A a); /类B的函数成员,以类A的对象为参数 /因为在前面定义了类A,所以是合法

13、的 private: A a; ;,10.1 类的组合,19,10.1.2 向前引用声明,两个类可以以彼此的指针为对象成员,但不能通过指针调用成员函数 例如: class B; /前向引用声明 class A /定义类A public: void funA() b-funB(); /非法,在类B的完整定义之前,不能使用B的对象 private: B* b; /合法,经过前向引用声明,可以声明B的指针 ; class B /定义类B public: void funB(); private: A* a; ; 类A和类B能够以彼此的指针为数据成员,但是A的成员函数中,不能再B的完整定义之前使用B的

14、对象。解决这个问题的方法是,更改两个类的定义顺序,或者将A的funA改为非内联形式,且在类B的完整定义之后,再对funA进行定义,10.1 类的组合,20,10.1.2 向前引用声明,总结:使用前向引用声明时,只能使用被声明的符号,而不能涉及类的任何细节,10.1 类的组合,21,10.2继承与派生,面向对象的程序设计提供了类的继承机制 将二维几何图形抽象为一个类,这个类具有面积这一属性,以及将自己的形状画出来的功能 多边形和几何图形的关系是什么呢?显然,多边形式几何图形的一种,因此,我们在对多边形进行抽象的时候,就可以将多边形类继承自几何图形类 被继承的类叫做基类,继承它类的类叫做派生类 基

15、类的成员都自动成为派生类的成员,派生类自己新定义的数据和函数成员称为派生类成员 派生类成员就是派生类不同于基类的关键所在,是派生类对基类的发展,22,10.2继承与派生,派生类的定义格式为: class 派生类名:继承方式 基类名, 继承方式 基类名,.,继承方式 基类名n 派生类成员声明及定义; ; 一个类可继承多个类,此时称为多继承,派生类得到多个基类的特征。如果一个类只继承单个类,则称为单继承 继承方式规定了如何访问从基类继承的成员。在派生类的定义中,每一个继承方式,只限定紧跟其后的基类。继承方式的关键字为:public,protected,private,分别表示公有继承,保护继承,私

16、有继承。如果不显式给出继承方式,则表示默认的私有继承,23,10.2继承与派生,派生出来的新类,也同样可以作为基类,即再派生出新的派生类。这样,就形成了一个相互关联的类的家族,有时也称为类族。例如,多边形继承自己和图形,而三角形继承自多边形。直接派生某个类的基类称为该类的直接基类,基类的基类或者更高层的基类称为间接基类。比如,多边形是三角形的直接基类,几何图形是三角形的间接基类,24,10.2继承与派生,例如,针对几何图形、多边形、三角形的继承关系,我们可以得到如下的类: class Shape /几何形状类 public: void Draw(); /画图形的函数 private: float area; /图形的面积 ; class Polygon:public Shape /多边形类,继承自几何形状类 private: int pointNum; /新增属

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

当前位置:首页 > 高等教育 > 大学课件

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