第7章 类和对象.ppt_第1页
第7章 类和对象.ppt_第2页
第7章 类和对象.ppt_第3页
第7章 类和对象.ppt_第4页
第7章 类和对象.ppt_第5页
已阅读5页,还剩63页未读 继续免费阅读

下载本文档

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

文档简介

1、C+程序设计,第7章类和对象,面向对象程序设计 类的定义 对象的定义 对象的初始化 成员函数的特性 对象数组 对象指针 静态成员 常对象 子对象 友元函数与友元类,主 要 内 容,1、面向对象程序设计,1、面向对象的基本概念 类是对某一类对象的抽象,而对象是某一种类的实例。因此,类和对象是密切相关的。没有脱离对象的类,当然也没有不依赖于类的对象,类是对现实世界的抽象得到的。 当我们把现实世界分解为一个个的对象,解决现实世界问题的计算机程序也与此相对应,由一个个对象组成,这些程序就称为面向对象的程序,编写面向对象程序的过程就称为面向对象的程序设计(Object-Oriented Programm

2、ing,简称为OOP)。,2、面向对象程序设计的特点 面向对象程序设计面对的是一个个对象。其中每一组数据都是有特定的用途的,是某种操作的对象。也就是说,一组操作调用一组数据。 程序设计者的任务包括: 一是设计所需的各种类和对象,即决定把哪些数据和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。 对一个大型任务来说,面向对象程序设计方法是十分有效的,它能大大降低程序设计人员的工作难度,减少出错机会。,)封装与信息隐蔽 对一个对象进行封装处理,把它的一部分属性和功能对外界屏蔽,也就是说从外界是看不到的,甚至是不可知的。其好处是大大降低了操作对象的复杂程度。 封装:一是将有关的数据

3、和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相对独立,互不干扰。二是将对象中某些部分对外隐蔽,即隐蔽其内部细节,只留下少量接口,以便与外界联系,接收外界的消息。,这种对外界隐蔽的做法称为信息隐蔽(information hiding)。 信息隐蔽还有利于数据安全,防止无关的人了解和修改数据。 对程序设计而言,封装性使对象内部的实现与外界隔离, 提供了更理想的模块化机制,减少了程序间的相互干扰。,)继承与重用 类具有层次性,即一个类的上层有父类,下层有子类,一个类继承了父类的某些特性,这种继承具有传递性。继承是一种连接类与类的层次模型,利用现有的类派生出新的类的过程称为类的继承,新

4、类(子类)拥有原有类(父类)的特性,又增加了自身新的特性。设计程序时只需对新增的内容或对原内容修改设计代码,除了共享机制外,继承还有传递机制,即下层的子类可以继承各层父类的全部特性。,)多态性 如果有几个相似而不完全相同的对象,有时人们要求在向它们发出同一个消息时,它们的反应各不相同,分别执行不同的操作,这就是多态现象。 (在Windows下,用鼠标双击一个文件对象(这就是向对象传送一个消息),如果对象是一个可执行文件,则会执行此程序,如果对象是一个文本文件,则启动文本编辑器并打开该文件。) 多态性(polymorphism)是指: 由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响

5、应。多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性。,面向对象的程序设计是以类和对象为基础的,程序的操作是围绕对象进行的,在此基础上利用了继承机制和多态性等。 面向过程的结构化程序设计中,常用以下公式来表述程序: 程序=算法数据结构,面向对象程序设计就是把一个算法和一组数据结构封装在一个对象中。因此就形成了新的观念: 对象 = 算法 数据结构 程序 = (对象+对象+对象+) + 消息 或: 程序 = 对象s + 消息,面向对象程序设计的特点,类是面向对象程序设计的核心。类是对某一类对象的抽象,而对象是某一种类的实例。在现实中,类是对一组客观对象的抽象,它将该组对象所具有的共同特征

