C++程序设计:第六章 类

上传人:新** 文档编号:570209341 上传时间:2024-08-02 格式:PPT 页数:229 大小:540.50KB
返回 下载 相关 举报
C++程序设计:第六章 类_第1页
第1页 / 共229页
C++程序设计:第六章 类_第2页
第2页 / 共229页
C++程序设计:第六章 类_第3页
第3页 / 共229页
C++程序设计:第六章 类_第4页
第4页 / 共229页
C++程序设计:第六章 类_第5页
第5页 / 共229页
点击查看更多>>
资源描述

《C++程序设计:第六章 类》由会员分享,可在线阅读,更多相关《C++程序设计:第六章 类(229页珍藏版)》请在金锄头文库上搜索。

1、本章重点本章重点6.1类的定义类的定义在C+语言中,类的定义形式如下: 其中,数据成员是类中所包含的变量,用于表示某种数据结构,而成员函数则用于对数据成员进行操作的函数。类的定义举例类的定义举例这里,cInt相当于一种数据类型,用于定义类对象;x为数据成员,其数据类型为整型;xRet()为成员函数,其返回值类型为整型。定义类的对象定义类的对象类对象的定义,例如:类的数据成员和成员函数的使用,例如:6.2公共、私有和保护公共、私有和保护在定义类时,可以对类中的数据成员和成员函数设置如下三种访问控制:(1)public:公共的公共的(2)private:私有的私有的(3)protected:受保护

2、的受保护的定义类时,注意事项(定义类时,注意事项(1 1)定义类时,注意事项(定义类时,注意事项(2 2) 在定义类时,最初的private关键字可以省略。例如: 例例 如如classcTestinta;intReta();intseta(intx);public:intb;private:intx10;类的定义说明类的定义说明 在类的定义中,用于设置访问权限的public、private和protected可以出现任意次,且没有顺序要求。例如: class cValue public: int x; private: int y; public : int z;6.3数据成员和成员函数数据成

3、员和成员函数下面定义一个类的框架:voidsetage(inttage);char*getname();intgetage();voiddisp();classcPersonprivate:charname40;intage;public:voidsetname(char*ss);6.3.1成员函数的使用成员函数的使用例例 如如注意: (1)调用类中的函数也需要给出参数(2)实参类型同形参类型要一致(3)在访问类中的成员函数时,一定要 注意其访问控制权限。6.3.2成员函数的内部定义和外部定义成员函数的内部定义和外部定义类中的成员函数只有被定义了之后才能被调用。类的成员函数可以有两种定义方法:

4、 (1)内部定义)内部定义 特点:在类中定义的函数其长度都比较短,但这不是绝对的,任何函数都可以在类中进行定义。内部定义的函数即使不加inline关键词也被默认为inline函数。例例 如如classcPersonpublic:voidsetname(char*ss); 这里的这里的setnamesetname( )( )函数采用的就是内函数采用的就是内部定义形式部定义形式,默认,默认为为inlineinline函数。函数。(2)外部定义)外部定义外部定义的成员函数的写法外部定义的成员函数的写法外部定义的成员函数的写法如下: 其中,:是作用域限定运算符,它表示这里定义的disp()函数是属于c

5、Person类的。voidcPerson:disp()disp()函数的另一种定义形式函数的另一种定义形式voiddisp() 这样定义的disp()函数,是全局函数,而不是属于cPerson类的。说明:classDatepublic:intgetDay();inlineintDate:getDay()外部定义的inline函数可有如下三种写法:classDatepublic:inlineintgetDay();inlineintDate:getDay()classDatepublic:inlineintgetDay();intDate:getDay()6.3.3数据成员的保护数据成员的保护比

6、如,在cPerson类中,由于表示年令的变量age是私有的,因此,除了此类中的成员函数以外,其它函数是无法访问到此变量的,这样,就可以通过成员函数来保证赋给age变量的值是有意义的,从而起到对数据成员的保护作用。【例例6.1】编一程序,用于说明对对象中的成员编一程序,用于说明对对象中的成员设置访问控制的作用设置访问控制的作用#include#includeclasscPersoncharname40;intage;public:voidsetname(char*ss)strcpy(name,ss);voidsetage(inttage)age=(tage0)?0:tage;char*getna

7、me()returnname;intgetage()returnage;voiddisp();voidcPerson:disp()cout“Name:”namen;cout“Age:“agen;voidmain()cPersonman;intn;man.setname(“Wang”);man.setage(20);n=man.getage();man.disp();coutman.getname()man.getage()nn;执行结果:执行结果:Name:WangAge:20Wang2020说说 明明6.4构造函数和析构函数构造函数和析构函数6.4.1构造函数构造函数构造函数的特征构造函数的

8、特征1 1、构造函数的说明和定义、构造函数的说明和定义【例例6.2】编写程序,说明构造函数的定编写程序,说明构造函数的定义方式。义方式。#includeclasscExamintaInt;public:cExam();/构造函数构造函数voiddisp()cout“aInt=”aIntn;cExam:cExam()aInt=999;voidmain()cExamdt;dt.disp();执行结果:执行结果:aInt=999说说明明(1) 在此程序中,cExam类中的cExam();是构造函数的说明。这里需要注意的是,此构造函数没有函数值类型的说明。cExam:cExam()aInt=999;

