第12章组合与继承_第1页
第12章组合与继承_第2页
第12章组合与继承_第3页
第12章组合与继承_第4页
已阅读5页,还剩109页未读 继续免费阅读

下载本文档

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

文档简介

1、程序设计 cs.sjtu 2011.9程序设计 - 1v组合组合 v继承继承 v虚函数与多态性虚函数与多态性v纯虚函数与抽象类纯虚函数与抽象类 v多继承多继承 v面向对象设计范例面向对象设计范例程序设计 cs.sjtu 2011.9程序设计 - 2v继承是面向对象程序设计的一个重要特征,继承是面向对象程序设计的一个重要特征,它允许在已有类的基础上创建新的类它允许在已有类的基础上创建新的类v基类、父类基类、父类v派生类、导出类或子类派生类、导出类或子类v继承可以让程序员在已有类的基础上通过增继承可以让程序员在已有类的基础上通过增加或修改少量代码的方法得到新的类,从而加或修改少量代码的方法得到新的

2、类,从而较好地解决代码重用的问题。较好地解决代码重用的问题。程序设计 cs.sjtu 2011.9程序设计 - 3v单继承的格式单继承的格式v基类成员在派生类中的访问特性基类成员在派生类中的访问特性 v派生类对象的构造、析构与赋值操作派生类对象的构造、析构与赋值操作 v重定义基类的函数重定义基类的函数 v派生类作为基类派生类作为基类 v将派生类对象隐式转换为基类对象将派生类对象隐式转换为基类对象 程序设计 cs.sjtu 2011.9程序设计 - 4v一般格式:一般格式: class 派生类名:派生方法派生类名:派生方法 基类名基类名 /派生类新增的数据成员和成员函数派生类新增的数据成员和成员

3、函数 ;v派生方法:派生方法:1.公有派生公有派生: public2.私有派生:私有派生:private3.保护派生:保护派生:protected程序设计 cs.sjtu 2011.9程序设计 - 5class base int x; public: void setx(int k);class derived1:public base int y; public: void sety(int k); Derived1有两个数据有两个数据成员:成员:x,y。有两个成员函数:有两个成员函数:setx和和sety程序设计 cs.sjtu 2011.9程序设计 - 6v派生类的成员函数不能访问基类的

4、私有数派生类的成员函数不能访问基类的私有数据成员据成员 vprotected访问特性访问特性 protected成员是一类特殊的私有成员,它不成员是一类特殊的私有成员,它不可以被全局函数或其他类的成员函数访问,可以被全局函数或其他类的成员函数访问,但能被派生类的成员函数访问但能被派生类的成员函数访问 protected成员破坏了类的封装,基类的成员破坏了类的封装,基类的protected成员改变时,所有派生类都要修改成员改变时,所有派生类都要修改 程序设计 cs.sjtu 2011.9程序设计 - 7v单继承的格式单继承的格式v基类成员在派生类中的访问特性基类成员在派生类中的访问特性 v派生类

5、对象的构造、析构与赋值操作派生类对象的构造、析构与赋值操作 v重定义基类的函数重定义基类的函数 v派生类作为基类派生类作为基类 v将派生类对象隐式转换为基类对象将派生类对象隐式转换为基类对象 程序设计 cs.sjtu 2011.9程序设计 - 8基类成员的基类成员的访问说明符访问说明符 继承类型继承类型 public继承继承 protected继承继承 private继承继承public 在派生类中为在派生类中为public 在派生类中为在派生类中为protected 在派生类中为在派生类中为private 可以由任何非可以由任何非static 可以直接由任何非可以直接由任何非static 可

6、以直接由任何非可以直接由任何非static 成员函数、友元函数和成员函数、友元函数和 成员函数、友元函数成员函数、友元函数 成员函数、友元函数成员函数、友元函数 非成员函数访问非成员函数访问 访问访问 访问访问protecetd 在派生类中为在派生类中为proteced 在派生类中为在派生类中为protected 在派生类中在派生类中private 可以直接由任何非可以直接由任何非static 成员函数、友元函数访问成员函数、友元函数访问private 在派生类中隐藏在派生类中隐藏 在派生类中隐藏在派生类中隐藏 在派生类中隐藏在派生类中隐藏 可以通过基类的可以通过基类的public 或或pro

7、tected成员函数或非成员函数或非static成员函数和友元函数访问成员函数和友元函数访问程序设计 cs.sjtu 2011.9程序设计 - 9 Derived1不可访问不可访问 Int xprivateInt ypublicSetx()Sety()class base int x; public: void setx(int k);class derived1:public base int y; public: void sety(int k); 程序设计 cs.sjtu 2011.9程序设计 - 10v 定义一个二维平面上的点类型,可以设定义一个二维平面上的点类型,可以设置点的位置,获

