第三讲 C++面向对象程序设计_第1页
第三讲 C++面向对象程序设计_第2页
第三讲 C++面向对象程序设计_第3页
第三讲 C++面向对象程序设计_第4页
第三讲 C++面向对象程序设计_第5页
已阅读5页,还剩130页未读 继续免费阅读

下载本文档

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

文档简介

1、3.1 类的诞生 3.2 类的声明和对象的定义 3.3 类的成员及特征 3.4 继承与派生类 3.5 多态性与虚函数 3.6 运算符重载 3.7 输入/输出流库,第3讲 c+面向对象程序设计,visual c+ 程序设计,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.1 类的诞生,从面向过程到面向对象,上世纪六十年代中后期软件危机发生之后,面向过程(procedure-oriented)的结构化程序设计(structured programming,sp)成为主流。,在结构化程序设计中,采用的是“自顶向下,逐步细化”的思想。它的具体操作方法是模块化,是按功能来分的,所以也称功

2、能块。,当程序规模大到一定程度了,一点点小的变化会引起整个程序的改动,这样面向过程中的困难就呈现出来了。,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.1 类的诞生,从面向过程到面向对象,面向对象的程序设计思路,相关概念:,1)对象 属性与行为 2)封装 3)信息隐蔽:信息隐蔽指在设计和确定模块时,使得一个模块内包含信息(过程或数据),对于不需要这些信息的其他模块来说,是不能访问的.4)抽象与类,对象,类,计算机世界,实体,抽象类别,现实世界 客观世界,抽象,抽象,实例化,映射,主观世界,对象、实体与类,现实世界中的实体可以抽象出类别的概念。对应于计算机世界就有一个类(cla

3、ss)的概念,因为类是一个抽象的概念的对应体,所以计算机不给它分配内存,只给对象分配内存。左图表达了计算机世界与现实世界之间的对应关系。,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.1 类的诞生,visual c+ 程序设计,第3讲 c+面向对象程序设计,类的诞生,3.1 类的诞生,类(class)是面向对象思想中的一个重要组成部分。如何在计算机中将“类”表达出来?,从结构体到类,1)定义一个结构体,struct sample int member1, member2; var1;,以后,就可以使用结构中的成员:int var = var1.member1*var1.mem

4、ber2;,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.1 类的诞生,2)将结构体成员的使用代码写成一个函数, 得到:,从结构体到类,int fun1(struct sample var) return var.member1*var.member2; ,操作结构体变量,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.1 类的诞生,3)将上面的函数放入结构体中:,从结构体到类,struct sample int fun1() return var.member1*var.member2; int member1, member2; ;,函数成员,数据成员,v

5、isual c+ 程序设计,第3讲 c+面向对象程序设计,3.1 类的诞生,这样的结构体就具有了一定的属性(member1和member2),也具有一定的行为(函数fun1) 。它就是“类”的雏形。,struct sample var; var.member1 = var.member2 = 10; int temp = var.calcu();,该结构体的使用方法如下:,visual c+ 程序设计,第3讲 c+面向对象程序设计,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,类的定义,类一般分为声明部分和实现部分。其一般格式如下:,visual c+ 程

6、序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,说明:,(1)声明部分用来声明数据成员和成员函数,实现部分是用来对成员函数的定义; (2)最后的分号不可少,这是一条说明语句; (3)关键字class是数据类型说明符,指出下面说明的是类。关键字private 、public和protected是一种访问限定符。 (4)数据成员的类型可以是任意的,包含整型、浮点型、字符型、数组、指针等。不允许对所定义的数据成员进行初始化。,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,访问限定符,public private protected,注意: (1)

7、后两种说明的成员是不能从外部进行访问的; (2) 每种说明符可在类体中使用多次; (3) 它们的作用域是从该说明符出现开始到下一个说 明符之前或类体结束之前结束; (4) 如果在类体起始点无访问说明符,系统默认定义 为私有(private); (5)访问说明符private(私有的)和protected(保 护的)体现了类具有封装性(encapsulation).,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,成员函数的定义,函数定义通常在类的说明之后进行,其格式如下:,返回值类型 类名:函数名(参数表) /函数体,其中运算符“:”称为作用域运算符,它指出