6、(包括属性和服务)封装起来,以说明该组对象的能力和性质。 在系统中,类(class)是一种用户自定义的数据类型。通过类使得现实中的抽象实体在程序中直接表示为一个标识符,并可以进行引用和操作。 这使得程序中的概念与应用中的概念相互比较一致和对应。,2、类的定义,1、类的定义格式 类的定义格式一般地分为说明部分和实现部分。 说明部分是用来说明该类中的成员,包含数据成员的说明和成 员函数的说明。实现部分是用来对成员函数的定义。 概括说来,说明部分将告诉使用者“干什么”,而实现部 分是告诉使用者“怎么干”。,类的一般定义格式如下: class public: private: protected: ;

7、 ,【例7.1】定义一个Clock时钟类 class Clock public: void init( );/初始化时间 void update( );/当改变时间时刷新时间数据 void display( ); /显示时间 private: int hour, minute, second; /时,分,秒 ; /别忘了“”后面的“;”!,2、定义类时应注意的事项 在说明部分中,class是定义类类型的关键字,Clock是类名,通常用大写字母开始的字符串作为类名。 花括号内是类的说明部分,说明该类包含哪些数据成员和哪些成员函数。类中的数据成员的类型可以是任意的,包含整型、浮点型、字符型、数组、

8、指针和引用等。同时另一个类的对象,可以作该类的成员。当一个类的对象作为这个类的成员时,如果另一个类的定义在后面,需要提前说明。 在类体中不允许对所定义的数据成员进行初始化,因为类的定义只是在创造一个类型而已,而不是在说明“变量”。相当于先设计好一个模具(类),之后才可用模具来生产产品(对象)。,3、类成员函数的实现 类的成员函数是对类内中数据的操作,同时作为外部数据成员的接口,代表了类的对象的行为。这些函数可以定义在类的内部,也可以定义在类体的外部。 在类的内部定义的成员函数叫内联函数,在类的外部定义的成员函数叫外联函数。 在类的外部定义的成员函数需要在函数名的前面加Clock:,称为成员名限

9、定。 其中 “:”称为作用域运算符。,在类体外定义成员函数的格式如下: 返回值的类型 :(参数表) 函数体 如: void Clock : display( ) couthour:minute:secondendl;,3、对象的定义,对象的定义格式 对象成员的表示方法,对象的定义格式如下: 例如:给上述时钟类定义对象: Clock clockA, clockB;/定义两个对象 Clock*pclockA;/定义对象指针 Clock clockD5; /定义对象数组 其中,是对象所属的类的名字,即所定义的对象是该类类型的对象。中可以有一个或多个对象名,多个对象名时用逗号分隔。中,可以是一般的对象

10、名,还可以是指向对象的指针名或引用名,也可以是对象数组名。本例定义了2个对象、1个对象指针、一个对象数组。,对象成员的表示方法,对象是广义“变量”,一个对象的成员就是该对象所属类所定义的成员。由于封装性,对象只能访问其中的公有成员,包括公有数据成员和公有成员函数。用运算符“.”来访问其中公有成员。 对象名.公有数据成员名 或者 对象名.公有成员函数名(参数表) 例如: clockA.cnt;/正确,访问数据成员 clockA.minute;/错误,minute是私有成员,不能访问! clockA. init( ) ;/正确,访问成员函数 此处的“.”运算符,功能是表示对象的成员。,【例7.4】

11、写出以下程序的执行结果: #include class Rectangle int x1,y1,x2,y2; public: void setRectangle(int a1,int b1,int a2,int b2) x1=a1; y1=b1; x2=a2; y2=b2; void dispRectangle() coutRectangle:x1=x1,y1=y1endl; coutx2=x2,y2=y2endl; ; void main() Rectangle Rect1;/定义对象 Rectangle *Rect2= /定义对象指针指向对象,Rect1.setRectangle(0,0,

12、10,10); Rect1.dispRectangle(); Rect2-setRectangle(10,10,20,20); Rect2-dispRectangle(); 程序执行结果如下: Rectangle:x1=0,y1=0 x2=10,y2=10 Rectangle:x1=10,y1=10 x2=20,y2=20 注意:如果类中的成员没有指明权限的,默认为私有。所以x1,y1,x2,y2的权限是private。,4、对象的初始化,简单构造函数和析构函数 缺省构造函数和缺省析构函数 拷贝构造函数,构造函数和析构函数,构造函数和析构函数是在类体中说明的两种特殊的成员函数。 构造函数的功能