8、取点的位置。在此基础置点的位置,获取点的位置。在此基础上,扩展出一个三维空间上的点类型。上,扩展出一个三维空间上的点类型。程序设计 cs.sjtu 2011.9程序设计 - 11class point_2d private: int x,y; public: void setpoint2(int a, int b) x = a; y = b; int getx() return x; int gety() return y; ;程序设计 cs.sjtu 2011.9程序设计 - 12class point_3d:public point_2dint z; public: void setpoi

9、nt3(int a,int b,int c) setpoint2(a,b); z=c; int getz() return z; 程序设计 cs.sjtu 2011.9程序设计 - 13vpoint_3d的组成:有三个数据成员:的组成:有三个数据成员:x,y和和z,有,有五个公有的成员函数:五个公有的成员函数:setpoint2, setpoint3, getx, gety和和getz。vpoint_3d的成员函数无法直接访问基类的的成员函数无法直接访问基类的x和和y,因此在因此在setpoint3函数中必须调用在函数中必须调用在point_2d的公的公有成员函数有成员函数setpoint2实

10、现。实现。vpoint_3d类的使用和普通类完全一样,用户不用类的使用和普通类完全一样,用户不用去管这个类是用继承方式从另外一个类扩展而来去管这个类是用继承方式从另外一个类扩展而来,还是完全直接定义的。,还是完全直接定义的。程序设计 cs.sjtu 2011.9程序设计 - 14int main()point_2d p1; point_3d p2; p1.setpoint2(1, 2); cout p1: ( p1.getx() , p1.gety() ) endl; p2.setpoint3(1, 2, 3); cout p2: ( p2.getx() , p2.gety() , p2.ge

11、tz() ) endl; return 0;P1: (1, 2)P2: (1, 2, 3)程序设计 cs.sjtu 2011.9程序设计 - 15v单继承的格式单继承的格式v基类成员在派生类中的访问特性基类成员在派生类中的访问特性 v派生类对象的构造、析构与赋值操作派生类对象的构造、析构与赋值操作 v重定义基类的函数重定义基类的函数 v派生类作为基类派生类作为基类 v将派生类对象隐式转换为基类对象将派生类对象隐式转换为基类对象 程序设计 cs.sjtu 2011.9程序设计 - 16v由于派生类继承了其基类的成员,所以在由于派生类继承了其基类的成员,所以在建立派生类的实例对象时,必须初始化基建

12、立派生类的实例对象时,必须初始化基类继承的数据成员。派生类对象析构时,类继承的数据成员。派生类对象析构时,也必须析构基类对象。也必须析构基类对象。v派生类不继承基类的构造函数、析构函数派生类不继承基类的构造函数、析构函数和赋值运算符,但是派生类的构造函数、和赋值运算符,但是派生类的构造函数、析构函数和赋值运算符能调用基类的构造析构函数和赋值运算符能调用基类的构造函数、析构函数和赋值运算符。函数、析构函数和赋值运算符。程序设计 cs.sjtu 2011.9程序设计 - 17v基类成员的初始化由基类的构造函数完成。基类成员的初始化由基类的构造函数完成。派生类的构造函数调用基类的构造函数完成派生类的

13、构造函数调用基类的构造函数完成基类成员的初始化。基类成员的初始化。v派生类构造函数可以隐式调用基类缺省的构派生类构造函数可以隐式调用基类缺省的构造函数,也可以在派生类的构造函数的初始造函数,也可以在派生类的构造函数的初始化列表显式地调用基类的构造函数。化列表显式地调用基类的构造函数。程序设计 cs.sjtu 2011.9程序设计 - 18v派生类构造函数的格式:派生类构造函数的格式:派生类构造函数名(参数表):派生类构造函数名(参数表): 基类构造函数名(参数表)基类构造函数名(参数表) 。 v基类构造函数中的参数表通常来源于派生类构造函数基类构造函数中的参数表通常来源于派生类构造函数的参数表

14、,也可以用常数值。的参数表,也可以用常数值。 v如果构造派生类对象时调用的是基类的缺省构造函数如果构造派生类对象时调用的是基类的缺省构造函数,则可以不要初始化列表。,则可以不要初始化列表。v如果派生类新增的数据成员中含有对象成员,则在创如果派生类新增的数据成员中含有对象成员,则在创建对象时,先执行基类的构造函数,再执行成员对象建对象时,先执行基类的构造函数,再执行成员对象的构造函数,最后执行自己的构造函数体。的构造函数,最后执行自己的构造函数体。 程序设计 cs.sjtu 2011.9程序设计 - 19v派生类的析构函数值析构自己新增的数派生类的析构函数值析构自己新增的数据成员,基类成员的析构

