面向对象程序设计中的概念.ppt

上传人:牧羊曲112 文档编号:6034431 上传时间:2023-09-16 格式:PPT 页数:125 大小:505.50KB
返回 下载 相关 举报
面向对象程序设计中的概念.ppt_第1页
第1页 / 共125页
面向对象程序设计中的概念.ppt_第2页
第2页 / 共125页
面向对象程序设计中的概念.ppt_第3页
第3页 / 共125页
面向对象程序设计中的概念.ppt_第4页
第4页 / 共125页
面向对象程序设计中的概念.ppt_第5页
第5页 / 共125页
点击查看更多>>
资源描述

《面向对象程序设计中的概念.ppt》由会员分享,可在线阅读,更多相关《面向对象程序设计中的概念.ppt(125页珍藏版)》请在三一办公上搜索。

1、1,1.对象客观世界中任何一个事物都可以看成一个对象(object)。对象可大可小。对象是构成系统的基本单位。一个对象往往是由一组属性和一组行为构成的。2.封装与信息隐蔽面向对象程序设计方法的一个重要特点就是“封装性”(encapsulation),所谓“封装”,指两方面的含义:一、将有关的数据和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相对独立,互不干扰。二、将对象中某些部分对外隐蔽,即隐蔽其内部细节,只留下少量接口,以便与外界联系,接收外界的消息。信息隐蔽还有利于数据安全,防止无关的人了解和修改数据。,面向对象程序设计中的概念,2,3.抽象在程序设计方法中,常用到抽象(abs

2、traction)这一名词。抽象的过程是将有关事物的共性归纳、集中的过程。抽象的作用是表示同一类事物的本质。C+中的类就是对一批具体的数的抽象。类是对象的抽象,而对象则是类的特例,或者说是类的具体表现形式。4.继承与重用如果在软件开发中已经建立了一个名为A的“类”,又想另外建立一个名为B的“类”,而后者与前者内容基本相同,只是在前者的基础上增加一些属性和行为,只需在类A的基础上增加一些新内容即可。这就是面向对象程序设计中的继承机制。利用继承可以简化程序设计的步骤。C+提供了继承机制,采用继承的方法可以很方便地利用一个已有的类建立一个新的类。这就是常说的“软件重用”的思想。,3,5.多态性如果有

3、几个相似而不完全相同的对象,有时人们要求在向它们发出同一个消息时,它们的反应各不相同,分别执行不同的操作。这种情况就是多态现象。如,在Windows环境下,用鼠标双击一个文件对象(这就是向对象传送一个消息),如果对象是一个可执行文件,则会执行此程序,如果对象是一个文本文件,则启动文本编辑器并打开该文件。在C+中,所谓多态性(polymorphism)是指:由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性。,4,传统的面向过程程序设计是围绕功能进行的,用一个函数实现一个功能。所有的数据都是公用的,一个函数可以使用任何一组数

4、据,而一组数据又能被多个函数所使用(见图8.3)。,面向对象程序设计的特点,5,面向对象程序设计采取的是另外一种思路。程序设计者的任务包括两个方面:一是设计所需的各种类和对象,即决定把哪些数据和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。这时它如同一个总调度,不断地向各个对象发出命令,让这些对象活动起来(或者说激活这些对象),完成自己职责范围内的工作。各个对象的操作完成了,整体任务也就完成了。显然,对一个大型任务来说,面向对象程序设计方法是十分有效的,它利用代码的重用,大大降低程序设计人员的工作难度,减少出错机会。,6,类是C+中十分重要的概念,它是实现面向对象程序设计的

5、基础。类是所有面向对象的语言的共同特征,所有面向对象的语言都提供了这种类型。一个有一定规模的C+程序是由许多类所构成的。面向对象的软件工程是面向对象方法在软件工程领域的全面应用。它包括:面向对象的分析(OOA)面向对象的设计(OOD)面向对象的编程(OOP)Object-Oriented Programming面向对象的测试(OOT)面向对象的软件维护(OOSM),类和对象的作用,7,类是用户自己定义的类型。如果程序中要用到类类型,必须自己根据需要进行声明,或者使用别人已设计好的类。类(class)就是对象的类型。类是一种广义的数据类型。类这种数据类型中的数据既包含数据,也包含操作数据的函数。