9、其作用是为aInt数据成员赋初值999。有了构造函数的定义之后,在main()函数中定义cExam类对象dt时,将自动调用此构造函数,以便为dt.aInt数据成员赋以999的初值。在类的外面定义:说说 明(明(2) (1)构造函数cExam()没有参数,故将其称为无参构造函数或缺省构造函数。 (2)当构造函数的定义比较短时(不是绝对的),也可以在类中进行说明的同时进行定义。例如,上面cExam类可改为如下形式:classcExamintaInt;public:cExam()aInt=999;voiddisp()cout“aInt=”aIntn;2 2、带有参数的构造函数、带有参数的构造函数#i

10、ncludeclasscXydataintx;inty;public:cXydata(inta,intb);/构造函数的说明构造函数的说明voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;cXydata:cXydata(inta,intb)/构造函数的定义构造函数的定义x=a;y=b;【例例6.3】编写一程序,用于说明带有参数的构造编写一程序,用于说明带有参数的构造函数的说明和定义方式函数的说明和定义方式voidmain()cXydatadt1(100,200);/设定初值设定初值dt1.disp();执行结果:执行结果:x=100y=200 由于在定义

11、对象时,系统将根据后由于在定义对象时,系统将根据后面给出的参数个数来决定所要调用的构面给出的参数个数来决定所要调用的构造函数,所以对于上述定义的造函数,所以对于上述定义的cXydatacXydata类来讲,此时若有如下定义,则出错,类来讲,此时若有如下定义,则出错,因为没有与之对应的缺省构造函数:因为没有与之对应的缺省构造函数: cXydatacXydata dtdt; /; /出错出错说说 明明3 3、构造函数的显式调用、构造函数的显式调用【例例6.4】编写一程序,用于说明显式调编写一程序,用于说明显式调用构造函数的方法用构造函数的方法#includeclasscXydataintx;int

12、y;public:cXydata(inta,intb);/构造函数的说明构造函数的说明voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;cXydata:cXydata(inta,intb)/构造函数的定义构造函数的定义x=a;y=b; voidmain()cXydatadt1(100,200);/隐式调用构造函数隐式调用构造函数dt1.disp();cXydatadt2=cXydata(300,400);/显式调用构造函数显式调用构造函数dt2.disp();dt2.clear();/清除数据成员的值清除数据成员的值dt2.disp();dt2=cXyd

13、ata(500,600);dt2.disp();执行结果:x=100y=200x=300y=400x=0y=0x=500y=600说说明明1(1)构造函数的显式调用是在等号的后面直接给出构造函数名及其参数,其形式如下:说说明明2(2)一般来讲,构造函数的显式调用和隐式调用的效果是一样的,通常使用隐式调用的方式比较多。4 4、构造函数的重载、构造函数的重载【例例6.5】编写一程序,用于说明构造函数的编写一程序,用于说明构造函数的重载方法及其使用重载方法及其使用#includeclasscXydataintx;inty;public:cXydata();/构造函数构造函数1cXydata(inta

14、);/构造函数构造函数2cXydata(inta,intb);/构造函数构造函数3voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;cXydata:cXydata()x=0;y=0;cXydata:cXydata(inta)x=a;y=0;cXydata:cXydata(inta,intb)x=a;y=b;voidmain()cXydatadt1;cXydatadt2(100);cXydatadt3=200;cXydatadt4(300,400);cXydatadt5=cXydata(500,600);dt1.disp();dt2.disp();dt3.

15、disp();dt4.disp();dt5.disp();运行结果:运行结果:x=0y=0x=100y=0x=200y=0x=300y=400x=500y=600(1)当需要调用具有一个参数的构造函数时,可以直接采用下面两种方式中的任一个:cXydatadt2(100);cXydatadt3=200;说说明明1(2)当需要调用无参数构造函数时,下面的写法是错误的:cXydatadt1(); 这是因为上述定义表示dt1是返回值类型为cXydata的函数,而不是对象名,因此在定义时需要去掉括号。说说明明2(3)构造函数的重载同一般函数的重载一样,也需要满足相应的重载条件。 有了类的定义以后,函数的

16、返回值也可以是所定义的类的类型了。下面的例子将说明当函数的返回值为某个类类型时的用法。说说明明3【例例6.6】编写一个程序,用于说明当函数的返编写一个程序,用于说明当函数的返回值为某个类类型时的用法回值为某个类类型时的用法。#includeclasscXydataintx;inty;public:cXydata();/构造函数1cXydata(inta);/构造函数2cXydata(inta,intb);/构造函数3voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;cXydata:cXydata()x=0;y=0;cXydata:cXydata(inta

17、)x=a;y=0;cXydata:cXydata(inta,intb)x=a;y=b;cXydatadt1()/定义全局函数定义全局函数dt1()cXydataa(800,900);returna;voidmain()cXydatadt1();/函数说明函数说明cXydatadt2;dt2.disp()dt2=dt1();/函数调用函数调用dt2.disp();执行结果:执行结果:x=0y=0x=800y=900说说明:明:5、缺省构造函数缺省构造函数 没有参数的构造函数被称为缺省构造函数。缺省构造函数的说明如下所示: 所有参数都可以省略的构造函数也可以成为缺省构造函数。例如: 此时,若以无参

18、形式来生成对象时,上面两个构造函数都将充当缺省构造函数的角色,因此,上述两种形式的构造函数是不能同时存在的。以下面的形式来定义对象时,将自动调用缺省构造函数:说说明明:6.4.2析构函数析构函数析构函数的作用析构函数的作用析构函数有如下一些特征析构函数有如下一些特征【例例6.7】编一程序,用于说明析构函数编一程序,用于说明析构函数的定义和使用的定义和使用#include#includeclasscMystringchar*text;public:cMystring(char*str);/构造函数构造函数voiddisp()cout“text=”textn;cMystring();/析构函数析构

19、函数;cMystring:cMystring(char*str)/构造函数的定义构造函数的定义coutstr“constructorn”;text=newcharstrlen(str)+1;strcpy(text,str);cMystring:cMystring()/析构函数的定义析构函数的定义couttext“destructorn”;deletetext;voidsubfunc()cMystringss1=“ABCDE”;ss1.disp();voidmain()subfunc();cMystringss2(“12345”);ss2.disp();执行结果:执行结果:ABCDEconstr

20、uctor/ss1对象定义时对象定义时text=ABCDEABCDEdestructor/离开离开subfunc()函数时函数时12345constructor/ss2对象定象定义时text=1234512345destructor/main()函数函数执行完了行完了时说说明明1(1)在main()函数中,subfunc()函数调用结束时,其中定义的自动类的ss1对象就要被释放掉,这时就将自动调用析构函数;同时,由于ss2对象是在main()函数中生成的,因此,在main()函数执行结束时(也就是整个程序执行结束时),也将自动调用析构函数,以便释放已申请到的内存空间。说说明明2 (2)在此程序

21、中,如果没有析构函数,则在对象中定义的char*text;这样的指针变量是可以被自动释放掉的,但动态申请到的内存空间就不能被自动释放掉了,这样,其它程序能够使用的内存空间就将减少。因此,当在程序中需要申请动态存储空间时,往往需要定义析构函数,以便在析构函数中释放掉申请到的内存空间。6.5复制构造函数复制构造函数6.5.1复制构造函数的说明和定义复制构造函数的说明和定义【例例6.8】编一函数,用于说明复制构编一函数,用于说明复制构造函数的定义和使用造函数的定义和使用#includeclasscXydataintx;inty;public:cXydata();/构造函数构造函数1cXydata(i

22、nta);/构造函数构造函数2cXydata(inta,intb);/构造函数构造函数3cXydata(constcXydata&another);/复制构造函数复制构造函数voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;cXydata:cXydata()x=0;y=0; cXydata:cXydata(inta)x=a;y=0;cXydata:cXydata(inta,intb)x=a;y=b;cXydata:cXydata(constcXydata&another)x=another.x;y=another.y;voidmain()cXydatad

23、t1(100,200);cXydatadt2(dt1);cXydatadat3=dt1;dt1.disp();dt2.disp();dt3.disp();执行结果:执行结果:x=100y=200x=100y=200x=100y=200说说 明明 1 1(1)复制构造函数的特点是其入口参数为当前类的对象,一般把其说明为对象引用。说说明明2(2)当复制构造函数只有一个参数时,可以采用如下两种方式来调用复制构造函数:其作用都是通过自动调用复制构造函数,将dt1对象中的数据成员的值赋给新定义的对象(dt2或dt3)中的对应的数据成员。6.5.2缺省复制构造函数缺省复制构造函数注意事项注意事项cXyda

