




已阅读5页,还剩64页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章怎样使用类和对象,9.1利用构造函数对类对象进行初始化9.2析构函数9.3调用构造函数和析构函数的顺序9.4对象数组9.5对象指针9.6共用数据的保护9.7对象的动态建立和释放9.8对象的赋值和复制9.9静态成员9.10友元9.11类模板,9.1利用构造函数对类对象进行初始化,9.1.1对象的初始化,在建立一个对象时,常常需要作某些初始化的工作,例如对数据成员赋初值。如果一个数据成员未被赋值,则它的值是不可预知的。注意:类的数据成员是不能在声明类时初始化的。classTimepublic:/声明为公用成员hour=0;/错:类的数据成员不能在定义时初始化minute=0;/错:类的数据成员不能在定义时初始化sec=0;/错:类的数据成员不能在定义时初始化;,如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成员进行初始化。如classTimepublic:/声明为公用成员hour;minute;sec;Timet1=14,56,30;/将t1初始化为14:56:30但是,如果数据成员是私有的,或者类中有private或protected的成员,就不能用这种方法初始化。,structStudent/结构声明intnum;charname20;floatscore;;Studentstu1=1001,“zhangsan”,89;/对,定义结构体变量时同时初始化,对结构体,其成员默认是public,structStudent/结构声明private:intnum;charname20;floatscore;;Studentstu1=1001,“zhangsan”,89;/错,错:不能对私有成员初始化,Student类,classStudent/类声明private:intnum;charname20;floatscore;public:voiddisplay()coutnum:numendl;coutname:nameendl;coutscore:scoreendl;,数据成员是私有的,本类外不能直接访问,Studentstu1=1001,”zhangsan”,89;/定义对象并初始化?不能!,C+提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数的名字必须与类名同名,而不能由用户任意命名,以便编译系统能识别它并把它作为构造函数处理。它不具有任何类型,不返回任何值。构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数。,9.1.2构造函数的作用,创建Student类的构造函数,#includeusingnamespacestd;classStudentprivate:intnum;charname20;floatscore;public:Student(intn,char*p,floats);/构造函数的声明voiddisplay();Student:Student(intn,char*p,floats)/构造函数的定义num=n;strcpy(name,p);score=s;,创建Student类的构造函数,voidStudent:display()coutdisplay:endl;coutnum:numendl;coutname:nameendl;coutscore:scoreendl;intmain()Studentstu1(1001,zhangsan,89);stu1.display();return0;,在建立对象stu1时,系统自动调用构造函数一次:Student(1001,zhangsan,89)将初始值存储到对象stu1中。,#includeusingnamespacestd;classStudentprivate:intnum;charname20;floatscore;public:Student(intn,char*p,floats);/构造函数的声明voiddisplay();Student:Student(intn,char*p,floats)/构造函数的定义num=n;strcpy(name,p);score=s;,构造函数代码与input()函数相同,input(intn,char*p,floats);/输入函数的声明,Student:input(intn,char*p,floats)/输入函数的定义,voidStudent:display()coutdisplay:endl;coutnum:numendl;coutname:nameendl;coutscore:scorehour;cinminute;cinsec;voidTimeshow_time()/定义成员函数,输出数据成员的值couthour:minute:secendl;intmain()Timet1;/建立对象t1,同时调用构造函数t1.Time()t1.set_time();/对t1的数据成员赋值t1.show_time();/显示t1的数据成员的值Timet2;/建立对象t2,同时调用构造函数t2.Time()t2.show_time();/显示t2的数据成员的值return0;,程序运行的情况为:102554(从键盘输入新值赋给t1的数据成员)10:25:54(输出t1的时、分、秒值)0:0:0(输出t2的时、分、秒值),也可以只在类内对构造函数进行声明而在类外定义构造函数。,classTimepublic:Time()hour=0;minute=0;sec=0;voidset_time();voidshow_time();private:inthour;intminute;intsec;,classTimepublic:Time();voidset_time();voidshow_time();private:inthour;intminute;intsec;Time:Time()hour=0;minute=0;sec=0;,在例9.1中构造函数不带参数,在函数体中对数据成员赋初值。这种方式使该类的每一个对象都得到同一组初值(例如例9.1中各数据成员的初值均为0)。但是有时用户希望对不同的对象赋予不同的初值。可以采用带参数的构造函数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现不同的初始化。构造函数首部的一般格式为构造函数名(类型1形参1,类型2形参2,)前面已说明:用户是不能调用构造函数的,因此无法采用常规的调用函数的方法给出实参。实参是在定义对象时给出的。定义对象的一般格式为类名对象名(实参1,实参2,);,9.1.3带参数的构造函数,有两个长方柱,其长、宽、高分别为:(1)12,20,25;(2)10,14,20。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。#includeusingnamespacestd;classBoxpublic:Box(int,int,int);/声明带参数的构造函数intvolume();/声明计算体积的成员函数private:intheight;intwidth;intlength;BoxBox(inth,intw,intlen)/在类外定义带参数的构造函数height=h;width=w;length=len;,/例9.2,intBoxvolume()/定义计算体积的成员函数return(height*width*length);intmain()Boxbox1(12,25,30);/建立对象box1,并指定box1长、宽、高的值coutThevolumeofbox1isbox1.volume()endl;Boxbox2(15,30,21);/建立对象box2,并指定box2长、宽、高的值coutThevolumeofbox2isbox2.volume()endl;return0;程序运行结果如下:Thevolumeofbox1is9000Thevolumeofbox2is9450,/例9.2,在9.1.3节中介绍的是在构造函数的函数体内通过赋值语句对数据成员实现初始化。C+还提供另一种初始化数据成员的方法参数初始化表来实现对数据成员的初始化。这种方法不在函数体内对数据成员初始化,而是在函数首部实现。例如例9.2中定义构造函数可以改用以下形式:BoxBox(inth,intw,intlen):height(h),width(w),length(len)类名:构造函数名(参数表):成员初始化表构造函数体这种写法方便、简练,尤其当需要初始化的数据成员较多时更显其优越性。甚至可以直接在类体中(而不是在类外)定义构造函数。,9.1.4用参数初始化表对数据成员初始化,classBoxpublic:Box(int,int,int);intvolume();private:intheight;intwidth;intlength;BoxBox(inth,intw,intlen)height=h;width=w;length=len;赋值语句对数据成员实现初始化,classBoxpublic:Box(int,int,int);intvolume();private:intheight;intwidth;intlength;BoxBox(inth,intw,intlen):height(h),width(w),length(len)参数初始化表实现对数据成员的初始化,在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法,供用户选用。这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。这称为构造函数的重载。在第4章第4.8节中所介绍的函数重载的知识也适用于构造函数。,9.1.5构造函数的重载,例9.3在例9.2的基础上,定义两个构造函数,其中一个无参数,一个有参数。#includeusingnamespacestd;classBoxpublic:Box();/声明一个无参的构造函数Box(inth,intw,intlen):height(h),width(w),length(len);/声明一个有参的构造函数,用参数的初始化表对数据成员初始化intvolume();private:intheight;intwidth;intlength;BoxBox()/定义一个无参的构造函数height=10;width=10;length=10;,intBoxvolume()return(height*width*length);intmain()Boxbox1;/建立对象box1,不指定实参coutThevolumeofbox1isbox1.volume()endl;Boxbox2(15,30,25);/建立对象box2,指定3个实参coutThevolumeofbox2isbox2.volume()endl;return0;,说明:(1)在建立对象时不必给出实参的构造函数,称为默认构造函数(defaultconstructor)。显然,无参的构造函数属于默认构造函数。一个类只能有一个默认构造函数。(2)如果在建立对象时选用的是无参构造函数,应注意正确书写定义对象的语句:类名对象名;(3)尽管在一个类中可以包含多个构造函数,但是对于每一个对象来说,建立对象时只执行其中一个构造函数,并非每个构造函数都被执行。,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。在第4章第4.10节中介绍过在函数中可以使用有默认值的参数。在构造函数中也可以采用这样的方法来实现初始化。,9.1.6使用默认参数的构造函数,例9.4将例9.3程序中的构造函数改用含默认值的参数,长、宽、高的默认值均为10#includeusingnamespacestd;classBoxpublic:Box(inth=10,intw=10,intlen=10);/在声明构造函数时指定默认参数intvolume();private:intheight;intwidth;intlength;BoxBox(inth,intw,intlen)/在定义函数时可以不指定默认参数height=h;width=w;length=len;,intBoxvolume()return(height*width*length);intmain()Boxbox1;/没有给实参coutThevolumeofbox1isbox1.volume()endl;Boxbox2(15);/只给定一个实参coutThevolumeofbox2isbox2.volume()endl;Boxbox3(15,30);/只给定2个实参coutThevolumeofbox3isbox3.volume()endl;Boxbox4(15,30,20);/给定3个实参coutThevolumeofbox4isbox4.volume()endl;return0;,当对象的生命期结束时,会自动执行析构函数。每个类只能有一个析构函数;析构函数没有返回类型(连void也没有),也没有参数;其名称为类名称前加上Student();/Student类析构函数析构函数的任务由程序设计者安排。如:完成清理工作,释放内存等。,9.2析构函数,classStudentprivate:intnum;charname20;floatscore;public:Student(intn,char*p,floats);/构造函数声明Student();/析构函数声明voiddisplay()coutndisplay:nnum:numendl;coutname:nameendl;coutscore:scoreendl;intmain()Studentstu1(1001,zhangsan,89);stu1.display();return0;/当函数结束前,要释放对象stu1的空间,此时自动调用StudentStudent:Student(intn,char*p,floats)/构造函数定义num=n;strcpy(name,p);score=s;Student:Student()/析构函数定义cout“结束”;,例:classAAAA()/构造函数AA()/析构函数;voidtest()intx,y;AAt1,t2;return;,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,构造函数,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,析构函数,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,/声明变量时开辟两个整型存储空间,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,/创建2个对象,两次调用构造函数,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,/创建2个对象,两次调用构造函数,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,/两次调用析构函数,撤消对象,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,/两次调用析构函数,撤消对象,构造函数和析构函数,例:classAAAA()AA();voidtest()intx,y;AAt1,t2;return;,/两次调用析构函数,撤消对象,/变量x,y生存期结束,构造函数和析构函数,有两个长方柱,其长、宽、高分别为:(1)12,20,25;(2)10,14,20。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。#includeusingnamespacestd;classBoxpublic:Box(int,int,int);/声明带参数的构造函数Box();/没有函数类型,没有参数intvolume();/声明计算体积的成员函数private:intheight;intwidth;intlength;BoxBox(inth,intw,intlen)/在类外定义带参数的构造函数height=h;width=w;length=len;cout“构造函数被调用”endl;Box:Box()cout“析构函数被自动调用”endl;,intBoxvolume()/定义计算体积的成员函数return(height*width*length);intmain()Boxbox1(12,25,30);/建立对象box1,并指定box1长、宽、高的值coutThevolumeofbox1isbox1.volume()endl;Boxbox2(15,30,21);/建立对象box2,并指定box2长、宽、高的值coutThevolumeofbox2isbox2.volume()endl;return0;/结束时,自动调用析构函数,显示:构造函数被调用Thevolumeofbox1is9000构造函数被调用Thevolumeofbox2is9450析构函数被调用析构函数被调用,9.3调用构造函数和析构函数的顺序,在使用构造函数和析构函数时,需要特别注意对它们的调用时间和调用顺序。在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。如图9.1示意。,图9.1,9.3调用构造函数和析构函数的顺序,main()Boxbox1(1,2,3);Boxbox2(2,5,3);Boxbox3(1,1,1);return;,box1的构造函数被调用Box2的构造函数被调用Box3的构造函数被调用Box3的析构函数被调用Box2的析构函数被调用Box1的析构函数被调用,但是,并不是在任何情况下都是按这一原则处理的。在第4章第4.11和4.12节中曾介绍过作用域和存储类别的概念,这些概念对于对象也是适用的。对象可以在不同的作用域中定义,可以有不同的存储类别。这些会影响调用构造函数和析构函数的时机。下面归纳一下什么时候调用构造函数和析构函数:(1)在全局范围中定义的对象(即在所有函数之外定义的对象),它的构造函数在文件中的所有函数(包括main函数)执行之前调用。但如果一个程序中有多个文件,而不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时(此时程序终止),调用析构函数。,Boxbox1(1,2,3);main()Boxbox2(2,5,3);Boxbox3(1,1,1);return;,全局对象box1的构造函数被调用局部自动对象Box2的构造函数被调用局部对象Box3的构造函数被调用Box3的析构函数被调用Box2的析构函数被调用Box1的析构函数被调用,(2)如果定义的是局部自动对象(例如在函数中定义对象),则在建立对象时调用其构造函数。如果函数被多次调用,则在每次建立对象时都要调用构造函数。在函数调用结束、对象释放时先调用析构函数。(3)如果在函数中定义静态(static)局部对象,则只在程序第一次调用此函数建立对象时调用构造函数一次,在调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。,9.4对象数组,数组不仅可以由简单变量组成(例如整型数组的每一个元素都是整型变量),也可以由对象组成(对象数组的每一个元素都是同类的对象)。对于已经定义的类Student:Studentstu3;/stu是对象数组在建立数组时,同样要调用构造函数。如果有3个元素,自动调用3次构造函数。若定义数组时要初始化,只能用构造函数:Studentstu3=Student(1001,18,87),Student(1002,19,90),Student(1001,17,85);,如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供实参。如Student:Student(intno);Studentstud3=60,70,78;/合法,3个实参分别传递/给3个数组元素的构造函数当然,也可以:Studentstud3=Student(60),Student(70),Student(78);如果构造函数有多个参数,则不能用在定义数组时直接提供所有实参的方法,要用构造函数Student:Student(intno,ints1,ints2);Studentstu3=Student(1001,18,87),Student(1002,19,90),Student(1001,17,85);,有3个长方柱,其长、宽、高分别为:(1)3,2,1;(2)6,4,5;(3)2,2,2。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。#includeusingnamespacestd;classBoxpublic:Box(int,int,int);/声明带参数的构造函数intvolume();/声明计算体积的成员函数private:intheight;intwidth;intlength;BoxBox(inth,intw,intlen)/在类外定义带参数的构造函数height=h;width=w;length=len;,intBoxvolume()/定义计算体积的成员函数return(height*width*length);intmain()Boxa3=Box(3,2,1),/用构造函数初始化box0Box(6,5,4),/用构造函数初始化box1Box(2,2,2)/用构造函数初始化box2;inti;for(i=0;i3;i+)coutThevolumeofbox”i+1“isai.volume()endl;return0;/结束时,自动调用析构函数,习题9.5建立对象数组,内放5个学生数据(学号,成绩),设立一个函数max,用指向对象的指针作为函数参数,在max函数中找出成绩最高者,输出其学号。,#includeiostreamusingnamespacestd;classStudentprivate:intnum;floatscore;public:Student(intnu,floatsco):num(nu),score(sco);voiddisplay();friendvoidmax(Student*,int);/友元函数声明;,voidStudent:display()cout学号:num分数:scoreendl;voidmax(Student*ps,intn)inti,k;k=0;for(i=1;in;i+)if(*(ps+k).score(*(ps+i).score)k=i;cout成绩最高者的学号:(*(ps+k).numnamestu.display()相当于p-display(),9.5.2指向对象成员的指针,对象有地址,存放对象初始地址的指针变量就是指向对象的指针变量。对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量。classTimepublic:inthour;intminute;intsec;voidget_time();Timet;对象t有存储地址;t中的成员t.hour,t.minute,t.sec也有存储地址。可定义指针变量指向这些成员。,指向对象数据成员的指针定义指向对象数据成员的指针变量的方法和定义指向普通变量的指针变量方法相同。例如Timet;Time*p;/定义指向对象的指针变量int*p1;/定义指向整型数据的指针变量p=/p1指向了对象中的成员hour/*p1就是t.hour,2.指向对象成员函数的指针定义指向对象成员函数的指针变量的方法和定义指向普通函数的指针变量方法有所不同。成员函数与普通函数有一个最根本的区别:它是类中的一个成员。编译系统要求在上面的赋值语句中,指针变量的类型必须与赋值号右侧函数的类型相匹配,要求在以下3方面都要匹配:函数参数的类型和参数个数;函数返回值的类型;所属的类。定义指向成员函数的指针变量应该采用下面的形式:void(Time*p2)();/定义p2为指向Time类中公用成/员函数的指针变量定义指向公用成员函数的指针变量的一般形式为数据类型名(类名*指针变量名)(参数表列);,可以让指针变量p2指向一个公用成员函数,只需把公用成员函数的入口地址赋给p2即可。如p2=,例9.7有关对象指针的使用方法。#includeusingnamespacestd;classTimepublic:Time(int,int,int);inthour;intminute;intsec;voidget_time();/声明公有成员函数;TimeTime(inth,intm,ints)hour=h;minute=m;sec=s;voidTimeget_time()/定义公有成员函数couthour:minute:secwidth)*(this-length)由于当前this指向a,因此相当于执行:(a.height)*(a.width)*(a.length)这就计算出长方体a的体积。同样如果有b.volume(),编译系统就把对象b的起始地址赋给成员函数volume的this指针,显然计算出来的是长方体b的体积。,this指针是隐式使用的,它是作为参数被传递给成员函数的。本来,成员函数volume的定义如下:intBoxvolume()return(height*width*length);C+把它处理为intBoxvolume(Box*this)return(this-height*this-width*this-length);即在成员函数的形参表列中增加一个this指针。在调用该成员函数时,实
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025福建泉州市德化县公办学校专项招聘编制内新任教师19人(二)考前自测高频考点模拟试题有完整答案详解
- 2025昆明学院招聘准聘制教师岗位工作人员考前自测高频考点模拟试题完整答案详解
- 2025年甘肃省兰州新区石化产业投资集团有限公司丙烯腈项目急需紧缺专业技术岗位招聘10人考前自测高频考点模拟试题及1套完整答案详解
- 2025年宁波一院龙山医院医疗健康集团招聘派遣制工作人员6人考前自测高频考点模拟试题有答案详解
- 2025年中国己酸丙酯行业市场分析及投资价值评估前景预测报告
- 2025甘肃张掖市民乐县招聘教师10人考前自测高频考点模拟试题附答案详解
- 2025江苏连云港市灌南县招聘事业单位人员43人模拟试卷及答案详解(网校专用)
- 2025春季北方华创招聘考前自测高频考点模拟试题及答案详解(名师系列)
- 2025年中国环绕标签膜行业市场分析及投资价值评估前景预测报告
- 2025黑龙江绥化市北林区劳动就业服务中心招聘公益性岗位100人考前自测高频考点模拟试题带答案详解
- 2024−2025学年高二上学期第一次月考数学试题含答案
- 光伏项目达标投产实施细则-施工
- 三年级上册道德与法治说课稿-1 学习伴我成长 部编版
- 道德与法治二上6.《班级生活有规则》(人教)公开课教案教学设计课件
- 土地承包土地合作农作物种植投标文件技术方案(技术方案)
- 2024年新人教版道德与法治七年级上册全册教案(新版教材)
- 基本公共卫生服务居民健康档案课件
- 10kV试验报告模板-大全
- 英语专业导论(第2版)PPT完整全套教学课件
- 民航安检理论与实务整套教学课件
- 软式棒垒球-上手传接球教案高一上学期体育与健康人教版
评论
0/150
提交评论