13、是在创建对象时给对象分配内存空间 ,并可使用给定值来初始化对象。 析构函数的功能是用来释放一个对象的已分配空间。并可在对象被清除前,完成一些清理工作。 构造函数与析构函数的功能正好是对应的。,构造函数有以下特点: 1)构造函数是类的一个成员函数,但有其特殊性; 2)构造函数的函数名与类名相同,它不能有返回值,即使是void也不行。 3)构造函数可以有参数,也可以没有参数,换句话说,构造函数可以重载; 4)程序一般不直接调用构造函数,在创建对象时会自动调用构造函数,以完成对象的初始化工作。,而析构函数有以下特点: 1)析构函数是类的一个特殊成员函数,一个类中只能有一个析构函数; 2)析构函数的函

14、数名与类名相同,并在前面加上“”; 3)析构函数也不能有返回值,并且也不能有函数参数,换句话说,析构函数不能被重载; 4)析构函数的主要功能是在对象消失时,执行如释放内存等清理工作; 5)在对象消失时,析构函数会被自动调用。,缺省构造函数和缺省析构函数,1、缺省构造函数 C+规定,每个类必须有构造函数,没有构造函数就不能创建对象。 如果在类的定义中,程序员没有设计任何构造函数, C+会自动提供一个缺省的构造函数,它只分配对象的实体空间外。此时,如果创建的是静态对象或全局对象,则对象所有数据成员都初始化为零或空,如果是普通对象,它的值将会是随机的。 缺省构造函数的形式是: 类名:类名() /类体

15、为空 只要在类的定义中提供了任意一个构造函数,那么C+就不再自动提供缺省构造函数。,2、缺省析构函数 如果在类的定义中,程序员没有设计析构函数,C+也会自动提供一个缺省析构函数,格式: 类名:类名() /缺省析构函数体为空,拷贝构造函数,构造函数除可以用基本数据类型初始化对象外,还可以使用已存在的同类型的对象即类类型的对象来初始化正在创建的对象。为此,必须在类中定义一个特殊的构造函数来完成这个工作,这个构造函数被称为拷贝初始化构造函数。 它实现了在初始化时将一个已知对象的数据成员的值拷贝给正在创建的另一个同类的对象。当然,它具有一般构造函数的所有特性。 格式为: :( Y=yy; /构造函数参

16、数设置了缺省值 Point(const Point Point:Point(const Point Y=p.Y; coutCopy_constructor called.n; void main() Point A(10,20); /创建一个对象并传入参数去初始化 Point B(A); /会自动调用拷贝构造函数 coutB:B.GetX(),B.GetY()endl; 程序运行的输出结果: Copy_constructor called. B:10,20,5、成员函数的特性,内联函数和外联函数 成员函数的重载性 设置参数的缺省值,内联函数:指定义在类体内的成员函数。 外联函数:指说明在类体内

17、,定义在类体外的成员函数。 类外定义的函数缺省情况下都是外联函数,用关键字inline可以强制转换。 对于内联函数,不是在调用时才转去执行函数体,而是在编译时对所有调用该函数的地方装入实际的函数代码。节省了调用开销,提高了运行速度。内联函数必须在调用之前进行定义。,外联函数变成内联函数的方法很简单,只需在函数头前加上关键字inline。但是并不是所有外联函数加上inline后就一定会成为内联函数。有以下限制条件: 1)内联函数中,不能含有复杂的结构控制语句,如switch和while。如果内联函数有这些语句,则编译器将该函数视同普通函数那样产生函数调用代码。 2)递归函数不能被用来做内联函数。

18、 3)内联函数只适合于只有15行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数来实现。,一般的成员函数都可以进行重载。构造函数可以,但析构函数不能。(至少参数类型或个数不同) 【例7.11】构造函数的重载。 #include class A public: A( ) /无参构造函数 a=b=0; coutDefault constructor called.n; A(int i,int j) /有参构造函数,重载,成员函数的重载性, a=i, b=j; coutConstructor called.n; void print( ); pri

