资源预览内容
第1页 / 共80页
第2页 / 共80页
第3页 / 共80页
第4页 / 共80页
第5页 / 共80页
第6页 / 共80页
第7页 / 共80页
第8页 / 共80页
第9页 / 共80页
第10页 / 共80页
亲,该文档总共80页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
浩搽磅攘诌烛知中惕撼葫属贬拽摈械启视银窗冈懊滥勿导巡刁晨筒慰砸迹经典C学习经验分享经典C学习经验分享C+面向对象程序设计第三章再论类和对象益姬寥呻嫂揍战棉援甄驰赤侠相鹅横过泥层冷搔扭用可酞黎钦址受韩塞蕊经典C学习经验分享经典C学习经验分享C+ 3- 1 第一第一章C+的初步知识第二章 类和对象第三章 再论类和对象第四章第四章运算符重载运算符重载第五章第五章继承与派生继承与派生第六章第六章多态性与虚函数第七章第七章输入输出流输入输出流第八章第八章 C+工具工具呀鸣响堑痛储播仙彰支啃翅焙吧良瘁零肛沂甚牟芭蛮顿扬豆籽晾胳匝席嗡经典C学习经验分享经典C学习经验分享C+ 3- 2 3.1构造函数构造函数3.2析构函数析构函数3.3调用构造函数和析构函数的顺序调用构造函数和析构函数的顺序3.4对象数组对象数组3.5对象指针对象指针3.6共用数据的保护共用数据的保护3.7对象的动态建立和释放对象的动态建立和释放3.8对象的赋值和复制对象的赋值和复制3.9静态成员静态成员3.10友元友元3.11类模板类模板慈锹巡菩抬拼冕供辞琴叼唆候咖怒疵乐唬眷芜恨砒椎乙琼滥瓢脊歪滁邢肿经典C学习经验分享经典C学习经验分享C+ 3- 3 3.1构造函数构造函数l对象的初始化对象的初始化和普通变量一样,我们定义一个变量,往往同时进行初和普通变量一样,我们定义一个变量,往往同时进行初始化:始化:inta=3;而声明类时,数据成员不能进行初始化:而声明类时,数据成员不能进行初始化:classtimeinthour=0;intminute=0;intsecond=0;因为类不是实体,不占分配存储空间,显然无法容纳数因为类不是实体,不占分配存储空间,显然无法容纳数据。据。植削来徒树酵艰婴梆娩替细梗秽剃验塌朱柳疵倡梯佯贮膝蛀案业吭誓鸳球经典C学习经验分享经典C学习经验分享C+ 3- 4 3.1构造函数构造函数如果一个类的所有数据成员都是公用的,我们可以象结如果一个类的所有数据成员都是公用的,我们可以象结构体变量那样,在定义对象时(而不是声明类时)进行初始化:构体变量那样,在定义对象时(而不是声明类时)进行初始化:classtimepublic:inthour;intminute;intsecond;timet1=13,30,20;但在类的声明中,数据成员往往都是私有的,不能这样但在类的声明中,数据成员往往都是私有的,不能这样初始化。就需要一个公有成员函数来完成,而且应该是自动调初始化。就需要一个公有成员函数来完成,而且应该是自动调用地完成。这就是构造函数。用地完成。这就是构造函数。痴狭烯权同哨隘榔簿疫恤问宠吏虹垄酿坪操枫馏刽雀贩岛假拂辈侠海抒旋经典C学习经验分享经典C学习经验分享C+ 3- 5 3.1构造函数构造函数l构造函数的作用构造函数的作用C+提供了构造函数提供了构造函数(constructor)来处理对象来处理对象的初始化。构造函数是一个由用户定义的特殊的成员的初始化。构造函数是一个由用户定义的特殊的成员函数。与其他成员函数不同之处在于:函数。与其他成员函数不同之处在于:u用户不能调用它,而是在定义对象时,有系统自用户不能调用它,而是在定义对象时,有系统自动调用构造函数。动调用构造函数。u构造函数的名字必须与类名一致,不能是其他名构造函数的名字必须与类名一致,不能是其他名字。字。u构造函数不能有任何返回类型。构造函数不能有任何返回类型。u用户如果没有定义构造函数,系统会自动生成一用户如果没有定义构造函数,系统会自动生成一个构造函数,只不过函数体中没有任何语句。个构造函数,只不过函数体中没有任何语句。售嘲黔酵蛋跟婶佯瓢牺榴汹心面警辨补庚叮漱诊拢霜捧们滦猪澎形敬韶待经典C学习经验分享经典C学习经验分享C+ 3- 6 3.1构造函数构造函数l例例3.1将前例的时间类定义构造函数。在构造函数中加入将前例的时间类定义构造函数。在构造函数中加入输出语句,看看运行效果。输出语句,看看运行效果。classtimeprivate:inthour,minute,second;public:time()/time类的构造函数类的构造函数hour=0;minute=0;second=0;voidsetTime();voidshowTime()couthour:minute:secondendl;voidtime:setTime()couthour=hour;coutminute=minute;coutsecond=second;voidmain()timet1;/定义定义time类对象类对象t1,调用构造函数调用构造函数tume()t1.setTime();t1.showTime();timet2;/定义定义time类对象类对象t2,调用构造函数调用构造函数tume()t2.setTime();t2.showTime();赐优蜀擞蔫糙侩遭沿郭擞戏倘粪适韭涛缘腐馆跳撞硒愧七喀奖回溯史刷咬经典C学习经验分享经典C学习经验分享C+ 3- 7 3.1构造函数构造函数l带参数的构造函数带参数的构造函数前一个示例中,每产生一个前一个示例中,每产生一个time了的对象,其初值都初了的对象,其初值都初始化为始化为0。如果用户初始化时,不想将对象初值置为。如果用户初始化时,不想将对象初值置为0而是其它而是其它值,就需要用带参数的构造函数来实现。值,就需要用带参数的构造函数来实现。u声明一个构造函数的一般格式为:声明一个构造函数的一般格式为:构造函数名构造函数名(类型类型1形参形参1,类型,类型2形参形参2,);u定义一个对象的一般格式为:定义一个对象的一般格式为:类名类名对象名对象名(实参实参1,实参,实参2,););下面举例说明用法。下面举例说明用法。楞遇逾冕劫硅刨秒鞍础布霸肪胖谩帚谗夕毕凋封嚏找博扼寡择撰塘讨恩咐经典C学习经验分享经典C学习经验分享C+ 3- 8 3.1构造函数构造函数l例例3.2:有两个长方体,长宽高分别为:有两个长方体,长宽高分别为(1,2,3)和和(4,5,6)。试编写一基于对象的程序,分别求他们的体积,并且试编写一基于对象的程序,分别求他们的体积,并且要求用带参数的构造函数初始化他们。要求用带参数的构造函数初始化他们。#includeclassboxprivate:intheight,width,length;public:box(inth,intw,intlen)height=h;width=w;length=len;intvolume()returnheight*width*length;voidmain()boxbox1(1,2,3);coutbox1的体积为的体积为box1.volume()endl;boxbox2(4,5,6);coutbox2的体积为的体积为box2.volume()endl;梢僳腥窝狈心聘沁菏抠问写者踞险坦媚慈焉虹翠眠臂攀挺间馁瞥屯水钵臀经典C学习经验分享经典C学习经验分享C+ 3- 9 3.1构造函数构造函数l用参数初始化表对数据成员初始化用参数初始化表对数据成员初始化C+提供另一种初始化数据成员的方法:提供另一种初始化数据成员的方法:参数初始化表参数初始化表来来实现对数据成员的初始化。这种方法不在函数体内初始化数据实现对数据成员的初始化。这种方法不在函数体内初始化数据成员,而是在函数首部实现。例成员,而是在函数首部实现。例3.2我们改写成如下形式:我们改写成如下形式:#includeclassboxprivate:intheight,width,length;public:box(inth,intw,intlen):height(h),width(w),length(len)intvolume()returnheight*width*length;voidmain()boxbox1(1,2,3);coutbox1的体积为的体积为box1.volume()endl;boxbox2(4,5,6);coutbox2的体积为的体积为box2.volume()endl;耪映恫酗掇忙汁方钓珍哈汪絮嗣铜衰筑低吐恢刮膨敌关寂隘耽褂玄扛盟长经典C学习经验分享经典C学习经验分享C+ 3- 10 3.1构造函数构造函数示例中的初始化表表示,用形参示例中的初始化表表示,用形参h的值初始化数据成的值初始化数据成员员height,用,用w值初始化值初始化width,用,用len值初始化值初始化length。这种初始化方法比较简练,可以直接在类体中定义构造函这种初始化方法比较简练,可以直接在类体中定义构造函数。数。秩雏般崎让描馏谓湿猜从喳呜舒芝碴啃糟阑琴懈砰磐厨龚瞧垮丈默非鳖兄经典C学习经验分享经典C学习经验分享C+ 3- 11 3.1构造函数构造函数l构造函数的重载构造函数的重载一个类中,可以有多个构造函数,只要他们的参数表不一个类中,可以有多个构造函数,只要他们的参数表不同。以方便同类对象不同初始化的需要。见下例同。以方便同类对象不同初始化的需要。见下例3.3:#includeclasscircleprivate:floatradius;public:circle();/声明一个无参数构造函数声明一个无参数构造函数circle(floatr):radius(r)/声明一个带参数构造函数声明一个带参数构造函数floatarea()returnradius*radius*3.14159;circle:circle()radius=10.0;voidmain()circlec1(1.0),c2;coutc1的面积为的面积为c1.area()endl;coutc2的面积为的面积为c2.area()endl;汇均抓幽奶膨桩良腻敏锣窟峭芳潮掐咙马朝殖反峪乏撩琐跃仅篡姐拘易焕经典C学习经验分享经典C学习经验分享C+ 3- 12 3.1构造函数构造函数l说明说明u参数表为空的构造函数叫默认构造函数,一个类中只能有参数表为空的构造函数叫默认构造函数,一个类中只能有一个默认函数。一个默认函数。u定义对象时,如果想用默认构造函数初始化它,正确的定定义对象时,如果想用默认构造函数初始化它,正确的定义形式为:义形式为:circlec2;而不是:而不是:circlec2();u一个类尽管定义了多个构造函数,一个对象只能用其中一一个类尽管定义了多个构造函数,一个对象只能用其中一个来初始化。个来初始化。栽粒粟妨谓斯纤卵憋潜悍室茵门纤节栽陛善拴讨牛葛洋桂拢撰策吁讹挫啪经典C学习经验分享经典C学习经验分享C+ 3- 13 3.1构造函数构造函数l使用默认参数的构造函数使用默认参数的构造函数构造函数的参数既可以通过实参传送,也可以指定为构造函数的参数既可以通过实参传送,也可以指定为某些默认值。当用户不指定实参值时,编译系统便将默认某些默认值。当用户不指定实参值时,编译系统便将默认值为形参值。值为形参值。在实际生活中,常有一些这样的默认值。如计数器的在实际生活中,常有一些这样的默认值。如计数器的默认值为默认值为0;战士的性别默认值为;战士的性别默认值为男男;男性职工退休年龄;男性职工退休年龄默认值为默认值为60岁等,如果实际情况不是默认值,则由用户另岁等,如果实际情况不是默认值,则由用户另外指定。采用默认值,可以减少用户的输入量。外指定。采用默认值,可以减少用户的输入量。下面举例说明。下面举例说明。吱礁李愚笛裸塑迹佰碟熬呻妹捂桂嘱岸伯秘氯朱油拭指黔行守驾琳桅箔澜经典C学习经验分享经典C学习经验分享C+ 3- 14 3.1构造函数构造函数例例3.4试将例试将例3.3的构造函数改用默认值的参数,半径值默认的构造函数改用默认值的参数,半径值默认为为1.0。#includeclasscircleprivate:floatradius;public:circle(floatr=1.0);/声明构造函数是指定默认参数声明构造函数是指定默认参数floatarea()returnradius*radius*3.14159;circle:circle(floatr)/定义函数时,可不再指定默认参数定义函数时,可不再指定默认参数radius=r;voidmain()circlec1(10.0),c2;coutc1的面积为的面积为c1.area()endl;coutc2的面积为的面积为c2.area()endl;旁送瓢湃朵撞涟但垦但疤荷匀贴信撅孔摘讼松瞧进全富擂视缀花脊飘仑乳经典C学习经验分享经典C学习经验分享C+ 3- 15 3.1构造函数构造函数l构造函数中使用默认参数的好处构造函数中使用默认参数的好处u提供建立对象时的多种选择,相当于好几个重载的构造提供建立对象时的多种选择,相当于好几个重载的构造函数。函数。u即使在调用构造时不提供参数也不会出错,因为有默认即使在调用构造时不提供参数也不会出错,因为有默认参数值参与对象初始化。参数值参与对象初始化。u当每一个对象都是相同的初始值时,非常方便,用户不当每一个对象都是相同的初始值时,非常方便,用户不需要输入数据。需要输入数据。井旭工瘤唁嫩稻徐溉陌惋血捡猩沼帧险翘剂才圭撕无正凌栅呈毖笺颇埂纸经典C学习经验分享经典C学习经验分享C+ 3- 16 3.1构造函数构造函数l默认参数值的构造函数使用注意默认参数值的构造函数使用注意u何处指定默认参数值?构造函数的声明处还是定义处?何处指定默认参数值?构造函数的声明处还是定义处?应该在构造函数的声明处指定默认参数值。因为类的声应该在构造函数的声明处指定默认参数值。因为类的声明在头文件中,用户是看得见的,而防在函数的定义处,明在头文件中,用户是看得见的,而防在函数的定义处,用户不一定看得见。用户不一定看得见。u一个类定义了全部是默认参数的构造函数后,不能再定一个类定义了全部是默认参数的构造函数后,不能再定义重载的构造函数。否则会产生多义性,系统不知道调义重载的构造函数。否则会产生多义性,系统不知道调用哪一个。例如一个类有右边形式用哪一个。例如一个类有右边形式的三个重载构造函数,若定义了如的三个重载构造函数,若定义了如下对象下对象:circlecircle1;它调用哪一个构造函数呢?系统不它调用哪一个构造函数呢?系统不能确定,从而引起混乱。能确定,从而引起混乱。circle(floatr=2.3);circle();circle(float);脱阎土抿粳正抵睫皂装蛆粤纽顿相抖吓鸥心憨骇竖摩垮决氯半天峭边肤测经典C学习经验分享经典C学习经验分享C+ 3- 17 3.2析构函数析构函数l什么是析构函数?什么是析构函数?析构函数析构函数(destructor)也是一个特殊函数,它的作用也是一个特殊函数,它的作用与构造函数相反,与构造函数相反,是在撤消对象占用的内存前进行一些清理是在撤消对象占用的内存前进行一些清理工作工作。它还可以被用来执行。它还可以被用来执行用户希望在最后依次使用对象之用户希望在最后依次使用对象之后所执行的任何操作后所执行的任何操作。析构函数的名称是类名的前面加一个取反符号析构函数的名称是类名的前面加一个取反符号。我。我们在类的声明中定义析构函数。如果用户不定义析构函数,们在类的声明中定义析构函数。如果用户不定义析构函数,系统便自动生成一个空的析构函数。系统便自动生成一个空的析构函数。l析构函数特点:析构函数特点:u没有返回类型;没有返回类型;u没有函数参数;没有函数参数;u不能被重载。不能被重载。肘风报延启砸狐淹耸贵告羹隋柿阶耘作组臆思厨椰颖袍芍足沙枚贸簿牢更经典C学习经验分享经典C学习经验分享C+ 3- 18 3.2析构函数析构函数l什么时候运行析构函数?什么时候运行析构函数?当对象的生命结束时,会自动执行它的析构函数。具当对象的生命结束时,会自动执行它的析构函数。具体而言,当出现以下几种情况,析构函数就会被执行。体而言,当出现以下几种情况,析构函数就会被执行。u如果在函数中定义了一个对象,当函数调用结束时,释如果在函数中定义了一个对象,当函数调用结束时,释放对象,释放对象前自动执行析构函数。放对象,释放对象前自动执行析构函数。ustatic局部对象在函数调用结束时,包含的对象不会被局部对象在函数调用结束时,包含的对象不会被释放,只在释放,只在main函数结束或调用函数结束或调用exit函数时,才调用函数时,才调用static局部对象的析构函数。局部对象的析构函数。u如果定义了一个全局对象,则在程序的流程离开其作如果定义了一个全局对象,则在程序的流程离开其作用域时(如用域时(如main函数结束,或函数结束,或exit语句),调用该全局语句),调用该全局对象的析构函数。对象的析构函数。u如果用如果用new运算符动态地建立了一个对象,当用运算符动态地建立了一个对象,当用delete运算符释放对象时,先调用该全局对象的析构函数。运算符释放对象时,先调用该全局对象的析构函数。紫偶注去矽虾萤葱筏惕前挽苗竭泼淤汪德史邵著奏康酒舱蹬鲜宽襄卸所门经典C学习经验分享经典C学习经验分享C+ 3- 19 3.2析构函数析构函数#includeclassboxprivate:intheight,width,length;public:box(inth,intw,intlen)height=h;width=w;length=len;box()/析构函数析构函数coutDestructoringaobjectendl;intvolume()returnheight*width*length;voidmain()boxbox1(1,2,3);coutbox1的体积为的体积为box1.volume()endl;boxbox2(4,5,6);coutbox2的体积为的体积为box2.volume()endl;例例3.5析构函数举例。析构函数举例。渤毗砧寅卡线叮篮励洽瓜鸭目气燎闸临沙事戮瘫走摄设荚谚就抵靖泌拂凝经典C学习经验分享经典C学习经验分享C+ 3- 20 3.3调用构造函数和析构函数的顺序调用构造函数和析构函数的顺序l调用构造函数和析构函数的顺序调用构造函数和析构函数的顺序先构造的后析构,后构造的先析构。先构造的后析构,后构造的先析构。例例:C3-5-1.CPP店刚看钎禄鸡矛孰遂润前庶篓讶绎搓省岂猫开株户订卜轻张驾例捶醇堪盾经典C学习经验分享经典C学习经验分享C+ 3- 21 3.3调用构造函数和析构函数的顺序调用构造函数和析构函数的顺序l注意注意:先构造的后析构,后构造的先析构先构造的后析构,后构造的先析构,并非绝对成立并非绝对成立!u对象不同的作用域对象不同的作用域,不同的存储类别不同的存储类别,那么调用构造函数和析构函数的那么调用构造函数和析构函数的时候也有所不同时候也有所不同.l例如例如:u一个程序中有多个文件一个程序中有多个文件,在多个文件中定义了全局对象在多个文件中定义了全局对象,那么这些对象那么这些对象的执行顺序是不确定的的执行顺序是不确定的u在函数中定义局部自动对象在函数中定义局部自动对象,如果函数被多次调用如果函数被多次调用u如果函数中定义静态局部对象如果函数中定义静态局部对象,那么函数调用结束时对象并不释放那么函数调用结束时对象并不释放,只只有有main结束或调用结束或调用exit中才调用析构函数中才调用析构函数.Voidfn()Students1;staticStudents2;例例:C3-5-2.CPP除川卢哦岩射巨呜渍做阿竟图对铰刹绕窥顶界渔梅拖尹朱俄荚楔锐蒋筑油经典C学习经验分享经典C学习经验分享C+ 3- 22 3.4对象数组对象数组数组不仅可以由简单变量组成,也可以由对象组成,数组不仅可以由简单变量组成,也可以由对象组成,即每一个数组元素都是同类的对象。即每一个数组元素都是同类的对象。例如,一个班有例如,一个班有30人,每个学生的属性包括学号、姓人,每个学生的属性包括学号、姓名、性别。我们建立起学生类后,为每个学生建立一个对名、性别。我们建立起学生类后,为每个学生建立一个对象,需要分别取象,需要分别取30个对象名,很不方便。较好的做法是,个对象名,很不方便。较好的做法是,定义一个定义一个学生类学生类,的对象数组,每一个数组元素是一个,的对象数组,每一个数组元素是一个学生类学生类的对象。的对象。例如例如:Studentstud30;兑肯请钾姥针屹忻柏胁凿垄侵喂专剃冗虞俗薯苛蛛疼葱伶浑浸退蹦印饱壤经典C学习经验分享经典C学习经验分享C+ 3- 23 3.4对象数组对象数组l在建立对象数组时,同样调用构造函数。在建立对象数组时,同样调用构造函数。l如果构造函数只有一个参数,在定义数组时可以在等号后面花括号内提如果构造函数只有一个参数,在定义数组时可以在等号后面花括号内提供实参。供实参。Studentstud3=60,70,80;l实参个数不能超过数组元素个数,因为编译系统只为每个对象元素的实参个数不能超过数组元素个数,因为编译系统只为每个对象元素的构造函数传递一个实参构造函数传递一个实参Studentstud3=60,70,80,90;/不合法不合法l如果构造函数有多个参数,则不能用在定义数组时直接提供所有实参的如果构造函数有多个参数,则不能用在定义数组时直接提供所有实参的方法。方法。例如:例如:Student:Student(int=1001,int=18,int=60)/构造函数构造函数Studentstud3=111,34,31;这种使用方式关系不清晰,出现歧义性这种使用方式关系不清晰,出现歧义性邮滁红历垢澈努亩脸怯奉舀蔷骄瞬象摇窘眶摊看僻掠葡将嚏缆沪脾岿陋害经典C学习经验分享经典C学习经验分享C+ 3- 24 3.4对象数组对象数组l构造函数有多个参数时构造函数有多个参数时,如下实现对数组对象的初始化如下实现对数组对象的初始化.StudentStud3=Student(11,32,74),Student(12,34,27),Student(14,45,63);如下面的例子如下面的例子.鲁姥未言檬叠红圈物自陇眯图湍蔫思中裙搐态话蝴富祥靠份脆侨眺贤盟插经典C学习经验分享经典C学习经验分享C+ 3- 25 3.4对象数组对象数组l例例:3.6-1.cpp#include#includeusingnamespacestd;classstudentprivate:intnum;stringname;charsex;public:student(intn,stringnam,chars)num=n;name=nam;sex=s;coutConstructorcalled.endl;student()coutDestructorcalled.endl;voiddisplay();voidstudent:display()coutnum:numendl;coutname:nameendl;coutsex:;if(sex=0)cout男男endl;elsecout女女endl;voidmain()studentstud3=student(1001,张三张三,1),student(1002,李四李四,0),student(1003,王五王五,0);/用指定参数的构造函数初始化数组用指定参数的构造函数初始化数组cout第一个学生第一个学生;stud0.display();cout第二个学生第二个学生;stud1.display();cout第三个学生第三个学生;stud2.display();务辩仿斟瘩冀涎凰名装扦坊猿挪垢深从噶攻扦克鸥净沙壤紫麦典髓妖戌抿经典C学习经验分享经典C学习经验分享C+ 3- 26 3.4对象数组对象数组l例例:C3-6.CPP#includeusingnamespacestd;classBoxpublic:Box(inth=10,intw=12,intlen=15):height(h),width(w),length(len)intvolume();private:intheight;intwidth;intlength;intBox:volume()return(height*width*length);intmain()Boxa3=Box(10,12,15),Box(15,18,20),Box(16,20,26);coutvolumeofa0isa0.volume()endl;coutvolumeofa0isa1.volume()endl;coutvolumeofa0isa2.volume()hour,pt-put()classTimepublic:inthour,minute,sec;voidput()hour=12;minute=0;sec=0;voidmain()Time*pt,t1;pt=&t1;p1.put();couthour:minute:secendl;cout(*pt).hour:(*pt).minute:(*pt).secendl;贪娥樱疟迈五纂的货桑剁疗产苇纽旧济哮崖宇晒盎象醇型牌渤赛惕哮呵膳经典C学习经验分享经典C学习经验分享C+ 3- 29 3.5对象指针对象指针l指向对象数据成员的指针指向对象数据成员的指针定义一个指向对象数据成员的指针变量的方法和前面介定义一个指向对象数据成员的指针变量的方法和前面介绍的定义指向普通变量的指针变量方法相同。绍的定义指向普通变量的指针变量方法相同。定义格式:数据类型名定义格式:数据类型名*指针变量名;指针变量名;例如:例如:int*pl;/定义指向整形数据的指针变量定义指向整形数据的指针变量pl=&t1.hour;/将将t1的数据成员的数据成员hour地址赋给指针地址赋给指针pl,使其指向使其指向t1.hourcout*plendl;/输出输出t1.hour的值的值顾血隋抛磷幅鲍羚偷龟迭绰船殷日殊篡虫劫肆钧据坟沿狄穆蝶岛酵滓肄煮经典C学习经验分享经典C学习经验分享C+ 3- 30 3.5对象指针对象指针l指向对象成员函数的指针指向对象成员函数的指针定义指向对象成员函数的指针变量的方法和定义指向普定义指向对象成员函数的指针变量的方法和定义指向普通函数的指针变量的方法有所不同。通函数的指针变量的方法有所不同。u指向普通函数的指针变量的定义方法:指向普通函数的指针变量的定义方法:返回数据类型返回数据类型(*指针变量名指针变量名)(参数表列参数表列);例:例:void(*p)();/p是指向是指向void类型函数的指针变量类型函数的指针变量p=fun;/将将fun函数的入口地址赋给指针变量函数的入口地址赋给指针变量p(*p)();/调用调用fun函数函数而定义一个指向对象成员函数的指针变量则不能这样:而定义一个指向对象成员函数的指针变量则不能这样:p=t1.put;/出现编译错误,不知道出现编译错误,不知道t1.put所属的类所属的类韵腥搬喇捧腊任兑换通本瓢庙荔拳勉滋豌吻剖疵逊披署继褐怎沿辙沾灰钠经典C学习经验分享经典C学习经验分享C+ 3- 31 3.5对象指针对象指针u定义指向公用成员函数的指针变量方法:定义指向公用成员函数的指针变量方法:返回数据类型返回数据类型(类名类名:*指针变量名指针变量名)(参数表列参数表列);例:例:void(Time:*p2)();/Time:*p2的括号必须加上的括号必须加上u令指针变量指向一个公用成员函数的方法:令指针变量指向一个公用成员函数的方法:指针变量名指针变量名=&类名类名:成员函数名;成员函数名;例:例:p2=&Time:put;棱番吞昔探粥每纫墩漂姻些十潍寐顿焉佯弦仇棠屹寨迟鼻卞致判萤沦溯缆经典C学习经验分享经典C学习经验分享C+ 3- 32 3.5对象指针对象指针#includeusingnamespacestd;classTimepublic:inthour,minute,sec;Time(inth,intm,ints)hour=h;minute=m;sec=s;voidget_Time()couthour:minute:secendl;intmain()Timet1(10,13,56);int*pl=&t1.hour;/定义指向整形数据的指针,指向定义指向整形数据的指针,指向t1.hourcout*p1get_Time();/调用调用p2所指对象的成员函数所指对象的成员函数void(Time:*p3)();/定义指向定义指向Time类公用成员函数的指针变量类公用成员函数的指针变量p3p3=&Time:get_Time;p53页页/使使p3指向指向Time类公用成员函数类公用成员函数get_Time()(t1.*p3)();/调用调用p3所指的成员函数所指的成员函数t1.get_Time()return0;德薛描蛙洛挛渤敌卑厂际晌涌肘蚕鼎窒仑激春是憾豫零整蒲评便塘侗啸汽经典C学习经验分享经典C学习经验分享C+ 3- 33 3.5对象指针对象指针lthis指针指针通过第二章的学习我们知道,多个同类对象在内存中是通过第二章的学习我们知道,多个同类对象在内存中是共享成员函数的,以节省内存空间。那么,不同对象的成员共享成员函数的,以节省内存空间。那么,不同对象的成员函数引用数据成员时,怎么找到自己的数据成员呢?函数引用数据成员时,怎么找到自己的数据成员呢?C+在每一个成员函数中都包含一个特殊的指针,这个在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,成为指针的名字是固定的,成为this。它是指向本对象的指针,。它是指向本对象的指针,它的值是当前被调用的成员函数所在对象的起始地址。它的值是当前被调用的成员函数所在对象的起始地址。例如,当例如,当a的成员函数调用数据成员的成员函数调用数据成员a.volume时,编译时,编译系统就把对象系统就把对象a的起始地址赋给的起始地址赋给this指针,于是在成员函数指针,于是在成员函数引用数据成员时,就按照引用数据成员时,就按照this的指向找到对象的指向找到对象a的数据成员。的数据成员。破恼驮发察栗肚丘腋酮蛰幂凌育银纶鸭市鹏制嫌麻援沤慰贾纪傍泽袋蚀淡经典C学习经验分享经典C学习经验分享C+ 3- 34 3.5对象指针对象指针比如下列涉及数据成员的运算的返回语句:比如下列涉及数据成员的运算的返回语句:returnlength*width*height;实际上实际上C+处理为:处理为:return(this-length)*(this-width)*(this-height);也可以写成如下形式:也可以写成如下形式:return(*this).length*(*this).width*(*this).height);但不能写成:但不能写成:return(*this.length)*(*this.width)*(*this.height);/错误错误因为因为.操作符的优先级高于指针运算符操作符的优先级高于指针运算符*,(*this.length)就就相当于相当于*(this.length),而,而this.length是不合法的,编译出错是不合法的,编译出错(应该是(应该是this-length)。)。届搀艇箭涣计峰探缸冈甚济哄冗牺椭靠莲侈漆熬机钝捅俄惟字氖拟娶罗富经典C学习经验分享经典C学习经验分享C+ 3- 35 3.6共用数据的保护共用数据的保护C+采用了不少的数据保护措施。最常用的,是将数据采用了不少的数据保护措施。最常用的,是将数据成员设置成私有数据成员设置成私有数据(private),以增加数据的安全性和私密,以增加数据的安全性和私密性。性。但是,有时候要求数据在能共享的前提下不能被篡改,但是,有时候要求数据在能共享的前提下不能被篡改,我们就需要借助其他手段了。我们就需要借助其他手段了。什么手段呢?可以采用什么手段呢?可以采用const,即把要保护的数据定义,即把要保护的数据定义为常量。为常量。彬鸦镐狙壕铣小装渗夫勿取疑刻包寿涯团仟吴酱蹦掌岂抖浚孕吵侯狸锦没经典C学习经验分享经典C学习经验分享C+ 3- 36 3.6共用数据的保护共用数据的保护l常对象常对象在定义对象时指定对象为常对象。常对象中的数据成员在定义对象时指定对象为常对象。常对象中的数据成员为常变量,并且必须要有初值:为常变量,并且必须要有初值:Timeconstt1(12,34,56);这样,在所有的场合中,对象这样,在所有的场合中,对象t1的所有数据成员都被的所有数据成员都被保护了,不能被修改。因此,凡是希望数据成员不能被改变保护了,不能被修改。因此,凡是希望数据成员不能被改变的对象,可以声明为常对象。其声明格式为:的对象,可以声明为常对象。其声明格式为:类名类名const对象名对象名(参数表列参数表列);或者:或者:const类名对象名类名对象名(参数表列参数表列);两者等价。两者等价。刹臼毁且肺庞卸程佑茧禽丝灰磋他臼惕玩鲍窃神焉衷郡晰造氢恕磨舵妙汛经典C学习经验分享经典C学习经验分享C+ 3- 37 3.6共用数据的保护共用数据的保护如果一个对象被定义成常对象,那么不能调用该对象的如果一个对象被定义成常对象,那么不能调用该对象的非非const型成员函数,当然,系统隐含调用的构造函数和析型成员函数,当然,系统隐含调用的构造函数和析构函数除外。比如:构函数除外。比如:Timeconstt1(12,34,56);/定义定义t1为常对象为常对象t1.get_Time();/错误,错误,get_Tiem()不是不是const型型,不能调用不能调用为什么会这样?因为成员函数有可能修改数据成员,而为什么会这样?因为成员函数有可能修改数据成员,而成员函数的定义可能和成员函数的声明不在同一文件,系统成员函数的定义可能和成员函数的声明不在同一文件,系统没法检测。所以,系统只能统一拦截,不让用户调用常对象没法检测。所以,系统只能统一拦截,不让用户调用常对象的成员函数,除非该成员函数被声明成的成员函数,除非该成员函数被声明成const类型。类型。穿肖美灵骤舵细芥旦板舱尧冲过诛岔拜俭吐湃沫杨霹父巳绕蝎嫡轨骤乘鞋经典C学习经验分享经典C学习经验分享C+ 3- 38 3.6共用数据的保护共用数据的保护怎样才能引用常对象的成员函数呢?很简单,只需要把该成怎样才能引用常对象的成员函数呢?很简单,只需要把该成员函数的声明为员函数的声明为const类型,即类型,即常成员函数常成员函数就行了。方法为:就行了。方法为:函数返回类型函数名函数返回类型函数名(参数表列参数表列)const;比如:比如:voidget_Time()const;/将函数声明成将函数声明成const类型类型常成员函数可以访问常对象中的数据成员,但仍然不准修改常成员函数可以访问常对象中的数据成员,但仍然不准修改它们。它们。有时候编程要求必须修改某个常对象中的数据成员,如某个有时候编程要求必须修改某个常对象中的数据成员,如某个计数器计数器count,ANSIC+对此做了特殊的处理,将该数据成员对此做了特殊的处理,将该数据成员声声明为明为mutable,如:,如:mutableintcount;这样,常对象的数据成员这样,常对象的数据成员count,就可以用常成员函数来访问和修,就可以用常成员函数来访问和修改了。改了。肆童胀瓣咆给蹋铆凝挥灌遵苗渗侩姬间挡甫级李叶缘汛硷公痘英绢食穴跨经典C学习经验分享经典C学习经验分享C+ 3- 39 3.6共用数据的保护共用数据的保护l常对象成员常对象成员u常数据成员常数据成员:其作用和用法与一般常变量相似,在类的:其作用和用法与一般常变量相似,在类的声明中,用关键词声明中,用关键词const来声明常数据成员,例如:来声明常数据成员,例如:constinthour;注意:常数据成员的初始化,不能采用在构造函数中对常注意:常数据成员的初始化,不能采用在构造函数中对常数据成员赋予初值的方法,数据成员赋予初值的方法,只能通过构造函数的参数初始只能通过构造函数的参数初始化表对常数据成员进行初始化化表对常数据成员进行初始化。在类外定义构造函数,初始化形式为:在类外定义构造函数,初始化形式为:Time:Time(inth):hour(h)在类中声明了某一个数据成员为常数据成员后,该类的在类中声明了某一个数据成员为常数据成员后,该类的所有对象中的该数据成员的值是不可改变的,但可以是不所有对象中的该数据成员的值是不可改变的,但可以是不同的(由每个对象的参数初始化表决定)。同的(由每个对象的参数初始化表决定)。如榜毁钢庇啪攘皋浊柠管请妖饶庇嘎场角弱以遣彩膊询铭保蹈饼洞熬嘴奈经典C学习经验分享经典C学习经验分享C+ 3- 40 3.6共用数据的保护共用数据的保护u常成员函数常成员函数一般的成员函数可以引用本对象中的非一般的成员函数可以引用本对象中的非const数据成员,数据成员,也可以修改它们。但也可以修改它们。但如果成员函数声明为常成员函数,则如果成员函数声明为常成员函数,则只能引用本对象中的数据成员,而不能修改它们只能引用本对象中的数据成员,而不能修改它们。如。如voidget_Time()const;/const位置在最后位置在最后const是函数类型的一部分,在声明函数和定义函数时是函数类型的一部分,在声明函数和定义函数时都要用到都要用到const关键字。关键字。常成员函数可以引用常数据成员,也可以引用非常成员函数可以引用常数据成员,也可以引用非const数据成员;而常数据成员可以被常成员函数引用,也可以数据成员;而常数据成员可以被常成员函数引用,也可以被非被非const成员函数引用。见成员函数引用。见90页表总结。页表总结。疾岗办暴弃睛飘洼短萤某葛至呵艺奇首刁值碘赠鲁誉馈媚兑秩撰茁蔬袍浮经典C学习经验分享经典C学习经验分享C+ 3- 41 3.6共用数据的保护共用数据的保护数据成员数据成员非非const成员函数成员函数const成员函数成员函数非非const数据成员数据成员可引用,可修改可引用,可修改可引用,不可修改可引用,不可修改const数据成员数据成员可引用,不可修改可引用,不可修改可引用,不可修改可引用,不可修改常对象的数据成员常对象的数据成员不可引用,不可修改不可引用,不可修改可引用,不可修改可引用,不可修改寇傀榜所疾墩廷蛀崭障溃戏恰迂仆到退戏热棕舜搁喝奎棱徒虽敲耶俊蜘匡经典C学习经验分享经典C学习经验分享C+ 3- 42 3.6共用数据的保护共用数据的保护l怎样使用常成员函数呢?怎样使用常成员函数呢?u类中如果一些数据成员需要保护,另一些数据成员不需保类中如果一些数据成员需要保护,另一些数据成员不需保护,我们就将需要保护的数据成员声明为护,我们就将需要保护的数据成员声明为const,以保证,以保证其值不被改变。其值不被改变。u类中如果所有数据成员都需保护,可以将所有数据成员都类中如果所有数据成员都需保护,可以将所有数据成员都声明成声明成const,本对象的任何成员函数,都只能引用,不,本对象的任何成员函数,都只能引用,不能改变它们。或者将这些数据成员所属的对象声明成能改变它们。或者将这些数据成员所属的对象声明成const,只让本对象的,只让本对象的const成员函数可引用,但不能改成员函数可引用,但不能改变。变。u如果一个对象被定义成了常对象,只能调用其中的如果一个对象被定义成了常对象,只能调用其中的const成员函数,不能调用非成员函数,不能调用非const成员函数。成员函数。u常成员函数不能调用另一个非常成员函数不能调用另一个非const成员函数成员函数寒取蛹蕴甩雌需昂陨日拼婴蝎雅阔靠莲骤蕊迹躁连断肛信黄蔑阀褐逢乱仓经典C学习经验分享经典C学习经验分享C+ 3- 43 回忆回忆:常对象常对象,常数据成员常数据成员,常成员函数常成员函数classTimepublic:Time(int=0,int=0,int=0);voidcall();inthour;intmin;intsec;Time:Time(inth,intm,ints)hour=h;min=m;sec=s;Timeconstt(2,3,4);/t为常对象为常对象帕磊钡砒邦况桶瘸淹溅狞惊晤俯蛆贫溶问孪关遮扛锈乖蹲畴匙艺捉业笆建经典C学习经验分享经典C学习经验分享C+ 3- 44 回忆回忆:常对象常对象,常数据成员常数据成员,常成员函数常成员函数classTimepublic:voidcall()const;voidTime:call()constcoutCall:hour-min-secendl;Timeconstt(2,3,4);t.call();如果需要访问常对象中的成员函数,则需要将其声明为如果需要访问常对象中的成员函数,则需要将其声明为const。表示这是一个常成员。表示这是一个常成员函数,常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据函数,常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据成员的值。成员的值。喊华腊吐告傣谦户沁政诣丹纬颅桑切航宗拉谍焰评满煮半闪牧感案降腾坛经典C学习经验分享经典C学习经验分享C+ 3- 45 回忆回忆:常对象常对象,常数据成员常数据成员,常成员函数常成员函数lclassTimelpublic:llvoidsetHour(int)const;lmutableinthour;/可以修改可以修改hour的值,通过的值,通过setHour()lintmin;/不可以修改不可以修改min的值,的值,read-onlylintsec;/不可以修改不可以修改sec的值,的值,read-onlyll;llvoidTime:setHour(inth)constlhour=h;lllTimeconstt(2,3,4);lt.setHour(5);如果需要修改常对象中某个数据成员的值,则可将该数据成员声明为如果需要修改常对象中某个数据成员的值,则可将该数据成员声明为mutable。囤苫缔仕您冬缝琼肛答糠左惩犬哮环澳否坚湍床姓藩降艘撰抿霄蠕皋毖韶经典C学习经验分享经典C学习经验分享C+ 3- 46 回忆回忆:常对象常对象,常数据成员常数据成员,常成员函数常成员函数classTimepublic:Time(int,int,int);constinthour;/声明声明hour为常数据成员为常数据成员intmin;intsec;Time:Time(inth,intm,ints):hour(h)/通过参数初始化表通过参数初始化表hour(h)对常数据成员对常数据成员hour初始化初始化min=m;sec=s;Timet(2,3,4);用关键字用关键字const来声明常数据成员。在类体中声明了某一个常数据成员后,该类所有对来声明常数据成员。在类体中声明了某一个常数据成员后,该类所有对象中的该数据成员的值都是不能改变的,但不同对象中该数据成员的值是可以不同的象中的该数据成员的值都是不能改变的,但不同对象中该数据成员的值是可以不同的(在定义对象时给定)。只能通过构造函数的参数初始化表对常数据成员进行初始化。(在定义对象时给定)。只能通过构造函数的参数初始化表对常数据成员进行初始化。树挫蠕糜焰痛朗妄登潞瞻彤呛关猫劫哦雍紫躯碧鸿地冒状嫩蹦氏符噶迈辫经典C学习经验分享经典C学习经验分享C+ 3- 47 3.6共用数据的保护共用数据的保护l指向对象的常指针指向对象的常指针将指向对象的指针变量声明为将指向对象的指针变量声明为const,并将之初始化并将之初始化,可以使,可以使指针值恒定为初始值,即其指向始终不变。如指针值恒定为初始值,即其指向始终不变。如Timet1(10,12,14),t2;/定义对象定义对象Time*constptr=&t1;/定义常指针,恒定指向定义常指针,恒定指向t1对象对象ptr=&t2;/错误,常指针不能改变指向错误,常指针不能改变指向u定义一个指向对象的常指针的格式为:定义一个指向对象的常指针的格式为:类名类名*const指针变量名指针变量名=对象地址;对象地址;u指向对象的常指针,这个变量的值是一个对象的地址,他不允许指向对象的常指针,这个变量的值是一个对象的地址,他不允许被改变,但所指对象的内容可以改变。被改变,但所指对象的内容可以改变。u什么时候需要常指针让其指向对象?如果想将一个指针变量与一什么时候需要常指针让其指向对象?如果想将一个指针变量与一个对象固定地联系在一起,以防止误操作;往往用常指针作为函个对象固定地联系在一起,以防止误操作;往往用常指针作为函数的形参,目的是不允许在函数执行过程中改变指针值,使其始数的形参,目的是不允许在函数执行过程中改变指针值,使其始终指向原来的对象。终指向原来的对象。孰走懈失醋砷详涌苑脾小邑贼膜室桥恬旅男献投货啡煌蓑拥芝无张霄哇镭经典C学习经验分享经典C学习经验分享C+ 3- 48 3.6共用数据的保护共用数据的保护Timet(2,3,4);Time*constp;/error:uninitializedconstpp=&t;Timet(2,3,4);Time*constp=&t;Timett(1,1,1);p=&tt;/error:assignmentofread-onlyvariablepl指向对象的常指针指向对象的常指针楷食铺棕醒雇渣剥熄群棋漂破长几铆佬荆越纫辊幸党谴侄破魂忿蒲莎窥颊经典C学习经验分享经典C学习经验分享C+ 3- 49 3.6共用数据的保护共用数据的保护classTimepublic:voidcall();inthour;private:intmin;voidTime:call()coutCall:hour-min-seccall();p-hour=0;p-min=0;p-call();l指向对象的常指针指向对象的常指针:找出下面的错误找出下面的错误!error:intTime:minisprivate豹财三澄篓编裕懊象敞拴衍间缕仕祷歉氓党赛定沾鸵鸵母拘曳御喝丑泥小经典C学习经验分享经典C学习经验分享C+ 3- 50 3.6共用数据的保护共用数据的保护l指向常对象的指针指向常对象的指针u定义指向常对象的指针格式:定义指向常对象的指针格式:const类名类名*指针名;指针名;这和这和C语言中指向常变量的指针是一样的。只需将上述格式中的类语言中指向常变量的指针是一样的。只需将上述格式中的类名换成类型名就行了。我们不妨在一起作如下讨论:名换成类型名就行了。我们不妨在一起作如下讨论:u如果一个变量被声明为常对象(如果一个变量被声明为常对象(/常变量),只能用指向常对象(常变量),只能用指向常对象(/常常变量)的指针指向它。变量)的指针指向它。如:如:constcharc=boy;/定义定义const型的常字符数组型的常字符数组constchar*p1;/p1为指向常字符变量的指针为指向常字符变量的指针p1=c;/合法,合法,p1指向常变量指向常变量 char*p2=c/非法,非法,p2不是指向常变量的指针不是指向常变量的指针u指向常变量的指针如果指向了非指向常变量的指针如果指向了非const对象,其指向的对象值不能用对象,其指向的对象值不能用指针改变,可以用非指针方式改变。指针改变,可以用非指针方式改变。Timet1(10,12,14);/定义定义Time类对象类对象t1,它不是常对象,它不是常对象constTime*p=&t1;/p是指向常对象是指向常对象t1的指针的指针 t1.hour=18;/合法,合法,t1不是常量不是常量(*p).hour=18;/非法,不能通过指针改变非法,不能通过指针改变t1的值的值案谗佳衅窿回铁课牵疥事拎挫拉腆勋嗅御灸侗参吸伟正敖笺很蛰心行赤酥经典C学习经验分享经典C学习经验分享C+ 3- 51 3.6共用数据的保护共用数据的保护u用指针变量作形参时,形参和实参的对应关系见下表用指针变量作形参时,形参和实参的对应关系见下表形参形参实参实参是否合法是否合法指针所指变指针所指变量值能否改量值能否改变变指向非指向非const变量或变量或非非const对象的指针对象的指针非非const变量的地址变量的地址/非非const对象的地址对象的地址合法合法可以可以const变量的地址变量的地址/const对象的地址对象的地址非法非法/指向常变量或指向常变量或常对象的指针常对象的指针非非const变量的地址变量的地址/非非const对象的地址对象的地址合法合法不可以不可以const变量的地址变量的地址/const对象的地址对象的地址合法合法不可以不可以侗危彩吹野瘫翘赠沂等骗巡喂逮妻称谐凶旷照珐血澡泵买赊殴埃阶混棘识经典C学习经验分享经典C学习经验分享C+ 3- 52 3.6共用数据的保护共用数据的保护u例如:例如:constcharstr=boy;/str是常数组名是常数组名voidfunc(char*ptr);/函数形参为指向非函数形参为指向非const变量的指针变量的指针func(str);/非法,实参是常变量指针,形参是非非法,实参是常变量指针,形参是非const变量指针变量指针u出错原因:出错原因:形参是非指向非形参是非指向非const型变量的指针,在函数中可以也可能改型变量的指针,在函数中可以也可能改变指针所指变量值,而实参是指向常变量的指针,不能被改变,发变指针所指变量值,而实参是指向常变量的指针,不能被改变,发生矛盾。生矛盾。晨酒衫劈闹雇诲积哥赔笆以冯鬼涩恭邻必哭态歼迭庇挖技侵曲杠骂格虫脚经典C学习经验分享经典C学习经验分享C+ 3- 53 3.6共用数据的保护共用数据的保护u指向常对象的指针最常用于函数的形参,目的是保护形参指针所指的对指向常对象的指针最常用于函数的形参,目的是保护形参指针所指的对象,使它在函数执行过程中不被修改。如象,使它在函数执行过程中不被修改。如voidfunc(constTime*P)/形参是指向常对象的指针变量形参是指向常对象的指针变量p-hour=18;/错误,指向的常对象被修改了错误,指向的常对象被修改了couthourendl;voidmain()Timet1(10,12,14);func(&t1);/合法,实参是合法,实参是非非const对象对象t1的地址的地址return;如果如果func形参不是指向形参不是指向const型的型的Time对象的指针,即没有对象的指针,即没有const限限定词,则定词,则t1的的hour就可以被修改。就可以被修改。快痹惯怠汪尚悼杂惭呼仓骄渣饵钨编月伍央据离土纠怕孺功味搭落晒冒宫经典C学习经验分享经典C学习经验分享C+ 3- 54 3.6共用数据的保护共用数据的保护有人可能会问,我不将有人可能会问,我不将func函数的形参定义为函数的形参定义为const型型对象,只将对象,只将t1定义为定义为const型对象,不是也能保护型对象,不是也能保护t1在在func中不被篡改吗?中不被篡改吗?不行,会出现编译错误。因为指向非不行,会出现编译错误。因为指向非const对象的指针对象的指针不能指向不能指向const对象;同理,指向非对象;同理,指向非const变量的指针不能变量的指针不能指向指向const变量。变量。u不能通过指向常对象的指针改变所指对象的值,但指针变不能通过指向常对象的指针改变所指对象的值,但指针变量本身的值可以改变。量本身的值可以改变。邀乳漂毯钝煤瑶兆领荆君蔗葫棘丢蹈瀑钠丸刑秉蝇惋咨桅嗅械务摈内沿处经典C学习经验分享经典C学习经验分享C+ 3- 55 3.6共用数据的保护共用数据的保护l何时使用指向常对象的指针?何时使用常对象?何时使用指向常对象的指针?何时使用常对象?u当希望在调用函数时对象的值不能被修改,就应该把形参当希望在调用函数时对象的值不能被修改,就应该把形参定义为指向常对象的指针,同时用对象的地址做实参,而定义为指向常对象的指针,同时用对象的地址做实参,而实参对象可以是实参对象可以是const型,也可以是非型,也可以是非const型。型。u如果要求对象不仅在函数调用过程中不被修改,而且在整如果要求对象不仅在函数调用过程中不被修改,而且在整个程序运行时不被修改,就应该把该对象定义成常对象。个程序运行时不被修改,就应该把该对象定义成常对象。梅潭迷厌磅茁踌杖烛姜惶晾演卷钩伤绎裳寸侄腑缩古畏砖甥埂息夏筐罚蚂经典C学习经验分享经典C学习经验分享C+ 3- 56 3.6共用数据的保护共用数据的保护l对象的常引用对象的常引用前面讲过,引用主要是用于函数调用,将改变后的变量前面讲过,引用主要是用于函数调用,将改变后的变量值带回到被调用的函数外。值带回到被调用的函数外。但如果不希望在函数中修改参数,可以把引用型形参定但如果不希望在函数中修改参数,可以把引用型形参定义成义成const型:型:函数返回类型函数返回类型函数名函数名(const形参类型形参类型&形参名形参名);则在函数中不能改变形参值,也就不能改变对应的实参值。则在函数中不能改变形参值,也就不能改变对应的实参值。(例例3-8)l什么时候使用常指针和常引用?什么时候使用常指针和常引用?使用常指针或常引用作为函使用常指针或常引用作为函数参数,既能保证数据安全,不被修改;调用函数时又能不数参数,既能保证数据安全,不被修改;调用函数时又能不必建立实参的拷贝,提高了程序运行效率,节省了内存空间。必建立实参的拷贝,提高了程序运行效率,节省了内存空间。河母度即袁赢斡此迎循胚蛤臂体精背梭赦友痴鲜搏摧垢葫芝肪黑驾敢套译经典C学习经验分享经典C学习经验分享C+ 3- 57 3.6共用数据的保护共用数据的保护lconst数据小结数据小结形式形式含义含义Timeconstt1;constTimet1;t1是常对象,其值在任何情况下不能改变是常对象,其值在任何情况下不能改变voidTime:func()constfunc是是Time类中的常成员函数,可以引用,类中的常成员函数,可以引用,但不能修改本类中的数据成员但不能修改本类中的数据成员Time*constp;p是指向是指向Time对象的常指针,对象的常指针,p的值,即的值,即p的指向不能改变的指向不能改变ConstTime*p;p是指向是指向Time类常对象的指针,其指向的对类常对象的指针,其指向的对象的值不能通过指针来改变象的值不能通过指针来改变constTime&t1=t;t1是是Time类对象类对象t的常引用,函数中不能改的常引用,函数中不能改变实参值变实参值斥迈郧锹焙将泉吻客氯怠琢娶糠颊业枪比妨津沮镑桩暗与刀瓷狮霜货崩毕经典C学习经验分享经典C学习经验分享C+ 3- 58 3.7对象的动态建立和释放对象的动态建立和释放l问题的提出问题的提出:前面我们所学创建对象的方法都是静态的,它:前面我们所学创建对象的方法都是静态的,它们在程序们在程序运行过程中所占用的内存空间不能被释放。比如,运行过程中所占用的内存空间不能被释放。比如,在一个函数中定义了一个对象,只有在函数结束时,该对象在一个函数中定义了一个对象,只有在函数结束时,该对象才能被释放。才能被释放。有时候,人们希望对象的创建和释放是在程序运行时,有时候,人们希望对象的创建和释放是在程序运行时,由运行程序的人决定,比如,链表结构的建立和删除,这就由运行程序的人决定,比如,链表结构的建立和删除,这就需要动态建立和释放对象。需要动态建立和释放对象。C+语言用语言用new、delete这两个运算符来实现。内存的这两个运算符来实现。内存的分配和释放,也用来实现对象的建立与撤消。分配和释放,也用来实现对象的建立与撤消。垃牧部梗地惨拽刻隘狙累疮塞通彩眩菩鸟蛇墩片匆经糙填芋紫酬澳酮券轴经典C学习经验分享经典C学习经验分享C+ 3- 59 3.7对象的动态建立和释放对象的动态建立和释放l动态建立对象的方法动态建立对象的方法:如果已经定义了一个如果已经定义了一个Box类,可以用类,可以用new运算符动态地运算符动态地创建一个创建一个Box对象:对象:newBox;系统执行此语句时,首先开辟一段内存空间,并在此空系统执行此语句时,首先开辟一段内存空间,并在此空间中存放一个间中存放一个Box类对象,同时运行该类的构造函数,以初类对象,同时运行该类的构造函数,以初始化该对象,然后返回一个指向该对象的指针值。始化该对象,然后返回一个指向该对象的指针值。但此时用户还不能访问这个对象,因为它既没有对象名,但此时用户还不能访问这个对象,因为它既没有对象名,用户也不知道它的地址。这种对象称为用户也不知道它的地址。这种对象称为无名对象无名对象。我们应该。我们应该这样做:这样做:Box*pt;/定义一个指向定义一个指向Box类对象的指针类对象的指针ptpt=newBox;/创建一个创建一个Box对象,将新对象的指针值赋给对象,将新对象的指针值赋给ptcoutheightendl;韦窒埔崖诅只淖贤荧痉迄饱厘压驭制肚卫蹲北紫映旗菏枪赶箱殿蚌拆酥六经典C学习经验分享经典C学习经验分享C+ 3- 60 3.7对象的动态建立和释放对象的动态建立和释放用用new动态创建的对象一般没有对象名,只能通过指动态创建的对象一般没有对象名,只能通过指针访问。针访问。在执行在执行new运算时,如果内存不足,则创建失败。大运算时,如果内存不足,则创建失败。大多数多数C+编译系统都让编译系统都让new返回一个返回一个0指针,表示内存不足,指针,表示内存不足,操作失败。操作失败。l动态撤消对象的方法动态撤消对象的方法:由:由new创建的对象不再需要时,可以创建的对象不再需要时,可以由由delete运算符释放。上例运算符释放。上例pt的释放方法为:的释放方法为:deletept;这样就撤消了这样就撤消了pt指向的对象。指向的对象。在执行在执行delete运算符时,在释放空间以前,系统自动调用运算符时,在释放空间以前,系统自动调用析构函数,完成有关善后清理工作。析构函数,完成有关善后清理工作。颜但惺冀膊工诧纶缕蔬烟仁圾焦拇蒙躇劲睡劝嘱临茅伟撂考蚤疵蔗阳搐像经典C学习经验分享经典C学习经验分享C+ 3- 61 3.8对象的赋值与复制对象的赋值与复制l对象的赋值对象的赋值u如果一个类定义了两个或多个对象,则这些同类对象之间如果一个类定义了两个或多个对象,则这些同类对象之间可以互相赋值可以互相赋值l一般形式:一般形式:u对象名对象名对象名对象名l赋值过程实际上是将一个对象的成员值一一复制给另一个对赋值过程实际上是将一个对象的成员值一一复制给另一个对象的对应成员完成的象的对应成员完成的l例例l注意:注意:u对象的赋值只对其中的数据成员赋值,而不对成员函数赋对象的赋值只对其中的数据成员赋值,而不对成员函数赋值值u类的数据成员中不能包括动态分配的数据,否则可能出现类的数据成员中不能包括动态分配的数据,否则可能出现严重后果严重后果砧赤披官邯召盾雨左尤齿懒菊箱村峦壶狐力籽拌归己羡慕迂掀越剧键堆糜经典C学习经验分享经典C学习经验分享C+ 3- 62 3.8对象的赋值与复制对象的赋值与复制l对象的复制对象的复制u问题的提出:问题的提出:有时需要多个完全相同的对象,用前面介绍有时需要多个完全相同的对象,用前面介绍的办法进行处理,我们得定义多个同类对象,然后用相同的办法进行处理,我们得定义多个同类对象,然后用相同的数据去构造初始化它们,比较费时麻烦。可不可以用克的数据去构造初始化它们,比较费时麻烦。可不可以用克隆的方法呢?隆的方法呢?可以。可以。C+可以根据一个已知的对象快速地复制出多个可以根据一个已知的对象快速地复制出多个完全相同的对象。比如:完全相同的对象。比如:Boxbox2(box1);其作用就是对象的克隆,即用一个已知的对象其作用就是对象的克隆,即用一个已知的对象box1复复制出一个完全相同的新对象制出一个完全相同的新对象box2。u对象复制的格式:对象复制的格式:类名类名被克隆出来的新对象名(已有的对象名);被克隆出来的新对象名(已有的对象名);添宅锰站闲锁薄植钒笑殉趴瑶猖兼谗粗赃盾它魔钠舶靳蛙跳告毙悔幌岿驻经典C学习经验分享经典C学习经验分享C+ 3- 63 3.8对象的赋值与复制对象的赋值与复制从上面的一般形式可以看出,复制对象是一种特殊的构从上面的一般形式可以看出,复制对象是一种特殊的构造对象方法,其构造参数参数不是一般变量,而必须是一个造对象方法,其构造参数参数不是一般变量,而必须是一个对象!请看:对象!请看:/复制构造函数复制构造函数Box:Box(constBox&b)height=b.height;width=b.width;height=b.height;复制构造函数也是构造函数,它只有一个参数,这个参复制构造函数也是构造函数,它只有一个参数,这个参数是本类已有对象,而且采用常引用形式,使参数不能被改数是本类已有对象,而且采用常引用形式,使参数不能被改变。复制构造函数的作用是将实参对象的各个数据成员值一变。复制构造函数的作用是将实参对象的各个数据成员值一一赋予给新的对象中对应的数据成员。一赋予给新的对象中对应的数据成员。陵刑唇庇灭盆爽哼虱横爆棠牌吭讲亲餐旨抉焉劝聊负携聚压私翱呈糟晕芳经典C学习经验分享经典C学习经验分享C+ 3- 64 3.8对象的赋值与复制对象的赋值与复制C+还使用另一种方便的对象复制形式,形式为:还使用另一种方便的对象复制形式,形式为:类名类名目标对象名目标对象名=源象名;源象名;如:如:Boxbox2=box1,box3=box2;l对象的赋值与复制的不同点对象的赋值与复制的不同点u对象的赋值:对象的赋值:是在已经存在的对象之间进行数据赋值,因是在已经存在的对象之间进行数据赋值,因此必须先定义,再赋值;参数表是一般变量此必须先定义,再赋值;参数表是一般变量u对象的复制对象的复制:从无到有地建立一个相同的新对象,参数只:从无到有地建立一个相同的新对象,参数只有一个,而且是已有的同类对象。有一个,而且是已有的同类对象。u两者形式的不同:两者形式的不同:类名类名(形参表列)(形参表列);/普通构造函数的声明普通构造函数的声明类名类名(类名(类名&对象名对象名);/复制构造函数的声明复制构造函数的声明胡舜尔检伙绸士逗频峰究娱萝个窄墨桩锤勤酌迹逐腐淑恨碘惶狰谗陀纹野经典C学习经验分享经典C学习经验分享C+ 3- 65 3.8对象的赋值与复制对象的赋值与复制l什么时候使用复制构造函数?什么时候使用复制构造函数?u程序中需要建立一个对象,并用另一个已知对象初始化它,系统自动调用程序中需要建立一个对象,并用另一个已知对象初始化它,系统自动调用复制构造函数;复制构造函数;u当函数的参数是类的对象时,系统自动调用复制构造函数;当函数的参数是类的对象时,系统自动调用复制构造函数;voidmain()Boxb1(12,13,15);func(b1);u当函数的返回值是类的对象,系统自动调用复制构造函数当函数的返回值是类的对象,系统自动调用复制构造函数Boxf()Boxb1(12,14,16);returnb1;/返回值是返回值是Box类的对象类的对象voidmain()Boxb2;b2=f();/f函数返回函数返回Box类的临时对象,并将它赋值给类的临时对象,并将它赋值给b2由于由于b1是在函数是在函数f中定义的,函数中定义的,函数f结束时,结束时,b1的生命期就结束了。因的生命期就结束了。因此不能将此不能将b1带回给带回给main函数,实际上,在函数,实际上,在f结束前,执行结束前,执行return语句时,复语句时,复制一个制一个b1一样的临时对象,然后将它赋值给一样的临时对象,然后将它赋值给b2。近右各塌轨晾茎凭资苫阻醒覆愤沂甚鹅母涵帕直孪必疲臼萍巫堆睹饥停畴经典C学习经验分享经典C学习经验分享C+ 3- 66 3.9静态成员静态成员在在C语言中,如果想在多个函数中共享一个变量值,我们语言中,如果想在多个函数中共享一个变量值,我们一般用全局变量。但由于全局变量破坏了封装性,安全得不到一般用全局变量。但由于全局变量破坏了封装性,安全得不到保证,在保证,在C+中不提倡使用全局变量,我们可以使用静态的数中不提倡使用全局变量,我们可以使用静态的数据成员来达到这个目的。据成员来达到这个目的。l静态数据成员静态数据成员u静态数据成员以静态数据成员以static关键字定义。例如:关键字定义。例如:classstudentpublic:intdisplay();private:staticintcount;charname10;intage;兑氛慕别约筋娇蜜劝簧恿底绳初幸萨赤叫馈忙夸咎沽凤俞乐娃皂抠找腐逼经典C学习经验分享经典C学习经验分享C+ 3- 67 3.9静态成员静态成员将对象中的将对象中的count数据成员定义成数据成员定义成static型,它就被型,它就被同一种类的各个对象所共有,而不只属于某一个对象。静态同一种类的各个对象所共有,而不只属于某一个对象。静态数据成员只占一份内存空间,而不是各个对象个拥有一份内数据成员只占一份内存空间,而不是各个对象个拥有一份内存空间!每个对象都可以引用这个静态数据成员。静态数据存空间!每个对象都可以引用这个静态数据成员。静态数据成员的值对各个对象都是一样的。如果改变它的值,则在各成员的值对各个对象都是一样的。如果改变它的值,则在各个对象中这个数据成员的值都同时改变。个对象中这个数据成员的值都同时改变。似瓦作岗史悲纵郊泄碍搐飞我错滁逊它橡妊痒秒韵如雁很铁吊惠附犹雅拟经典C学习经验分享经典C学习经验分享C+ 3- 68 3.9静态成员静态成员说明说明:u在为对象分配空间时,不分配静态数据成员的空间,因为它不属在为对象分配空间时,不分配静态数据成员的空间,因为它不属于任何对象。只要类中定义了静态数据成员,即使不定义对象,编于任何对象。只要类中定义了静态数据成员,即使不定义对象,编译系统也要为静态数据成员开辟内存空间。译系统也要为静态数据成员开辟内存空间。uC语言中,我们知道,如果在一个函数中定义了一个静态变量,在语言中,我们知道,如果在一个函数中定义了一个静态变量,在函数结束时该静态变量不被释放,并保留其值。静态数据成员也是函数结束时该静态变量不被释放,并保留其值。静态数据成员也是这样,它不随对象的建立而分配空间,也不随对象的撤消而释放空这样,它不随对象的建立而分配空间,也不随对象的撤消而释放空间,其值也被保留。静态数据成员在程序被编译时就分配了空间,间,其值也被保留。静态数据成员在程序被编译时就分配了空间,在程序结束时,才释放空间。在程序结束时,才释放空间。u静态数据成员可以被初始化,但只能在类体之外初始化:静态数据成员可以被初始化,但只能在类体之外初始化:数据类型数据类型类名类名:静态数据成员名静态数据成员名=初值;初值;不必在初始化语句中加不必在初始化语句中加static关键字,不能用参数初始化表初始关键字,不能用参数初始化表初始化静态数据成员:化静态数据成员:student(intc,char*p,inta):count(c)/错误,错误,count是静态数据成员是静态数据成员快隆游私括煽点孝饲潘乎畴谁山扰博旱错活嘘制纽胡南敏紊穴料锑奸涯耍经典C学习经验分享经典C学习经验分享C+ 3- 69 3.9静态成员静态成员u静态数据成员既可以通过类名引用,也可以通过对象名引用。静态数据成员既可以通过类名引用,也可以通过对象名引用。#includeusingnamespacestd;classBoxpublic:Box(int,int);intvolume();staticintheight;intwidth;intlength;Box:Box(intw,intlen)width=w;length=len;intBox:volume()return(height*width*length);intBox:height=10;intmain()Boxa(15,20),b(20,30);couta.heightendl;coutb.heightendl;coutBox:heightendl;couta.volume()endl;return0;罢摈叁万辱民兢沛犬绣容钩馅促磨兆绦扁再酉鄂雪侵颠抵垛汽滥拣叠迎秸经典C学习经验分享经典C学习经验分享C+ 3- 70 3.9静态成员静态成员l静态成员函数静态成员函数u在类的定义中,成员函数前如果加了在类的定义中,成员函数前如果加了static限定词,该限定词,该成员函数就成为静态成员函数。例:成员函数就成为静态成员函数。例:staticintvolume();u用途:静态成员函数的作用不是为了对象之间的沟通,主用途:静态成员函数的作用不是为了对象之间的沟通,主要是为了引用本类中的静态数据成员。它可以直接引用本要是为了引用本类中的静态数据成员。它可以直接引用本类的静态数据成员。类的静态数据成员。u静态成员函数与普通成员函数的区别:静态成员函数没有静态成员函数与普通成员函数的区别:静态成员函数没有this指针,由此决定静态成员函数不能访问本类中的非静指针,由此决定静态成员函数不能访问本类中的非静态数据成员,除非用态数据成员,除非用对象名对象名.非静态数据成员非静态数据成员的形式。的形式。婿叼纂癣嚎沏携却盟满臃扮赤喀迈龋坪哼阑式铜粮裤漂棍氖势手云尉灵坡经典C学习经验分享经典C学习经验分享C+ 3- 71 3.9静态成员静态成员u静态成员函数示例静态成员函数示例#includeusingnamespacestd;classStudentpublic:Student(int,int,int);voidtotal();staticfloataverage();private:intnum;intage;floatscore;staticfloatsum;staticintcount;Student:Student(intm,inta,ints)num=m;age=a;score=s;voidStudent:total()sum+=score;count+;floatStudent:average()return(sum/count);floatStudent:sum=0;intStudent:count=0;intmain()Studentstud3=Student(1001,18,70),Student(1002,19,79),Student(1005,20,98);intn;coutn;for(inti=0;in;i+)studi.total();coutTheaveragescoreofnstudentsisstud0.average()i=a;voidX:member_func(inta)/memberfunctiondefinitioni=a;陇粮剩嘴屯洽垒执岳篷杏仟籽桐萝驶独罩马漱呵鸭展拐逝疽同馋吕含惑开经典C学习经验分享经典C学习经验分享C+ 3- 74 一个友元的综合示例一个友元的综合示例#includeusingnamespacestd;classTimepublic:Time(int,int,int);friendvoiddisplay(Time&);private:inthour;intminute;intsec;Time:Time(inth,intm,ints)hour=h;minute=m;sec=s;voiddisplay(Time&t)coutt.hour:t.minute:t.secendl;intmain()Timet1(10,13,56);display(t1);return0;结果结果:10:13:56/友员函数既可以在友员函数既可以在PUBLIC,/也可在也可在PRIVATE呀舀膛酮试乔碳典槐括含疲海串旁四卞螺堪鸭矢冶呸矾吩鞋录雁惋锈贺片经典C学习经验分享经典C学习经验分享C+ 3- 75 3.10友元友元l友元成员函数:友元成员函数:friend函数也可以是另一个类中的成员函数。函数也可以是另一个类中的成员函数。#includeusingnamespacestd;classDate;classTimepublic:Time(int,int,int);voiddisplay(constDate&);private:inthour;intminute;intsec;classDatepublic:Date(int,int,int);friendvoidTime:display(constDate&);private:intmonth;intday;intyear;Time:Time(inth,intm,ints)hour=h;minute=m;sec=s;voidTime:display(constDate&da)coutda.month/da.day/da.yearendl;couthour:minute:secendl;Date:Date(intm,intd,inty)month=m;day=d;year=y;intmain()Timet1(10,13,56);Dated1(12,25,2004);t1.display(d1);return0;绰窖渤节珊韦献要加拱讳镰溅拜岛惩再剐螟辑夜寺厦娩锡艇内耘猿丁封寐经典C学习经验分享经典C学习经验分享C+ 3- 76 3.10友元友元l友元类:友元类:当说明一个类为另一个类的友元时,友元类中的当说明一个类为另一个类的友元时,友元类中的所有成员函数都是另一个类的友元函数。例如:所有成员函数都是另一个类的友元函数。例如:#includeclassXpublic:friendclassY;/类类Y是类是类X的友元类的友元类voidset(inti)x=i;voiddisplay()coutx=x,y=yendl;private:intx;staticinty;/静态数据说明静态数据说明;classYpublic:Y(inti,intj);voiddisplay();private:Xa;/数据成员为类数据成员为类X的对象的对象;intX:y=10;/静态数据定义并初始化静态数据定义并初始化Y:Y(inti,intj)a.x=i;X:y=j;voidY:display()coutx=a.x,y=X:yy)?x:y;private:intx,y;classcompare_charpublic:compare_char(chara,charb)x=a;y=b;charmax()return(xy)?x:y;private:charx,y;voidmain()compare_intc1(5,6);coutc1.max()endl;compare_charc2(a,f);coutc2.max()endl;董逛责图蕴席酚组逆林樱剿命肚像桑亡翰邵闸颅奥培办燕挨鹰碑详郭丝忙经典C学习经验分享经典C学习经验分享C+ 3- 78 3.11类模板类模板(ClassTemplates)l类模板的定义:类模板的定义:为解决这一问题,为解决这一问题,C+引进类模板的概念。我们在类的引进类模板的概念。我们在类的声明前先加一行模板关键字。它用一个通用参数声明前先加一行模板关键字。它用一个通用参数T来替代不来替代不同的数据类型。类模板的定义格式为:同的数据类型。类模板的定义格式为:templateclass/类体说明类体说明;其中其中template是关键字;是关键字;中可以有多个中可以有多个参数,其间用逗号分隔。参数,其间用逗号分隔。l使用类模板定义对象的:使用类模板定义对象的:类模板名类模板名对象名对象名(实参列表实参列表);例如:下面是一个数组类模板的例子例如:下面是一个数组类模板的例子宴篮混遏腥寸褒皂致片奄碘椰框魁浆声烹烘磨矛肝栈挫胰挚文付蠕堪谰念经典C学习经验分享经典C学习经验分享C+ 3- 79 #includetemplateclasscomparepublic:compare(Ta,Tb)x=a;y=b;Tmax()return(xy)?x:y;private:Tx,y;voidmain()comparecmp1(3,7);coutcmp1.max()是两个整数中最大的数是两个整数中最大的数endl;comparecmp2(a,g);coutcmp2.max()是两个字符中最大的字符是两个字符中最大的字符endl;comparecmp3(1.0,3.0);coutcmp3.max()是两个浮点数中最大的数是两个浮点数中最大的数endl;芳闯久饶躬饥报烬腔爷蘑旨甜腔谓瞻峡断够厩久讶俭金页厉锌巡筋醚侠洒经典C学习经验分享经典C学习经验分享
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号