24、ta:cXydata()x=0;y=0;cXydata:cXydata(inta)x=a;y=0;【例例6.9】编一程序,用于说明附加一些功能的复编一程序,用于说明附加一些功能的复制构造函数的定义和使用制构造函数的定义和使用#includeclasscXydataintx;inty;public:cXydata();cXydata(inta);cXydata(inta,intb);cXydata(constcXydata&another,intn=1);voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;cXydata:cXydata(inta,intb)

25、x=a;y=b;cXydata:cXydata(constcXydata&another,intn)if(n1)n=1;x=another.x*n;y=another.y*n;voidmain()cXydatadt1(100,200);cXydatadt2(dt1);/相当于相当于n=1cXydatadt3(dt1,3);/复制复制dt1对象中的对象中的3倍的值倍的值dt1.disp();dt2.disp();dt3.disp();执行结果:x=100y=200x=100y=200x=300y=600程程序说序说明明1一般的复制构造函数只有一个参数,即同一个类的引用变量,但本程序中的复制构造函

26、数却有两个参数,这是允许的。由于第二个参数是缺省参数,因此,可以利用如下两种形式来调用复制构造函数:或程程序说序说明明2当一个类中包含指针变量时,这时如果利用缺省复制构造函数来复制对象的话,由于缺省复制构造函数仅仅是将指针变量中的地址(指针值),复制到另一个对象中去,这样,两个对象中的指针值都是相同的,即它们都指向同一存储区域,这在多数情况下是不方便的。为了使它们分别指向不同的存储区域,就必须在程序中来定义复制构造函数。【例例6.10】编一程序,用于说明类中编一程序,用于说明类中包含指针变量时复制构造函数的定包含指针变量时复制构造函数的定义和使用义和使用运行结果:abcdabcd#includ

27、e#includeclasscStringchar*s;public:cString(void);cString(constchar*);cString(constcString&);voidprint(void)printf(“%sn”,s);cString:cString(void)/构造函数构造函数1s=newchar1;*s=0;cString:cString(constchar*x)/构造函数构造函数2s=newcharstrlen(x)+1;strcpy(s,x);cString:cString(constcString&x)/构造函数构造函数3s=newcharstrlen(x.

28、s)+1;strcpy(s,x.s);voidmain()cStringx(“abcd”);/调用一般构造函数调用一般构造函数cStringy=x;/调用复制构造函数调用复制构造函数x.print();y.print();程序说明程序说明 本程序中定义了3个构造函数,其中的复制构造函数用于将入口参数(对象)中的字符串复制到当前对象中的字符串成员中,这一操作的结果使得入口参数对象中的字符串与当前对象中的字符串分别占用不同的存储区域。注意事项注意事项需要注意的是,在此程序中即使不定义复制构造函数,系统也将自动生成一个缺省复制构造函数,但由缺省构造函数所完成的操作将使得入口参数中的字符串与当前对象中

29、的字符串占用同样的存储空间,这也就是说如果改变了其中任何一个对象中的字符串,则另一个对象中的字符串也将随之改变。下面的程序说明了当类中定义了复制构造函数时,即使类中存在指针变量,由于分别指向不同的地址,因此相互之间也没有影响。下面的程序说明了当类中没有定义复制构造函数而是利用缺省复制构造函数时,如果类中存在指针变量,则由于都指向相同的地址,因此相互之间将产生影响。#include#includeclasscStringchar*s;public:cString(void);cString(constchar*);cString(constcString&);voidprint(void)pri

30、ntf(%sn,s);voidstrcon(char*p);voidcString:strcon(char*p)strcat(s,p);/将p连接到s上cString:cString(void)/构造函数1s=newchar1;*s=0;cString:cString(constchar*x)s=newcharstrlen(x)+1;strcpy(s,x);cString:cString(constcString&x)s=newcharstrlen(x.s)+1;strcpy(s,x.s);voidmain()cStringx(abcd);cStringy=x;x.print();y.prin

31、t();y.strcon(mmm);x.print();y.print();运行结果:abcdabcdabcdabcdmmm程序#include#includeclasscStringchar*s;public:cString(void);cString(constchar*);/cString(constcString&);/去掉voidprint(void)printf(%sn,s);voidstrcon(char*p);voidcString:strcon(char*p)strcat(s,p);/将p连接到s上cString:cString(void)/构造函数1s=newchar1;*

32、s=0;程序cString:cString(constchar*x)s=newcharstrlen(x)+1;strcpy(s,x);/cString:cString(constcString&x)/s=newcharstrlen(x.s)+1;/strcpy(s,x.s);/voidmain()cStringx(abcd);cStringy=x;x.print();y.print();y.strcon(mmm);x.print();y.print();运行结果:abcdabcdabcdmmmabcdmmm注意:无论在类中是否定义了复制构造函数,带有一个参数的缺省复制构造函数总是存在的。在下面

33、的程序中,尽管base类中没有定义base(base&a)这样带有一个参数的构造函数,系统会自动添加一个这样的复制构造函数,这样main()函数中的定义是正确的。classbaseintx;public:base(base&a,intn)x=a.x*n;voidmain()basea;baseb(a);/正确basec(b,2)/正确*复制构造函数的进一步说明#includeiostream.hclassxyzintx;inty;intz;public:xyz(inta,intb,intc)x=a;y=b;z=c;xyz(xyz&m)x=m.x;y=m.y;z=m.z;coutEntering

34、copyconstructor.n;intgetx()returnx;intgety()returny;intgetz()returnz;voidmain()xyza(10,20,30);couta.getx()a.gety()a.getz()n;xyzb(a);/调用复制构造函数coutb.getx()b.gety()b.getz()n;此程序的执行结果如下:102030Enteringcopyconstructor.102030以下3种情况都要调用复制构造函数:(1)当利用类的已有对象来初始化另一个新对象时,系统将自动调用复制构造函数(2)如果函数的形参是类对象,则在进行函数调用时(将实参

35、传递给形参时),将自动调用复制构造函数voidf(xyzm)coutf:m.getx()m.gety()m.getz()n;voidmain()xyza(1,2,3);f(a);此程序的执行结果如下:Enteringcopyconstructor.f:123由此可见,如果复制构造函数的参数不是对象引用而是对象本身,则将出现运行错误,这是由于将对象传递给复制构造函数时还需要调用复制构造函数,这就产生无限循环调用.需要注意的是,如果函数的形参是类对象的指针或对象引用,则在函数调用时并不调用复制构造函数voidf(xyz&m)coutf:m.getx()m.gety()m.getz()n;这时,程序