19、vate: int a,b; ; inline void A:print()/由外联变内联函数 couta=a,b=bendl; void main() A m,n(4,8); m.print(); n.print(); ,程序执行结果如下: Default constructor called. Constructor called. a=0,b=0 a=4,b=8,一般的成员函数可以被设置参数的缺省值。构造函数也可以,但析构函数无参数,也不能。 C+在调用时会根据函数的形参型式配于相应的实参值。,设置参数的缺省值,函数设置参数的缺省值时要避免二义性!,6、对象数组,数组不仅可由简单变量组成

20、,也可由对象组成。如果一个数组中的每一个元素都是由同一个类的若干个对象组成,此数组称为对象数组。 1 、对象数组的定义 对象数组定义格式如下: . 其中,指出该数组元素是属于该类的对象,方括号内的给出某一维的元素个数。一维对象数组只有一个方括号,二维对象数组要有两个方括号,等等,例如: Pointpoints10; 定义一个由10个Point类的对象组成的一维对象数组上。,2 、对象数组的赋值 同普通数组一样,对象数组可以被初始化,也可以被赋值。假设类的定义为: class Point public: Point(int xx=0,int yy=0) X=xx; Y=yy; /构造函数参数设置

21、了缺省值 private: int X,Y; ;,则可定义并初始化对象数组,如下: Pointpoints3= Point(1,2), Point(3,4), Point(5,6); 也可以先定义对象数组,然后再赋值,如: Pointpoints3 points0=Point(1,2); points0=Point(3,4); points0=Point(5,6);,、对象指针数组 在C+中,指针是一个比较复杂的概念,之前已经接触过不少指针的应用。但本节的指向数组的指针和指针数组是两个完全不同的概念。 1. 指向对象数组的指针 我们前面已经学过指向一般数组的指针,它的定义格式如下: (*).

22、其中,用来说明指针的 * 要与括在一起。用一个方括号表示该指针指向一维数组,用二个方括号表示该指针指向二维数组。用来说明指针所指向的数组的元素的类型。,例如: int (*P)3; P是指向一维数组的指针,该数组有3个int型元素。 对于指向对象数组的指针,把改为即可: (*).,、指针数组 如果一个数组的每个元素存放的都是指向某个变量或某个对象的指针(即地址),此数组即为指针数组。如: int * pa3;/存放三个整型指针的指针数组 再如:char * pc25;可存放2个字符串的字符指针数组,每个字符串最多可存放4个字符。 一般在编程中,使用字符型的指针数组用来存放若干个字符串。,、带参

23、数的main( )函数 到现在为止,程序中使用main()函数都没有带参数。在实际编程中,有时需要main()带参数。比如DOS下用copy命令把windows目录下win.ini文件拷贝到D盘根目录,就需要有输入2个参数: C: copy windowswin.ini d: 其中copy是命令,参数1是“windowswin.ini”,参数2是“d:”。 带参数的main()函数格式如下: void main(int argc, char * argv),7、对象指针,1对象指针 是指向对象的指针。如果有一个类Rect,则: Clock clockA;/定义一个对象 Clock *pcloc

24、kA=/用对象指针访问成员函数,2指向函数的指针 函数的入口地址是指函数体内第一条可执行语句的代码在内存中的地址,C+语言中规定函数名代表函数的入口地址。函数指针是专门用来存放函数入口地址的变量。 指向一般函数的指针的定义格式: *() 给指向函数的指针赋值的格式: = 调用指向函数的指针调用函数的格式: (*)(),this指针 this指针是类的一个自动生成、自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象的地址。当一个对象被创建时,该对象的this指针就指向对象数据的首地址。“*this”表示该对象。,8、静态成员,静态数据成员 静态成员函数,1、静态数据成员