15、由基类的析构据成员,基类成员的析构由基类的析构函数析构函数析构v派生类析构函数会自动调用基类的析构派生类析构函数会自动调用基类的析构函数函数v派生类对象析构时,先执行派生类的析派生类对象析构时,先执行派生类的析构函数,再执行基类的析构函数构函数,再执行基类的析构函数程序设计 cs.sjtu 2011.9程序设计 - 20v定义一个二维平面上的点类,并从它派定义一个二维平面上的点类,并从它派生出一个圆类生出一个圆类程序设计 cs.sjtu 2011.9程序设计 - 21/ Definition of class Point#ifndef POINT2_H#define POINT2_Hclass

16、 Point public: Point( int = 0, int = 0 ); / default constructor Point(); / destructorprotected: / accessible by derived classes int x, y; / x and y coordinates of Point;#endif程序设计 cs.sjtu 2011.9程序设计 - 22#include point2.h/ Constructor for class PointPoint:Point( int a, int b ) x = a; y = b; cout Poin

17、t constructor: x , y endl; / Destructor for class PointPoint:Point() cout Point destructor: x , y endl; 程序设计 cs.sjtu 2011.9程序设计 - 23#ifndef CIRCLE2_H#define CIRCLE2_H#include point2.hclass Circle : public Point public: / default constructor Circle( double r = 0.0, int x = 0, int y = 0 ); Circle(); p

18、rivate: double radius; ; #endif程序设计 cs.sjtu 2011.9程序设计 - 24#include circle2.h / Constructor for Circle calls constructor for PointCircle:Circle( double r, int a, int b ) : Point( a, b ) / call base-class Constructor radius = r; / should validatecout Circle constructor: radius is radius x , y endl; /

19、 Destructor roi class CircleCircle:Circle() cout Circle destructor: radius is radius x , y endl; 程序设计 cs.sjtu 2011.9程序设计 - 25#include point2.h“#include circle2.h int main() / Show constructor and destructor calls for Point Point p( 11, 22 ); cout endl;Circle circle1( 4.5, 72, 29 );cout endl;Circle c

20、ircle2( 10, 5, 5 );cout endl;return 0; Point constructor: 11, 22 Point destructor: 11, 22 Point constructor: 72, 29 Circle constructor: radius is 4.5 72, 29Point constructor: 5, 5 Circle constructor: radius is 10 5, 5 Circle destructor: radius is 10 5, 5 Point destructor: 5, 5 Circle destructor: rad

21、ius is 4.5 72, 29 Point destructor: 72, 29 程序设计 cs.sjtu 2011.9程序设计 - 26v若基类使用缺省或不带参数的构造函数,则在若基类使用缺省或不带参数的构造函数,则在派生类定义构造函数是可略去:基类构造函数派生类定义构造函数是可略去:基类构造函数名(参数表)。此时若派生类也不需要构造函名(参数表)。此时若派生类也不需要构造函数,则可不定义构造函数。数,则可不定义构造函数。v当基类构造函数需要参数,而派生类本身并不当基类构造函数需要参数,而派生类本身并不需要构造函数时,派生类还必须定义构造函数需要构造函数时,派生类还必须定义构造函数。该函

22、数只是起了一个参数传递作用。该函数只是起了一个参数传递作用。v如果省略了派生类的构造函数,那么就由派生如果省略了派生类的构造函数,那么就由派生类的默认构造函数调用基类的默认构造函数。类的默认构造函数调用基类的默认构造函数。程序设计 cs.sjtu 2011.9程序设计 - 27v定义一个图书馆系统中的读者类,每个定义一个图书馆系统中的读者类,每个读者的信息包括:卡号、姓名、单位、读者的信息包括:卡号、姓名、单位、允许借书的数量以及已借书记录。学生允许借书的数量以及已借书记录。学生最多允许借最多允许借5本书,教师最多允许借本书,教师最多允许借10本书。本书。 程序设计 cs.sjtu 2011.