8、该函数是属于哪一个类的成员函数。当然也可以在类的定义中直接定义函数。,说明:将类单独存放在一个文件中或将类的声明放在.h文件中而将成员函数的实现放在与.h文件同名的.cpp文件中。,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,成员函数的特征,1) 内联性 定义在类体内的成员函数为内联函数, 定义在类体外的成员函数为外联函数。 2) 重载性 成员函数可以重载。 3) 设置参数默认值 成员函数可以设置参数的默认值。,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,练习,构建一个time类,私有型数据成员(int) hour

9、, minute, second, 两个公共型成员函数display1, display2分别以两种不同的格式(“ # : # : # ”, “ # 时# 分#秒 ”)显示时间。,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.2 类和对象的定义,对象的定义,(1) 一般对象的定义格式 类名对象名表; (2) 指向对象的指针定义格式 类名*指针名; (3) 对象引用的定义格式 类名 . 构造函数cmeter(int npos=10)中,npos被设置了10,构造函数中相应实参没有被指定时,使用此缺省值。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.1 构造函数

10、与析构函数,析构函数,当一个对象定义时,c+自动调用构造函数建立该对象并进行初始化,那么当一个对象的生命周期结束时,c+也会自动调用一个函数注销该对象并进行善后工作,这个特殊的成员函数即析构函数(destructor)。 析构函数是另一种特殊的c+成员函数,它只是在类名称前面加上一个“”符号。,例如:class cmeter public: . cmeter( ) / 析构函数 . ,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.1 构造函数与析构函数,析构函数的特点,1)构函数名与类名相同,但在前面加上字符,如 cmeter()。 2)析构函数无函数返回类型,不带任何参数。

11、3) 一个类有且只有一个析构函数,可以缺省。 4) 对象注销时,系统自动调用析构函数。 5) new为对象分配动态内存,用delete释放对象时,析构函数被自动调用。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.1 构造函数与析构函数,默认构造函数和析构函数,类定义时,如果没有定义任何构造函数,编译器自动生成一个不带参数的默认构造函数,格式如下: :() ,如果一个类中没有定义析构函数,编译系统生成一个默认析构函数,格式: :() 默认析构函数名与该类的类名同名。是一个空函数。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.1 构造函数与析构函数,构造函数重载

12、,例 3.3-1 带默认参数的构造函数。 #include class cdate public: cdate(int year = 2002, int month = 7, int day = 30) nyear = year; nmonth = month; nday = day; coutnyear-nmonth-ndayendl; private: int nyear, nmonth, nday; ;,第3讲 c+面向对象程序设计,3.3 类的成员及特征,void main() cdate day1; cdate day2(2002, 8); ,2002-7-30 2002-8-30,

13、运行结果为:,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.1 构造函数与析构函数,复制构造函数,例 3.3-2 复制构造函数的使用。 #include class cdate public: cdate(int year = 2002, int month = 7, int day = 30) cout调用构造函数endl; nyear = year; nmonth = month; nday = day; coutnyear-nmonth-ndayendl; ,第3讲 c+面向对象程序设计,3.3 类的成员及特征,cdate(const cdate ,运行结果?,第3讲 c

14、+面向对象程序设计,3.3 类的成员及特征,3.3.2 对象成员的初始化,在实际应用中往往需要多个类,这时就可能把一个已定义类的对象作为另一个类的成员。 为了能对这些对象成员进行初始化,构造函数定义格式: :(形参表):对象1(参数表), 对象2(参数表), , 对象n(参数表) ,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.2 对象成员的初始化,说明:,(1) 对象成员必须初始化,但不能将对象成员直接在构造函数体内进行初始化。 (2) 对象成员初始化时,必须有相应的构造函数,且多个对象成员的构造次序不是按初始化成员列表的顺序,而是按各类声明的先后次序进行的。 (3) 对象成