25、类是类型而不是数据对象,每个类的对象都是该类数据成员的拷贝。 然而,往往需要让类的所有对象在类的范围内共享某个数据。声明为 static的类成员便能在类的范围中共享,称之为静态成员。 若想在同一个类的多个对象之间共享某个数据。可将该类成员声明 为static,使之成为静态成员。静态成员是在编译时被创建,其空间 只有一个,且与对象是否存在无关,可为所有以后创建的该类对象共 享。并且空间一直保存到程序结束。而一般成员是在对象创建时由构 造函数分配空间,属于具体的某个对象,对象不同则成员空间也不 同,并在函数结束时由析构函数释放对象空间而随之释放。,例如:一个学生类,有一个对应学生总数属的数据成员c

26、ount 则对于每一个已有学生对象而言,一旦现有学生人数变化,那 么已有学生对象中count所保存的数据就不适用,则要对每个 对象逐个修改,显然这是不实际的,而应采用静态成员。,1、静态数据成员在定义或说明时前面加关键字:static。 2、静态数据成员是静态存储的,必须对它进行初始化,其初始化必须在类体外进行,但前面不再加static,也不加访问控制标识符public、private等。 3、由于静态数据成员是类的成员,而不是对象的成员,因此,初始化静态数据成员时,使用作用域运算符(“:”)来标识其所属的类,采用以下格式初始化: 数据类型 类名:静态数据成员名=值; 4、可按如下格式使用静态

27、数据成员: 类名:静态数据成员名,2、静态成员函数 与静态数据成员一样,静态成员函数也是属于类的,而不 依赖对象而存在,即为所有对象共有的。因此,静态成员函数 没有this指针。使用时,通过类名(而不是对象名)进行引用。 【例7.24】类中包含静态成员函数的使用示例。 #include class M public: M(int a) A=a; B+=a; /构造函数,内联 static void f1(M m);/静态成员函数 static int B;/静态数据成员 private: int A; ;,int M:B=0;/静态数据成员初始化 void M:f1(M m) coutA=m.

28、Aendl; /必须通过对象才能引用一般数据成员 coutB=Bendl; /直接引用静态数据成员 void main() coutValue B: M:Bendl; /注意此时对象还没有建立! M P(5),Q(10); /建立对象P、Q M:f1(P); /通过类调用静态成员函数 M:f1(Q); coutValue B: M:Bendl;/可见,B不依赖对象! ,程序输出结果: Value B: 0 A=5 B=15 A=10 B=15 Value B: 15 程序分析:见代码注释。其中特别要注意,静态成员函数可以直接引用静态成员,但不能直接引用非静态数据成员,必须通过象来引用类中的非静

29、态成员。如本例中: coutA=m.Aendl; /通过对象使用一般数据成员 coutB=Bendl; /直接使用静态数据成员,9、常对象,1、常对象 常对象是指用const修饰的对象。定义常对象时,同样要进行初始化,并且以后该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。 定义格式如下: const 或者 const ,例如: class M public: M(int a) A=a; B+=a; void f1(int x); private: int A,B; ; const M obj1(10,20) ; M const obj2(30,40) ; 其中obj

30、1 和obj2都是常对象,以后不能被更新。,2、常数据成员 如果某个数据成员的值是不应该被修改的,可以用const声明为常数据成员,它受到强制保护,以防止被意外改动。对于常数据成员,在任何函数中都不能对它赋值,也不能更新。因此必须对它进行初始化,而且只能通过成员初始化列表的方式进行初始化。,3、常成员函数 常成员函数说明格式如下: () const; 其中,const是加在函数说明后面的类型修饰符,它也是函数类型的一个组成部分,因此在函数实现部分必须要带const关键字。 特别注意:只有常成员函数才能操作常量或常对象,非常成员函数不能用来操作常对象。,4、对象的常引用 对象常引用是指所引用的对象不能被更新,它也一般做为函数的形参来使用。 定义格式如下: c

温馨提示

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

评论

0/150

提交评论