




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章怎样使用类和对象9.1利用构造函数对类对象进行初始化9.2析构函数9.3调用构造函数和析构函数的顺序9.4对象数组9.5对象指针9.6共用数据的保护9.7对象的动态建立和释放9.8对象的赋值和复制9.9静态成员9.10友元9.11类模板第9章怎样使用类和对象9.1利用构造函数对类对象进行19.1利用构造函数对类对象进行初始化9.1.1对象的初始化在建立一个对象时,常常需要作某些初始化的工作,例如对数据成员赋初值。如果一个数据成员未被赋值,则它的值是不可预知的。注意:类的数据成员是不能在声明类时初始化的。classTime{public://声明为公用成员
hour=0;//错:类的数据成员不能在定义时初始化minute=0;//错:类的数据成员不能在定义时初始化sec=0;//错:类的数据成员不能在定义时初始化};
9.1利用构造函数对类对象进行初始化9.1.1对象的初2如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成员进行初始化。如classTime{public://声明为公用成员
hour;minute;sec;};Timet1={14,56,30};//将t1初始化为14:56:30但是,如果数据成员是私有的,或者类中有private或protected的成员,就不能用这种方法初始化。
如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成3structStudent//结构声明{intnum;charname[20];floatscore;};Studentstu1={1001,“zhangsan”,89};//对定义结构体变量时同时初始化对结构体,其成员默认是publicstructStudent//结构声明{private:intnum;charname[20];floatscore;};Studentstu1={1001,“zhangsan”,89};//错错:不能对私有成员初始化structStudent//结构声明定义结构体变4Student类classStudent//类声明{private:intnum;charname[20];floatscore;
public:voiddisplay(){cout<<"num:"<<num<<endl;cout<<"name:"<<name<<endl;cout<<"score:"<<score<<endl;}}数据成员是私有的,本类外不能直接访问Studentstu1={1001,”zhangsan”,89};//定义对象并初始化?不能!Student类classStudent//类声5C++提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数的名字必须与类名同名,而不能由用户任意命名,以便编译系统能识别它并把它作为构造函数处理。它不具有任何类型,不返回任何值。构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数。9.1.2构造函数的作用C++提供了构造函数(constructor)来6创建Student类的构造函数#include<iostream>usingnamespacestd;classStudent{private:intnum;charname[20];floatscore;public:
Student(intn,char*p,floats);
//构造函数的声明voiddisplay();};Student::Student(intn,char*p,floats)//构造函数的定义{num=n;strcpy(name,p);score=s;}创建Student类的构造函数#include<iost7创建Student类的构造函数voidStudent::display(){cout<<"display:"<<endl;cout<<"num:"<<num<<endl;cout<<"name:"<<name<<endl;cout<<"score:"<<score<<endl;};intmain(){Studentstu1(1001,"zhangsan",89);
stu1.display();return0;}在建立对象stu1时,系统自动调用构造函数一次:Student(1001,"zhangsan",89)将初始值存储到对象stu1中。创建Student类的构造函数voidStudent::d8#include<iostream>usingnamespacestd;classStudent{private:intnum;charname[20];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)//输入函数的定义#include<iostream>构造函数代码与inp9voidStudent::display(){cout<<"display:"<<endl;cout<<"num:"<<num<<endl;cout<<"name:"<<name<<endl;cout<<"score:"<<score<<endl;};intmain(){Studentstu1;stu1.input(1001,"zhangsan",89);
stu1.display();return0;}构造函数代码与input()函数相同要调用对象stu1的成员函数input(),通过它输入相关的数据。voidStudent::display()构造函数代码10特殊的类成员函数;与类名同名;
虽然没有返回值,但没有被声明为void类型。实际上,构造函数没有声明类型;在建立对象时自动调用执行;C++为构造函数提供了名称和使用句法,程序员则根据初始化的要求设计函数体和函数参数。构造函数特性
特殊的类成员函数;构造函数特性
11例9.1在例8.3基础上定义构造成员函数。#include<iostream>usingnamespacestd;classTime{public:
Time()//定义构造成员函数,函数名与类名相同
{hour=0;//利用构造函数对对象中的数据成员赋初值
minute=0;
sec=0;
}voidset_time();//函数声明voidshow_time();//函数声明private:
inthour;//私有数据成员
intminute;
intsec;};例9.1在例8.3基础上定义构造成员函数。12voidTime∷set_time()//定义成员函数,向数据成员赋值{cin>>hour;cin>>minute;cin>>sec;}voidTime∷show_time()//定义成员函数,输出数据成员的值{
cout<<hour<<″:″<<minute<<″:″<<sec<<endl;}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的时、分、秒值)voidTime∷set_time()/13也可以只在类内对构造函数进行声明而在类外定义构造函数。classTime{public:
Time()
{hour=0;
minute=0;
sec=0;
}voidset_time();voidshow_time();private:inthour;intminute;intsec;};classTime{public:
Time();voidset_time();voidshow_time();private:inthour;intminute;intsec;};Time::Time(){hour=0;
minute=0;
sec=0;
}也可以只在类内对构造函数进行声明而在类外定义构造函数。cla14在例9.1中构造函数不带参数,在函数体中对数据成员赋初值。这种方式使该类的每一个对象都得到同一组初值(例如例9.1中各数据成员的初值均为0)。但是有时用户希望对不同的对象赋予不同的初值。可以采用带参数的构造函数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现不同的初始化。构造函数首部的一般格式为
构造函数名(类型1形参1,类型2形参2,…)前面已说明:用户是不能调用构造函数的,因此无法采用常规的调用函数的方法给出实参。实参是在定义对象时给出的。定义对象的一般格式为
类名对象名(实参1,实参2,…);9.1.3带参数的构造函数在例9.1中构造函数不带参数,在函数体中对数据成员15有两个长方柱,其长、宽、高分别为:(1)12,20,25;(2)10,14,20。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。#include<iostream>usingnamespacestd;classBox{public:
Box(int,int,int);//声明带参数的构造函数intvolume();//声明计算体积的成员函数
private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen)//在类外定义带参数的构造函数{height=h;width=w;length=len;}//例9.2有两个长方柱,其长、宽、高分别为:(1)12,2016intBox∷volume()//定义计算体积的成员函数{return(height*width*length);}intmain(){Boxbox1(12,25,30);//建立对象box1,并指定box1长、宽、高的值cout<<″Thevolumeofbox1is″<<box1.volume()<<endl;Boxbox2(15,30,21);//建立对象box2,并指定box2长、宽、高的值cout<<″Thevolumeofbox2is″<<box2.volume()<<endl;return0;}程序运行结果如下:Thevolumeofbox1is9000Thevolumeofbox2is9450//例9.2intBox∷volume()17在9.1.3节中介绍的是在构造函数的函数体内通过赋值语句对数据成员实现初始化。C++还提供另一种初始化数据成员的方法——参数初始化表来实现对数据成员的初始化。这种方法不在函数体内对数据成员初始化,而是在函数首部实现。例如例9.2中定义构造函数可以改用以下形式:Box∷Box(inth,intw,intlen):height(h),width(w),length(len){}类名::构造函数名(参数表):成员初始化表
{构造函数体}这种写法方便、简练,尤其当需要初始化的数据成员较多时更显其优越性。甚至可以直接在类体中(而不是在类外)定义构造函数。9.1.4用参数初始化表对数据成员初始化在9.1.3节中介绍的是在构造函数的函数体内通过赋值语句对数18classBox{public:
Box(int,int,int);intvolume();private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen){height=h;width=w;length=len;}赋值语句对数据成员实现初始化classBox{public:
Box(int,int,int);intvolume();private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen):height(h),width(w),length(len){}参数初始化表实现对数据成员的初始化classBoxclassBox19在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法,供用户选用。这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。这称为构造函数的重载。在第4章第4.8节中所介绍的函数重载的知识也适用于构造函数。9.1.5构造函数的重载在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化20例9.3在例9.2的基础上,定义两个构造函数,其中一个无参数,一个有参数。#include<iostream>usingnamespacestd;classBox{public:
Box();
//声明一个无参的构造函数
Box(inth,intw,intlen):height(h),width(w),length(len){};
//声明一个有参的构造函数,用参数的初始化表对数据成员初始化intvolume();private:intheight;intwidth;intlength;};Box∷Box()//定义一个无参的构造函数{height=10;width=10;length=10;}例9.3在例9.2的基础上,定义两个构造函数,其中一个无参21intBox∷volume(){return(height*width*length);}intmain(){Boxbox1;//建立对象box1,不指定实参cout<<″Thevolumeofbox1is″<<box1.volume()<<endl;Boxbox2(15,30,25);//建立对象box2,指定3个实参cout<<″Thevolumeofbox2is″<<box2.volume()<<endl;return0;}intBox∷volume()22说明:(1)在建立对象时不必给出实参的构造函数,称为默认构造函数(defaultconstructor)。显然,无参的构造函数属于默认构造函数。一个类只能有一个默认构造函数。(2)如果在建立对象时选用的是无参构造函数,应注意正确书写定义对象的语句:类名对象名;(3)尽管在一个类中可以包含多个构造函数,但是对于每一个对象来说,建立对象时只执行其中一个构造函数,并非每个构造函数都被执行。说明:23
构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。在第4章第4.10节中介绍过在函数中可以使用有默认值的参数。在构造函数中也可以采用这样的方法来实现初始化。9.1.6使用默认参数的构造函数构造函数中参数的值既可以通过实参传递,也可以指定为某24例9.4将例9.3程序中的构造函数改用含默认值的参数,长、宽、高的默认值均为10#include<iostream>usingnamespacestd;classBox{public:
Box(inth=10,intw=10,intlen=10);//在声明构造函数时指定默认参数intvolume();private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen)//在定义函数时可以不指定默认参数{height=h;width=w;length=len;}例9.4将例9.3程序中的构造函数改用含默认值的参数,25intBox∷volume(){return(height*width*length);}intmain(){Boxbox1;//没有给实参cout<<″Thevolumeofbox1is″<<box1.volume()<<endl;Boxbox2(15);//只给定一个实参cout<<″Thevolumeofbox2is″<<box2.volume()<<endl;Boxbox3(15,30);//只给定2个实参cout<<″Thevolumeofbox3is″<<box3.volume()<<endl;Boxbox4(15,30,20);//给定3个实参cout<<″Thevolumeofbox4is″<<box4.volume()<<endl;return0;}intBox∷volume()26当对象的生命期结束时,会自动执行析构函数。每个类只能有一个析构函数;析构函数没有返回类型(连void也没有),也没有参数;其名称为类名称前加上~~Student();//Student类析构函数析构函数的任务由程序设计者安排。如:完成清理工作,释放内存等。
9.2析构函数当对象的生命期结束时,会自动执行析构函数。9.2析构函27classStudent{private:intnum;charname[20];floatscore;public:
Student(intn,char*p,floats);
//构造函数声明
~Student();//析构函数声明 voiddisplay() {cout<<"\ndisplay:\nnum:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"score:"<<score<<endl; }};intmain(){Studentstu1(1001,"zhangsan",89);stu1.display();return0;//当函数结束前,要释放对象stu1的空间,此时自动调用~Student}Student::Student(intn,char*p,floats)//构造函数定义{num=n;strcpy(name,p);score=s;}Student::~Student()//析构函数定义{cout<<“结束”;}classStudent28例:
classAA{AA(){……}//构造函数~AA(){……}//析构函数……};……voidtest(){intx,y; AAt1,t2; ……return;}构造函数和析构函数例:构造函数和析构函数29例:
classAA{AA(){……}~AA(){……}……};……voidtest(){intx,y; AAt1,t2; ……return;}构造函数构造函数和析构函数例:构造函数构造函数和析构函数30例:
classAA{AA(){……}
~AA(){……}……};……voidtest(){intx,y; AAt1,t2; ……return;}析构函数构造函数和析构函数例:析构函数构造函数和析构函数31例:
classAA{AA(){……}~AA(){……}……};……voidtest(){intx,y;
AAt1,t2; ……return;}//声明变量时开辟两个整型存储空间构造函数和析构函数例://声明变量时开辟两个整型存储空间构造函数和析构32例:
classAA{AA(){……}~AA(){……}……};……voidtest(){intx,y;
AAt1,t2;
……return;}//创建2个对象,两次调用构造函数构造函数和析构函数例://创建2个对象,两次调用构造函数构造函数和33例:
classAA{AA(){……}~AA(){……}……};……voidtest(){intx,y;
AAt1,t2;
……return;}//创建2个对象,两次调用构造函数构造函数和析构函数例://创建2个对象,两次调用构造函数构造函数和34例:
classAA{AA(){……}~AA(){……}……};……voidtest(){intx,y; AAt1,t2; ……
return;}//两次调用析构函数,撤消对象构造函数和析构函数例://两次调用析构函数,撤消对象构造函数和析构函数35例:
classAA{AA(){……}
~AA(){……}……};……voidtest(){intx,y; AAt1,t2; ……
return;}//两次调用析构函数,撤消对象构造函数和析构函数例://两次调用析构函数,撤消对象构造函数和析构函数36例:
classAA{AA(){……}~AA(){……}……};……voidtest(){intx,y; AAt1,t2; ……
return;}//两次调用析构函数,撤消对象//变量x,y生存期结束构造函数和析构函数例://两次调用析构函数,撤消对象//变量x,y生存37有两个长方柱,其长、宽、高分别为:(1)12,20,25;(2)10,14,20。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。#include<iostream>usingnamespacestd;classBox{public:
Box(int,int,int);
//声明带参数的构造函数
~Box();//没有函数类型,没有参数intvolume();//声明计算体积的成员函数
private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen)//在类外定义带参数的构造函数{height=h;width=w;length=len;
cout<<“构造函数被调用”<<endl;}Box::~Box(){cout<<“析构函数被自动调用”<<endl;}有两个长方柱,其长、宽、高分别为:(1)12,20,25;38intBox∷volume()//定义计算体积的成员函数{return(height*width*length);}intmain(){Boxbox1(12,25,30);
//建立对象box1,并指定box1长、宽、高的值cout<<″Thevolumeofbox1is″<<box1.volume()<<endl;Boxbox2(15,30,21);
//建立对象box2,并指定box2长、宽、高的值cout<<″Thevolumeofbox2is″<<box2.volume()<<endl;return0;//结束时,自动调用析构函数}显示:构造函数被调用
Thevolumeofbox1is
9000构造函数被调用
Thevolumeofbox2is
9450
析构函数被调用析构函数被调用intBox∷volume()399.3调用构造函数和析构函数的顺序在使用构造函数和析构函数时,需要特别注意对它们的调用时间和调用顺序。在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。如图9.1示意。9.3调用构造函数和析构函数的顺序在使40图9.1C++程序设计-cchp9怎样使用类和对象课件419.3调用构造函数和析构函数的顺序main(){Boxbox1(1,2,3);Boxbox2(2,5,3);Boxbox3(1,1,1);…………return;}box1的构造函数被调用Box2的构造函数被调用Box3的构造函数被调用Box3的析构函数被调用Box2的析构函数被调用Box1的析构函数被调用9.3调用构造函数和析构函数的顺序main()box142但是,并不是在任何情况下都是按这一原则处理的。在第4章第4.11和4.12节中曾介绍过作用域和存储类别的概念,这些概念对于对象也是适用的。对象可以在不同的作用域中定义,可以有不同的存储类别。这些会影响调用构造函数和析构函数的时机。下面归纳一下什么时候调用构造函数和析构函数:(1)在全局范围中定义的对象(即在所有函数之外定义的对象),它的构造函数在文件中的所有函数(包括main函数)执行之前调用。但如果一个程序中有多个文件,而不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时(此时程序终止),调用析构函数。但是,并不是在任何情况下都是按这一原则处理的43Boxbox1(1,2,3);main(){Boxbox2(2,5,3);Boxbox3(1,1,1);…………return;}全局对象box1的构造函数被调用局部自动对象Box2的构造函数被调用局部对象Box3的构造函数被调用Box3的析构函数被调用Box2的析构函数被调用Box1的析构函数被调用Boxbox1(1,2,3);全局对象box1的构造函数44(2)如果定义的是局部自动对象(例如在函数中定义对象),则在建立对象时调用其构造函数。如果函数被多次调用,则在每次建立对象时都要调用构造函数。在函数调用结束、对象释放时先调用析构函数。(3)如果在函数中定义静态(static)局部对象,则只在程序第一次调用此函数建立对象时调用构造函数一次,在调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。(2)如果定义的是局部自动对象(例如在函数中定义对象),则459.4对象数组数组不仅可以由简单变量组成(例如整型数组的每一个元素都是整型变量),也可以由对象组成(对象数组的每一个元素都是同类的对象)。对于已经定义的类Student:Studentstu[3];//stu是对象数组在建立数组时,同样要调用构造函数。如果有3个元素,自动调用3次构造函数。若定义数组时要初始化,只能用构造函数:Studentstu[3]={Student(1001,18,87),Student(1002,19,90),Student(1001,17,85)};9.4对象数组数组不仅可以由简单变量组成(例如整46如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供实参。如Student::Student(intno){……};Studentstud[3]={60,70,78};//合法,3个实参分别传递
//给3个数组元素的构造函数当然,也可以:Studentstud[3]={Student(60),Student(70),Student(78)};如果构造函数有多个参数,则不能用在定义数组时直接提供所有实参的方法,要用构造函数Student::Student(intno,ints1,ints2
){……};Studentstu[3]={Student(1001,18,87),Student(1002,19,90),Student(1001,17,85)};如果构造函数只有一个参数,在定义数组时可以直47有3个长方柱,其长、宽、高分别为:(1)3,2,1;(2)6,4,5;(3)2,2,2。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。#include<iostream>usingnamespacestd;classBox{public:
Box(int,int,int);
//声明带参数的构造函数
intvolume();//声明计算体积的成员函数
private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen)//在类外定义带参数的构造函数{height=h;width=w;length=len;}有3个长方柱,其长、宽、高分别为:(1)3,2,1;(2)48intBox∷volume()//定义计算体积的成员函数{return(height*width*length);}intmain(){Boxa[3]={Box(3,2,1),//用构造函数初始化box[0]
Box(6,5,4),//用构造函数初始化box[1]Box(2,2,2)//用构造函数初始化box[2]};inti;for(i=0;i<3;i++)cout<<″Thevolumeofbox”<<i+1<<“is″<<a[i].volume()<<endl;return0;//结束时,自动调用析构函数}intBox∷volume()49习题9.5
建立对象数组,内放5个学生数据(学号,成绩),设立一个函数max,用指向对象的指针作为函数参数,在max函数中找出成绩最高者,输出其学号。#include"iostream"usingnamespacestd;classStudent{private:intnum;floatscore;
public:Student(intnu,floatsco):num(nu),score(sco){};voiddisplay();friendvoidmax(Student*,int);//友元函数声明};习题9.5建立对象数组,内放5个学生数据(学号,成绩50voidStudent::display(){cout<<"学号:"<<num<<"分数:"<<score<<endl;}voidmax(Student*ps,intn){inti,k;k=0;for(i=1;i<n;i++)if((*(ps+k)).score<(*(ps+i)).score)k=i;cout<<"成绩最高者的学号:"<<(*(ps+k)).num<<endl;}voidStudent::display()51intmain(){Studentstu[5]={Student(1001,75),Student(1002,78), Student(1003,95), Student(1004,60), Student(1005,62)};inti;for(i=0;i<5;i++)stu[i].display();max(stu,5);return0;}学号:1001分数:75学号:1002分数:78学号:1003分数:95学号:1004分数:60学号:1005分数:62成绩最高者的学号:1003Pressanykeytocontinueintmain()学号:1001分数:75529.5对象指针9.5.1指向对象的指针
在建立对象时,编译系统会为每一个对象分配一定的存储空间,以存放其成员。对象空间的起始地址就是对象的指针。可以定义一个指针变量,用来存放对象的指针。对于已经定义的类Student:Student*p;//p是指向对象的指针变量Studentstu;//stu是对象p=&stu;//p指向了对象stu则:stu.num相当于(*p).nump->相当于(*p).namep->namestu.display()相当于p->display()9.5对象指针9.5.1指向对象的指针539.5.2指向对象成员的指针对象有地址,存放对象初始地址的指针变量就是指向对象的指针变量。对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量。classTime{public:inthour;intminute;intsec;voidget_time();};Timet;对象t有存储地址;t中的成员t.hour,t.minute,t.sec也有存储地址。可定义指针变量指向这些成员。9.5.2指向对象成员的指针对象有地址,存54指向对象数据成员的指针定义指向对象数据成员的指针变量的方法和定义指向普通变量的指针变量方法相同。例如Timet;Time*p;//定义指向对象的指针变量int*p1;//定义指向整型数据的指针变量p=&t;//p指向了对象tp1=&t1.hour;//p1指向了对象中的成员hour//*p1就是t.hour指向对象数据成员的指针552.指向对象成员函数的指针定义指向对象成员函数的指针变量的方法和定义指向普通函数的指针变量方法有所不同。成员函数与普通函数有一个最根本的区别:它是类中的一个成员。编译系统要求在上面的赋值语句中,指针变量的类型必须与赋值号右侧函数的类型相匹配,要求在以下3方面都要匹配:①函数参数的类型和参数个数;②函数返回值的类型;③所属的类。定义指向成员函数的指针变量应该采用下面的形式:void(Time∷*p2)();//定义p2为指向Time类中公用成
//员函数的指针变量定义指向公用成员函数的指针变量的一般形式为
数据类型名(类名∷*指针变量名)(参数表列);2.指向对象成员函数的指针56可以让指针变量p2指向一个公用成员函数,只需把公用成员函数的入口地址赋给p2即可。如p2=&Time∷get_time;使指针变量指向一个公用成员函数的一般形式为
指针变量名=&类名∷成员函数名;可以让指针变量p2指向一个公用成员函数,只需57例9.7有关对象指针的使用方法。#include<iostream>usingnamespacestd;classTime{public:Time(int,int,int);inthour;intminute;intsec;voidget_time();//声明公有成员函数};Time∷Time(inth,intm,ints){hour=h;minute=m;sec=s;}voidTime∷get_time()//定义公有成员函数{cout<<hour<<″:″<<minute<<″:″<<sec<<endl;}例9.7有关对象指针的使用方法。58intmain(){Timet1(10,13,56);//定义Time类对象t1int*p1=&t1.hour;//定义指向整型数据的指针变量//p1,并使p1指向t1.hourcout<<*p1<<endl;//输出p1所指的数据成员t1.hourt1.get_time();//调用对象t1的成员函数get_timeTime*p2=&t1;//定义指向Time类对象的指针变
//量p2,并使p2指向t1p2->get_time();//调用p2所指向对象(即t1)的//get_time函数void(Time∷*p3)();//定义指向Time类公用成员函数
//的指针变量p3p3=&Time∷get_time;//使p3指向Time类公用成员函数//get_time(t1.*p3)();//调用对象t1中p3所指的成员函数
//(即t1.get_time())}程序运行结果为10(main函数第4行的输出)10:13:56(main函数第5行的输出)10:13:56(main函数第7行的输出)10:13:56(main函数第10行的输出)intmain()程序运行结果为59this指针在类的每个成员函数中,都内含一个系统定义好的特殊指针,名字是this,它总是指向当前被调用的成员函数所在的对象。例如,当调用成员函数a.volume()时,编译系统就把对象a的起始地址赋给this指针,于是在成员函数引用数据成员时,就按照this的指向找到对象a的数据成员。例如volume函数要计算height*width*length的值,实际上是执行:
(this->height)*(this->width)*(this->length)由于当前this指向a,因此相当于执行:
(a.height)*(a.width)*(a.length)这就计算出长方体a的体积。同样如果有b.volume(),编译系统就把对象b的起始地址赋给成员函数volume的this指针,显然计算出来的是长方体b的体积。this指针在类的每个成员函数中,都内含一个系统定60this指针是隐式使用的,它是作为参数被传递给成员函数的。本来,成员函数volume的定义如下:intBox∷volume(){return(height*width*length);}C++把它处理为intBox∷volume(Box*this){return(this->height*this->width*this->length);}即在成员函数的形参表列中增加一个this指针。在调用该成员函数时,实际上是用以下方式调用的:a.volume(&a);将对象a的地址传给形参this指针。然后按this的指向去引用其他成员。this指针是隐式使用的,它是作为参数被传递给成员函数的。本61需要说明:这些都是编译系统自动实现的,编程序者不必人为地在形参中增加this指针,也不必将对象a的地址传给this指针。在需要时也可以显式地使用this指针。例如在Box类的volume函数中,下面两种表示方法都是合法的、相互等价的。return(height*width*length);//隐含使用this指针return(this->height*this->width*this->length);//显式使用this指针
可以用*this表示被调用的成员函数所在的对象需要说明:这些都是编译系统自动实现的,编程序者不必人为地在62this指针classBox{public:Box(int,int,int);//声明带参数的构造函数
intvolume();//声明计算体积的成员函数
private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen)//在类外定义带参数的构造函数{this->height=h;//可省略为height=h;
this->width=w;//可省略为width=w;
this->length=len;//可省略为length=len;}this指针63intBox∷volume()//定义计算体积的成员函数{return(this->height*this->width*this->length);}intmain(){Boxbox[3]={Box(3,2,1),//用构造函数初始化box[0]Box(6,5,4),//用构造函数初始化box[1]Box(2,2,2)//用构造函数初始化box[2]};inti;for(i=0;i<3;i++)cout<<″Thevolumeofbox”<<i+1<<“is″<<box[i].volume()<<endl;return0;//结束时,自动调用析构函数}当调用box[i].volume()时,this=&box[i]intBox∷volume()649.7对象的动态建立和释放有时人们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用。这样可提高内存空间的利用率。在第7章7.1.7节中介绍了用new运算符动态地分配内存,用delete运算符释放这些内存空间。这也适用于对象,可以用new运算符动态建立对象,用delete运算符撤销对象。9.7对象的动态建立和释放有时人们希望659.7对象的动态建立和释放对于已经定义的类Student:Student*p;//p是指向对象的指针变量p=newStudent;//p指向Student类的新对象p=newStudent(1001,“zhang”,87);//p指向Student类的新对象,用构造函数初始化可以用指针访问该新对象:
p->num,p->name,p->age,p->score当不再使用对象时,可撤销对象(释放内存空间):
deletep;//一般在析构函数中9.7对象的动态建立和释放对于已经定义的类Studen66#include<iostream>usingnamespacestd;classBox{public:
Box(int,int,int);
//声明带参数的构造函数
~Box();
intvolume();//声明计算体积的成员函数
private:intheight;intwidth;intlength;};Box∷Box(inth,intw,intlen)//在类外定义带参数的构造函数{height=h;width=w;length=len;}Box::~Box(){deletethis;};#include<iostream>67intBox∷volume()//定义计算体积的成员函数{return(height*width*length);}intmain(){Box*bp[3];
inti,h,w,l;for(i=0;i<3;i++){cout<<“input:”;cin>>h>>w>>l;
bp[i]=newBox(h,w,l);}for(i=0;i<3;i++)cout<<″Thevolumeofbox”<<i+1<<“is″<<bp[i]->volume()<<endl;return0;//结束时,自动调用析构函数}intBox∷volume()68在执行new运算时,如果内存量不足,无法开辟所需的内存空间,目前大多数C++编译系统都使new返回一个0指针值。只要检测返回值是否为0,就可判断分配内存是否成功。Box*bp;
inth,w,l;cout<<“input:”;cin>>h>>w>>l;
bp=newBox(h,w,l);if(bp==NULL){cout<<“无内存空间建立对象”;return0;}
……在执行new运算时,如果内存量不足,无法开辟所需的内存空间,69第9章怎样使用类和对象9.1利用构造函数对类对象进行初始化9.2析构函数9.3调用构造函数和析构函数的顺序9.4对象数组9.5对象指针9.6共用数据的保护9.7对象的动态建立和释放9.8对象的赋值和复制9.9静态成员9.10友元9.11类模板第9章怎样使用类和对象9.1利用构造函数对类对象进行709.1利用构造函数对类对象进行初始化9.1.1对象的初始化在建立一个对象时,常常需要作某些初始化的工作,例如对数据成员赋初值。如果一个数据成员未被赋值,则它的值是不可预知的。注意:类的数据成员是不能在声明类时初始化的。classTime{public://声明为公用成员
hour=0;//错:类的数据成员不能在定义时初始化minute=0;//错:类的数据成员不能在定义时初始化sec=0;//错:类的数据成员不能在定义时初始化};
9.1利用构造函数对类对象进行初始化9.1.1对象的初71如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成员进行初始化。如classTime{public://声明为公用成员
hour;minute;sec;};Timet1={14,56,30};//将t1初始化为14:56:30但是,如果数据成员是私有的,或者类中有private或protected的成员,就不能用这种方法初始化。
如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成72structStudent//结构声明{intnum;charname[20];floatscore;};Studentstu1={1001,“zhangsan”,89};//对定义结构体变量时同时初始化对结构体,其成员默认是publicstructStudent//结构声明{private:intnum;charname[20];floatscore;};Studentstu1={1001,“zhangsan”,89};//错错:不能对私有成员初始化structStudent//结构声明定义结构体变73Student类classStudent//类声明{private:intnum;charname[20];floatscore;
public:voiddisplay(){cout<<"num:"<<num<<endl;cout<<"name:"<<name<<endl;cout<<"score:"<<score<<endl;}}数据成员是私有的,本类外不能直接访问Studentstu1={1001,”zhangsan”,89};//定义对象并初始化?不能!Student类classStudent//类声74C++提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数的名字必须与类名同名,而不能由用户任意命名,以便编译系统能识别它并把它作为构造函数处理。它不具有任何类型,不返回任何值。构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数。9.1.2构造函数的作用C++提供了构造函数(constructor)来75创建Student类的构造函数#include<iostream>usingnamespacestd;classStudent{private:intnum;charname[20];floatscore;public:
Student(intn,char*p,floats);
//构造函数的声明voiddisplay();};Student::St
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 伊春市新青区2025届数学五下期末考试模拟试题含答案
- 货物买卖合同协议书范本
- 2025年度个人股权融资合同样本
- 智慧农业农业物联网技术革新与实践
- 智慧农业技术创新与人才培养策略
- 企业法律顾问服务合同示范文本
- 连锁药房加盟经营合同
- 软件公司与程序员劳动合同
- 房产抵债合同范文
- 2024-2025年济南天桥区泺口实验学校第二学期七年级地理期中考试试题(含答案)
- 单绒毛膜双羊膜囊双胎2022优秀课件
- 沥青路面精细化施工质量控制及验收标准课件
- XX县“四好”农村公路提升工程可行性研究报告
- 高考数学你真的掌握了吗(最新)
- 亚里士多德哲学课件
- DB32-T 4357-2022《建筑工程施工机械安装质量检验规程》
- 发成果转化项目可行性研究报告(定稿)
- (新版教材)粤教粤科版六年级下册科学全册教案(教学设计)
- 个人分期还款协议书模板(5篇)
- 仪表电气专业安全检查表
- 航空煤油MSDS安全技术说明书
评论
0/150
提交评论