清华C++语言程序设计:第14章 继承.ppt_第1页
清华C++语言程序设计:第14章 继承.ppt_第2页
清华C++语言程序设计:第14章 继承.ppt_第3页
清华C++语言程序设计:第14章 继承.ppt_第4页
清华C++语言程序设计:第14章 继承.ppt_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

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

文档简介

1、第14章 继承,讲授内容,继承和派生的基本概念 继承的定义 在派生类中重定义基类的函数 基类和派生类对象的转换 类指针的使用 继承关系中构造函数、析构函数之间的关系 多重继承 复合与继承的关系,14.1 继承和派生的概念(1/2),实体之间的关系 有(has_a)类的复合 班级和学校,班级不是学校,学校拥有班级,班级是学校的一部分 是(is_a)类的继承 中学和学校,中学是学校,学校不能拥有中学,中学是学校的一个特例,是某一种学校,14.1 继承和派生的概念(2/2),继承 继承允许以现有的类为基础来构建新类 新类(派生类)继承现有类(基类)的属性和行为 派生类可以修改继承的属性和行为 派生类

2、可以增加新的属性和行为 派生类对象也是基类对象 派生类对象和基类对象可以被统一管理 复合和继承可以直观自然地描述客观世界中的实体,14.2 继承的定义(1/9),继承结构的例子无处不在 家具和柜子 建筑和房子 道路和高速公路 动物和猫 电视和彩色电视 电脑和笔记本电脑,例子1:定义基类Mammal和派生类Lion,class Mammal public: Mammal(); Mammal(); . ; class Lion: public Mammal public: Lion(); Lion(); . ;,14.2 继承的定义(2/9),继承的三种方式 公有继承(public) 受保护继承(

3、protected) 私有继承(private) 基类中的成员被派生类继承后成员对外的可见性会有所不同,14.2 继承的定义(3/9),公有继承(public) 基类中公有成员和受保护成员被继承后可见性不变 受保护继承(protected) 基类中公有成员和受保护成员被继承后都是受保护的 私有继承(private) 基类中公有成员和受保护成员被继承后都是私有的,14.2 继承的定义(4/9),基类中的私有成员 能被派生类继承 不能被派生类的成员函数直接访问 可通过定义于基类的公有和受保护成员函数访问,例子2:私有继承的例子,class Mammal public: Mammal(); Mamm

4、al(); . ; class Lion: private Mammal public: Lion(); Lion(); . ;,14.2 继承的定义(5/9),类的层次 一个类可以是某个继承关系中的基类,也可以是另一个继承关系中的派生类 类A派生出类B,类B又派生出类C,则类B是类C的直接基类,类A是类C的间接基类 定义派生类时,直接基类要明确列出,间接基类不用列出,例子3:间接基类的例子,class A protected: int aMember; . ; class B: protected A protected: int bMember; . ; class C: private

5、B protected: int cMember; . ;,14.2 继承的定义(6/9),在派生类中重定义基类的函数 派生类自动继承基类的所有成员 如果基类成员函数功能不满足需要在派生类中重定义该函数 派生类对象可以直接访问自己定义的函数,也可以访问定义于基类被覆盖的函数 调用方式:基类名 + : + 函数名,例子4:派生类重定义基类成员函数(1/5),/文件people.h #if !defined _PEOPLE_H_ #define _PEOPLE_H_ class People public: /构造函数中参数s大于0表示男性,否则为女性 People(char *str, int

6、s); People(); void show(); private: char *name; int sex; ; #endif,例子4:派生类重定义基类成员函数(2/5),/文件people.cpp #include #include #include people.h People:People(char *str, int s) name = new charstrlen(str)+1; strcpy(name, str); if (s0) sex = 1;/男性 else sex = 0;/女性 People:People() delete name; void People:sho