15、员初始化也可在类的外部进行,但必须与构造函数在一起。 (4) 事实上,成员初始化列表也可用于类中的普通数据成员的初始化。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.3 静态成员,静态数据成员,定义静态数据成员: (1)使用关键词static声明静态数据成员。 (2) 对静态数据成员进行初始化。 静态数据成员要分配空间,不能在类声明中进行初始化。静态数据成员初始化在类的外部进行,它的格式如下: :=,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.3 静态成员,静态数据成员的特点:,静态数据成员是同一个类中所有对象共享的成员,不是某一对象的成员。 2) 用静态数

16、据成员可以节省内存,是所有对象所公有的,对多个对象来说,静态数据成员只存储一处,供所有对象共用。p93 3) 静态数据成员的值对每个对象都是一样,它的值是可以更新的。 4) 静态数据成员是静态存储的,具有静态生存期。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.3 静态成员,静态成员函数(p94 改错),1) 静态成员函数属于类的静态成员,不是对象成员。对静态成员的引用不需要用对象名。 2) 在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。如果静态成员函数中要引用非静态成员时,可通过对象来引用。 3) 公有的静态成员函数既可以有通过相应的对

17、象访问,也可以通过其所属的类名来引用。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.4 友 元,友元函数,1)将普通函数声明为友元函数,类的重要特性就是使数据封装和隐藏,但同时也给外部函数访问类中的私有和保护型数据成员带来不方便。为了解决这个问题,c+使用了一个特殊的处理方式友元。,2)友元成员函数,3)一个函数可以被多个类声明为友元,这样 就可以引用多个类的私有数据。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.4 友 元,例 3.3-3 友元函数的使用。 #include class cpoint public: cpoint() m_x = m_y =