6、不能把类中的全部成员与外界隔离,一般是把数据隐蔽起来,而把成员函数作为对外界的接口。class Student/声明类类型 private:/声明以下部分为私有的int num;char name20;char sex;public:/声明以下部分为公用的void display()coutnum:numendl;coutname:nameendl;coutsex:sexendl;Student stud1,stud2;/定义了两个Student 类的对象,声明类类型,8,类的成员函数(简称类函数)是函数的一种,它的用法和作用和函数基本上是一样的,它也有返回值和函数类型。它与一般函数的区别只是

7、:它是属于一个类的成员,出现在类体中。一般的做法是将需要被外界调用的成员函数指定为public,它们是类的对外接口。注意,并非要求把所有成员函数都指定为public。有的函数并不是准备为外界调用的,而是为本类中的成员函数所调用的,就应该将它们指定为private。这种函数的作用是支持其他函数的操作,是类中其他成员的工具函数(utility function),类外用户不能调用这些私有的工具函数。类的成员函数是类体中十分重要的部分。如果一个类中不包含成员函数,就等同于C语言中的结构体了,体现不出类在面向对象程序设计中的作用。,类的成员函数成员函数的性质,9,在前面的成员函数是在类体中定义的。也可

8、以在类体中只写成员函数的声明,而在类的外面进行函数定义。如:class Student public:void display();/公用成员函数原型声明 private:int num;string name;char sex;/以上3行是私有数据成员;void Studentdisplay()/在类外定义display类函数 coutnum:numendl;/函数体 coutname:nameendl;coutsex:sexendl;Student stud1,stud2;/定义两个类对象注意:成员函数在类外定义时,必须在函数名前面加上类名,予以限定(qualifed),“”是作用域运算符

9、,用它声明函数是属于哪个类的。,在类外定义成员函数,10,用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如图所示。,成员函数的存储方式,11,能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码。如图所示。显然,这样做会大大节约存储空间。C+编译系统正是这样做的,因此每个对象所占用的存储空间只是该对象的数据部分所占用的存储空间,而不包括函数代码所占用的存储空间。,12,例:8-1-(1).c

10、pp,#includeiostreamusing namespace std;class Timepublic:int hour;int minute;int sec;void set();void Time:set()cinhourminutesec;int main()Time t1,t2;coutsizeof(Time)endl;coutsizeof(t1)endl;coutsizeof(t1)endl;return 0;,13,C+通过类来实现封装性,把数据和与这些数据有关的操作封装在一个类中。公用成员函数是用户使用类的公用接口,或称类的对外接口。类中被操作的数据是私有的,实现的细节对

11、用户是隐蔽的,这种实现称为私有实现(private implementation)。这种“类的公用接口与私有实现的分离”形成了信息隐蔽。软件工程的一个最基本的原则就是将接口与实现分离,它的好处在于:(1)如果想修改或扩充类的功能,只需修改本类中有关的数据成员和与它有关的成员函数,程序中类外的部分可以不必修改。(2)如果在编译时发现类中的数据读写有错,不必检查整个程序,只需检查本类中访问这些数据的少数成员函数。,类的封装性和信息隐蔽 公用接口与私有实现的分离,14,在面向对象的程序开发中,一般做法是将类的声明放在指定的头文件中,用户如果想用该类,只要把有关的头文件包含进来即可,不必在程序中重复书

12、写类的声明,提高编程的效率。由于在头文件中包含了类的声明,因此在程序中就可以用该类来定义对象。由于在类体中包含了对成员函数的声明,在程序中就可以调用这些对象的公用成员函数。为了实现信息隐蔽,对类成员函数的定义一般不放在头文件中,而另外放在一个文件中。,类声明和成员函数定义的分离,15,/student.h(头文件可以包括:外部变量声明、函数原型声明、类声明、常量声明、内联函数和typedef声明,该头文件则进行类的声明)class Student/类声明 public:void display();/公用成员函数原型声明private:int num;char name20;char sex;