23、9程序设计 - 28v系统中有两类读者:学生读者和教师读者系统中有两类读者:学生读者和教师读者。v这两类读者有一部分内容是相同的:卡号这两类读者有一部分内容是相同的:卡号、姓名和单位。、姓名和单位。v可将两类读者的共同部分内容设计成一个可将两类读者的共同部分内容设计成一个基类。基类。v学生读者和教师读者从基类派生,增加已学生读者和教师读者从基类派生,增加已借书的数量以及已借书记录两个数据成员借书的数量以及已借书记录两个数据成员,并将允许借书的数量定义为整个类共享,并将允许借书的数量定义为整个类共享的常量的常量 程序设计 cs.sjtu 2011.9程序设计 - 29class readerin

24、t no;char name10;char dept20;public:reader(int n, char *nm, char *d) no = n; strcpy(name, nm); strcpy(dept, d); ;程序设计 cs.sjtu 2011.9程序设计 - 30class readerTeacher :public readerenum MAX = 10; int borrowed;int recordMAX;public:readerTeacher(int n, char *nm, char *d):reader(n, nm, d) borrowed = 0;bool b

25、ookBorrow(int bookNo);bool bookReturn(int bookNo); void show(); /显示已借书信息显示已借书信息; 程序设计 cs.sjtu 2011.9程序设计 - 31class readerStudent :public reader enum MAX = 5;int borrowed;int recordMAX;public:readerStudent(int n, char *nm, char *d):reader(n, nm, d) borrowed = 0; bool bookBorrow(int bookNo);bool bookR

26、eturn(int bookNo); void show(); /显示已借书信息显示已借书信息; 程序设计 cs.sjtu 2011.9程序设计 - 32v单继承的格式单继承的格式v基类成员在派生类中的访问特性基类成员在派生类中的访问特性 v派生类对象的构造、析构与赋值操作派生类对象的构造、析构与赋值操作 v重定义基类的函数重定义基类的函数 v派生类作为基类派生类作为基类 v将派生类对象隐式转换为基类对象将派生类对象隐式转换为基类对象 程序设计 cs.sjtu 2011.9程序设计 - 33v派生类是基类的扩展,可以是保存的数据内容的派生类是基类的扩展,可以是保存的数据内容的扩展,也可以是功能

27、的扩展。扩展,也可以是功能的扩展。v当派生类对基类的某个功能进行扩展时,他定义当派生类对基类的某个功能进行扩展时,他定义的成员函数名可能会和基类的成员函数名重复。的成员函数名可能会和基类的成员函数名重复。v如果只是函数名相同,而原型不同时,系统认为如果只是函数名相同,而原型不同时,系统认为派生类中有两个重载函数。如果原型完全相同,派生类中有两个重载函数。如果原型完全相同,则派生类的函数会覆盖基类的函数。这称为重定则派生类的函数会覆盖基类的函数。这称为重定义基类的成员函数。义基类的成员函数。程序设计 cs.sjtu 2011.9程序设计 - 34v 定义一个圆类型,用于保存圆以及输出定义一个圆类

28、型,用于保存圆以及输出圆的面积和周长。在此类型的基础上派圆的面积和周长。在此类型的基础上派生出一个球类型,可以计算球的表面积生出一个球类型,可以计算球的表面积和体积。和体积。 程序设计 cs.sjtu 2011.9程序设计 - 35v数据成员:圆的半径数据成员:圆的半径v成员函数:由于需要提供圆的面积和周成员函数:由于需要提供圆的面积和周长,需要提供两个公有的成员函数。除长,需要提供两个公有的成员函数。除了这些之外,还需要一个构造函数了这些之外,还需要一个构造函数 程序设计 cs.sjtu 2011.9程序设计 - 36class circle protected: double radius

29、;public:circle(double r = 0) radius = r;double getr() return radius;double area() return 3.14 * radius * radius; double circum() return 2 * 3.14 * radius; 程序设计 cs.sjtu 2011.9程序设计 - 37class ball:public circle public:ball(double r = 0):circle(r) double area() return 4 * 3.14 * radius * radius; double

30、volumn() return 4 * 3.14 * radius * radius * radius / 3; ;程序设计 cs.sjtu 2011.9程序设计 - 38vBall类没有新增加数据成员,因而不需类没有新增加数据成员,因而不需要构造函数。但基类的构造函数需要参要构造函数。但基类的构造函数需要参数,所以数,所以ball类必须写构造函数类必须写构造函数vBall类构造函数的作用是为类构造函数的作用是为circle类的构类的构造函数传递参数造函数传递参数程序设计 cs.sjtu 2011.9程序设计 - 39vBall类包含了两个原型完全一样的类包含了两个原型完全一样的area函数。