18、 0; cpoint( unsigned x, unsigned y ) m_x = x; m_y = y; void print() cout point( m_x , m_y ) endl; friend cpoint inflate(cpoint ,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.4 友 元,cpoint inflate ( cpoint ,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.4 友 元,友元类,声明友元类的一般形式:,friend 类名;,说明:,(1)友元类的关系是单向的而不是双向的。声明了b类是a类的友元类,不等于a类是b类的

19、友元类,a类中的成员函数不能访问b类中的私有成员; (2)友元的关系不能传递。如果b类是a类的友元类,c类是b类的友元类,不等于c类是a类的友元类。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.5 常类型,常类型指的是使用关键字const声明的类型。由于常类型的变量或对象的值是不能被改变的,因此,定义或声明常类型时必须进行初始化。,常对象是指对象常量。定义格式: const 或 const 定义常对象要进行初始化,该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。,常对象,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.5 常类型,常指针

20、和常引用(p98),常指针也是使用关键字const来修饰的。有三种形式。 第一种形式是将const放在指针变量的类型之前,表示声明一个指向常量的指针。此时,在程序中不能通过指针来改变它所指向的数据值,但可以改变指针本身的值。 第二种形式是将const放在指针定义语句的指针名前,表示指针本身是一个常量,称为指针常量或常指针。因此,不能改变这种指针变量的值,但可以改变指变量所指向的数据值。 第三种形式是将const在上述两个地方都加,表示声明一个指向常量的指针常量,指针本身的值不可改变,而且它所指向的数据的值也不能通过指针改变。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.5 常

21、类型,例 3.3-4 常参数的函数传递。 #include class cone public: void print (const int *p, int n)/ 使用常参数 cout*p; for (int i = 1; in; i+) cout, *(p+i); coutendl; ; void main() int array6 = 1, 2, 3, 4, 5, 6; cone one; one.print(array, 6); ,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.5 常类型,常成员函数,使用const关键字进行声明的成员函数为常成员函数, 只有常成员函数才

22、有资格操作常量或常对象。 常成员函数说明格式如下: ()const,常成员函数可以理解成是“只读”函数,既不能更改数据成员的值,也不能调用那些引起数据成员值变化的成员函数,只能调用const成员函数。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.5 常类型,常数据成员,类型修饰符const不仅可以说明成员函数,也可以说明数据成员。类中声明const数据成员时,只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。,例见书100页,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.6 this指针,在每一个成员函数(除静态成员函数)中都包含一个特殊的指针,这个

23、指针的名字时固定的,称为this。 对一个对象调用成员函数时,编译器将对象的地址赋给this指针,再调用成员函数,每次成员函数存取数据成员时,由隐含作用this指针。 可以用*this来标识调用该成员函数的对象。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.7 类的作用域和对象的生存期,类作用域,类的作用域简称为类域,指在类的定义中由一对花括号所括起来的部分。 类域介于文件域和函数域之间。 文件作用域中可以包含类作用域,类作用域小于文件作用域。一般地,类作用域中可包含成员函数的作用域。,嵌套类和局部类,(1)嵌套类是指在一个类中再定义一个类。定义嵌套类的类称外围类。嵌套类只能

24、在外围类内使用,在外围类外使用时应加类名限定。 (2) 局部类是指在一个函数体内定义的类。,第3讲 c+面向对象程序设计,3.3 类的成员及特征,3.3.7 类的作用域和对象的生存期,按生存期可将对象分为如下3类。 (1) 局部对象 作用域在函数体内或程序块内。 (2) 静态对象 作用域在定义它的文件内。 (3) 全局对象 作用域是整个的程序。,对象的生存期,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.4.1 继承与派生的概述 3.4.2 派生类成员的访问属性 3.4.3 派生类的构造函数和析构函数 3.4.4 多继承 3.4.5 虚基类 3.4.6 继承与组合 3.4.7

25、 在软件开发中的重要意义,3.4 继承与派生类,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,继承与派生的概念,派生类的声明方式,派生类的构成,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,继承与派生的概念,类的关系,类的相互关系而言可以概括为: 包容关系(嵌套类)和继承关系。,继 承,包 容,第3讲 c+面向对象程序设计,3.4 继承与派生类,2、基类和派生类,在设计新类时,允许重用某个原有类的所有特征,并在此基础上添加新类的新特征。被重用的原有类称为基类,而新创建的类称为派生类。,3、单继承和多继承,在c+中, 一个子

26、类可由一个父类派生, 也可从多个父类派生, 前者叫单一继承, 后者叫多重继承。,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,派生类的声明方式,声明派生类的一般形式如下:,class 派生类名:继承方式 基类名 派生类新增加的成员 ;,继承方式包括: public、private和protected。,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.1 继承与派生的概述,派生类的构成,派生类包括两部分:一部分从基类继承的;一部分是在声明派生类时增加的。,每以部分分别包括数据成员和成员函数。,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.

27、4.2 派生类成员的访问属性,访问控制: 用于数据的保护和数据封装,c+中,两种类的访问方式:,1) 水平访问 实例化使用, 类中声明的访问控制约束访问权限。 2)垂直访问 继承使用, 子类中的成员函数对父类成员的访问。,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,在讨论访问属性时,需要考虑以下几种情况:,(1)基类的成员函数访问基类成员?,(2)派生类的成员函数访问派生类的自己 增加的成员?,(3)基类的成员函数访问派生类的成员?,(4)派生类的成员函数访问基类的成员?,(5)在派生类外访问派生类的成员?,(6)在派生类外访问基类的成员?,第3讲 c

28、+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,说明:,基类的成员函数只可以访问基类成员, 不能访问派生类的成员; 派生类的成员函数访问派生类的成员; 在派生类外可以访问派生类公有成员,但不能访问派生类私有成员; 私有数据成员只能被同一类的成员函数访问,公有成员可以被外界访问,保护性成员是有选择性的被访问。,第3讲 c+面向对象程序设计,3.4 继承与派生类,继承的3种方式,公有继承方式(public) (2) 私有继承方式(private) (3) 保护继承方式(protected),3.4.2 派生类成员的访问属性,第3讲 c+面向对象程序设计,3.4 继承与派