13、/student.cpp/在此文件中进行函数的定义#include#include“student.h”/不要漏写此行,否则编译通不过Using namespace std;void Studentdisplay()/在类外定义display类函数coutnum:numendl;coutname:nameendl;coutsex:sexendl;,类声明和成员函数定义的分离,16,为了组成一个完整的源程序,还应当有包括主函数的源文件:/main.cpp 主函数模块/#include#include“student.h”/将类声明头文件包含进来/using namespace std;int m

14、ain()Student stud;/定义对象 stud.display();/执行stud对象的display函数 return 0;这是一个包括3个文件的程序,组成两个文件模块:一个是主模块main.cpp,一个是student.cpp。在主模块中又包含头文件student.h。在预编译时会将头文件student.h中的内容取代#include student.h行。,17,请注意:由于将头文件student.h放在用户当前目录中,因此在文件名两侧用双撇号包起来(student.h)而不用尖括号(),否则编译时会找不到此文件。,18,由于要求接口与实现分离,为软件开发商向用户提供类库创造了

15、很好的条件。开发商把用户所需的各种类的声明按类放在不同的头文件中,同时对包含成员函数定义的源文件进行编译,得到成员函数定义的目标代码。软件商向用户提供这些头文件和类的实现的目标代码(不提供函数定义的源代码)。用户在使用类库中的类时,只需将有关头文件包含到自己的程序中,并且在编译后连接成员函数定义的目标代码即可。由于类库的出现,用户可以像使用零件一样方便地使用在实践中积累的通用的或专用的类,这就大大减少了程序设计的工作量,有效地提高了工作效率。,19,在面向对象程序理论中,“方法”是指对数据的操作。一个“方法”对应一种操作。显然,只有被声明为公用的方法(成员函数)才能被对象外界所激活。外界是通过

16、发“消息”来激活有关方法的。所谓“消息”,其实就是一个命令,由程序语句来实现。stud.display();就是向对象stud发出的一个“消息”,通知它执行其中的display“方法”(即display函数)。上面这个语句涉及3个术语:对象、方法和消息。stud是对象,display()是方法,语句“stud.display();”是消息。,面向对象程序设计中的几个名词,20,例8.3 将程序用含成员函数的类来处理。#include using namespace std;class Timepublic:void set_time();/公用成员函数void show_time();/公用成

17、员函数 private:/数据成员为私有int hour;int minute;int sec;int main()Time t1;/定义对象t1 t1.set_time();/调用对象t1的成员函数set_time,向t1的数据成员输入数据 t1.show_time();/调用对象t1的成员函数show_time,输出t1的数据成员的值 Time t2;/定义对象t2,类和对象的简单应用举例,21,t2.set_time();/调用对象t2的成员函数set_time,向t2的数据成员输入数据 t2.show_time();/调用对象t2的成员函数show_time,输出t2的数据成员的值 r

18、eturn 0;void Timeset_time()/在类外定义set_time函数 cinhour;cinminute;cinsec;void Timeshow_time()/在类外定义show_time函数 couthour:minute:secendl;,22,例8.4 找出一个整型数组中的元素的最大值。这个问题可以不用类的方法来解决,现在用类来处理,读者可以比较不同方法的特点。#include using namespace std;class Array_max/声明类public:/以下3行为成员函数原型声明void set_value();/对数组元素设置值void max_v