36、的运行结果如下:f:123(3)如果函数的返回值是类对象,则在执行返回语句时将自动调用复制构造函数(返回类指针和引用时不调用复制构造函数)xyzg()xyzm(7,8,9);coutg:m.getx()m.gety()m.getz()n;returnm;voidmain()xyzn(1,2,3);coutn.getx()n.gety()n.getz()n;n=g();coutn.getx()n.gety()n.getz()n;此程序的执行结果如下:123g:789Enteringcopyconstructor.7896.6变换构造函数和变换函数变换构造函数和变换函数6.6.1变换构造函数变换构

37、造函数 只有一个参数的构造函数被称为变换构造函数或转换构造函数。例如: 程序中如果定义了变换构造函数,就可以使用下面的形式来对类的对象进行初始化:这种初始化方式和下面初始化方式完全一样:它的初始化结果如下:就上面的例子而言,它相当于如下的变换: 由于变换构造函数在初始化方面的简洁性,使其在实际程序设计中经常被用到。变换构造函数6.6.2变换函数变换函数变换函数用于将对象中的一个值返回出来。 变换函数采用如下定义形式:【例例6.11】编一程序,用于说明变编一程序,用于说明变换函数的定义和使用换函数的定义和使用#includeclasscAdatainta;public:cAdata(intx)a

38、=x;/变换构造函数变换构造函数operatorint()returna;/变换函数变换函数voiddisp()cout“a=”an;voidmain()cAdatadt=1234;/调用变换构造函数调用变换构造函数intidt=dt;/调用变换函数调用变换函数dt.disp();cout“idt=”idtn;执行结果:a=1234idt=1234说说明明(1)程序中定义了某种类型的变换函数之后,就可以使用语句来调用变换函数。(2)如果没有定义变换函数,则上述写法是错误的。 一般来讲,变换函数都是直接从类中返回某一个变量的值,但这不是绝对的,在变换函数中也允许做一些简单的运算,并把运算结果返回

39、出来。cXydata:cXydata(constcXydata&another,intn)if(n1)n=1;x=another.x*n;y=another.y*n;voidmain()cXydatadt1(1234,5678);longldt;dt1.disp();ldt=dt1;cout“ldt=”ldtn;cout“(long)dt1=”(long)dt1n;【例例6.12】编一程序,在变换函数中进行一些编一程序,在变换函数中进行一些简单的运算,并把运算结果返回出来。简单的运算,并把运算结果返回出来。#includeclasscXydataintx;inty;public:cXydata

40、()x=0;y=0;cXydata(inta)x=a;y=0;cXydata(inta,intb)x=a;y=b;cXydata(constcXydata&another,intn=1);operatorlong()return(x*10000+y);voidclear()x=0;y=0;voiddisp()cout“x=”x“y=”yn;执行结果:x=1234y=5678ldt=12345678(long)dt1=12345678说说明明在程序中对变换函数的利用方式是非常灵活的。一般来讲,如果在cXydata类中有如下的变换函数定义:变换函数主要用于返回类中的数据成员,但变换函数本身也可以定

41、义变量并可以包含多个语句,也可以对数据成员进行更改。需要注意的是,变换函数中必须包含return语句,同时需要注意其访问权限。cXydatadt1(100,200);longldt;ldt=dt1;/默认的long型变换ldt=long(dt1);/函数型的显式变换ldt=(long)dt1;/强制型的显式变换cout(long)dt110000)/强制变换后进行比较下面的利用方法都是正确的:下面的利用方法都是正确的:6.7静态数据成员和静态成员函数静态数据成员和静态成员函数静态成员的定义方法静态成员的定义方法 在类的定义中,下面的写法用于说明一个静态数据成员ct和静态成员函数count():

42、 需要说明的是这仅仅是说明而已,系统并没有为ct分配任何存储空间,而ct的实体应该在类的外面以下列方式进行定义(可以在定义的同时进行初始化):注:上述语句必须在cVdata类的定义的后面给出。如果在前面给出的话,将因找不到cVdata类的定义而出错。 静态成员函数既可以通过已生成的对象来调用,又可以利用作用域限定运算符以下列方式来调用(这里假设count是cVdata类中的静态成员函数)【例例6.13】编一程序,用于说明静态数据成编一程序,用于说明静态数据成员和静态成员函数的定义和使用员和静态成员函数的定义和使用#include#includeclasscVdataintv;staticint

43、ct;public:cVdata()v=0;+ct;voidsetdata(intdt)v=dt;intgetdata()returnv;staticintcount()returnct;cVdata()-ct;intcVdata:ct=0;voidsubprg()cVdatadt3;cout“cVdataobjectscount=”dt3.count()n;voidmain()cVdatadt1;cout“cVdataobjectscount=”dt1.count()n;cVdata*dt2=newcVdata;cout“cVdataobjectscount=”dt1.count()n;co

44、ut“cVdataobjectscount=”count()n;cout“cVdataobjectscount=”cVdata:count()n;subprg();deletedt2;/调用析构函数用析构函数cout“cVdataobjecscount=”dt1.count()n;执行结果:执行结果:cVdataobjectscount=1cVdataobjectscount=2cVdataobjectscount=2cVdataobjectscount=2cVdataobjectscount=3cVdataobjectscount=1说说 明明(1)对于静态数据成员可以利用如下两种方式来进行

45、访问: 需要注意的是,在利用静态数据成员时,也需要注意其访问控制权限。说明说明(2)静态成员函数只能直接访问该类的静态数据成员和静态成员函数。若要访问非静态数据成员则必须通过对象来访问。例如:classApublic:staticvoidf(Aa);private:intx;voidA:f(Aa)coutx;/出错couta.x;/正确(3)需要注意的是,构造函数和析构函数不能定义为静态的。6.8this指针指针【例6.14】编一程序,用于说明this指针的用法。#includeclasscExamintva;intvb;public:cExam(inta,intb)va=a;vb=b;voi

46、ddisp();voidcExam:disp()cout“va=”van;cout“vb=”vbn;voidmain()cExame(10,20);e.disp();执行结果:va=10vb=20说说明:明: 在调用成员函数时,系统自动将this指针传递给成员函数,this指针中存放的是当前对象的地址。 为了明确起见,上面的disp()函数也可以改为如下形式:voidcExam:disp()cout“va=”van;cout“vb=”vbn;如果在main()函数内有如下语句: 则表示将指向temp对象的this指针传递给disp()函数,这样,在disp()函数中就可以直接对temp对象中的

47、数据成员进行访问了。 尽管this指针一般都是缺省使用的,但在需要时,也可以显式地使用this指针。下面的例子将给出this指针的显式使用方法。说说明明【例例6.15】编一程序,用于说明编一程序,用于说明this指针的显式用法。指针的显式用法。#includeclasscSmpintva;intvb;public:cSmp(inta,intb)va=a;vb=b;intcomp(cSmp&some);intget_a()returnva;intget_b()returnvb;intcSmp:comp(cSmp&some)if(&some=this)/some是变量的别名,不是地址是变量的别名,