29、生类,公有继承方式(public),公有继承的特点是基类的公有成员和保护成员作为派生类 的成员时,它们都保持原有的状态,而基类的私有成员仍 然是私有的。例如:,class cstick : public cmeter int m_nsticknum;/ 声明一个私有数据成员 public: void dispstick(); / 声明一个公有成员函数 ;/ 注意分号不能省略 void cstick: dispstick() m_nsticknum = getpos();/ 调用基类cmeter的成员函数 coutm_nsticknum ; ,3.4.2 派生类成员的访问属性,第3讲 c+面向对

30、象程序设计,3.4 继承与派生类,注意: 派生类中或派生类的对象可以使用基类的公有成员(包括保护成员),例如cstick的成员函数dispstick中调用了基类cmeter的getpos函数,但基类或基类的对象却不可以使用派生类的成员。,3.4.2 派生类成员的访问属性,表1 公有基类在派生类中的访问属性,第3讲 c+面向对象程序设计,3.4 继承与派生类,(2) 私有继承方式(private),私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。,3.4.2 派生类成员的访问属性,表2 私有基类在派生类中的访问属性,第3讲 c+面向对象程序设计,

31、3.4 继承与派生类,#include class cmeter public: cmeter(int npos = 10) m_npos = npos; cmeter() void stepit() m_npos+; int getpos()return m_npos; protected: void setpos(int npos) m_npos = npos; private: int m_npos; ; class cstick : private cmeter / 从cmeter派生,私有继承 int m_nsticknum;/ 声明一个私有数据成员 public: void dis

32、pstick();/ 声明一个公有成员函数 void setstick(int npos) setpos(npos); int getstick() return getpos(); ;,例3.4-1 派生类的私有继承示例。,第3讲 c+面向对象程序设计,3.4 继承与派生类,void cstick: dispstick() m_nsticknum = getpos(); / 调用基类cmeter的成员函数 coutm_nsticknum ; void main() cmeter ometer(20); cstick ostick; coutcmeter:ometer.getpos(),cst

33、ick: ostick.getstick()endl; ometer.stepit(); coutcmeter:ometer.getpos(),cstick: ostick.getstick()endl; ostick.dispstick(); ,第3讲 c+面向对象程序设计,3.4 继承与派生类,(3) 保护继承方式(protected),特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。,3.4.2 派生类成员的访问属性,表3 保护基类在派生类中的访问属性,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4

34、.2 派生类成员的访问属性,表4 不同继承方式的基类特性和派生类特性,小结1:,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.2 派生类成员的访问属性,表5 派生类中的成员的访问属性,小结2:,注意: 一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。例如, (1) 在公有继承时,派生类的对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有成员和保护成员。 (2) 在私有继承和保护继承时,基类的所有成员不能被派生类的对象访问,而派生类的成员函数可以访问基类中的公有成员和保护成员。,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.3 派生

35、类的构造函数与析构函数,1、简单派生类的构造函数,派生类的构造函数和析构函数被执行时,基类相应的构造函数和析构函数也会被执行。 派生类对象在建立时,先执行基类的构造函数,然后执行派生类的构造函数。但对于析构函数来说,其顺序刚好相反,先执行派生类的析构函数,而后执行基类的析构函数。 更需要注意不同派生类构造函数的格式。,2、有子对象的派生类的构造函数,3、有多层派生时的构造函数,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.3 派生类的构造函数与析构函数,1、简单派生类的构造函数,其一般形式为:,派生类构造函数名(总参数列表): 基类构造函数名(参数列表) 派生类中新增数据成员初始

36、化语句;,class student public: student (int n, char *nam, char s) num=n; name=nam; sex=s; ; class student1:public student public: student1(int n, char *nam, char s, int a, char *addr):student(n,nam,s) age=a; address=addr; ;,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.3 派生类的构造函数与析构函数,2、有子对象的派生类的构造函数,其一般形式为:,派生类构造函数名(总

37、参数列表): 基类构造函数名(参数列表), 子对象名(参数列表) 派生类中新增数据成员初始化语句; ,类的数据成员包含类对象,此数据成员叫做该类的子对象。,class student public: student (int n, char *nam, char s) num=n; name=nam; sex=s; ; class student1:public student public: student1( int n, char *nam, int n1, char s, char *nam1, char s1, int a, char *addr) :student(n,nam,s)