7、w() cout My name is name , I am ; cout (sex ? male. : female.) endl; ,例子4:派生类重定义基类成员函数(3/5),/文件teacher.h #include people.h #if !defined _TEACHER_H_ #define _TEACHER_H_ class Teacher : public People public: Teacher(char *str, int s, char *sch, int y); Teacher(); void show(); private: char *school; in

8、t years; ; #endif,例子4:派生类重定义基类成员函数(4/5),/文件 teacher.cpp #include #include #include teacher.h Teacher:Teacher(char *str, int s, char *sch, int y) :People(str, s)/调用基类的构造函数 school = new charstrlen(sch)+1; strcpy(school,sch); years = (y0) ? y : 0; Teacher:Teacher() delete school; void Teacher:show() Pe

9、ople:show();/调用基类被重定义的函数 coutI am in school for years years. endl; ,例子4:派生类重定义基类成员函数(5/5),/文件ex14_1.cpp /测试类Teacher #include #include teacher.h main() People people(Zhang san, 1); Teacher teacher (Li si,-1, Wuhan University, 4); people.show(); cout endl; teacher.show(); return 0; ,14.2 继承的定义(7/9),创建

10、派生类对象时,派生类构造函数要调用基类的构造函数 先执行基类构造函数,然后执行派生类构造函数体 基类构造函数需要参数时,显式调用,格式: Teacher:Teacher(char *s,int t,char *c,int y) :People(s,c)/调用基类的构造函数 . 基类构造函数不需要参数时(有默认构造函数),隐式调用 基类的构造函数不被继承,但会被自动调用,14.2 继承的定义(8/9),派生类重定义基类的函数 重定义函数的函数原型和基类中被重定义函数的函数原型必须完全相同 不同则是函数重载 重定义之后两个函数共存,但调用方法不同 调用基类函数:基类名 + : + 函数名 调用派生

11、类函数:直接调用,14.2 继承的定义(9/9),派生类和基类的转换 派生类和基类具有不同的类型 派生类对象也是基类对象,可以作为基类对象处理 可以把派生类对象直接赋值给基类对象 基类对象不能直接作为派生类对象处理(需要类型转换),14.3 类指针(1/3),类是一种新的用户自定义类型 类名可以用来声明变量(类的对象)、数组、指针等 类的指针可以操作类的对象,也可以操作派生类的对象(派生类对象也是基类对象) 派生类对象和基类对象可以通过指针统一操作和管理,14.3 类指针(2/3),类指针操作类对象的几种可能 基类指针操作基类对象(自然) 派生类指针操作派生类对象(自然) 基类指针操作派生类对

12、象把派生类对象作为基类对象看(安全) 派生类指针操作基类对象把基类对象作为派生类对象看(危险),例子5:用类指针操作基类和派生类对象(1/9),/文件people.h #if !defined _PEOPLE_H_ #define _PEOPLE_H_ class People public: /构造函数中参数s大于0表示男性,否则为女性 People(char *str, int s); People(); int getSex(); char* getName(); private: char *name; int sex; ; #endif,例子5:用类指针操作基类和派生类对象(2/9)

13、,/文件people.cpp #include #include #include people.h People:People(char *str, int s) name = new charstrlen(str)+1; strcpy(name, str); if (s0)sex = 1;/男性 elsesex = 0;/女性 People:People() delete name; ,例子5:用类指针操作基类和派生类对象(3/9),int People:getSex() return sex; char * People:getName() static char str128; str

14、cpy(str,name); return str; ,例子5:用类指针操作基类和派生类对象(4/9),/文件teacher.h #include people.h #if !defined _TEACHER_H_ #define _TEACHER_H_ class Teacher : public People public: Teacher(char *str, int s, char *sch, int y); Teacher(); int getWorkYears(); char *getSchool(); private: char *school; int years; ; #en