31、一个是自己定义的,一个是从函数。一个是自己定义的,一个是从circle类继承来的类继承来的v当对当对ball类的对象调用类的对象调用area函数时,调函数时,调用的是用的是ball类自己定义的类自己定义的area函数函数程序设计 cs.sjtu 2011.9程序设计 - 40v派生类中重新定义基类的成员函数时,派生类中重新定义基类的成员函数时,它的功能往往是基类功能的扩展。为完它的功能往往是基类功能的扩展。为完成扩展的工作,派生类版本通常要调用成扩展的工作,派生类版本通常要调用基类中的该函数版本。基类中的该函数版本。v引用基类的同名函数必须使用作用域运引用基类的同名函数必须使用作用域运算符,否

32、则会由于派生类成员函数实际算符,否则会由于派生类成员函数实际上调用了自身而引起无穷递归。这样会上调用了自身而引起无穷递归。这样会使系统用光内存,是致命的运行时错误使系统用光内存,是致命的运行时错误。程序设计 cs.sjtu 2011.9程序设计 - 41v在在circle类的基础上定义一个类的基础上定义一个cylinder类。可类。可以计算圆柱体的表面积和体积以计算圆柱体的表面积和体积 v设计考虑:设计考虑:存储圆柱体可以在圆的基础上增加一个高度。存储圆柱体可以在圆的基础上增加一个高度。圆柱体的表面积是上下两个圆的面积加上它的圆柱体的表面积是上下两个圆的面积加上它的侧面积侧面积圆柱体的体积是底

33、面积乘上高度。而求圆的面圆柱体的体积是底面积乘上高度。而求圆的面积的函数在积的函数在circle类中已经存在。类中已经存在。 程序设计 cs.sjtu 2011.9程序设计 - 42class cylinder:public circle double height;public:cylinder(double r = 0, double h = 0):circle(r) height = h;double geth() return height;double area() return 2 * circle:area() + circum() * height; double volumn

34、() return circle:area() * height ; ;程序设计 cs.sjtu 2011.9程序设计 - 43int main()circle c(3); ball b(2); cylinder cy(1,2); cout circle: r= c.getr() endl; cout area= c.area() tcircum= c.circum() endl; cout ball: r= b.getr() endl; cout area= b.area() tvolumn= b.volumn() endl; cout cylinder: r= cy.getr() th =

35、 cy.geth() endl; cout area= cy.area() tvolumn= cy.volumn() endl; return 0;程序设计 cs.sjtu 2011.9程序设计 - 44circle: r=3area=28.26 circum=18.84ball: r=2area=50.24 volumn=33.4933cylinder: r=1area=18.84 volumn=6.28程序设计 cs.sjtu 2011.9程序设计 - 45v单继承的格式单继承的格式v基类成员在派生类中的访问特性基类成员在派生类中的访问特性 v派生类对象的构造、析构与赋值操作派生类对象的构

36、造、析构与赋值操作 v重定义基类的函数重定义基类的函数 v派生类作为基类派生类作为基类 v将派生类对象隐式转换为基类对象将派生类对象隐式转换为基类对象 程序设计 cs.sjtu 2011.9程序设计 - 46v基类本身可以是一个派生类,如:基类本身可以是一个派生类,如:class base class d1:public base class d2:public d1 v每个派生类继承他的直接基类的所有成员。每个派生类继承他的直接基类的所有成员。v如果派生类的基类是一个派生类,则每个派生类只负责如果派生类的基类是一个派生类,则每个派生类只负责他的直接基类的构造,依次上溯。他的直接基类的构造,依

37、次上溯。v当构造当构造d2类的对象时,会先调用类的对象时,会先调用d1的构造函数,而的构造函数,而d1的构造函数执行时又会先调用的构造函数执行时又会先调用base的构造函数。因此,的构造函数。因此,构造构造d2类的对象时,最先初始化的是类的对象时,最先初始化的是base的数据成员,的数据成员,再初始化再初始化d1新增的成员,最后初始化新增的成员,最后初始化d2新增的成员。新增的成员。v析构的过程正好相反。析构的过程正好相反。 程序设计 cs.sjtu 2011.9程序设计 - 47#include using namespace std;class base int x; public: ba

38、se(int xx) x=xx; coutconstructing basen; base() coutdestructint basen; ;class derive1:public base int y;public:derive1(int xx, int yy): base(xx) y = yy; coutconstructing derive1n; derive1() coutdestructing derive1n; ;程序设计 cs.sjtu 2011.9程序设计 - 48class derive2:public derive1 int z;public:derive2(int x

39、x, int yy, int zz):derive1(xx, yy) z = zz;coutconstructing derive2n; derive2() coutdestructing derive2n; ;main()derive2 op(1, 2, 3); return 0;constructing baseconstructing derive1constructing derive2 destructing derive2destructing derive1destructint base程序设计 cs.sjtu 2011.9程序设计 - 49v单继承的格式单继承的格式v基类成员