38、, monitor(n1,nam1,s1) age=a; address=addr; private: student monitor; ;,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.3 派生类的构造函数与析构函数,3、有多层派生时的构造函数,格式与“有子对象派生时的构造函数”同,但要注意,不要列出每一层派生的构造函数,只需写出上一层派生类的构造函数即可。,例3.4-2 多层派生的构造函数。 注意:构造函数的书写格式。,#include class student public: student(int n,char *nam) num=n; name=nam; void d

39、isplay() coutnum:numendl; coutname:nameendl; protected: int num; char *name; ; class student1:public student public: student1(int n,char nam10,int a): student(n,nam) age=a; ,void show() display(); coutage:ageendl; protected: int age; ; class student2:public student1 public: student2(int n,char nam10

40、, int a,int s):student1(n,nam,a) score=s; void show_all() show(); coutscore:scoreendl; protected: int score; ; int main() student2 stud(10010,li,20,92); stud.show_all(); return 0; ,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.4 多继承,在类的继承中, c+允许一个派生类继承多个基类,这种行为称为多继承(multiple inheritance)。 这种多继承的方式可使派生类具有多个基类的特性,大大提

41、高了程序代码的可重用性。 多继承下派生类的定义的格式: class : , ,. ;,其中的继承方式还是前面的三种:public、private和protected。,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.4 多继承,class a . class b . class c:public a,private b . 派生类c的成员包含了基类a中成员和b中成员以及该类本身的成员。 允许一个基类有多个派生类以及从一个基类的派生类中再进行多个层次的派生。,例如:,多继承派生类的构造函数,(总参表) : (参数表1), (参数表2), , (参数表n) 派生类中新增数据成员初始化语

42、句; ,格式:,例3.4-3 声明一个教师(teacher)类和一个学生类(student)类,用多重继承的方式声明一个研究生(graduate)类,研究生类包括了教师类和学生类的所有成员以及新增了wage(工资)成员。 教师类中包括数据成员name(姓名),age(年龄),title(职称), 学生类中包括数据成员name1(姓名),sex(性别),score(成绩)。在定义派生类对象时给出初始化的数据,并输出这些数据。,#include class teacher public: teacher(char *nam,int a, char *t) name=nam; age=a; titl

43、e=t; protected: char *name; int age; char *title; ; class student public: student(char *nam1,char se,float sc) name1=nam1; sex=se; score=sc; protected: char *name1; char sex; float score; ;,class graduate: public teacher,public student public: graduate(char *nam,int a, char *t, char se,float sc,floa

44、t w): teacher(nam, a, t),student( nam, se, sc), wage(w) void show() coutname: nameendl; coutage: ageendl; couttitle: titleendl; coutsex: sexendl; coutscore: scoreendl; coutwage: wageendl; private: float wage; ; int main() graduate grad(yang_li,28, 教授, m,92.5,5500); grad.show(); return 0; ,多继承引起的二义性问

45、题,1、两个基类有同名成员,a类,int num1;,void display();,b类,int num1;,void display();,c类,int num1;,void display();,int num1;,void display();,int num2;,void show();,基类a 的成员,基类b 的成员,派生类c 的新增成员,多继承引起的二义性问题,2、两个基类和派生类三者都有同名成员,a类,int num1;,void display();,b类,int num1;,void display();,c类,int num1;,void display();,int n

46、um1;,void display();,int num1;,void show();,基类a 的成员,基类b 的成员,派生类c 的新增成员,int num2;,多继承引起的二义性问题,3、多个基类从同一个基类派生,class a public: int a; void fun(); ; class b1:public a public: int b1; ; class b2:public a public: int b2; ; class c:public b1,public b2 public: int f( ); ; ,a,b1,b2和c类之间关系如下:,a a a,fun() a,fu