15、dif,例子5:用类指针操作基类和派生类对象(5/9),/文件 teacher.cpp #include #include #include teacher.h Teacher:Teacher(char *str,int s,char *sch,int y) :People(str, s)/调用基类的构造函数 school = new charstrlen(sch)+1; strcpy(school,sch); years = (y0) ? y : 0; Teacher:Teacher() delete school; ,例子5:用类指针操作基类和派生类对象(6/9),int Teacher:

16、getWorkYears() return years; char * Teacher:getSchool() static char str1024; strcpy(str,school); return str; ,例子5:用类指针操作基类和派生类对象(7/9),/文件ex14_2.cpp #include #include teacher.h main() People p(Zhang San, 1), *pptr; Teacher t(Li Si, 0, Wuhan University, 4), *tptr; /用基类指针操作对象 pptr = ,例子5:用类指针操作基类和派生类对象

17、(8/9),/要调用定义于派生类中的函数必须进行类型的强制转换 coutgetSchool() getWorkYears() getName() getSex()?male:female)getSchool() getWorkYears() years. endl;,例子5:用类指针操作基类和派生类对象(9/9),tptr = ,程序运行结果:,People p: Zhang San, male Teacher t: Li Si, female in Wuhan University for 4 years. People p: Zhang San, male in ? for 4278034

18、 years. People p: Li Si, female in Wuhan University for 4 years.,14.3 类指针(3/3),常用的程序设计方法 用数组或链表组织和管理继承关系中的各对象 然后用基类指针操作它们 麻烦可能需要类型转换 下一章的多态性可以解决这个问题,14.4 继承中的构造函数和析构函数(1/2),派生类不继承基类的构造函数和析构函数 派生类和基类的构造函数和析构函数之间是一种自动调用的关系 派生类的构造函数需要调用基类的构造函数对其中定义于基类的数据成员进行初始化 显式调用(需要传递参数) 隐式调用(不需要传递参数) 派生类的析构函数也需要调用基

19、类的析构函数做一些和基类相关的清理工作,14.4 继承中的构造函数和析构函数(2/2),构造函数的执行顺序 先调用基类的构造函数初始化从基类继承的数据成员 再执行自己的函数体初始化定义于派生类的数据成员 析构函数的执行顺序 派生类的析构函数先执行自己的函数体 再调用基类的析构函数,例子6:继承关系中构造函数和析构函数的执行顺序(1/5),/文件people.h /定义类People #if !defined _PEOPLE_H_ #define _PEOPLE_H_ class People public: People(char *str);/构造函数 People();/析构函数 prot

20、ected: char *name; ; #endif,例子6:继承关系中构造函数和析构函数的执行顺序(2/5),/文件people.cpp,类People的实现 #include #include #include people.h /构造函数的实现 People:People(char *str) name = new charstrlen(str)+1; strcpy(name, str); coutPeople construct: nameendl; /析构函数的实现 People:People() coutPeople destroy: nameendl; delete name;

21、 ,例子6:继承关系中构造函数和析构函数的执行顺序(3/5),/文件teacher.h /定义类Teacher #include people.h #if !defined _TEACHER_H_ #define _TEACHER_H_ class Teacher : public People public: Teacher(char *str, char *sch);/构造函数 Teacher();/析构函数 protected: char *school; ; #endif,例子6:继承关系中构造函数和析构函数的执行顺序(4/5),/文件 teacher.cpp,类 Teacher的实现

22、 #include #include #include teacher.h Teacher:Teacher(char *str, char *sch) :People(str)/调用基类的构造函数 school = new charstrlen(sch)+1; strcpy(school,sch); coutTeacher construct: name in schoolendl; Teacher:Teacher() coutTeacher destroy: name in schoolendl; delete school; ,例子6:继承关系中构造函数和析构函数的执行顺序(5/5),/文

23、件ex14_3.cpp /测试继承中基类和派生类的构造函数与析构函数的执行顺序 #include #include teacher.h main () People tmp(Zhang San); People p(Li Si); Teacher t(Wang Wu, Wuhan University); return 0; ,程序运行结果,People construct: Zhang San People destroy: Zhang San People construct: Li Si People construct: Wang Wu Teacher construct: Wang