40、在派生类中的访问特性基类成员在派生类中的访问特性 v派生类对象的构造、析构与赋值操作派生类对象的构造、析构与赋值操作 v重定义基类的函数重定义基类的函数 v派生类作为基类派生类作为基类 v将派生类对象隐式转换为基类对象将派生类对象隐式转换为基类对象 程序设计 cs.sjtu 2011.9程序设计 - 50v将派生类对象赋给基类对象将派生类对象赋给基类对象v基类指针指向派生类对象基类指针指向派生类对象v基类的对象引用派生类的对象基类的对象引用派生类的对象程序设计 cs.sjtu 2011.9程序设计 - 51v派生类中的基类部分赋给此基类对象,派生派生类中的基类部分赋给此基类对象,派生类新增加的

41、成员就舍弃了。赋值后,基类对类新增加的成员就舍弃了。赋值后,基类对象和派生类对象再无任何关系。象和派生类对象再无任何关系。 class base public: int a; ;class d1:public base public: int b; ; d1 d;d.a = 1; d.b = 2;base bb = d;cout bb.a; /输出输出1bb.a = 3;cout d.a; /输出输出1程序设计 cs.sjtu 2011.9程序设计 - 52v尽管该指针指向的对象是一个派生类对象,但由尽管该指针指向的对象是一个派生类对象,但由于它本身是一个基类的指针,它只能解释基类的于它本身是

42、一个基类的指针,它只能解释基类的成员,而不能解释派生类新增的成员。因此,只成员,而不能解释派生类新增的成员。因此,只能访问派生类中的基类部分。能访问派生类中的基类部分。 v通过指针修改基类对象时,派生类对象也被修改通过指针修改基类对象时,派生类对象也被修改。d1 d;d.a = 1; d.b = 2;base *bp = &d;cout a; /输出输出1Bp-a = 3;cout d.a; /输出输出3程序设计 cs.sjtu 2011.9程序设计 - 53v给派生类中的基类部分取个别名。给派生类中的基类部分取个别名。v基类对象改变时,派生类对象也被修改。基类对象改变时,派生类对象也被修改。

43、d1 d;d.a = 1; d.b = 2;base &bb = d;cout bb.a; /输出输出1bb.a = 3;cout d.a; /输出输出3程序设计 cs.sjtu 2011.9程序设计 - 54class Shape public: void printShapeName() cout“Shape”endl; ;class Point : public Shape public: void printShapeName() cout“Point”endl;class Circle : public Point public: void printShapeName() cout

44、“Circle”endl;class Cylinder : public Circle public: void printShapeName() cout“Cylinder”endl;实例程序设计 cs.sjtu 2011.9程序设计 - 55int i;Point aPoint;Circle aCircle;Cylinder aCylinder;Shape shapes3= aPoint, aCircle, aCylinder;for (i=0;i3;i+) shapesi.printShapeName(); ShapeShapeShape程序设计 cs.sjtu 2011.9程序设计 -