47、n() b1 b2 b1 b2 c f( ),当c c1;时, 则c1.a和c1.aa都有二义性。,a类,int a;,void fun();,b1类,int b1;,b2类,int b2;,c类,int b1:a;,int a;,void fun();,int a;,void fun();,int b2:a;,int b1;,int b2;,void b1:fun();,int b1:a;,int b2:a;,int b1;,void b2:fun();,int f ();,virtual,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.5 虚基类,虚基类的作用,虚基类的初始化,

48、虚基类的简单应用,虚基类的声明,第3讲 c+面向对象程序设计,3.4 继承与派生类,虚基类的作用,派生类b1和b2都从基类a继承,这时在派生类中就有两个基类a的拷贝。当编译器编译到“cout”a = “aendl;”语句时,因无法确定成员a是从类b1中继承来的,还是从类b2继承来,产生了二义性,从而出现编译错误。 解决这个问题的方法之一是使用域作用运算符“:”来消除二义性。 方法之二使用虚基类,其目的是在多重派生的过程中,使公有的基类在派生类中只有一个拷贝,从而解决上述这种二义性问题。,第3讲 c+面向对象程序设计,3.4 继承与派生类,虚基类的声明,虚基类的声明不是在声明基类时声明的,而是在

49、声明派生类时,指定继承方式时声明的。 声明虚基类的一般形式为:,calss 派生类名 : virtual 继承方式 基类名,class a ; class b: virtual public a ; class c: virtual public a ;,例如:,虚基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。,第3讲 c+面向对象程序设计,3.4 继承与派生类,虚基类的初始化,c+规定,由虚基类经过一次或多次派生出来的派生类,在其每一个派生类的构造函数的成员初始化列表中必须给出对虚基类的构造函数的调用,如果没有列出,则调用虚基类的默认构造函数。例如:3.4-4 出

50、现多次调用虚基类的构造函数时,c+编译系统只执行最后的派生类对虚基类的构造函数的调用。例如:3.4-5,第3讲 c+面向对象程序设计,3.4 继承与派生类,虚基类的简单应用,例3.4-4 在例3.4-3基础上,在teacher类和student类之上增加了一个共同的基类person。如下图。作为人员的一些基本数据都放在peoson类中,在teacher类和student类中再增加一些必要的数据。,#include class person public: person( char *nam, char s ,int a) name=nam; sex=s;age=a; protected: ch

51、ar *name; char sex; int age; ; class teacher: virtual public person public: teacher(char *nam,char s,int a, char *t): person(nam,s,a), title(t) protected: char *title; ; class student : virtual public person public: student(char *nam1,char se,int a,float sc) :person(nam1,se,a) score=sc; protected: f

52、loat score; ;,class graduate: public teacher,public student public: graduate(char *nam,char s,int a, char *t,float sc,float w): person(nam,s,a),teacher(nam, s, a, t),student( nam, s,a, sc) wage=w; void show() coutname: nameendl; coutage: ageendl; couttitle: titleendl; coutsex: sexendl; coutscore: sc

53、oreendl; coutwage: wageendl; private: float wage; ; int main() graduate grad(yang_li, m, 28, 教授,92.5,5500); grad.show(); return 0; ,例3.4-5 虚基类的使用。 #include class a public: int a; a(int x = 0) a = x; ; class b1 : virtual public a public: int b1; b1( int x = 0, int y = 0):a(x)b1 = y; void print() cout

54、b1:a= a,b1=b1endl; ; class b2 : virtual public a public: int b2; b2( int x = 0, int y = 0):a(x)b2 = y; void print() coutb2:a= a,b2=b2endl; ;,class c : public b1, public b2 public: int c; c(int x, int y, int m, int n,int s): b1(x,y), b2(m,n) c = s; void print() b1:print(); b2:print(); coutc = cendl;