24、Wu in Wuhan University Teacher destroy: Wang Wu in Wuhan University People destroy: Wang Wu People destroy: Li Si,14.5 多重继承(1/2),单重继承一个派生类最多只能有一个基类 多重继承一个派生类可以有多个基类 派生类同时继承多个基类的成员,更好的软件重用 可能会有大量的二义性,多个基类中可能包含同名变量或函数,14.5 多重继承(2/2),多重继承中解决访问歧义的方法 基类名 + : + 数据成员名(或成员函数) 明确指明要访问定义于哪个基类中的成员,14.6 软件渐增式开发

25、,复合与继承 代码重用的两种方式 都可以使新类重用已有类的数据和函数 有助于逐步开发功能越来越强大的程序 使用复合还是继承? 依据是实体之间的关系和程序设计的需要,例子7:软件渐增式开发(part 1,1/5),/文件Point.h: interface for the Point class. #if !defined _POINT_H_ #define _POINT_H_ #include class Point friend ostream,例子7:软件渐增式开发(part 1,2/5),/ 重载的定值函数 void setPoint(double a, double b); void

26、setPoint(Point #endif,例子7:软件渐增式开发(part 1,3/5),/ 文件Point.cpp,类Point的实现 #include Point.h Point:Point(double a, double b) x = a; y = b; Point:Point(const Point ,例子7:软件渐增式开发(part 1,4/5),void Point:setPoint(Point ,例子7:软件渐增式开发(part 1,5/5),/文件ex14_5.cpp,第一个程序 #include Point.h main() / 声明并输出两个点 Point p1(3.0

27、, 3.5); Point p2(6.5, 5.5); cout p1:t p1 endl; cout p2:t p2 endl; return 0; ,例子7:软件渐增式开发(part 2,1/6),/文件Line.h,类Line的定义 #if !defined _LINE_H_ #define _LINE_H_ #include #include point.h class Line friend ostream ,例子7:软件渐增式开发(part 2,2/6),/ 重载的定值函数 void setLine(double startX=0,double startY=0, double e

28、ndX=0, double endY=0); void setLine(Point , Point ); double getLength() const; / 计算线段的长度 / 取值函数 Point getStartPoint() return startPoint; Point getEndPoint() return endPoint; private: Point startPoint, endPoint; ; #endif,例子7:软件渐增式开发(part 2,3/6),/文件line.cpp,类Line的实现 #include #include Line.h Line:Line(

29、double startX, double startY, double endX, double endY) :startPoint(startX, startY),endPoint(endX, endY) Line:Line(Point start, Point end) :startPoint(start), endPoint(end) Line:Line() ,例子7:软件渐增式开发(part 2,4/6),void Line:setLine(double startX, double startY, double endX, double endY) startPoint.setPo

30、int(startX, startY); endPoint.setPoint(endX, endY); void Line:setLine(Point start, Point end) startPoint.setPoint(start); endPoint.setPoint(end); double Line:getLength() const double x1 = startPoint.getX(); double y1 = startPoint.getY(); double x2 = endPoint.getX(); double y2 = endPoint.getY(); retu

31、rn sqrt(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1); ,例子7:软件渐增式开发(part 2,5/6),ostream ,例子7:软件渐增式开发(part 2,6/6),/文件ex14_6.cpp,第二个程序 #include Line.h main() Point p1(3.0, 3.5); Point p2(6.5, 5.5); cout p1:t p1 endl; cout p2:t p2 endl; Line l1 (p1, p2); Line l2 (1.0, 2.5, 4.5, 5.0); cout nl1:t l1 endl; cout l2:t l2 endl; return 0; ,例子7:软件渐增式开发(part 3,1/5),/ 文件Polygon.h,类Polygon的定义 #include

温馨提示

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

评论

0/150

提交评论