45、 56int i;Point aPoint;Circle aCircle;Cylinder aCylinder;Shape *pShape3= &aPoint, &aCircle, &aCylinder ;for (i=0;iprintShapeName(); ShapeShapeShape程序设计 cs.sjtu 2011.9程序设计 - 57int i;Point aPoint;Circle aCircle;Cylinder aCylinder;Shape &shape1= aPoint;shape1.printShapeName(); shape程序设计 cs.sjtu 2011.9程序

46、设计 - 58v不能将基类对象赋给派生类对象,除非在基不能将基类对象赋给派生类对象,除非在基类中定义了向派生类的类型转换函数类中定义了向派生类的类型转换函数v不能将基类对象地址赋给指向派生类对象的不能将基类对象地址赋给指向派生类对象的指针指针v也不能将指向基类对象的指针赋给指向派生也不能将指向基类对象的指针赋给指向派生类对象的指针。如果程序员能确保这个基类类对象的指针。如果程序员能确保这个基类指针指向的是一个派生类的对象,则可以用指针指向的是一个派生类的对象,则可以用reinterpret_cast类型的强制类型转换。表示程类型的强制类型转换。表示程序员知道这个风险序员知道这个风险程序设计 c

47、s.sjtu 2011.9程序设计 - 59v组合组合 v继承继承 v虚函数与多态性虚函数与多态性v纯虚函数与抽象类纯虚函数与抽象类 v多继承多继承 v面向对象设计范例面向对象设计范例程序设计 cs.sjtu 2011.9程序设计 - 60v多态性多态性v虚函数虚函数v虚析构函数虚析构函数程序设计 cs.sjtu 2011.9程序设计 - 61v多态性:不同对象收到相同的消息时产多态性:不同对象收到相同的消息时产生不同的动作。生不同的动作。v多态性的作用:便于系统功能的扩展多态性的作用:便于系统功能的扩展程序设计 cs.sjtu 2011.9程序设计 - 62v静态联编:编译时已决定用哪一个函

48、数静态联编:编译时已决定用哪一个函数实现某一动作。实现某一动作。v动态联编:直到运行时才决定用哪一个动态联编:直到运行时才决定用哪一个函数来实现动作函数来实现动作程序设计 cs.sjtu 2011.9程序设计 - 63v函数重载:用同一名字实现访问一组相函数重载:用同一名字实现访问一组相关的函数关的函数v运算符重载运算符重载v重载函数是通过重载函数是通过“名字压延名字压延”方法来实方法来实现。即在编译时将函数名和参数结合起现。即在编译时将函数名和参数结合起来创造一个新的函数名,用新的名字替来创造一个新的函数名,用新的名字替换原有名字。换原有名字。程序设计 cs.sjtu 2011.9程序设计

49、- 64v运行时多态性是指必须等到运行时多态性是指必须等到程序动态运行程序动态运行时才可确定的多态性,时才可确定的多态性,主要通过主要通过继承继承结合结合动态绑定动态绑定获得。这与类的继承密切相关。获得。这与类的继承密切相关。因为存在类型的兼容性,所以有些函数只因为存在类型的兼容性,所以有些函数只有在运行时才能确定是调用父类的还是子有在运行时才能确定是调用父类的还是子类的函数。在类的函数。在C+C+中,使用中,使用虚函数虚函数(Virtual FunctionsVirtual Functions)来实现。)来实现。程序设计 cs.sjtu 2011.9程序设计 - 65v多态性多态性v虚函数虚

50、函数v虚析构函数虚析构函数程序设计 cs.sjtu 2011.9程序设计 - 66v虚函数提供动态重载方式,允许函数调用与函数虚函数提供动态重载方式,允许函数调用与函数体之间的联系在运行时才建立。体之间的联系在运行时才建立。v虚函数的定义:在基类中用关键词虚函数的定义:在基类中用关键词virtual说明,说明,并在派生类中重新定义的函数称为虚函数。在派并在派生类中重新定义的函数称为虚函数。在派生类中重新定义时,其函数原型,包括返回类型生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数与参数类型的顺序都必须与、函数名、参数个数与参数类型的顺序都必须与基类中的原型完全相同。基类中的原型完

51、全相同。v当把一个函数定义为虚函数时,等于告诉编译器当把一个函数定义为虚函数时,等于告诉编译器,这个成员函数在派生类中可能有不同的实现。,这个成员函数在派生类中可能有不同的实现。必须在执行时根据传递的参数来决定调用哪一个必须在执行时根据传递的参数来决定调用哪一个函数函数程序设计 cs.sjtu 2011.9程序设计 - 67v虚函数是与基类指针指向派生类对象,或基类虚函数是与基类指针指向派生类对象,或基类对象引用派生类对象结合起来实现多态性。对象引用派生类对象结合起来实现多态性。v当基类指针指向派生类对象或基类对象引用派当基类指针指向派生类对象或基类对象引用派生类对象时,对基类指针或对象调用基

52、类的虚生类对象时,对基类指针或对象调用基类的虚函数,系统会到相应的派生类中寻找此虚函数函数,系统会到相应的派生类中寻找此虚函数的重定义。如找到,则执行派生类中的函数。的重定义。如找到,则执行派生类中的函数。如没有找到,则执行基类的虚函数。如没有找到,则执行基类的虚函数。程序设计 cs.sjtu 2011.9程序设计 - 68class Shape public:virtual void printShapeName() cout“Shape”endl; ;class Point:public Shape public:virtual void printShapeName() cout“Poi

53、nt”endl;class Circle:public Point public: virtual void printShapeName() cout“Circle”endl;class Cylinder:public Circle public: virtual void printShapeName() cout“Cylinder”endl;程序设计 cs.sjtu 2011.9程序设计 - 69int i;Point aPoint;Circle aCircle;Cylinder aCylinder;Shape shapes3= aPoint, aCircle, aCylinder;fo