55、; void main() c c1(100,200,300,400,500); c1.print(); c1.a=1000; c1.print(); ,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.6 继承与组合,在一个类中,以另一个类的对象作为数据成员的,称为类的组合。,例如:,class person public: char *name; int age; char sex; ; class birthdate public: . private: int year; int month; int day; ;,class professor:public person

56、public: . private: birthdate birthday; ;,* professor类通过继承从person类得到了name,age, sex等数据成 员,通过组合,从birthdate类得到了 year, month, day等数据成员。 继承是一种“是”的关系,而组合是一种“有”的关系。 *,第3讲 c+面向对象程序设计,3.4 继承与派生类,3.4.7 继承在软件开发中的重要意义,继承是面向对象技术的一个重要内容,也是c+和c的最重要的区别之一。 对类库中的类声明一般是放在头文件中,类的实现是单独编译的。由于基类是单独编译的,在程序编译时,只需对派生类的新增功能进行编

57、译,这就大大提高了程序调试的效率。如果在必要时修改了基类,只要基类的公共接口不变,派生类不必修改。 为什么要求在软件开发中使用继承机制,尽量通过继承来建立一批新类?,(1) 许多基类是被程序的其他部分或其他程序使用的,这些程序 要求基类不能受破坏。,(2) 用户往往得不到基类的源代码。如果要修改已有的类,必须 掌握类的声明和类的实现。但是使用类库,用户是无法知道成员函 数的代码的,因此无法对基类进行修改。,(3) 在类库中,一个基类可能已被指定与用户所需的组减建立了 某种关系,因此,在类库中基类是不容许修改的。,(4) 在类库中,许多类是专门作为基类而设计的。有些类可能没 有独立的功能,只是一

58、个框架,或者说是一个抽象类,以便用户在 此基础上添加新的功能。,(5) 在面向对象的程序设计中,需要设计类的层次结构,从最初 的抽象类出发,每一层派生类的建立都逐步实现具体的目标。也可 以说,是不断地从抽象到具体的过程。,3.4.1 继承与派生的概述* 3.4.2 派生类成员的访问属性* 3.4.3 派生类的构造函数和析构函数* 3.4.4 多继承* 3.4.5 虚基类* 3.4.6 继承与组合* 3.4.7 在软件开发中的重要意义*,3.4 继承与派生类,小结:,visual c+ 程序设计,第3讲 c+面向对象程序设计,3.5.1 多态性概述 3.5.2 虚函数 3.5.3 纯虚函数和抽象

59、类,3.5 多态与虚函数,第3讲 c+面向对象程序设计,3.5 多态与虚函数,3.5.1 多态性概述,多态性就是一个事物多种形态,就是同一符号或者名字在不同情况下具有不同解释的现象。 在c+中,多态性是指不同类型的对象接收相同的消息时产生不同的行为。这里的消息主要指的是对类成员函数的调用,而不同的行为指的是成员函数的不同实现。 不同功能的函数可以用同一函数名,可以用一个函数名调用不同内容的函数。即是“一个接口,多种方法”! 多态性、封装性、继承性是面向对象程序设计的三大特征!,什么是多态,第3讲 c+面向对象程序设计,3.5 多态与虚函数,3.5.1 多态性概述,多态的两种实现形式,从实现的角

60、度,多态性分为两类:编译时多态和运行时多态。,编译时多态也叫静态多态性,是通过函数的重载或运算符的重载来实现的。 运行时多态也叫动态多态性,是通过虚函数来实现的。是在程序执行过程中,根据执行情况动态确定调用哪一个函数。,第3讲 c+面向对象程序设计,3.5 多态与虚函数,3.5.1 多态性概述,与多态对应的两种编译方式,与多态方式相对应的是两种编译方式:静态联编和动态联编。,联编 (binding,又称绑定),就是将一个标识符和一个存储地址联系在一起的过程,或者是一个源程序经过编译、连接,最后生成可执行代码的过程。,静态联编,在编译阶段完成的绑定,又称为早期联编,编译时多态属于此类联编。,动态

温馨提示

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

评论

0/150

提交评论