




已阅读5页,还剩797页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C+面向对象程序设计,第一讲,第一章C+的初步知识第二章类和对象第三章关于类和对象的进一步讨论第四章运算符重载第五章继承与派生第六章多态性与虚函数第七章输入输出流,结束放映,第一章C+的初步知识,1.1从C到C+1.2C+语言的词法和词法规则1.3最简单的C+程序1.4C+对C的扩充1.5C+程序的编写和实现,1.1从C到C+,C语言是结构化和模块化的语言,C程序的设计者必须细致地设计程序中的每个细节,准确地考虑程序运行时每一时刻发生的事情,当程序规模变大时,结构化程序设计就显得力不从心。为了解决软件设计危机,在20世纪80年代提出了面向对象的程序设计思想(OOP)在实践中人们发现C语言使用如此广泛,如果在它的基础上发展一种面向对象的语言,一定会让大众容易接收这种语言,所以产生了C+。,AT/使用命名空间stdintmain()coutThisisaC+program.n;/上面用C+的方法输出一行return0;,(1)标准C+规定main函数必须声明为int类型,如果程序正常运行,向操作系统返回一个零值,否则返回非零值,通常是-1。(2)C+程序中可以用/*/做注释,可以用/做注释。前者可以做多行注释,后者只做单行注释。(3)C+程序中常用cout、cin进行输出输入,cout是C+定义的输出流对象,ab;/输入语句sum=a+b;/赋值语句couta+b=sum”是提取运算符,与cin配合,其作用是从输入设备中提取数据送到输入流cin中。在程序执行时,键盘输入的第一个数据赋予a,第二个数据赋予b。cout语句中的endl是C+控制符常数,作用是让光标换行。如果在本程序运行时输入:123456程序则输出:a+b=579,例1.3求两个数中的大数#includeusingnamespacestd;intmain()intmax(intx,inty);/对max函数作声明inta,b,c;cinab;c=max(a,b);/调用max函数coutmax=cnum;/输入num的值cinscore;/输入score的值voiddisplay()/定义公用函数displaycoutnum=numendl;/输出num的值coutscore=scoreendl;/输出score的值;/类的声明结束,Studentstud1,stud2;/定义stud1和stud2为Student类的变量,称为对象intmain()/主函数首部stud1.setdata();/调用对象stud1的setdata函数stud2.setdata();/调用对象stud2的setdata函数stud1.display();/调用对象stud1的display函数stud2.display();/调用对象stud1的display函数return0;,程序中声明一个被称为类的类型Student。声明时要用关键字class。C+类中可以包含两种成员即数据(如变量num、score)和函数(如setdata函数和display函数)。分别称为数据成员和成员函数。在C+中将一组数据和访问这组数据的函数封装在一起,组成类。一个类是由一组数据,一组对其访问的若干函数,以及数据和函数的访问属性组成的。在前面程序中看到的private(私有)public(公有)保留字代表数据和函数的访问属性。,凡是指定为公有的数据和函数,既可由本类的函数访问和调用,也可由其他函数或语句访问和调用;凡是指定为私有的数据和函数,通常只能由本类的函数访问和调用。程序中“Studentstud1,stud2;”是一个定义语句,定义两个Student类型变量stud1和stud2,Student类与int一样是C+的合法类型。,具有类类型的变量称为对象。Student的对象stud1,stud2具有同样的结构和特征。在类外调用成员函数时必须在函数名前冠以类的名称。,主函数中第一条语句输入学生1的学号和成绩,第二条语句输入学生2的学号和成绩,第三条语句输出学生1的学号和成绩,第四条语句输出学生2的学号和成绩。程序运行情况如下:100198.5100276.5num=1001Score=98.5num=1002Score=76.5,为了与C兼容,C+保留了C语言中的一些规定,例如头文件的文件名,以C语言里头文件的扩展名是.h,许多C+编译系统保留了这种扩展名,近年推出的C+编译系统新版本,推出了一批不带扩展名的头文件如iostream,string,cmath等。为了兼容C+仍允许使用带扩展名的头文件。由于C语言无命名空间,因此使用带扩展名的头文件时不用usingnamespacestd。,1.3C+对C的扩充,C+既可用于面向过程的程序设计,也可用于面向对象程序设计。C+继承了C语言提供的绝大部分功能和语法规定,并在此基础上作了扩充。,1.4.1C+的输入和输出1.4.2用const定义常变量1.4.3函数原型声明1.4.4函数的重载1.4.5函数模板1.4.6有默认参数的函数,1.4.7变量的引用1.4.8内置函数1.4.9作用域运算符1.4.10字符串变量1.4.11动态分配/回收内存运算符,1.3.1C+的输入输出,C+为了方便使用,除了可以利用printf和scanf函数进行输入和输出外,还增加了标准输入流输出流cin和cout。它们是在头文件iostream中定义的,标准流是不需要打开文件和关闭文件就能直接操作的流式文件,在此标准输入流是指从键盘上输入的数据,标准输出流是指向屏幕输出的数据流。C+预定义的标准流如表1.2所示。,1.用cout进行输出,格式:cout表达式1表达式2功能:由左向右逐个计算表达式的值,将其插入到输出流cout中。cout必须与输出运算符一起使用,每个后跟一个表达式,运算符的结合方向是从左向右,所以各个表达式的值按从左到右的顺序插入到输出流中。,For(k=1;k=3;k+)cout“k=“kendlendl是C+输出流的常数,在头文件iostream中定义,代表让光标换行。在C+中也可以用”n”控制光标换行。所以输出语句也可写成:cout“k=“k变量1变量2是C+的提取运算符,表示从标准输入设备取得数据,赋予其后的变量。从键盘输入数值数据时,两个数据之间用空格分隔或用回车分隔。,inta;floatbcinab;从键盘输入2032.45,例1.5cin和cout的使用,#includeusingnamespacestd;intmain()coutname;cinage;coutyournameisnameendl;coutyourageisagea)a=c;returna;floatmax(floata,floatb,floatc)/求3个实数中的最大者if(ba)a=b;if(ca)a=c;returna;longmax(longa,longb,longc)/求3个长整数中的最大者if(ba)a=b;if(ca)a=c;returna;,intmain()inta,b,c;floatd,e,f;longg,h,i;cinabc;cindef;cinghi;intm;m=max(a,b,c);/函数值为整型coutmax_i=mendl;floatn;n=max(d,e,f);/函数值为实型coutmax_f=nendl;longintp;p=max(g,h,i);/函数值为长整型coutmax_l=pa)a=c;returna;,intmax(inta,intb)/求两个整数中的最大者if(ab)returna;elsereturnb;intmain()inta=7,b=-4,c=9;coutmax(a,b,c)endl;/输出3个整数中的最大者coutmax(a,b)a)a=c;returna;,intmain()inti1=8,i2=5,i3=6,i;doubled1=56.9,d2=90.765,d3=43.1,d;longg1=67843,g2=-456,g3=78123,g;i=max(i1,i2,i3);d=max(d1,d2,d3);g=max(g1,g2,g3);couti_max=iendl;coutd_max=dendl;coutg_max=gendl;return0;,从程序中看到,此问题用函数模板比用函数重载更方便。注意,函数模板只适用于函数参数的个数相同而类型不同,并且函数体相同的情况,如果函数的参数个数不同,则不能用函数模板。,1.4.6有默认参数的函数,C+允许为函数的参数设置默认值,这时调用函数时,如果没有实参,就以默认值作为实参值。格式:形参类型形参变量名=常数功能:调用函数时,如果没有实参,就以常数作为该形参的值;如果有实参,仍以实参的值作为该形参的值。注意:有默认值的形参必须放在形参表的右边,不允许无默认参数值和有默认参数值的形参交错排列。,例:编写计算圆柱体体积函数floatvolume(floath,floatr=12.5)调用可以采用以下任何一种形式:volume(45.6);volume(32.5,10.5);函数参数结合从左到右,用第一种方式调用时,只有一个实参,圆半径的值取默认值12.5,用第二种方式调用时,有两个实参,圆半径的值取实参的值10.5。,注意:一、如果用函数原型声明,只要在函数原型声明中定义形参的默认值即可。二、一个函数名不能同时用于重载函数和带默认形参值的函数。当调用函数时,如少写一个参数,系统无法判断是利用重载函数还是利用带默认参数值的函数,出现二义性。,例如将例1.7中的第三行改为intmax(inta,intb,intc=100);此时max是重载函数,又带默认参数值,如果出现max(5,23)形式的调用,编译系统无法断定调用哪个函数,于是发出编译出错的信息。,1.4.7变量的引用,C+提供了为变量取别名的功能,这就是变量的引用。格式:类型int变量a有两个别名b和c。,#includeusingnamespacestd;intmain()inta=10;int,图1.1,程序运行结果如下:1002020,将引用作为函数参数,C+除了可以用普通变量、指针变量做形参外,还可以用引用变量做形参。(1)用普通变量做形参这时传递的是实参的值,在函数内形参与实参是两个不同的内存单元,对形参的修改不会影响实参的值。例1.10无法实现两个变量的值互换的程序,#includeusingnamespacestd;voidswap(inta,intb)inttemp;temp=a;a=b;b=temp;/实现a和b的值互换,intmain()inti=3,j=5;swap(i,j);couti,jendl;/i和j的值未互换return0;,图1.2,(2)用指针变量做形参C语言还允许用指针变量做形参,这时传递的是实参变量的地址(指针),在函数内利用这个指针访问实参变量。例1.11用指针变量做形参,实现两个变量值的交换。,#includeusingnamespacestd;voidswap(int*p1,int*p2)inttemp;temp=*p1;*p1=*p2;*p2=temp;,intmain()inti=3,j=5;swap(,图1.3,(3)用引用变量做形参用指针变量做形参,它将实参变量的地址传递给形参,在函数内用“*指针变量”的方式访问实参变量。我们知道引用变量是变量的别名,在调用函数时,用引用变量做的形参就成了实参变量的别名,在函数中用的形参名就是实参的别名,这样比用指针变量更直观、更方便。,例1.12利用引用变量实现两个变量值的交换#includeusingnamespacestd;voidswap(int,intmain()inti=3,j=5;swap(i,j);couti=ij=ja)a=c;returna;intmain()inti=7,j=10,k=25,m;m=max(i,j,k);coutmax=ma)a=c;m=a;,例1.15用内置函数计算平方根#includeusingnamespacestd;inlineintpower(intx)/定义内置函数returnx*x;intmain()coutpower(2)endl;coutpower(1+1)endl;return0;,编译程序遇见内置函数power时,先求出函数的实参值(1+1=2),然后用power函数体代替函数调用,调用语句变成:cout2*2endl;cout2*2endl;运行结果是44,使用内置函数可以节省程序的运行时间,但增加了目标程序的长度。所以在使用时要衡量时间和空间的得失。,1.4.9作用域运算符,并不是所有的变量在程序运行的时时刻刻都是可见的。有的变量在整个程序运行期间都是可见的,称它们为全局变量;有的变量只能在一个函数中可知,被称为局部变量。每个变量都有其有效的作用域,程序只能在变量的有效的作用域内使用变量,不能直接使用其他域中的变量。,程序的内存区域,程序的内存空间,代码区,全局数据区,堆区,栈区,程序中各个函数的代码,程序中全局数据和静态数据,程序中的动态数据,程序中各函数内的数据,例1.16局部变量和全局变量同名#includeusingnamespacestd;floata=13.5;intmain()inta=5;coutaendl;return0;,程序中有两个变量a,一个是全局变量,另一个是main函数的局部变量,根据局部变量会屏蔽同名的全局变量规则,在函数中出现的变量a是局部变量,因此输出的值是5,而不是13.5,为了在函数中访问全局变量C+提供了作用域运算符:,可以用来指定要访问的作用域,可以把main函数改写成,#includeusingnamespacestd;floata=13.5;intmain()inta=5;coutaendl;cout:a字符串变量cout=、=、!=、“chinese”运算结果是假。,1.4.11动态分配/撤销内存的运算符new和delete,分配内存运算new类型(初值)类型是决定分配空间尺寸的关键元素,如果运算结果正确,它的值是分配内存空间的起始地址,否则返回NULL。例:int*a=newint;int*b=newint(100);char*ch=newchar10;int*q=newint54;float*p=newfloat(3.14159);,归还动态内存运算delete指针变量代表数组,如果不是数组可以省略。运算功能:撤销指针变量所指的动态内存空间,指针变量的数据类型决定了空间尺寸的大小。例:char*p=newchar10;deletep;,例1.18用动态内存存放结构体变量#include#includeusingnamespacestd;structstudentcharname10;intnum;charsex;,intmain()student*p;p=newstudent;strcpy(p-name,WangFun);p-num=10123;p-sex=M;coutnamenumsexnum;cinname;cinsex;voiddisplay()coutnumendl;coutnameendl;coutsexnum;cinname;cinsex;voiddisplay()coutnumendl;coutnameendl;coutsexnum;cinname;cinsex;voidstudent:display()coutnumendl;coutnameendl;coutsexnum;cinname;cinsex;voidstudent:display()coutnumendl;coutnameendl;coutsexhourminutesec;可以用下面的语句计算该类对象占用的字节数coutsizeof(Time)hour、(*p).hour、t.hour三种表示是一个意思。,2.4.3通过对象的引用来访问对象中的成员,如果为一个对象A定义一个引用B,B是对象A的别名,A和B都是一个对象,所以完全可以通过引用访问对象中的成员。Timet1;Time这里t2是t1的别名,所以访问t2.hour就是访问t1.hour。,2.5类和对象的简单应用举例,这小节通过几个例子说明怎样用类设计程序,以及使用类的长处。,例2.1,#includeusingnamespacestd;classTimepublic:inthour;intminute;intsec;intmain()Timet1;Time,注意:必须在引用成员之前加对象名而不是类名。数据成员必须有初始值后才能访问,否则它们的值是不可预知的。,例2.2引用多个对象成员,(1)程序(a)#includeusingnamespacestd;classTimepublic:inthour;intminute;intsec;,intmain()Timet1;cint1.hourt1.minutet1.sec;coutt2.hourt2.minutet2.sec;coutt2.hour:t2.minute:t2.seccouthour;cinminute;cinsec;voidTime:show_time()couthour:minute:secarrayi;voidArray_max:max_value()inti;max=array0;for(i=1;imax)max=arrayi;voidArray_max:show_value()coutmax=numname;cinagesex;voidstudent:display()coutnumendlnameendl;coutageendlsexnum;cinname;cinsex;voidstudent:display()coutnumendl;coutnameendl;coutsext.hour;cint.minute;cint.sec;intshow_time(void)coutt.hour:t.minute:t.sechour;cinminute;cinsec;voidTime:show_time()couthour:minute:secendl;,在类Time中定义了构造函数Time,它与所在的类同名。在建立对象时自动执行构造函数,该函数的作用是为对象中的各个数据成员赋初值0。注意只有执行构造函数时才为数据成员赋初值。程序运行时首先建立对象t1,并对t1中的数据成员赋初值0,然后执行t1.set_time函数,从键盘输入新值给对象t1的数据成员,再输出t1的数据成员的值。接着建立对象t2,同时对t2中的数据成员赋初值0,最后输出t2的数据成员的初值。,程序运行的情况为:10255410:25:54/输出t1的值0:0:0/输出t2的值也可以在类内声明构造函数然后在类外定义构造函数。将程序修改为:Time();然后在类外定义构造函数:Time:Time()hour=0;minute=0;sec=0;,关于构造函数的使用,说明如下:(1)什么时候调用构造函数呢?当函数执行到对象定义语句时建立对象,此时就要调用构造函数,对象就有了自己的作用域,对象的生命周期开始了。(2)构造函数没有返回值,因此不需要在定义中声明类型。(3)构造函数不需要显式地调用,构造函数是在建立对象时由系统自动执行的,且只执行一次。构造函数一般定义为public。,(4)在构造函数中除了可以对数据成员赋初值,还可以使用其他语句。(5)如果用户没有定义构造函数,C+系统会自动生成一个构造函数,而这个函数体是空的,不执行初始化操作。,3.1.3带形参数的构造函数,可以采用带参数的构造函数,在调用不同对象的构造函数时,从外边将不同的数据传递给构造函数,实现不同对象的初始化。构造函数的首部的一般格式为:构造函数名(类型形参1,类型形参2,)在定义对象时指定实参,定义对象的格式为:类名对象名(实参1,实参2,);,例3.2有两个长方柱,其长、宽、高分别为:(1)12,25,30(2)15,30,21编写程序,在类中用带参数的构造函数,计算它们的体积。分析:可以在类中定义一个计算长方体体积的成员函数计算对象的体积。,#includeusingnamespacestd;classBoxpublic:Box(int,int,int);intvolume();private:intheight;intwidth;intlength;,Box:Box(inth,intw,intlen)/长方体构造函数height=h;width=w;length=len;intBox:volume()/计算长方体的体积return(height*width*length);,intmain()Boxbox1(12,25,30);/定义对象box1coutbox1体积=box1.volume()endl;Boxbox2(15,30,21);/定义对象box2coutbox2体积=box2.volume()endl;return0;,构造函数Box有3个参数,分别代表长、宽、高。在主函数中定义对象box1时,指定了实参12,25,30。然后调用成员函数计算长方体的体积。程序运行的结果如下:box1体积=9000box2体积=9450提醒:(1)带形参的构造函数在定义对象时必须指定实参(2)用这种方法可以实现不同对象的初始化。,3.1.4用参数初始化表对数据成员初始化,C+提供了参数初始化表的方法对数据成员初始化。这种方法不必在构造函数内对数据成员初始化,在函数的首部就能实现数据成员初始化。函数名(类型1形参1,类型2形参2):成员名1(形参1),成员名2(形参2)功能:执行构造函数时,将形参1的值赋予成员1,将形参2的值赋予成员2,形参的值由定义对象时的实参值决定。此时定义对象的格式依然是带实参的形式:类名对象名(实参1,实参2);,例:定义带形参初始化表的构造函数Box:Box(inth,intw,intlen):height(h),width(w),length(len)定义对象:Boxbox1(12,25,30);Boxbox2(15,30,21);,3.1.5构造函数的重载,构造函数也可以重载。一个类可以有多个同名构造函数,函数参数的个数、参数的类型各不相同。例3.3:在例3.2的基础上定义两个构造函数其中一个无参数,另一个有参数。,#includeusingnamespacestd;classBoxpublic:Box();Box(inth,intw,intlen):height(h),width(w),length(len)intvolume();private:intheight;intwidth;intlength;,Box:Box()height=10;width=10;length=10;intBox:volume()return(height*width*length);,intmain()Boxbox1;coutbox1体积=box1.volume()endl;Boxbox2(15,30,25);coutbox2体积=box2.volume()endl;return0;,例子中定义了两个构造函数,一个无参数另一个带三个参数。系统根据定义对象的格式决定调用哪个构造函数。对象box1没有实参系统为它调用无参数的构造函数;对象box2带三个实参系统为它调用带形参的构造函数。,说明:(1)不带形参的构造函数为默认构造函数每个类只有一个默认构造函数,如果是系统自动给的默认构造函数,其函数体是空的。(2)虽然每个类可以包含多个构造函数,但是创建对象时,系统仅执行其中一个。,3.1.6使用默认参数值的构造函数,C+允许在构造函数里为形参指定默认值,如果创建对象时,未给出相应的实参时,系统将用形参的默认值为形参赋值。格式:函数名(类型形参1=常数,类型形参2=常数,);例3.4:将例3.3中的构造函数改用带默认值的参数,长、宽、高的默认值都是10。,#includeusingnamespacestd;classBoxpublic:Box(intw=10,inth=10,intlen=10);intvolume();private:intheight;intwidth;intlength;,Box:Box(intw,inth,intlen)height=h;width=w;length=len;intBox:volume()return(height*width*length);,intmain()Boxbox1;coutbox1体积=box1.volume()endl;Boxbox2(15);coutbox2体积box2.volume()endl;Boxbox3(15,30);coutbox3体积box3.volume()endl;Boxbox4(15,30,20);coutbox4体积box4.volume()endl;return0;,程序运行结果为:box1体积=1000box2体积=1500box3体积=4500box4体积=9000构造函数也可以改写成带参数初始化表的形式:Box:Box(inth,intw,intlen):height(h),width(w),length(len)整个函数只需一行,简单方便。,在构造函数中使用默认参数提供了建立对象的多种选择,它的作用相当于多个重载构造函数。说明:(1)如果在类外定义构造函数,应该在声明构造函数时指定默认参数值,在定义函数时可以不再指定默认参数值。(2)在声明构造函数时,形参名可以省略例如:Box(int=10,int=10,int=10);,(3)如果构造函数的所有形参都指定了默认值,在定义对象时,可以指定实参也可不指定实参。由于不指定实参也可以调用构造函数,因此全部形参都指定了默认值的构造函数也属于默认构造函数。为了避免歧义,不允许同时定义不带形参的构造函数和全部形参都指定默认值的构造函数。(4)同样为了避免歧义性,如定义了全部形参带默认值的构造函数后,不能再定义重载构造函数。反之亦然。,Box(int=10,int=10,int=10);Box();Box(int,int);若定义对象:Boxbox1;Boxbox2(15,30);这时应该调用哪个构造函数呢?如果构造函数中参数并非都带默认值时,要具体分析情况。如有以下三个原型声明:,Box();Box(int,int=10,int=10);Box(int,int);若定义对象:Boxbox1;/正确,调用第一个Boxbox2(15);/调用第二个Boxbox3(15,30);/不知调用哪一个因此不要同时使用重载构造函数和带默认值的构造函数。,3.2析构函数,析构函数也是个特殊的成员函数,它的作用与构造函数相反,当对象的生命周期结束时,系统自动调用析构函数,收回对象占用的内存空间。执行析构函数的时机:在一个函数内定义的对象当这个函数结束时,自动执行析构函数释放对象。static局部对象要到main函数结束或执行exit命令时才自动执行析构函数释放对象。,全局对象(在函数外定义的对象)当main函数结束或执行exit命令时自动执行析构函数释放对象。如果用new建立动态对象,用delete时自动执行析构函数释放对象。,析构函数的特征析构函数名以符号开始后跟类名析构函数没有数据类型、返回值、形参。由于没有形参所以析构函数不能重载。一个类只有一个析构函数。如果程序员没有定义析构函数,C+编译系统会自动生成一个析构函数。析构函数除了释放对象(资源)外,还可以执行程序员在最后一次使用对象后希望执行的任何操作。例如输出有关的信息。,例3.5包含构造函数和析构函数的C+程序#include#includeusingnamespacestd;classStudentpublic:Student(intn,stringnam,chars)num=n;name=nam;sex=s;coutConstructorcalled.endl;,Student()coutDestructorcalled.endl;voiddisplay()coutnum:numendl;coutname:nameendl;coutsex:sexendlendl;private:intnum;stringname;charsex;,intmain()Studentstud1(10010,Wang_li,f);stud1.display();Studentstud2(10011,Zhang_fun,m);stud2.display();return0;,main函数前声明的类其作用域是全局的。程序运行结果如下:Constructorcalled.num:10010name:Wang_lisex:fConstructorcalled.num:10011name:Zhang_funsex:mDestructorcalled.Destructorcalled.,3.3调用构造函数和析构函数的顺序,在使用构造函数和析构函数时需要特别注意对它们的调用时间和调用顺序。在一般情况下,调用析构函数的次序与调用构造函数的次序恰好相反:最先调用构造函数的对象,最后调用析构函数。而最后调用构造函数的对象,最先调用析构函数。可简记为:先构造的后析构,后构造的先析构,它相当一个栈,后进先出。,对象1的构造函数,对象2的构造函数,对象3的构造函数,对象1的析构函数,对象2的析构函数,对象3的析构函数,上面提到,在一般情况下,调用析构函数的次序与调用构造函数的次序相反,这是对同一类存储类别的对象而言的。(1)在全局范围中定义的对象(在所有函数之外定义的对象),在文件中的所有函数(包括主函数)执行前调用构造函数。当主函数结束或执行exit函数时,调用析构函数。,(2)如果定义局部自动对象(在函数内定义对象),在创建对象时调用构造函数。如多次调用对象所在的函数,则每次创建对象时都调用构造函数。在函数调用结束时调用析构函数。(3)如果在函数中定义静态局部对象,则在第一次调用该函数建立对象时调用构造函数,但要在主函数结束或调用exit函数时才调用析构函数。,例如:Voidfn()studentst1;/定义局部自动对象staticstudentst2;/定义静态局部对象对象st1是每次调用函数fn时调用构造函数在函数fn结束时调用析构函数。对象st2是第一次调用函数fn时调用构造函数在函数fn结束时并不调用析构函数,在到主函数结束时才调用析构函数。,构造函数和析构函数在面向对象程序设计中是相当重要的。本章介绍了最基本的、使用最多的普通构造函数,在3.8节将介绍复制构造函数,在4.7节还要介绍转换构造函数。,3.4对象数组,类是一种特殊的数据类型,它当然是C+的合法类型,自然就可以定义对象数组。在一个对象数组中各个元素都是同类对象例如一个班级有50个学生,每个学生具有学号、年龄、成绩等属性,可以为这个班级建立一个对象数组,数组包括了50个元素:studentstd50;可以这样建立构造函数:student:student(int=1001,int=18,int=60);,在建立数组时,同样要调用构造函数。上面的数组有50个元素,要调用50次构造函数。如果构造函数有多个参数,C+要求:在等号后的花括号中为每个对象分别写出构造函数并指定实参。格式为:studentstn=student(实参1,实参2,实参3);student(实参1,实参2,实参3);,n个对象,假定对象有三个数据成员:学号、年龄、成绩。下面定义有三个学生的对象数组:studentstd3=student(1001,18,87),student(1002,19,76),student(1003,18,80);/构造函数带实参在建立对象数组时,分别调用构造函数,对每个对象初始化。每个元素的实参用括号括起来,实参的位置与构造函数形参的位置一一对应,不会混淆。,例3.6对象数组的使用方法。(长方体数组)#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);couta0的体积是a0.volume()endl;couta1的体积是a1.volume()endl;couta2的体积是a2.volume()hour;cinminute;cinsec;voidTime:show_time()couthour:minute:secshow_time(),3.5.2指向对象成员的指针,对象由成员组成。对象占据的内存区是各个数据成员占据的内存区的总和。对象成员也有地址,即指针。这指针分指向数据成员的指针和指向成员函数的指针。,1.指向对象公有数据成员的指针,定义数据成员的指针变量数据类型*指针变量名计算公有数据成员的地址,2.指向对象成员函数的指针,定义指向成员函数的指针变量数据类型(类名:*变量名)(形参表);数据类型是成员函数的类型。类名是对象所属的类变量名按标识符取名形参表:指定成员函数的形参表(形参个数、类型)取成员函数的地址classTimepublic:Time(int,int,int);inthour;intminute;intsec;voidget_time();,Time:Time(inth,intm,ints)hour=h;minute=m;sec=s;voidTime:get_time()couthour:minute:secget_time();的执行结果10:13:56/(t1.*p3)();的执行结果程序采用了三种方法输出t1的hour,minute,sec的值说明:(1)成员函数的起始地址的正确表示是:,3.5.3this指针,一个类的成员函数只有一个内存拷贝。类中不论哪个对象调用某个成员函数,调用的都是内存中同一个成员函数代码。例如Time类一个成员函数:voidTime:get_time()couthour:minute:secwidth*this-length);对于计算长方体体积的成员函数volume,当对象a调用它时,就把对象a地址给this指针,编译程序将a的地址作为实参调用成员函数:a.volume(实际上函数是计算:(this-height)*(this-width)*(this-length)这时就等价计算(a.height)*(a.width)*(a.length),可以用(*this)表示调用成员函数的对象。(*this)就是this所指的对象。如前面的计算长方体体积的函数中return语句可以写成:return(*this).height*(*this).width*(*this).length);注意this两侧的括号不能省略,不能写成:return(*this.height*this.width*this.length);根据运算符优先级语句被翻译成:*(this.height),而this.height是非法的,编译将报错。,C+通过编译程序,在对象调用成员函数时,把对象的地址赋予this指针,用this指针指向对象,实现了用同一个成员函数访问不同对象的数据成员。,3.6共用数据的保护,如果即希望数据在一定范围内共享,又不愿它被随意修改,从技术上可以把数据指定为只读型的。C+提供const手段,将数据、对象、成员函数指定为常量,从而实现了只读要求,达到保护数据的目的。,3.6.1常对象3.6.2常对象成员3.6.3指向对象的常指针*3.6.4指向常对象的指针变量3.6.5对象的常引用3.6.6const型数据小结,3.6.1常对象,定义格式:const类名对象名(实参表);或:类名const对象名(实参表);把对象定义为常对象,对象中的数据成员就是常变量,在定义时必须带实参作为数据成员的初值,在程序中不允许修改常对象的数据成员值。如果一个常对象的成员函数未被定义为常成员函数(除构造函数和析构函数外),则对象不能调用这样的成员函数。如:constTimet1(10,15,36);t1.get_time();/错误,不能调用为了访问常对象中的数据成员,要定义常成员函数:voidget_time()const,如果在常对象中要修改某个数据成员,C+提供了指定可变的数据成员方法。格式:mutable类型数据成员;在定义数据成员时加mutable后,将数据成员声明为可变的数据成员,就可以用声明为const的成员函数修改它的值。,3.6.2常对象成员,可以在声明普通对象时将数据成员或成员函数声明为常数据成员或常成员函数。,1.常数据成员,格式:const类型数据成员名将类中的数据成员定义为具有只读的性质。注意只能通过带参数初始表的构造函数对常数据成员进行初始化。例:constinthour;Time:Time(inth)hour=h;/错误应该写成:Time:Time(inth):hour(h),在类中声明了某个常数据成员后,该类中每个对象的这个数据成员的值都是只读的,而每个对象的这个数据成员的值可以不同,由定义对象时给出。,2.常成员函数,定义格式:类型函数名(形参表)constconst是函数类型的一部分,在声明函数原型和定义函数时都要用const关键字。,使用常成员函数需注意:,const是函数类型的一个组成部分,因此在函数的实现部分也要使用关键字const。常成员函数不能修改对象的数据成员,也不能调用该类中没有由关键字const修饰的成员函数,从而保证了在常成员函数中不会修改数据成员的值。如果一个对象被说明为常对象,则通过该对象只能调用它的常成员函数。,2.常成员函数,一般成员函数可以访问或修改本类中的非const数据成员。而常成员函数只能读本类中的数据成员,而不能写它们。,常成员函数的使用,(1)如果类中有部分数据成员的值要求为只读,可以将它们声明为const,这样成员函数只能读这些数据成员的值,但不能修改它们的值。(2)如果所有数据成员的值为只读,可将对象声明为const,在类中必须声明const成员函数,常对象只能通过常成员函数读数据成员。(3)常对象不能调用非const成员函数。提醒:如果常对象的成员函数未加const,编译系统将其当作非const成员函数;常成员函数不能调用非const成员函数。,3.6.3指向对象的常指针,如果在定义指向对象的指针时,使用了关键字const,它就是一个常指针,必须在定义时对其初始化。并且在程序运行中不能再修改指针的值。类名*const指针变量名=对象地址例:Timet1(10,12,15),t2;Time*constp1=/错误语句,指向对象的常指针,在程序运行中始终指的是同一个对象。即指针变量的值始终不变,但它所指对象的数据成员值可以修改。当需要将一个指针变量固定地与一个对象相联系时,就可将指针变量指定为const。往往用常指针作为函数的形参,目的是不允许在函数中修改指针变量的值,让它始终指向原来的对象。,3.6.5对象的常引用,前面学过引用是传递参数的有效办法。用引用形参时,形参变量与实参变量是
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年试验检测师考试题库(含答案)
- 阿尔山市2024-2025学年八年级下学期语文期中测试试卷
- 2024中国血脂管理指南解读课件
- 2025 年小升初忻州市初一新生分班考试数学试卷(带答案解析)-(冀教版)
- 2025 年小升初杭州市初一新生分班考试语文试卷(带答案解析)-(部编版)
- 中国儿童遗尿症疾病管理专家共识解读课件
- 物业公司2025上半年工作总结
- 普通话推广活动普通话与规范字常见易错字词趣味互动模板
- 四川省泸州市江阳区2022-2023学年八年级下学期期末考试生物试题(试卷)
- 福建省泉州市石狮市中英文实验学校2024-2025学年八年级下学期期中考试数学试卷(含简略答案)
- 信贷业务操作风险防控手册
- JG/T 317-2011混凝土用粒化电炉磷渣粉
- 缺血性脑血管病护理
- 入股原始股协议书
- (完整版)勾股定理测试题及参考答案
- 聘请画师劳动合同协议
- 汽车维修工(新能源汽车电控技术)赛项竞赛规程
- 2025年中职高考对口升学(旅游概论)真题试卷附参考答案
- 我心中的英雄:学生心目中的榜样
- 电竞赞助合同协议
- 电商模特合同协议
评论
0/150
提交评论