54、r (i=0;i3;i+) shapesi.printShapeName(); ShapeShapeShape程序设计 cs.sjtu 2011.9程序设计 - 70int i;Point aPoint;Circle aCircle;Cylinder aCylinder;Shape *pShape3= &aPoint, &aCircle, &aCylinder ;for (i=0;iprintShapeName(); PointCircleCylinder程序设计 cs.sjtu 2011.9程序设计 - 71int i;Point aPoint;Circle aCircle;Cylinder

55、 aCylinder;/Shape *pShape3= &aPoint, &aCircle, &aCylinder;Shape &shape1= aPoint;/for (i=0;iprintShapeName(); shape1.printShapeName(); Point程序设计 cs.sjtu 2011.9程序设计 - 72v在派生类中重新定义虚函数时,它的原型必在派生类中重新定义虚函数时,它的原型必须与基类中的虚函数完全相同。否则编译器须与基类中的虚函数完全相同。否则编译器会把它认为是重载函数,而不是虚函数的重会把它认为是重载函数,而不是虚函数的重定义。定义。v派生类在对基类的虚函数

56、重定义时,关键字派生类在对基类的虚函数重定义时,关键字virtual可以写也可以不写。不管可以写也可以不写。不管virtual写或者写或者不写,该函数都被认为是虚函数。但最好是不写,该函数都被认为是虚函数。但最好是在重定义时写上在重定义时写上virtual。程序设计 cs.sjtu 2011.9程序设计 - 73v正方形是一类特殊的矩形,因此,可以正方形是一类特殊的矩形,因此,可以从从rectangle类派生一个类派生一个square类。在这类。在这两个类中,都有一个显示形状的函数。两个类中,都有一个显示形状的函数。程序设计 cs.sjtu 2011.9程序设计 - 74class recta

57、ngle int w, h;public: rectangle(int ww, int hh): w(ww), h(hh) virtual void display() cout “this is a rectanglen”;class square:public rectangle public: square(int ss): rectangle(ss, ss) void display() /虚函数虚函数 cout “this is a squaren”;程序设计 cs.sjtu 2011.9程序设计 - 75v多态性多态性v虚函数虚函数v虚析构函数虚析构函数程序设计 cs.sjtu 2

58、011.9程序设计 - 76v构造函数不能是虚函数,但析构函数可以是构造函数不能是虚函数,但析构函数可以是虚函数,而且最好是虚函数虚函数,而且最好是虚函数 v如果派生类新增加的数据成员中含有指针,如果派生类新增加的数据成员中含有指针,指向动态申请的内存,那么派生类必须定义指向动态申请的内存,那么派生类必须定义析构函数释放这部分空间。但如果派生类的析构函数释放这部分空间。但如果派生类的对象是通过基类的指针操作的,则对象是通过基类的指针操作的,则delete基基类指针指向的对象就会造成内存泄漏。类指针指向的对象就会造成内存泄漏。程序设计 cs.sjtu 2011.9程序设计 - 77v将基类的析构

59、函数定义为虚函数。将基类的析构函数定义为虚函数。v当析构基类指向的派生类的对象时,找当析构基类指向的派生类的对象时,找到基类的析构函数。由于基类的析构函到基类的析构函数。由于基类的析构函数是虚函数,又会找到派生类的析构函数是虚函数,又会找到派生类的析构函数,执行派生类的析构函数。数,执行派生类的析构函数。程序设计 cs.sjtu 2011.9程序设计 - 78v和其他的虚函数一样,析构函数的虚函和其他的虚函数一样,析构函数的虚函数的性质将被继承。数的性质将被继承。v如果继承层次树中的根类的析构函数是如果继承层次树中的根类的析构函数是虚函数的话,所有派生类的析构函数都虚函数的话,所有派生类的析构

60、函数都将是虚函数。将是虚函数。程序设计 cs.sjtu 2011.9程序设计 - 79v组合组合 v继承继承 v虚函数与多态性虚函数与多态性v纯虚函数与抽象类纯虚函数与抽象类 v多继承多继承 v面向对象设计范例面向对象设计范例程序设计 cs.sjtu 2011.9程序设计 - 80v纯虚函数:是一个在基类中说明的虚函纯虚函数:是一个在基类中说明的虚函数,它在该基类中没有定义,但要在它数,它在该基类中没有定义,但要在它的派生类里定义自己的版本,或重新说的派生类里定义自己的版本,或重新说明为纯虚函数明为纯虚函数v纯虚函数的一般形式纯虚函数的一般形式 virtual 类型类型 函数名(参数表)函数名

温馨提示

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

评论

0/150

提交评论