48、不是地址return0;/相等相等if(va+vbsome.va+some.vb)return1;/大于大于elseif(va+vbsome.va+some.vb)return1;/小于小于elsereturn0;/相等相等voidmain()cSmpdt1(10,20);cSmpdt2(30,40);cout“comparison:”p(dt1)n;/自己同自己比自己同自己比cout“comparison:”p(dt2)some.va+some.vb)return1;elsereturn-1;6.9友元友元6.9.1友元函数友元函数【例例6.16】编一程序,用于说明友元函数编一程序,用于说明

49、友元函数的定义和使用的定义和使用#includeclasscFriendintva;intvb;public:cFriend()va=0;vb=0;cFriend(inta,intb)va=a;vb=b;voidset_va(intdt)va=dt;voidset_vb(intdt)vb=dt;intget_va()returnva;intget_vb()returnvb;voiddisp();friendvoidoneline_disp(cFrienddt);/友元函数友元函数;voidcFriend:disp()cout“va=”van;cout“vb=”vbn;voidoneline_d

50、isp(cFrienddt)/友元函数友元函数/若若oneline_disp()是友元函数是友元函数 访问访问vava vbvbcout“va=”dt.va“vb=”dt.vbn;/若若oneline_disp()不是友元函数则使用下面语句不是友元函数则使用下面语句cout“va=”dt.get_va()“vb=”dt.get_vb()n;voidmain()cFrienddt1(10,20);dt1.disp();oneline_disp(dt1);执行结果:执行结果:va=10vb=20va=10vb=20va=10vb=20说说明明1 (1)在类中,函数说明语句的前面加上friend就表

51、示该函数为此类的友元函数。友元函数可以直接引用类中的private变量。说说明明2 (2)友元函数的说明可以出现在类中的任何位置上(私有、受保护的或公共部分),其作用都是一样的。说说明明3 (3)需要注意的是,友元函数不是类中的成员函数,任何一个不是类的成员函数的函数都可以成为该类的友元函数。友元函数的定义也可以在类中直接给出,但这并不意味着该友元函数就是类的成员函数,在类中定义和在类外定义的友元函数都是一样的。classcFriendintva;intvb;public:cFriend()va=0;vb=0;cFriend(inta,intb)va=a;vb=b;voidset_va(int

52、dt)va=dt;voidset_vb(intdt)vb=dt;intget_va()returnva;intget_vb()returnvb;voiddisp()cout“va=”van;cout“vb=”vbn;friendvoidoneline_disp(cFrienddt);/友元友元函数函数/若若oneline_disp()是友元函数访问是友元函数访问vava vbvbcout“va=”dt.va“vb=”dt.vbn; /若若oneline_disponeline_disp( )( )不是友元函数不是友元函数则使用下面语句则使用下面语句cout“va=”dt.get_va()“vb

53、=”dt.get_vb()n;说说明明 这里,尽管oneline_disp()函数是在cFriend类的内部定义的,但其效果与在类的外部定义是一样的,也就是说oneline_disp()函数仍然是cFriend类的友元函数,而不是它的成员函数。6.9.2友元类友元类classcFriendcintva;public:;classcExamintvb;public:friendclasscFriendc;当类作为友元时,其定义方式如下:当类作为友元时,其定义方式如下:经过上面的说明以后,由于cFriendc类是cExam类的友元,因此cFriendc类中的所有成员函数,都可以直接对cExam类中

54、的所有数据成员(包括vb这样的私有成员)进行访问。说说明明友元类举例6.10运算符的重载运算符的重载6.10.1operator函数的功能函数的功能【例例6.17】编一程序,用于将两个对象中编一程序,用于将两个对象中的对应数据相加后生成一个新的对象的对应数据相加后生成一个新的对象#includeclasscAddintva;intvb;public:cAdd()va=0;vb=0;cAdd(inta,intb)va=a;vb=b;voidset_va(intdt)va=dt;voidset_vb(intdt)vb=dt;intget_va()returnva;intget_vb()return

