版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、C+语言程序设计教程(第6-10章)编辑课件 第6章 类与对象6.1 从面向过程到面向对象6.2 类与对象的定义6.3 对象的初始化6.4 对象数组与对象指针6.5 静态成员6.6 友元6.7 常对象和常成员6.8 程序实例编辑课件6.1 从面向过程到面向对象6.1.1 面向对象程序设计的基本概念1对象与方法对象是指现实世界中具体存在的实体。每一个对象都有自己的属性(包括自己特有的属性和同类对象的共同属性)。属性反映对象自身状态变化,表现为当前的属性值。方法是用来描述对象动态特征的一个操作序列。消息是用来请求对象执行某一操作或回答某些信息的要求。实际上是一个对象对另一个对象的调用。编辑课件2类
2、类是具有相同属性和方法的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述。将相似的对象分组形成一个类,每个这样的对象被称为类的一个实例,一个类中的所有对象共享一个公共的定义,尽管它们对属性所赋予的值不同。编辑课件3封装封装(Encapsulation)是指把对象属性和操作结合在一起,构成独立的单元,它的内部信息对外界是隐蔽的,不允许外界直接存取对象的属性,只能通过有限的接口与对象发生联系。编辑课件4继承继承(Inheritance)反映的是类与类之间抽象级别的不同,根据继承与被继承的关系,可分为基类和衍类,基类也称为父类,衍类也称为子类。子类将从父类那里获得所有的属性和方法,并且可以
3、对这些获得的属性和方法加以改造,使之具有自己的特点。一个父类可以派生出若干子类,每个子类都可以通过继承和改造获得自己的一套属性和方法,由此,父类表现出的是共性和一般性,子类表现出的是个性和特性,父类的抽象级别高于子类。继承具有传递性。继承使得程序设计人员可以在已有的类的基础上定义和实现新类,所以有效地支持了软件构件的复用。编辑课件5多态性不同的对象收到相同的消息产生不同的动作,这种功能称为多态性(Polymorphism)。将多态的概念应用于面向对象程序设计,增强了程序对客观世界的模拟性,使得对象程序具有了更好的可读性,更易于理解,而且显著提高了软件的可复用性和可扩充性。编辑课件6.1.2 C
4、+面向对象程序的结构一个面向对象的C+程序一般由类的声明和类的使用两部分组成。类的使用部分一般由主函数和有关子函数组成。编辑课件以下是一个典型的C+程序结构。#include /类的定义部分class C int x,y,z; /类C的数据成员声明f(); /类C的成员函数声明;/类的使用部分void main() C a; /建立一个类C的对象aa.f(); /给对象a发消息,调用成员函数f()编辑课件在C+程序中,程序设计始终围绕“类”展开。通过声明类,构建了程序所要完成的功能,体现了面向对象程序设计的思想。下面看一个具体的例子,直观地了解一下面向对象程序设计方法与结构化程序设计方法的区别
5、。【例6.1】 类的应用示例。编辑课件6.2 类与对象的定义6.2.1 类的定义在C+中,一个类指定一个独立的对象集合,该对象集合由组成该类的对象以及这些对象所允许的操作组成。编辑课件1类的定义形式类定义的一般形式如下:class 类名 public:数据成员或成员函数的定义private:数据成员或成员函数的定义protected:数据成员或成员函数的定义;编辑课件2类成员函数的定义对类的成员函数的定义通常有两种形式,一种是在类的定义中直接定义函数,一种是在类外定义。前面的例6.1就是在类内部实现成员函数,下面再看一个例子。【例6.2】 已知y,当f(n)122334n(n1)时,求y的值。
6、编辑课件按照类的定义形式,可以在类定义中只给出成员函数的原型,而在类外部定义具体的成员函数。这种成员函数在类外定义的一般形式如下:函数返回值的类型 类名:函数名(形参表)(函数体)其中双冒号:是作用域运算符,它指出该函数是属于哪一个类的成员函数。编辑课件6.2.2 对象的定义与使用1对象的定义对象的定义形式如下:类名 对象名表;其中对象名表代表有多个对象名,各对象名之间以逗号分隔。编辑课件2对象成员引用具体引用形式为:对象名.数据成员名对象名.成员函数名(实参表)【例6.3】 定义一个时钟类,类中有3个私有数据成员(Hour、Minute和Second)和两个公有成员函数(SetTime和Sh
7、owTime)。SetTime根据传递的3个参数为对象设置时间,ShowTime负责将对象表示的时间显示输出。在主函数中,建立一个时间类的对象,先利用默认时间设置,再设置时间为10时23分45秒并显示该时间。编辑课件6.2.3 类与结构体的区别在C+语言中,结构体除了具有原先C语言定义的功能外,还具有类似于类的功能,即也可以在其中定义函数。它们之间的区别是:在结构体中,成员的默认访问权限是public,而类成员的默认访问权限是private。【例6.4】 用结构体定义类的示例。编辑课件6.3 对象的初始化在类的定义中不能给数据成员赋初值。从封装的目的出发,类的数据成员应该多为私有的,对私有数据
8、成员的访问只能通过成员函数,而不能通过成员引用的方式来赋值。C+中定义了一种特殊的初始化函数,称之为构造函数(Constructor)。在特定对象使用结束时,还将进行一些清除工作。对象清除工作由析构函数(Destructor)来完成。编辑课件6.3.1 构造函数1构造函数的特点(1)构造函数名与类名相同,且没有返回值,不能指定函数类型。(2)构造函数必须使具有公有属性,但它不能像其它成员函数那样被显式地调用,它是在定义对象的同时被系统自动调用的。(3)构造函数是特殊的成员函数,函数体可以写在类体内,也可以写在类体外。(4)构造函数可以重载,即一个类中可以定义多个参数个数或参数类型不同的构造函数
9、。编辑课件【例6.5】 使用构造函数替代例6.3中SetTime()成员函数,并在主函数中,使用构造函数设置时间为15时19分56秒并显示该时间。构造函数也可以重载。关于重载的概念将在第7章详细介绍,这里先看一个例子。【例6.6】 构造函数重载定义示例。编辑课件综上所述,构造函数是一个有着特殊名字,在对象创建时被自动调用的一种函数,它的功能就是完成对象的初始化。编辑课件2默认的构造函数如果类定义中没有给出构造函数,则C+编译器自动给出一个默认的构造函数,而且默认的构造函数只能有一个,形式如下:类名:默认构造函数名() 若没有定义过任何形式的构造函数,系统会自动生成默认的构造函数。若已经定义过构
10、造函数,则系统不会自动生成默认的构造函数,一旦需要,则要求显式地定义这种形式的构造函数。在程序中,若定义一个静态对象而没有指明初始值时,编译器会按默认的构造函数对对象的数据成员初始化为0或空。【例6.7】 默认构造函数示例。【例6.8】 构造函数的调用。编辑课件6.3.2 析构函数1析构函数的特点当对象创建时,会自动调用构造函数进行初始化。当对象撤消时,也会自动调用析构函数进行一些清理工作,如释放分配给对象的内存空间等。与构造函数类似的是:析构函数也与类同名,但在名字前有一个“”符号,析构函数也具有公有属性,也没有返回类型和返回值,但析构函数不带参数,不能重载,所以析构函数只有一个。【例6.9
11、】 析构函数程序举例。编辑课件2默认的析构函数和默认构造函数一样,如果类定义中没有给出析构函数,系统也会自动生成一个默认的析构函数,其格式如下:类名称:默认析构函数名() 例如,编译系统为类Point生成默认的析构函数如下:Point:Point() 对于大多数类而言,默认的析构函数就能满足要求。只有在一个对象完成其操作之前需要做一些内部处理时,才显式地定义析构函数。编辑课件6.3.3 复制构造函数复制构造函数的作用是使用一个已存在的对象去初始化另一个同类对象,它也是一种构造函数,除了具有一般构造函数的特征外,它还具有如下特点:(1)其形参必须是本类的对象的引用。(2)某函数的形参是类的对象,
12、调用该函数需要复制构造函数进行形参和实参结合。(3)函数的返值是类的对象,函数调用返回的时候需要调用复制构造函数实现类对象的赋值。编辑课件复制构造函数的定义格式如下:类名:复制构造函数名(const 类名 &对象名)(函数体)复制构造函数与类同名,const是类型修饰符,被其修饰的对象是个不能被更新的常量。【例6.10】 默认复制构造函数示例。【例6.11】 复制构造函数示例。编辑课件普通构造函数在建立对象时被调用,而复制构造函数在用已有对象初始化一个新对象时被调用。复制构造函数被调用通常发生在以下3种情况:(1)程序中需要新建一个对象,并用一个类的对象去初始化类的另一个对象的时候。(2)当对
13、象作函数参数时,调用该函数时需要将实参对象完整地传递给形参,这就需要按实参复制一个形参,系统是通过调用复制构造函数来实现的,这样能保证形参具有和实参完全相同的值。(3)当函数的返回值是类的对象。在函数调用完毕需要将返回值带回函数调用处时,此时需要将函数中的对象复制一个临时对象并传给该函数的调用处。以上3种调用复制构造函数都是由编译系统自动完成的,不必由用户自己去调用。编辑课件6.4 对象数组与对象指针6.4.1 对象数组对象数组是指数组的每一个元素都是相同类型对象的数组,也就是说,若一个类有若干个对象,把这一系列的对象用一个数组来表示。对象数组的元素是对象,不仅具有数据成员,而且还有成员函数。
14、对象数组的定义和普通数组的定义类似,一般格式如下:类名 数组名第一维大小第二维数组大小其中,类名是指该数组元素属于该类的对象,方括号内的数组大小给出了某一维元素的个数。一维对象数组只有一对方括号,二维对象数组要有两个方括号对,等等。编辑课件与普通数组一样,在使用对象数组时也只能访问单个数组元素,也就是一个对象,通过这个对象,可以访问它的公有成员,一般形式如下:数组名下标.成员名和普通数组一样,对象数组既可以在定义时初始化,也可以在定义后赋值。【例6.12】 对象数组应用示例。编辑课件6.4.2 对象指针对象指针就是指向对象的指针,其定义的格式如下:类名 *对象指针名;对象成员也可以通过指向对象
15、的指针来引用,引用数据成员的具体形式如下:指向对象的指针-数据成员名或:(*指向对象的指针).数据成员名引用成员函数的具体形式如下:指向对象的指针-成员函数名(实参表)或:(*指向对象的指针).成员函数名(实参表)【例6.13】 对象指针应用示例。编辑课件6.4.3 指向类成员的指针1指向数据成员的指针指向数据成员的指针定义格式如下:类型说明符 类名:*数据成员指针名;定义了指向数据成员的指针后,需要对其进行赋值,也就是要确定指向类的哪一个成员。对数据成员指针赋值的一般格式如下:数据成员指针名=&类名:数据成员名;将指针指向类的数据成员后,就可以通过类的对象引用指针所指向的数据成员,其格式有两
16、种:对象名.*数据成员指针名;或:对象指针名-*数据成员指针名;【例6.14】 指向数据成员指针应用举例。编辑课件2指向成员函数的指针指向成员函数的指针定义格式如下:函数返回值类型 (类名:* 成员函数指针名)(参数表);定义成员函数指针后要对其赋值,也就是确定指向类的哪一个成员函数。给指向成员函数指针赋值的一般格式如下:成员函数指针名=&类名:成员函数名;调用成员函数指针所指向函数的格式如下:(对象名.*成员函数指针名)(实参表)或:(对象指针名-*成员函数指针名)(实参表)【例6.15】 指向类成员函数指针应用举例。编辑课件6.4.4 this指针类的每一个成员函数都有一个隐含的常量指针,
17、通常称为this指针。this指针的类型就是成员函数所属类的类型。当调用成员函数时,它被初始化为被调用函数的对象的地址。this指针在系统中是隐含地存在的,也可以显式地使用。【例6.16】 this指针应用举例。需要注意的是,this指针是一个const指针,不能在程序中修改它,而且this指针的作用域仅在一个对象的内部。编辑课件6.5 静态成员6.5.1 静态数据成员静态数据成员的定义格式如下:static 数据类型 变量名;静态数据成员初始化的方式也与一般的数据成员不同。静态数据成员初始化应在类外进行,而且应在对象定义之前。一般在main()函数之前,类定义之后的位置对它进行初始化,格式如
18、下:数据类型 类名:静态数据成员名初始值;引用静态数据成员的格式如下:类名:静态数据成员名【例6.17】 静态数据成员应用举例。编辑课件6.5.2 静态成员函数定义静态成员函数的格式如下:static 函数返回值的类型 静态成员函数名(形参表)(函数体)编辑课件静态成员函数仅能访问静态的数据成员,不能访问非静态的数据成员,也不能访问非静态的成员函数,这是由于静态的成员函数没有this指针。静态成员函数的调用不需要对象名。类似于静态的数据成员,公有的、静态的成员函数在类外的调用方式如下:类名:静态成员函数名(实参表)也允许用对象或指向对象的指针调用静态成员函数,一般格式如下:对象名.静态成员函数
19、名(实参表)对象指针-静态成员函数名(实参表)【例6.18】 静态成员函数应用举例。编辑课件6.6 友元6.6.1 友元函数友元函数是类定义中由关键字friend修饰的非成员函数。友元函数可以是一个普通函数,也可以是其它类的成员函数,它不是本类的成员函数,但是在它的函数体中可以通过“对象.成员名”访问类的私有成员和保护成员。友元函数声明的格式为:friend 函数返回值类型 友元函数名(参数表);【例6.19】 友元函数应用举例。编辑课件6.6.2 友元类和函数一样,类也可以说明为另一个类的友元,这时称该类为友元类。如果A类是B类的友元类,则A类中的私有成员函数都是B类的友元函数,都可以访问B
20、类的私有和保护成员。友元类说明的格式为:friend class 类名;类说明语句可以放在公有部分,也可以放在私有部分或保护部分。【例6.20】 友元类应用举例。编辑课件友元提供了一种非成员函数访问类的私有成员的方法,这在某些情况下为程序设计提供了一定的方便性。但是面向对象的程序设计要求类的接口与类的实现分开,对对象的访问通过其接口函数进行。如果直接访问对象的私有成员,就破坏了面向对象程序的数据隐藏和封装特性,虽然提供了一些方便,但有可能是得不偿失的,所以,需要慎用友元。编辑课件此外,还有两点需要注意:(1)友元关系不能传递。例如,B类是A类的友元,C类是B类的友元,如果C类和A类之间没有显式
21、说明,C类和A类之间不是友元关系。(2)友元关系的单向性。例如,如果B类是A类的友元,则B类的成员函数都是A类的友元函数,可以访问A类的所有数据成员,但A类的成员函数就不是B类的友元函数,也就不能访问B类的所有数据成员。编辑课件6.7 常对象和常成员6.7.1 常对象和常成员函数如果在定义对象时用const修饰,则被定义的对象为常对象。常对象的数据成员值在对象的整个生存期内不能被改变,常对象的定义形式如下:类名 const 对象名(参数表);或:const 类名 对象名(参数表);在定义常对象时必须进行初始化,而且不能被更新。编辑课件常成员函数的声明格式如下:函数返回值的类型 函数名(参数表)
22、 const;const是函数类型的组成部分,因此在函数的实现部分也要带const关键字。常成员函数表示该成员函数只能读类数据成员,而不能修改类的数据成员。定义常成员函数时,把const关键字放在函数的参数表和函数体之间。【例6.21】 常对象和常成员函数应用举例。编辑课件6.7.2 常数据成员带有成员初始化列表的构造函数的一般形式如下:类名:构造函数名(参数表):(成员初始化列表) /构造函数体成员初始化列表的一般形式如下:数据成员名1(初始值1),数据成员名2(初始值2),【例6.22】 常数据成员应用举例。编辑课件6.8 程序实例【例6.23】 已知,求:(1)yy) ? x: y);
23、double max (double x , double y) return ( (xy) ?x: y); #include void main( ) coutmax(10,20)endl; coutmax(1.23,2.34)endl; 重载方式靠将实参的个数及类型和所被调用的f()函数的形参的个数及类型一一比较来判断。编辑课件()作为重载函数至少在参数个数、参数类型上有所不同。若仅在返回类型上不同,编译器是无法区别的。如:void func(int); int func(int); /错误 int min(int ,int); int min(int,int,int); /正确 int
24、add(int,int); double add(double,double); /正确()typedef定义的类型只是给已有类型取另外一个名字,编译器不能将其同原类型区分。如: typedef INT int; void func(int x) . void func (INT x) (3)重载函数一般应具有相同的功能,否则会破坏程序的可读性。注意事项编辑课件问题的提出1、基本数据类型系统提供了大量运算符。如:int x,y; x=x+y; 表达简洁,使用方便。2、问题的提出: 对于串类的对象合并: string x, y; strcat(x,y);不如上述运算那样简单,希望能改造为:x=x
25、+y;更加简单和直观! 因此,需要对“+”进行不同的解释,即:重载7.1.2 运算符重载编辑课件一、C+中的运算符1、大多数系统预定义运算符都能重载,除开以下: . : ?: # *(当乘法运算符时可重载) “.” “:” “*”在C+中有特定定义 “?:”不值得重载 “#”不能被重载2、重载时的注意事项:(1)不能改变优先级;(2)不能改变结合性;(3)不能改变运算符所需操作数的个数;(4)重载后,可按这些运算符的表达方式使用。 编辑课件一、通过运算符重载函数进行重载1、运算符重载函数是成员函数 语法形式:Type X:operator(参数表) /相对于该类而定义的操作 运算符重载的语法形
26、式返回类型重载该运算符的类名要重载的运算符符号编辑课件2、运算符重载函数是友元函数 语法形式:Type operator(参数表) /相对于该类而定义的操作 罗列运算符所需要的操作数3、实例void operator+( ) void operator-( ) void counter:operator+( ) if (value0) value-;编辑课件注意:重载中注意的问题1、运算符重载函数是友元函数、成员函数的区别;2、运算符被重载时,只是相对一特定类被重载,在特定的环境下作出特定的解释。当离开这个特定环境后,具有原来的意义(系统定义);3、当重载运算符解释失败时,用该运算符的预定义版
27、本(系统)进行解释;4、用此方法重载时,只能对一个系统已有运算符进行特定环境下的新的解释,而不能创造新的运算符。当运算符不够用时,用函数调用来实现;5、除“=”以外,重载的运算符可以被任何派生类所继承,“=”需要每个类明确定义自己的解释;6、 重载可能让程序的可读性下降,在使用时应模仿运算符的习惯用法 。编辑课件一、运算符重载函数定义的两种方式1、成员函数和友元函数2、差别的关键原因:this指针二、一元运算符1、不论前缀还是后缀,需要一个操作数2、对于任意一元运算符:(1)成员函数重载运算符 定义 type x:operator ( ) 显式调用 objX.operator ( ) 隐式调用
28、 objX 或:ojbX(2)友元函数重载运算符 定义 type operator (Xobj) 显式调用 operator(obj X) 隐式调用 ojbX 或:objX 一元和二元运算符编辑课件方式 定义显式调用隐式调用备注成员函数Type X:operator ( )objX.operator () objX或:objX 操作数通过THIS指针隐含传递,因此参数表为空。友元函数Type operator ( X ojb)operator(objX)objX或:objX ()所需要的一个操作数在参数表中,由对象显式地提供。一元运算符的重载编辑课件三、二元运算符1、需要两个操作数;2、对于任
29、意二元运算符:方式 定义显式调用隐式调用备注成员函数Type X:operator (X obj)objX1.operator (objX2)objX1 (objX2)第一个操作数通过THIS指针隐含传递,第二个操作数通过参数提供,只有一个参数。友元函数Type operator ( X ojb)operator (objX1, objX2)objX1 (objX2)所需要的两个操作数在参数表中,由对象显式地提供。编辑课件用成员函数重载运算符例7-61、重载“+”、“=”、“+”;读懂几个成员函数;2、成员函数重载运算符,激活运算符的对象都是由THIS指针隐含传递的。用友元函数重载运算符1、成
30、员函数重载可能造成的麻烦:成员函数重载的运算符不具有交换性。 原因:成员函数仅能被一个“实际对象”所调用,如果引起成员函数调用的是一个值(非一个对象),成员函数将不能正确工作。2、可用友元函数解决这一问题:友元函数重载运算符时,需要明确给出参数,不会出错。3、不能用友元函数重载的运算符: = 、 ( )、- 4、注意:(1)对THIS所指向的数据的任何改变都会影响到激活运算数函数的对象。(2)可使用引用参数(指针)来解决重载时的二义性。编辑课件重载+和-一、关于+和- - 1、C中的+和- -的两种形式:前缀:+i; 后缀:i-;2、在C+中的约定 (显式地区分前缀和后缀)(1)对于前缀方式+
31、i: 成员函数:XX:operator + (); 友元函数:X operator + (X&);(2)对于后缀方式i+: 成员函数:XX:operator + (int); 友元函数:X operator +(X&, int); 第二个参数INT一般设置为0,如:i+ 等价于:i+(0) 或:i+=0编辑课件二、实例 Class X X operator +() a+; b+; return *this; X operator +(int x) X temp; a+; b+; return temp;Class X friend operator +(Y &a) a.x+; b.y+; re
32、turn a; friend operator +(Y &a, int i) Y temp=a; a.x+; b.y+; return temp;编辑课件重载赋值运算符一、概述1、“”赋值运算符可以被重载;2、重载后不能被继承;3、必须重载为成员函数。二、格式:X X : operator=(const X from) /复制X的成员;三、一般来说当缺省的类赋值函数不能正确工作时,考虑“”的重载。编辑课件模板编辑课件7.2.1 函数模板 1函数模板的定义函数模板的定义为: template (形参表) /函数定义体 由class或typename后加一个标识符构成 编辑课件【例7.13】函数模
33、板的说明template Glorp min( Glorp a, Glorp b ) return a b ? a : b; 注意:对函数模板的说明和定义必须是全局作用域,函数模板不能说明为类的成员函数 编辑课件2函数模板的实例化在函数模板中,函数模板只是说明,不能直接执行,需要实例化为模板函数后才能执行。当编译系统发现一个函数调用时,将根据实参表中的类型生成一个重载函数即模板函数。 编辑课件【例7.14】函数模板的实例化#include template A fab(A x) return x=0?x,-x;void main() int i=5; double y=-5.4;cout”整数
34、的绝对值”fab(i)endl;cout”实数的绝对值”fab(y)endl;编辑课件7.2.2 类模板 1类模板的定义 template class /类说明体 template :(形参表) /成员函数定义体 template :(形参表) /成员函数定义体 。template :(形参表) /成员函数定义体 编辑课件【例7.15】设计一套完整的算术运算来补充add函数。templateclass CCalculator public: CCalculator(const T &x, const T &y) : m_x(x), m_y(y) CCalculator(void) const
35、T add(void) return m_x + m_y; const T sub(void) return m_x - m_y; const T mult(void) return m_x * m_y; const T div(void) return m_x / m_y; private: const T m_x; const T m_y; ; 编辑课件2类模板的实例化类模板不能直接使用,必须实例化为相应的模板类 创建类模板的实例的一般格式为: ;例7.15类模板CCalculator的实例化为: CCalculator calc(5, 2); / 创建一个整数计算对象 const int
36、 z = calc.mult(); / 结果应该为 10编辑课件7.3 应用实例编辑课件第8章 继承和派生 在C+中可重用性是通过继承(inheritance)这一机制来实现的。继承是C+的一个重要组成部分。编辑课件8.1 继承和派生的概念 在C+中,所谓“继承”就是在一个已存在的类的基础上建立一个新的类。一个新类从已有的类那里获得其已有特性,这种现象称为类的继承。通过继承,一个新建子类从已有的父类那里获得父类的特性。从另一角度说,从已有的类(父类)产生一个新的子类,称为类的派生。类的继承是用已有的类来建立专用类的编程技术。8.1.1基类与派生类 1.继承与派生交通工具飞机滑翔机直升飞机喷气式
37、飞机编辑课件交通工具飞机滑翔机直升飞机喷气式飞机已存在的类(例如“交通工具”)称为“基类”或“父类”。新建立的类(例如“飞机”)称为“派生类”或“子类”。一个基类可以派生出多个派生类,每一个派生类又可以作为基类再派生出新的派生类,因此基类和派生类是相对而言的。2.基类与派生类 编辑课件请注意图中箭头的方向,在本书中约定,箭头表示继承的方向,从派生类指向基类。编辑课件8.1.2继承与派生的作用 1.避免公用代码的重复开发,在减少代码和数据冗余的同时,节省程序开发的时间,提高程序开发的效率和质量。2.通过增强代码一致性来减少模块间的接口和界面。3.通过层次关系来组织对象,使得高层类作为低层类的抽象
38、,有利于程序员掌握对象的共性,在此基础上,就能更快地掌握低层类中的个性特征,给编程与代码重用带来方便。编辑课件8.1.3派生类的声明 声明一个派生类的一般格式为:class 派生类名 : 派生存取说明符(可省) 基类名/派生类新增的数据成员和成员函数; 派生类名”是要从基类派生出的新类的名字,“基类名”是一个已经定义好的基类的名字,“派生存取说明符”可以是关键字public或protected或private,派生存取说明符的作用会在后面详细介绍,“派生存取说明符”可以省略,默认为private,即私有派生。 编辑课件/定义一个基类(Student类)class Studentpublic:
39、char name10; /姓名 int age; /年龄 char sex; /性别 char classname20;/班级名称;/定义一个派生类(GraduateStudent类)class GraduateStudent : public Studentpublic:char Advisorname10; /导师int qualifiergrade; /资格考试分; 编辑课件8.2 派生类成员的访问控制 8.2.1派生类成员访问控制简介从一个基类派生出一个子类时,可以通过指定派生时的存取说明符来实现对派生类成员的访问控制。 既然派生类中包含基类成员和派生类自己增加的成员,就产生了这两部
40、分成员的关系和访问属性的问题。在建立派生类的时候,并不是简单地把基类的私有成员直接作为派生类的私有成员,把基类的公用成员直接作为派生类的公用成员。实际上,对基类成员和派生类自己增加的成员是按不同的原则处理的。编辑课件8.2.2 private、protected与public类成员 1.private类成员 一个类中的私有(private)成员(包括数据成员和成员函数)只能被它们所在类的成员函数和友元函数访问,在C+中类成员存取说明符缺省的情况下的存取特征都是私有的(private)。 编辑课件【例8.1】 类私有成员的定义和访问 #include class Person /Person类的
41、三个私有成员 char name10; /姓名private: int age; /年龄 char sex; /性别;main()Person P1; P1.age=20;/非法 coutP1.nameendl; /非法 return 0; 编辑课件2.public类成员 一个类中的公有(public)成员(包括数据成员和成员函数)可以被程序中任何代码(包括函数)访问,一般情况下,应尽量将类的数据成员声明为私有(private),然后为需要被类外部访问的数据成员提供公有的成员函数,实现对私有成员的设置和访问,这种结构能够向类的客户很好的隐藏实现方法,在有效减少错误的同时,可以增强程序的可修改性
42、。 编辑课件3.protected类成员 使用protected声明的称为保护成员。任何一个类的保护成员仅可以被其自己和派生类的所有非静态成员函数和友元函数直接访问,也就是说其他的外部函数是不能访问它的。因此,对于那些既要对外界隐藏,又要能被派生类访问的成员,可以将它们声明为保护成员。 如果基类声明了私有成员,那么任何派生类都是不能访问它们的,若希望在派生类中能访问它们,应当把它们声明为保护成员。如果在一个类中声明了保护成员,就意味着该类可能要用作基类,在它的派生类中会访问这些成员。编辑课件8.2.3三种派生方式的定义 1.私有(private)派生 在声明一个派生类时将派生方式指定为priv
43、ate的,称为私有派生,用私有派生方式建立的派生类称为私有派生类 ,其基类称为私有基类。由私有派生得到的派生类,它从基类继承的成员都将变为私有成员,也就是说通过私有派生,派生类从基类继承来的公有成员和保护成员都将变成派生类的私有成员,这些成员将只能被派生类的成员函数和友元函数访问。需要重点说明的是,基类的私有成员经过私有派生后继续保持其基类的私有成员身份,无法被派生类访问。 编辑课件2.保护(protected)派生由保护派生得到的派生类,它从基类继承的公有和保护成员都将变为派生类的保护成员。基类的私有成员经过保护派生后继续保持其基类的私有成员身份,依然无法被派生类访问。 保护派生的特点是:
44、基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为基类私有。也就是把基类原有的公用成员也保护起来,不让类外任意访问。编辑课件3.公有(public)派生 由公有派生得到的派生类,它从基类继承的成员都将维持原有访问控制特征,即通过公有派生后,派生类从基类继承的公有成员在派生类中仍然是公有成员,保护成员仍然是保护成员,而基类的私有成员经过公有派生后继续保持其基类的私有成员身份,依然无法被派生类访问。 编辑课件8.2.4派生类成员访问控制规则 1.派生类中新增成员的访问控制遵循类成员访问控制的规则。 存取说明符访问控制规则Private此派生类的非静态成员函数和友元函数可以直接访问Pr
45、otected此派生类和其子类非静态成员函数和友元函数可以访问Public任何非静态成员函数,友元函数和非成员函数都可以直接访问编辑课件2. 类成员在派生类中的访问控制规则 基类成员的存取说明符派生方式public派生protected派生private派生Private在派生类中被隐藏在派生类中被隐藏在派生类中被隐藏Protected派生类中为protected派生类中为protected派生类中为privatePublic派生类中为public派生类中为protected派生类中为private注意:不管是何种派生,基类的private成员永远都不能被其派生类直接访问,但可以通过基类的pu
46、blic和protected成员函数访问。 编辑课件8.3 派生类的构造函数和析构函数8.3.1派生类的构造函数和析构函数的声明类的构造函数是类的一种特殊的成员函数,它的作用主要是为对象分配内存、进行初始化;而析构函数它的作用与构造函数相反。 派生类的构造函数声明格式如下 :派生类的构造函数名称(参数表): 基类的构造函数名(参数表)/派生类构造函数体编辑课件class Point int x,y;public:Point(int a,int b)/基类的构造函数x=a;y=b;cout”Constructing Point class n”;Point()/基类的析构函数cout”Destr
47、ucting Point class n”;class Circle :public Pointdouble radius;public : Circle (double r,int a,int b):Point(a,b)/派生类的构造函数 radius =r;cout”Constructing Circle class n”; Circle ()/派生类的析构函数cout”Destructing Circle class n”;编辑课件派生类中含有对象成员时,其构造函数的声明格式如下: 派生类的构造函数名称(参数表): 基类的构造函数名(参数表),对象成员名1(参数表),对象成员名N(参数表
48、)/派生类构造函数体 class Circle2 :public Pointdouble radius;Point P1;public : Circle2 (double r,int a,int b):Point(a,b),P1(a,b)/派生类的构造函数,定义时/指定了基类的构造函数和对象成员P1的构造函数radius =r;cout”Constructing Circle2 class n”; Circle2 ()/派生类的析构函数cout”Destructing Circle2 class n”; 编辑课件8.3.2派生类的构造函数和析构函数的构造规则 1. 基类具有显式的构造函数时(1
49、)基类具有不带参数的构造函数派生类既可以自己不定义构造函数,也可以根据需要定义自己的构造函数,构造函数可以带参数也可以省略,在派生类中定义构造函数时还可省略“:基类构造函数名(参数表)”。 (2)基类仅有带参数的构造函数 派生类必须显式的定义其构造函数,并在声明时指定其基类的某一构造函数和参数表,把参数传递给基类构造函数。 编辑课件2. 基类具有隐式的构造函数时 当基类没有显式的定义(即隐式的定义)构造函数时,派生类可以根据需要定义自己的构造函数,派生类构造函数的参数表、基类的构造函数名和参数表都可以根据需要省略。 编辑课件8.3.3派生类构造函数和析构函数的调用顺序1. 构造函数的调用顺序
50、派生类对象创建的时候,构造函数的执行顺序为:(1)基类的构造函数(2)对象成员的构造函数(3)派生类自身的构造函数 2. 析构函数的调用顺序与构造函数的调用顺序正好相反。即 (1)派生类自身的析构函数(2)对象成员的构造函数(3)基类的析构函数 编辑课件【例8.6】派生类Circle2的构造函数和析构函数的执行顺序/Point和Circle2类的定义main()Circle2 C1(0.0,1,1);cout”-program line- n”;return 0;编辑课件8.4 多重继承8.4.1多重继承的声明前面讨论的是单继承,即一个类是从一个基类派生而来的。在C+中还允许从多个基类中派生出
51、新的子类,这种派生方法称为多重继承(或多基派生)。这一强大的派生功能可以大大提高软件重用的灵活性 。 声明的格式如下: class 派生类名 : 派生存取说明符(可省)1 基类名1, 派生存取说明符N 基类名N/派生类新增的数据成员和成员函数;编辑课件【例8.7】 多重继承的声明#include class Circle1 /基类Circle1 protected: int r; public:void setx (int x) r=x;void draw( ) coutdrawingn;class Circle2 /基类Circle2 protected: int r; public:voi
52、d setx (int x) r=x;void write( ) coutwritingn;class Circle: public Circle1,public Circle2 /类Circle公有继承了Circle1和Circle2 public: void show() coutshowingn;void main() Circle cc;cc.draw();cc.write();cc.show();编辑课件8.4.2多重继承的几点说明1. 在多重继承中派生类成员的访问控制规则与单一继承规则相同。2. 多重继承的构造函数与析构函数定义与单一继承相似,只是在构造函数定义时N个基类的构造函数
53、之间用逗号分隔。3. 多重继承虽然功能强大,但也容易造成系统的复杂性,设计时务必正确和谨慎,能用单一继承时尽量不用多重继承。4. 多重继承容易产生模糊性,在引用时要注意 编辑课件例如前面例8.7如果按照下面来引用: void main() Circle cc;cc.setx(10); / Circle1的setx还是Circle2的setx? void main() Circle cc;cc.Circle1:setx(10); /说明是Circle1中的r为10 编辑课件8.4.3 虚基类 1. 虚基类的概念在很多情况下,程序员会定义一些类,而不想将其实例化为任何对象,这样的类称为“虚类”或“
54、抽象类”,因为这种虚类一般都要被用作基类,所以又被称为“虚基类”或“抽象基类”。 2. 虚基类的声明class 派生类名 : virtual 派生存取说明符(可省) 虚基类名/派生类新增的数据成员和成员函数;编辑课件3. 虚基类的初始化 虚基类初始化时,构造函数的调用顺序规则:(1)同一层派生中包含多个虚基类时,虚基类的构造函数按它们派生时声明的先后次序调用。 (2)如某虚基类是由实基类派生而来,则先调用此实基类的构造函数,再调用虚基类的构造函数,最后才是派生类的构造函数。 ( 3)若同一层派生中,同时存在虚基类与实基类,应先调用虚基类的构造函数,再调用实基类的构造函数,最后调用派生类的构造函
55、数。 编辑课件4. 虚基类的作用虚基类的作用就是为其他类提供一个合适的基类,以便派生类可以从它那里继承和实现所需的接口。在多重继承时,当派生类的多个基类有一个共同的基类时,为防止产生二义性问题可使用虚基类方法。注意: 虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。编辑课件【例8.11】存在二义性的虚基类多重派生#include class Base /基类protected: int b;public:Base()b =1;cout” Constructing Base class”e
56、ndl;class Base1:public Base /基类1从Base派生public:Base1()cout” Constructing Base1 class”endl;cout”Base b=”bendl;编辑课件class Base2:public Base /基类2从Base派生public:Base2()cout” Constructing Base2 class”endl;cout”Base b=”bendl;class Derived: public Base1, Base2 /从两个基类base1和base2多重派生出子类public: Derived ()cout” C
57、onstructing Derived class”endl;cout”Base b=”bendl;main ()Derived D1;return 0;改成如下语句:class Base1: virtual public Baseclass Base2: virtual public Base编辑课件8.5 基类和派生类的转换8.5.1 什么是基类和派生类的转换只有公用派生类才是基类真正的子类型,它完整地继承了基类的功能。基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替。大多数时候基类和派生类的转
58、换发生在对象之间进行赋值的时候。编辑课件8.5.2 基类与派生类的转换方法1可以用派生类对象为基类对象赋值;2可以用派生类对象初始化基类引用对象;3可以把指向派生类对象的指针赋给基类对象的指针;4可以把派生类对象的地址赋给基类对象的指针。 编辑课件8.6 继承与组合在C+中,为了重用已有的软件,除了可以通过继承和派生的方式从已有的类产生一个新类外,还可以通过将一个或多个类作为类成员的方式来产生一个新的类,这种方式就是组合。 class Date /基类Date/;class TelephoneNumber/;class Address /基类Address/;class Employee /
59、Employee类中包含类对象成员,组合了三个类 protected: Date birthday; TelephoneNumber phonenumber; Address homeaddress; /; 编辑课件类的组合和继承一样,是软件重用的重要方式。组合和继承都是有效地利用已有类的资源。但二者的概念和用法不同。编辑课件第9章 多态性和虚函数编辑课件9.1 多态性的概念 多态性是指不同类的对象对于同一消息的处理具有不同的实现。 多态性在C+中表现为同一形式的函数调用,可能调用不同的函数实现。从系统实现的角度看,C+的多态性分为两类,一类称为编译时刻多态性,另一类称为运行时刻多态性,也称动
60、态多态性。 编辑课件9.1.1 编译时刻的多态性 C+编译时多态性通过重载(函数重载和运算符重载)来实现 【例9.1】 编译时刻的多态性运算符重载:下面这段程序建立Data类和T_Data类,并重载运算符“+=”,使之能用于相应类对象的运算。 编辑课件#include using namespace std;class Datapublic:Data(int x=0,int y=0); /缺省构造函数void set_xy(int x,int y);int get_X() const;int get_Y() const;long norm();Data() ; /析构函数Data& opera
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 股骨颈骨折骨栓植入术后护理查房
- 宫腔镜子宫内膜粘连松解术后护理查房
- 资深园艺设计服务保证承诺书5篇
- 企业文化建设与推广方案制作工具
- 供应商货款结算申请函(7篇)范文
- 生产现场安全管理标准化流程清单
- 业务流程改进与创新思维工具集
- 湖南师大附中博才实验中学2025-2026学年初三寒假延长作业英语试题含解析
- 湖南省汨罗市弼时片区市级名校2026年初三下学期第一次联合语文试题试卷含解析
- 2026年江苏省句容市崇明中学9校联考初三语文试题含解析
- 2025年安徽工贸职业技术学院单招职业技能测试题库及一套完整答案
- 护理警示教育培训
- 临床重型颅脑损伤患者目标体温管理个案护理
- 电动单梁起重机培训
- 腹腔镜结肠癌手术步骤
- TGDNAS 043-2024 成人静脉中等长度导管置管技术
- 钢构厂房施工合同范本(2024版)
- YD-T 1159-2016光波分复用(WDM)系统测试方法
- 桥梁施工工程安全风险分级管控方案路桥工程建设安全风险分级管控体系方案2019-2020版标准实施文件汇编
- TB 10752-2018 高速铁路桥涵工程施工质量验收标准
- 应急资源调查研究报告范文
评论
0/150
提交评论