19、alue();/找出数组中的最大元素void show_value();/输出最大值private:int array10;/整型数组int max;/max用来存放最大值;void Array_max:set_value()/成员函数定义,向数组元素输入数值 int i;for(i=0;iarrayi;,23,void Array_max:max_value()/成员函数定义,找数组元素中的最大值 int i;max=array0;for(i=1;imax)max=arrayi;void Array_max:show_value()/成员函数定义,输出最大值 cout“max=”maxend

20、l;int main()Array_max arrmax;/定义对象arrmax arrmax.set_value();/调用arrmax的set_value函数,向数组元素输入数值 arrmax.max_value();/调用arrmax的max_value函数,找出数组元素中的最大值 arrmax.show_value();/调用arrmax的show_value函数,输出数组元素中的最大值 return 0;/运行结果如下:12 12 39-34 17 134 045-91 76(输入10个元素的值)max=134(输入10个元素中的最大值),24,C+提供了构造函数(construct

21、or)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数的名字必须与类名同名,而不能由用户任意命名,以便编译系统能识别它并把它作为构造函数处理。它不具有任何类型,不返回任何值。构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数。,构造函数的作用,25,例9.1 在例8.3基础上定义构造成员函数。#include using namespace std;class Timepublic:Time()/定义构造成员函数,函数名与类名相同 hour=0;/利用构造函数对对象中的数据成员赋初值 minute=

22、0;sec=0;void set_time();/函数声明void show_time();/函数声明private:int hour;/私有数据成员int minute;int sec;,26,void Timeset_time()/定义成员函数,向数据成员赋值cinhour;cinminute;cinsec;void Timeshow_time()/定义成员函数,输出数据成员的值 couthour:minute:secendl;int main()Time t1;/建立对象t1,同时调用构造函数t1.Time()t1.set_time();/对t1的数据成员赋值 t1.show_time(

23、);/显示t1的数据成员的值 Time t2;/建立对象t2,同时调用构造函数t2.Time()t2.show_time();/显示t2的数据成员的值 return 0;/程序运行的情况为:10 25 54(从键盘输入新值赋给t1的数据成员)10:25:54(输出t1的时、分、秒值)0:0:0(输出t2的时、分、秒值),27,有关构造函数的使用,有以下说明:(1)在类对象进入其作用域时调用构造函数,因此主函数中不需要指定调用构造函数,这是它和一般函数的一个重要的不同之点;(2)构造函数不需用户调用,也不能被用户调用;(3)构造函数没有返回值;(4)如果用户自己没有定义构造函数,则C+系统会自动

24、生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。,28,例9.2 有两个长方柱,其长、宽、高分别为:(1)12,20,25;(2)15,30,21。求它们的体积。#include using namespace std;class Boxpublic:Box(int,int,int);/声明带参数的构造函数 int volume();/声明计算体积的函数 private:int height;int width;int length;BoxBox(int h,int w,int len)/在类外定义带参数的构造函数 height=h;width=w;length

25、=len;int Boxvolume()/定义计算体积的函数 return(height*width*length);,带参数的构造函数,29,int main()Box box1(12,25,30);/建立对象box1,并指定box1长、宽、高的值 coutThe volume of box1 is box1.volume()endl;Box box2(15,30,21);/建立对象box2,并指定box2长、宽、高的值 coutThe volume of box2 is box2.volume()endl;return 0;程序运行结果如下:The volume of box1 is 90

26、00The volume of box2 is 9450可以知道:(1)带参数的构造函数中的形参,其对应的实参在定义对象时给定。(2)用这种方法可以方便地实现对不同的对象进行不同的初始化。,30,C+还提供另一种初始化数据成员的方法参数初始化表来实现对数据成员的初始化。这种方法不在函数体内对数据成员初始化,而是在函数首部实现。例如例9.2中定义构造函数可以改用以下形式:BoxBox(int h,int w,int len):height(h),width(w),length(len)这种写法方便、简练,尤其当需要初始化的数据成员较多时更显其优越性。甚至可以直接在类体中(而不是在类外)定义构造函

27、数。,用参数初始化表对数据成员初始化,31,例9.3在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法,供用户选用。#include using namespace std;class Boxpublic:Box();/声明一个无参的构造函数 Box(int h,int w,int len):height(h),width(w),length(len)/声明一个有参的构造函数,用参数的初始化表对数据成员初始化 int volume();private:int height;int width;int length;BoxBox()/定义一个无参的构造函数height=10;wi

28、dth=10;length=10;,构造函数的重载,32,int Boxvolume()return(height*width*length);int main()Box box1;/建立对象box1,不指定实参coutThe volume of box1 is box1.volume()endl;Box box2(15,30,25);/建立对象box2,指定3个实参coutThe volume of box2 is box2.volume()endl;return 0;/结果:The volume of box1 is 1000 The volume of box2 is 11250在本程序

29、中定义了两个重载的构造函数,其实还可以定义其他重载构造函数,其原型声明可以为BoxBox(int h);/有1个参数的构造函数BoxBox(int h,int w);/有两个参数的构造函数在建立对象时分别给定1个参数和2个参数。,33,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。#include using namespace std;class Boxpublic:Box(int h=10,int w=10,int len=10);/在声明构造函数时指定默认参数 int volume();private:int height

30、;int width;int length;BoxBox(int h,int w,int len)/在定义函数时可以不指定默认参数height=h;width=w;length=len;,默认参数的构造函数简化构造函数数,34,int Boxvolume()return(height*width*length);int main()Box box1;/没有给实参 coutThe volume of box1 is box1.volume()endl;Box box2(15);/只给定一个实参coutThe volume of box2 is box2.volume()endl;Box box3

31、(15,30);/只给定2个实参coutThe volume of box3 is box3.volume()endl;Box box4(15,30,20);/给定3个实参coutThe volume of box4 is box4.volume()endl;return 0;/程序运行结果为:The volume of box1 is 1000 The volume of box2 is 1500 The volume of box3 is 4500 The volume of box4 is 9000,35,析构函数(destructor)也是一个特殊的成员函数,它的作用与构造函数相反,它

32、的名字是类名的前面加一个“”符号。当对象的生命期结束时,会自动执行析构函数。具体地说如果出现以下几种情况,程序就会执行析构函数:如果在一个函数中定义了一个对象(它是自动局部对象),当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。如果定义了一个全局对象,则在程序的流程离开其作用域时(如main函数结束或调用exit函数)时,调用该全局对象的析构函数。如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。它撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。,析构函数,36,析构函数不返回任何值,没有函数

33、类型,也没有函数参数。它不能被重载。一个类可以有多个构造函数,但只能有一个析构函数。一般情况下,类的设计者应当在声明类的同时定义析构函数,以指定如何完成“清理”的工作。如果用户没有定义析构函数,C+编译系统会自动生成一个析构函数,但它只是徒有析构函数的名称和形式,实际上什么操作都不进行。想让析构函数完成任何工作,都必须在定义的析构函数中指定。,37,例9.5 包含构造函数和析构函数的C+程序。#include#includeusing namespace std;class Student/声明Student类public:student(int n,string nam,char s)/定义

34、构造函数num=n;name=nam;sex=s;coutConstructor called.endl;/输出有关信息Student()/定义析构函数coutDestructor called.endl;/输出有关信息void display()/定义成员函数coutnum:numendl;coutname:nameendl;coutsex:sexendlendl;,38,private:int num;char name10;char sex;int main()Student stud1(10010,Wang_li,f);/建立对象stud1stud1.display();/输出学生1的

35、数据 Student stud2(10011,Zhang_fun,m);/定义对象stud2stud2.display();/输出学生2的数据return 0;程序运行结果如下:Constructor called.(执行stud1的构造函数)num:10010(执行stud1的display函数)name:Wang_lisex:fConstructor called.(执行stud2的构造函数)num:10011(执行stud2的display函数)name:Zhang_funsex:mDestructor called.(执行stud2的析构函数)Destructor called.(执行

36、stud1的析构函数),39,在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。如图9.1示意。,调用构造函数和析构函数的顺序,40,说明:在建立数组时,同样要调用构造函数。如果有50个元素,需要调用50次构造函数。例9.6 对象数组的使用方法。#include using namespace std;class Boxpublic:Box(int h=10,int w=12,int len=15):height(h),width(w),length(len)/声明

37、有默认参数的构造函数,用参数初始化表对数据成员初始化 int volume();private:int height;int width;int length;int Boxvolume()return(height*width*length);,对象数组,41,int main()Box a3=/定义对象数组 Box(10,12,15),/调用构造函数Box,提供第1个元素的实参 Box(15,18,20),/调用构造函数Box,提供第2个元素的实参 Box(16,20,26)/调用构造函数Box,提供第3个元素的实参;coutvolume of a0 is a0.volume()endl;

38、/调用a0的volume函数coutvolume of a1 is a1.volume()endl;/调用a1 的volume函数coutvolume of a2 is a2.volume()endl;/调用a2 的volume函数运行结果如下:volume of a0 is 1800volume of a1 is 5400volume of a2 is 8320,42,既要使数据能在一定范围内共享,又要保证它不被任意修改,这时可以使用const,即把有关的数据定义为常量。常对象 凡希望保证数据成员不被改变的对象,可以声明为常对象。const Time t1(10,15,36);/定义常对象t

39、1Time const t1(10,15,36);/定义常对象t1 常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据成员的值。void get_time()const;/将函数声明为const 常数据成员,常数据成员的值是不能改变的。const int hour;/声明hour为常数据成员不能采用在构造函数中对常数据成员赋初值的方法。,共用数据的保护,43,多个对象之间可以互相赋值,或者说,一个对象的值可以赋给另一个同类的对象。对象之间的赋值也是通过赋值运算符“=”进行的。实际这个过程是通过对象的复制来完成的,即将一个对象的成员值一一复制给另一对象的对应成员。对象名1和对象名

40、2必须属于同一个类。Student stud1,stud2;/定义两个同类的对象 stud2=stud1;/将stud1赋给stud2有时需要用到多个完全相同的对象。如:Box box2=box1,box3=box2;/按box1来复制box2和box3。有时需要将对象在某一瞬时的状态保留下来。这也是对象的复制机制。用一个已有的对象快速地复制出多个完全相同的对象。如:Box box2(box1);/其作用是用已有的对象box1去克隆出一个新对象box2。,对象的赋值和复制,44,可以看到:它与前面介绍过的定义对象方式类似,但是括号中给出的参数不是一般的变量,而是对象。在建立对象时调用一个特殊的

41、构造函数复制构造函数(copy constructor)。这个函数的形式是这样的:/The copy constructor definition.BoxBox(const Box复制构造函数也是构造函数,但它只有一个参数,这个参数是本类的对象(不能是其他类的对象),而且采用对象的引用的形式(一般约定加const声明,使参数值不能改变,以免在调用此函数时因不慎而使对象值被修改)。,45,请注意普通构造函数和复制构造函数的区别。(1)在形式上类名(形参表列);/普通构造函数的声明,如Box(int h,int w,int len);类名(类名/实参是对象名,调用复制构造函数(3)在什么情况下被调

42、用普通构造函数在程序中建立对象时被调用。复制构造函数在用已有对象复制一个新对象时被调用,在以下3种情况下需要克隆对象:,46,程序中需要新建立一个对象,并用另一个同类的对象对它初始化:Box box2(box1);/实参是对象名,调用复制构造函数Box box2=box1;/调用复制构造函数 当函数的参数为类的对象时。在调用函数时需要将实参对象完整地传递给形参,也就是需要建立一个实参的拷贝,这就是按实参复制一个形参,系统是通过调用复制构造函数来实现的,这样能保证形参具有和实参完全相同的值。如 void fun(Box b)/形参是类的对象 int main()Box box1(12,15,18

43、);fun(box1);/实参是类的对象,调用函数时将复制一个新对象breturn 0;,47,函数的返回值是类的对象。在函数调用完毕将返回值带回函数调用处时。此时需要将函数中的对象复制一个临时对象并传给该函数的调用处。如 Box f()/函数f的类型为Box类类型Box box1(12,15,18);return box1;/返回值是Box类的对象int main()Box box2;/定义Box类的对象box2 box2=f();/调用f函数,返回Box类的临时对象,并将它赋值给box2 以上几种调用复制构造函数都是由编译系统自动实现的,不必由用户自己去调用,读者只要知道在这些情况下需要调

44、用复制构造函数就可以了。,48,如果想在同类的多个对象之间实现数据共享,不要用全局对象,可以用静态的数据成员。静态数据成员是一种特殊的数据成员。它以关键字static开头。例如class Boxpublic:int volume();private:static int height;/把height定义为静态的数据成员int width;int length;如果希望各对象中的height的值是一样的,就可以把它定义为静态数据成员,这样它就为各对象所共有,而不只属于某个对象的成员。,静态数据成员,49,所有对象都可以引用它。静态的数据成员在内存中只占一份空间。每个对象都可以引用这个静态数据成

45、员。静态数据成员的值对所有对象都是一样的。如果改变它的值,则在各对象中这个数据成员的值都同时改变了。这样可以节约空间,提高效率。例9.10 引用静态数据成员。#include using namespace std;class Boxpublic:Box(int,int);int volume();static int height;/把height定义为公用的静态的数据成员Private:int width;int length;BoxBox(int w,int len)/通过构造函数对width和length赋初值width=w;length=len;,50,int Boxvolume()

46、return(height*width*length);int Boxheight=10;/数据类型类名静态数据成员名=初值;int main()Box a(15,20),b(20,30);couta.heightendl;/通过对象名a引用静态数据成员coutb.heightendl;/通过对象名b引用静态数据成员coutBoxheightendl;/通过类名引用静态数据成员couta.volume()“”b.volume()endl;/调用volume函数,输出计算体积/10 10 10 3000 60003个输出语句的输出结果相同(都是10)。这就验证了所有对象的静态数据成员实际上是同一

47、个数据成员。,51,(1)在定义对象时,才为对象的数据成员分配空间。但是静态数据成员不属于某一个对象,在为对象所分配的空间中不包括静态数据成员所占的空间。静态数据成员是在所有对象之外单独开辟空间。(2)静态数据成员不随对象的建立而分配空间,也不随对象的撤销而释放。静态数据成员是在程序编译时被分配空间的,到程序结束时才释放空间。(3)静态数据成员可以初始化,但只能在类体外进行初始化。如int Boxheight=10;/表示对Box类中的数据成员初始化不必在初始化语句中加static。(4)静态数据成员既可以通过对象名引用,也可以通过类名来引用。(5)有了静态数据成员,各对象之间的数据有了沟通的

48、渠道,实现数据共享,因此可以不使用全局变量。全局变量破坏了封装的原则,不符合面向对象程序的要求。,52,在一个类中可以有公有的(public)成员和私有的(private)成员。在类外可以访问公有成员,只有本类中的函数可以访问本类的私有成员。但有一个例外友元(friend)。如果在本类以外的其他地方定义了一个函数这个函数可以是不属于任何类的普通函数也可以是其他类的成员函数在本类体中用friend对其进行声明,此函数就称为本类的友元函数。友元可以访问与其有好友关系的类中的私有成员。,友元,53,1.将普通函数声明为友元函数例9.12 友元函数的简单例子。#include using namesp

49、ace std;class Timepublic:Time(int,int,int);friend void display(Time,友元函数,54,TimeTime(int h,int m,int s)/构造函数,给hour,minute,sec赋初值 hour=h;minute=m;sec=s;void display(Time 类中友元函数被注释,这输出出错,提示无法访问私有数据,55,2.友元,56,class Date/声明Date类public:Date(int,int,int);friend void Timedisplay(Date,57,DateDate(int m,int

50、 d,int y)/类Date的构造函数month=m;day=d;year=y;void Timedisplay(Date 运行时输出:12/25/2010(输出Date类对象d1中的私有数据)10:13:56(输出Time类对象t1中的私有数据),58,友元的规则:(1)友元的关系是单向的而不是双向的。(2)友元的关系不能传递。一般并不把整个类声明为友元类,而只将确实有需要的成员函数声明为友元函数,这样更安全一些。友元的利弊:面向对象程序设计的一个基本原则是封装性和信息隐蔽,而友元却可以访问其他类中的私有成员,不能不说这是对封装原则的一个小的破坏。但是它的好处在于能有助于数据共享,能提高程

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号