55、vb;voiddisp();cAddadd(cAdd&data1,cAdd&data2)cAddsum;sum.set_va(data1.get_va()+data2.get_va();sum.set_vb(data1.get_vb()+data2.get_vb();returnsum;voidcAdd:disp()cout“va=”va”vb=”vbn;voidmain()cAdda(100,200),b(10,20),c;c=add(a,b);c.disp();运行结果:运行结果:va=110vb=220说说明明利用add()函数进行加法运算,看起来并不自然,最直观的运算是采用下列形式:这

56、一运算结果相当于同时进行下面两个式子的运算:【例例6.18】编一程序,用于实现编一程序,用于实现+和和-运算符的重载运算符的重载#includeclasscAddMintva;intvb;public:cAddM()va=0;vb=0;cAddM(inta,intb)va=a;vb=b;voidset_va(intdt)va=dt;voidset_vb(intdt)vb=dt;intget_va()returnva;intget_vb()returnvb;voiddisp();cAddMoperator+(cAddM&second);cAddMoperator-(cAddM&second);v

57、oidcAddM:disp()cout“va=”van;cout“vb=”vbn;cAddMcAddM:operator+(cAddM&second)returncAddM(va+second.va,vb+second.vb);/或或/cAddMcw;/cw.set_va(va+second.va);/cw.set_vb(vb+second.vb);/returncw;cAddMcAddM:operator-(cAddM&second)returncAddM(va-second.va,vb-second.vb);/或或/cAddMcw;/cw.set_va(va-second.va);/cw.

58、set_vb(vb-second.vb);/returncw;voidmain()cAddMa(100,200),b(10,20),c;c=a+b;c.disp();c=a-b;c.disp();执行结果:va=110vb=220va=90vb=180说说明明(1)由于operator+()是a对象的成员函数,可以直接得到指向当前对象的this指针。(2)c=a+b; 可解释为:c=a.operator+(b)这样,在定义operator+()函数时,只需要一个参数即可。(3)operator+()函数也可写成如下形式:由于operator+()是类中的成员函数,在程序中也可以使用如下语句来调

59、用该函数:说说明明 (4)需要注意的是,运算符的重载是很方便的功能,但不能乱用,也就是重载后的功能同运算符的原有功能应该保持一致。比如,加法运算符(+)经重载后还应该具有加法的功能而不能重载为其它功能,否则,在运算符的用法上将会出现混乱。说说明明 (5)在C+语言中,几乎所有运算符都可以进行重载。合理地进行运算符的重载会增强程序的可读性和可维护性。6.10.2operator函数的重载函数的重载 (1)在上例中,如果进行c=a+100;的运算则会出错,这是因为c=a+100;相当于执行了下面的操作:而operator+()函数参数是cAddM类型的。【例例6.19】编写一个用于进行分数计算的类

60、。编写一个用于进行分数计算的类。为了简化处理过程,假设分数的分子和分母都为了简化处理过程,假设分数的分子和分母都为正数,且只定义分数的加法(为正数,且只定义分数的加法(+)运算符。)运算符。所定义的类所定义的类fraction具有如下一些功能:具有如下一些功能:fractiona(2,16);经过约分,表示分数1/8fractionb(1,6);表示分数1/6fractionc(5);表示分数5/1fractiond;表示分数0/1c=a+b;1/8+1/6经通分后,c=7/24c=a+2;1/8+2/1经通分后,c=17/8程序程序#includeclassfractionlongnumer

61、a;/分子分子longdenomi;/分母分母longgcd(longa,longb);/求最大公约数求最大公约数public:fraction()numera=0;denomi=1;fraction(longa,longb=1);voiddisp();fractionoperator+(fraction&dt2);fractionoperator+(longdt2);fraction:fraction(longa,longb)longwk;if(b=0)b=1;wk=gcd(a,b);/求最大公约数求最大公约数numera=a/wk;denomi=b/wk;/约分约分fractionfrac

62、tion:operator+(fraction&dt2)longmul1,mul2;mul1=numera*dt2.denomi+dt2.numera*denomi;mul2=denomi*dt2.denomi;returnfraction(mul1,mul2);fractionfraction:operator+(longdt2)returnfraction(numera+denomi*dt2,denomi);longfraction:gcd(longa,longb)/求最大公约数求最大公约数longwk;while(b!=0)a=a%b;/求余求余wk=a;a=b;b=wk;/交换交换re

63、turna;voidfraction:disp()coutnumera“/”denomi“n”;voidmain()fractiona(2,16),b(1,6),c(5),d;cout“初始值:初始值:n”;a.disp();b.disp();c.disp();d.disp();cout“a+b的结果的结果:n”;c=a+b;c.disp();cout“a+2的结果的结果:n”;c=a+2;c.disp();执行结果:执行结果: 初始值:初始值:1/81/65/10/1a+b的结果:的结果:7/24(因为(因为1/8+1/6)a+2的结果:的结果:17/8(因为(因为1/8+2/1)说说 明明

64、 (1)在上面的程序中,由于求最大公约数的函数gcd()只在类的成员函数中使用,因此,把它的访问权限设置为private。说说 明明(2)对operator+()函数进行重载之后,下面的两个运算都可以进行处理了:c=a+b;第二个参数是fraction类型c=a+2;第二个参数是long类型说说 明明(3)由于对运算符的重载和对函数的重载类似,因此,对运算符的重载也需要满足相应的重载条件。 在上述例子中尽管进行了运算符的重载,但是,像下面这样的运算还是无法处理的: 由于2是数字而不是fraction类的对象,因此,它不具有operator+()成员函数,所以,c=2+a;是不能进行运算的。计算

65、过程相当于计算过程相当于6.10.3类的友类的友元是元是operator函数函数【例例6.20】本例和上例是一样的,只本例和上例是一样的,只加了作为类的友元加了作为类的友元的的operator+()函数,函数,解决类似解决类似于于c=2+a;这样的计算问题。对这样的计算问题。对本例的学习,将掌握作为类的友元本例的学习,将掌握作为类的友元operator函数的定义和使用函数的定义和使用。#includeclassfractionlongnumera;/分子分子longdenomi;/分母分母longgcd(longa,longb);/求最大公约数求最大公约数public:fraction()nu

66、mera=0;denomi=1;fraction(longa,longb=1);voiddisp();fractionoperator+(fraction&dt2);fractionoperator+(longdt2);friendfractionoperator+(longdt1,fraction&dt2);fraction:fraction(longa,longb)longwk;if(b=0)b=1;wk=gcd(a,b);/求最大公约数求最大公约数numera=a/wk;denomi=b/wk;/约分约分fractionfraction:operator+(fraction&dt2)lo

67、ngmul1,mul2;mul1=numera*dt2.denomi+dt2.numera*denomi;mul2=denomi*dt2.denomi;returnfraction(mul1,mul2);fractionfraction:operator+(longdt2)returnfraction(numera+denomi*dt2,denomi);longfraction:gcd(longa,longb)/最大公约数最大公约数longwk;while(b!=0)a=a%b;/求余求余wk=a;a=b;b=wk;/交换交换returna;voidfraction:disp()coutnum

68、era“/”denomi“n”;fractionoperator+(longdt1,fraction&dt2)returnfraction(dt1*dt2.denomi+dt2.numera,dt2.denomi);voidmain()fractionx(1,4),y;y=x+2;/调用成员函数调用成员函数y.disp();y=2+x;/调用友元函数调用友元函数y.disp();/友元函数的定义友元函数的定义执行结果:执行结果:9/49/4说说明明(1)在上面的程序中,作为类的成员函数的operator+()函数有两个,作为友元函数的operator+()函数有一个,系统将会根据所给定的参数个

69、数和参数类型来自动调用相应的函数。这里:计算相当于计算相当于说说明明 (2)需要注意的是,当将operator+()函数作为类的友元来定义时,应保证至少有一个参数是类的对象,否则,若两个参数都是数值的话,如进行2+3这样的运算时,系统将无法判断此运算是基本的数值加法运算还是需要调用operator+()函数来进行的计算。6.11const对象对象( (常对象常对象) )【例例6.21】编一程序,用于说明编一程序,用于说明const成成员函数员函数( (常成员函数常成员函数) )的定义与使用的定义与使用#includeclasscConstintva;intvb;public:cConst()v

70、a=0;vb=0;cConst(inta,intb)va=a;vb=b;voidset_va(intdt)va=dt;voidset_vb(intdt)vb=dt;intget_va()constreturnva;intget_vb()constreturnvb;voiddisp()const;voidcConst:disp()constcout“va=”van;cout“vb=”vbn;voidmain()constcConstdt1(10,20);dt1.disp();coutdt1.get_va();执行结果:执行结果:va=10vb=2010说说明明(1)const成员函数的内部定义形

71、式classcConstintget_va()constreturnva;(2)const成员函数的外部定义形式classcConstvoiddisp()const;voidcConst:disp()const说说明明 (3)需要注意的是,在函数上附加的const关键字,并不表示将什么变成const型,而是表示const对象也可以使用这些函数,而对于非const对象来讲,加上const和没加上const都是一样的。(4)对于改变数据成员的函数来讲,即使加上const,也不能利用const对象来使用。说说明明6.12类的嵌套定义类的嵌套定义【例例6.22】编一程序,用于说明类的编一程序,用于说明

72、类的嵌套定义及其使用嵌套定义及其使用#includeclasscStackintdata100;public:intcount;cStack(void)count=0;voidpush(intdt)if(count0)returndata-count;elsereturn0;classinsidepublic:intget_count(cStack*p)returnp-count;voidmain()intx,y,z,n;cStacka;/生成对象生成对象acStack*b=&a;/指向指向a的指针的指针bcStack&c=a;/c是是a的引用的引用cStack:insideisd;/生成内嵌

73、类的对象生成内嵌类的对象a.push(100);a.push(200);a.push(300);n=isd.get_count(&a);cout“Depthofstack=”npop();/利用指针来访问函数利用指针来访问函数z=c.pop();/利用引用来访问函数利用引用来访问函数cout“x=”x“y=”yn;cout“z=”zn;执行结果:执行结果:Depthofstack=3x=300y=200z=100说说 明明 (1)对类成员的访问尽管inside类是在cStack类的内部定义的,但是inside类的成员函数也不能直接访问cStack类中的成员,仍需要利用cStack类的对象来访问

74、cStack类的成员。 (2)inside类无法直接访问cStack类中的private的成员(为什么cStack类中的count数据成员被设置为public?)。(3)父类cStack中的成员函数也不能直接访问inside类中的成员。说说 明明 (4)内嵌类的使用在使用内嵌类时,需要指定完整的类名。例如:cStack:insideisd;而不能以下述方式进行定义:insideisd;由此可见,内嵌类并没有什么特权,它只是在类的内部定义而已。说说 明明(3)内嵌类成员函数的外部定义)内嵌类成员函数的外部定义classcStackintdata100;public:intcount;cStack

75、(void)count=0;voidpush(intdt)if(count0)returndata-count;elsereturn0;classinsidepublic:intget_count(cStack*p);intcStack:inside:get_count(cStack*p)returnp-count;#includeclasscStackintdata100;public:intcount;cStack(void)count=0;voidpush(intdt)if(count0)returndata-count;elsereturn0;注:在cStack类中可以直接利用insi

76、de类名定义对象voidf()/cStack:insidexx;/也可以利用insidexx;/可以直接利用insidecoutxx.gg;/出错,private成员cout“gg=“count;voidmain()intx,y,z,n;cStacka;/生成对象acStack*b=&a;/指向a的指针bcStack&c=a;/c是a的引用cStack:insideisd;/生成内嵌类的对象a.push(100);a.push(200);a.push(300);n=isd.get_count(&a);coutDepthofstack=npop();/利用指针来访问函数z=c.pop();/利用

77、引用来访问函数coutx=xy=yn;coutz=zn;a.f();运行结果如下:Depthofstack=3x=300y=200z=100gg=996.13类的数据成员是对象或常量类的数据成员是对象或常量6.13.1类的数据成员是对象类的数据成员是对象【例例6.23】编一程序,用于说明对一个类的内编一程序,用于说明对一个类的内部对象进行初始化的方法部对象进行初始化的方法#includeclassinner_classprivate:intx;public:inner_class(intz)x=z;voidwrite()printf(“%dn”,x);classouter_classinty;

78、inner_classx;inner_classr;public:outer_class(intz);voidwrite()printf(“%dn”,y);voidwrite_inner_x()x.write();voidwrite_inner_r()r.write();outer_class:outer_class(intz):x(200),r(-300)y=z;voidmain()outer_classtout(-12);tout.write_inner_x();tout.write_inner_r();tout.write();执行结果:200-300-12说说明明(1)对类中对象成员的

79、初始化需要在构造函数头部的后面用冒号隔开后给出,这里,冒号后面的部分称为初始化列表.outer_class:outer_class(intz):x(200),r(-300)y=z;这里,x(200),r(-300)分别表示需要调用inner_class类的构造函数为x对象和r对象进行初始化,即调用具有一个参数的构造函数.(2)如果希望利用缺省构造函数为对象成员初始化,则不需要显式给出初始化过程.这时,如果类中不存在缺省构造函数则出错.outer_class:outer_class(intz)y=z;如果构造函数如此定义,则系统将调用inner_class的缺省构造函数为x和r初始化.就本例而言

80、,需要追加缺省构造函数的定义,否则出错.(3)outer_class类中的y数据成员的初始化也可以在其构造函数的冒号后面给出outer_class:outer_class(intz):x(200),r(-300),y(z)(4)初始化x和r的参数(200和-300)也可以通过构造函数的参数传递过来,这样,可以根据需要利用不同的参数进行初始化outer_class:outer_class(inta,intb,intz):x(a),r(b),y(z)(5)当类的成员中包含对象时,其构造函数和析构函数的执行是有顺序的.#includeclassinnerApublic:innerA()coutEnt

81、eringinnerAconstructor.n;innerA()coutEnteringinnerAdestructor.n;classinnerBpublic:innerB()coutEnteringinnerBconstructor.n;innerB()coutEnteringinnerBdestructor.n;classouterAinnerAA1;innerAA2;innerBB1;innerBB2;public:outerA()coutEnteringouterAconstructor.n;outerA()coutEnteringouterAdestructor.n;Enteri

82、nginnerAconstructor./A1EnteringinnerAconstructor./A2EnteringinnerBconstructor./B1EnteringinnerBconstructor./B2EnteringouterAconstructor./xEnteringouterAdestructor./xEnteringinnerBdestructor./B2EnteringinnerBdestructor./B1EnteringinnerAdestructor./A2EnteringinnerAdestructor./A1voidmain()outerAx;由运行结果

83、可知,对于构造函数来讲,首先调用内嵌成员对象的构造函数,调用顺序按照它们在类中的定义顺序(即A1,A2,B1,B2),尽管本例采用缺省构造函数来初始化,即使采用显式初始化方式也一样,即构造函数的调用顺序与初始化列表的顺序无关.然后执行本类的构造函数.析构函数的调用顺序与构造函数正好相反.6.13.2类的数据成员是常量类的数据成员是常量在定义一个类时,类中的数据成员可以是某种数据类型的常量,对常量的初始化也需要利用构造函数来进行。【例例6.24】编一程序,用于说明对一个类中定编一程序,用于说明对一个类中定义的常量进行初始化的方法义的常量进行初始化的方法#includeclasscConstant

84、public:constintiConst;constdoubledConst;intvInt;public:cConstant():iConst(100),dConst(3.14)vInt=200;voidmain()cConstantcVar;cout“iConst=”cVar.iConstn;cout“dConst=”cVar.dConstn;cout“vInt=”cVar.vIntn;执行结果:执行结果:iConst=100fConst=3.14vInt=200说说明明 (1)在类中定义的常量的值不能直接在后面利用等号给出,必须如上所述那样在构造函数中进行设置。说说明明 (2)可以将常

85、量的值作为构造函数的参数来进行设置,这样就可以为每个对象设置不同的常量值。 例如,可以将上述程序进行如下修改:#includeclasscConstantpublic:constintiConst;constdoublefConst;intvInt;public:cConstant(inta,doubleb):iConst(a),fConst(b)vInt=200;/*或或cConstant(inta,doubleb):iConst(a),fConst(b),vInt(200)但但cConstant(inta,doubleb)错错!iConst=a;fConst=b;/不能这样初始化不能这样初

86、始化!,只能写在冒号后面只能写在冒号后面vInt=200;*/;voidmain()cConstantcVar(1000,8.88);cout“iConst=”cVar.iConstn;cout“fConst=”cVar.fConstn;cout“vInt=”cVar.vIntn;执行结果:执行结果:iConst=1000fConst=8.88vInt=200需要注意的是,当类中有const数据成员时,该类的对象之间是不能互相赋值的.例如,下面的语句将发生编译错误:cConstantx(10,1.23),y(20,4.56);y=x;这是由于x和y对象中定义了const数据成员,而const数

87、据成员的值不能被改变的,如果采用缺省的“=”运算符的功能,将会用x对象中的数据成员的值来更新y对象中的对应数据成员,因此发生错误。如果希望包含const数据成员的对象之间也能够互相赋值的话,就必须对“=”运算符进行重载。下面的例子就说明了这一用法。#includeclassassignoverintx;constinty;public:assignover(inta,intb):y(b)x=a;assignover&operator=(assignover&a)x=a.x;return*this;voiddisp()coutx=xn;couty=yn;voidmain()assignovera

88、(10,20),b(50,60);a.disp();b.disp();b=a;b.disp();x=10y=20x=50y=60x=10y=60在”=”重载函数中,只对x成员进行了赋值,而没有对const成员y进行赋值,这样对象之间就可以赋值了.6.14对象数组classarrdefintx;public:arrdef()x=0;arrdef(inta)x=a;intgetx()returnx;voidsetx(inta)x=a;voiddisp()coutx=xn;先定义如下类:对象数组的定义形式如下:类名数组名常量表达式;例如:arrdefa10;由此定义可知,a是具有10个元素的arrd

89、ef类型的对象数组。在定义对象数组时,系统都会调用构造函数对其每个元素进行初始化。这样,由于对象数组中的每一个元素都是对象,因此定义了对象数组之后,就可以访问其每一个元素的成员了(包括数据成员和成员函数)。对对象数组元素的成员的访问方式如下:数组名下标表达式.成员名例如:a0.setx(10);/调用对象a0的setx函数a6.disp();/调用对象a6的disp函数同一般数组元素一样,对象数组元素也可以初始化(包括显式的和缺省的)。对象数组的初始化方式(1)通过初始值表为对象数组元素初始化。例如:arrdefx3=arrdef(1),arrdef(2),arrdef(3);其中,由左、右化

90、括号括起来的初始值表中的每个初值,都是通过调用构造函数而创建的临时对象,这些临时对象将被赋给所对应的对象数组元素。(2)如果在定义对象数组时没有显式地为数组元素指定初值,则将利用缺省构造函数为数组元素赋初值。例如:arrdefy6;此时,对象数组y中的每个元素将通过利用缺省构造函数进行初始化。需要注意的是,在这种情况下,如果没有定义缺省构造函数的话,将发生编译错误。(3)在为对象数组初始化时,所给定的初值个数可以少于数组的长度,这时,将仅对数组中的前几个元素赋给定的初值,其余元素的初值将利用缺省构造函数来设置。例如:arrdefz5=arrdef(5),arrdef(6),arrdef(7);

91、这里,z0、z1和z2将被赋以给定的初值,而z3和z4的初值将通过调用缺省构造函数来设置。(4)当需要利用变换构造函数来初始化对象数组时,在初始值表中可以只给出参数,这同前面介绍的变换构造函数的意义是一致的。例如:arrdef5=arrdef(),6,8;这里的初始化方式与下述的相同:arrdef5=arrdef(),arrdef(6),arrdef(8),arrdef(),arrdef();【例6.28】编一程序,用于说明对象数组的用法。#includeclassarrdefintx;public:arrdef()x=0;coutConstructor1called.X=xn;arrdef(

92、inta)x=a;coutConstructor2called.X=xn;intgetx()returnx;voiddisp()coutx=xn;voidmain()arrdefx5=1,2,3;for(inti=0;i5;i+)xi.disp();xi.setx(xi.getx()*10);xi.disp();程序运行结果如下:Constructor2called.X=1Constructor2called.X=2Constructor2called.X=3Constructor1called.X=0Constructor1called.X=0x=1x=10x=2x=20x=3x=30x=0

93、x=0x=0x=0说明:(1)运行结果中的前5行是在初始化时调用相应的构造函数显示出来的。由运行结果可以看出,当初始值表中的初值个数少于数组元素个数时,后面的元素将由缺省构造函数进行初始化。(2)需要注意的是,在利用对象数组元素来访问其成员时也必须要注意其访问权限。6.15结构结构结构类型的定义形式如下:举例举例structdateintyear;intmonth;intday;(1)在C+语言中,struct同class一样,也是用于定义类的关键字。 (2)利用struct定义的类同利用class定义的类的主要差别在于对成员的缺省访问控制不同。利用class定义的类的缺省访问控制为priva

94、te,而利用struct定义的类的缺省访问控制为public。说明说明举举 例例classcStructinta;intb;classcStructprivate:inta;intb;相当于相当于structsClassinta;intb;structsClasspublic:inta;intb;相当于相当于举举 例例classcStack/此处缺省为此处缺省为private:intcount;intdata100;public:cStack(void)count=0;voidpush(intdt)if(count0)returndata-count;elsereturn0;structcSt

95、ack/此处缺省为此处缺省为private:如果在此处加上如果在此处加上/private:则同则同上面的上面的class定义的意义定义的意义/完全相同完全相同.private:intcount;intdata100;public:cStack(void)count=0;voidpush(intdt)if(count0)returndata-count;elsereturn0; 和class对象的使用一样,当利用结构变量(对象)来访问其成员时使用“.”,当利用结构指针来访问其成员时使用“-”。说说明明6.16联合联合联合的定义是利用关键字union来进行的。举例举例unionuSmpchara;

96、intb;longc;这里,这里,uSmp为联合数据类型,为联合数据类型,a、b和和c为联合数为联合数据成员。据成员。uSmpdt1;uSmp*dt2=&dt1;dt1.a=A;dt2-a=A;例如:【例例6.25】编一程序,用于说明联编一程序,用于说明联合的定义和使用合的定义和使用#includeunionuTypcharcVar;intiVar;voidmain()uTypuVar;uVar.iVar=0x1234;printf(“iVar=%xn”,uVar.iVar);printf(“cVar=%xn”,uVar.cVar);执行结果:执行结果:iVar=1234cVar=34 同结构

97、一样,union也是用于定义类的关键字,这也就是说,在union中也可以定义构造函数和成员函数,并可以设置访问控制权限,且其缺省的访问控制为public。由于以union来定义类的使用比较少,故在此不多加叙述。说说明明6.17位段位段举例举例structpacked_dataunsignedintf1:1;/f1占一个二进制位unsignedintf2:3;/f2占三个二进制位unsignedintf3:2;/f3占二个二进制位unsignedintf4:4;/f4占四个二进制位unsignedintf5:6;/f5占六个二进制位;需要注意的是,在对位段进行赋值操作时,应该考虑到每个位段所占的二进制位数。例如:说说明明

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号