第4章类与对象算法方法学语法开发平台(环境)类的声明类是实现抽象和封装的主要语法成分,C++的类是对象的抽象,封装了属性和行为。类是结构体的扩展类的书写格式数据成员和函数成员访问权限:public,private,默认的访问权限访问权限出现的顺序和次数任意,建议先公有后私有不能在类说明中对数据进行初始化类标识符最长32个字符,不能同名类的声明举例classClock{public:voidSetTime(intNewH,intNewM,intNewS);voidShowTime();private:intHour,Minute,Second;};类的成员函数的实现返回类型类名::成员函数名(参数说明)//还记得吗?“::”曾用于访问全局变量,它是作用域限定符{函数体}例如:voidClock::SetTime(intNewH,intNewM,intNewS){Hour=NewH;Minute=NewM;Second=NewS;}对象对象的声明Clockx1,x2;通过对象访问数据成员x1.Hour通过对象访问函数成员x1.SetTime(12,30,0)对象指针和对象引用的声明通过对象指针访问成员通过对象引用访问成员成员函数带默认形参值的成员函数内联成员函数有显示定义和隐式定义两种方法成员函数的重载关于“类内”和“类外”●“类内”指类的声明和类的实现的代码总和,在类内可以访问类的所有成员(包括公有的和私有的)。●“类外”指非类内的范围,包括类的使用处、main()函数体等。在类外只能访问类的公有成员。类的声明、类的实现和类的使用●类的声明:描述类的成员和访问权限,以及部分内联成员函数的代码。类的声明通常写在“类名.h”头文件中。●类的实现:描述类的所有成员函数的实现代码。类的实现通常写在“类名.cpp”源文件中。●类的使用:声明对象并通过对象访问其公有成员,使用类的功能。类的使用通常在其它类的实现代码或全局函数(像C语言那样的独立函数)中。类和对象的其它特性空类对象之间可以相互赋值a1=a2;对象可以用作数组的元素对象可以用作函数的参数,对象的值调用和引用调用构造函数使对象也具有类似于变量的初始化功能:inta(6);能在声明的同时立即初始化1.与类同名,不能指定返回类型,即使void也不行↓2.可把简单的初始化代码提到“:”分隔符之后↓必须在类的实现中,“:”引导的叫初始化列表。3.可重载定义,可为内联函数,可带默认的形参值。4.构造函数一般都写成public的。5.默认的构造函数:空函数体6.调用哪个构造函数?根据参数类型和个数,配合默认形参值。防止二义。7.何时调用构造函数?在初次分配内存时被自动调用↓构造函数例子类的声明中加:Clock(inth,intm,ints);类的实现中加:Clock::Clock(inth,intm,ints){Hour=h;Minute=m;Second=s;}构造函数例子(用初始化列表)类的声明中加:Clock(inth,intm,ints);类的实现中加:Clock::Clock(inth,intm,ints):Hour(h),Second(s){Minute=m;}构造函数的调用时机情形语句调用时机单个对象Clockclock1;调用无参的构造函数一次单个对象Clockclock2(8,0,0);调用三个参数的构造函数一次对象数组Clockclocks[5];调用无参的构造函数5次对象指针Clock*pClock;没有调用构造函数对象引用Clock&rClock=clock1;没有调用构造函数外部对象externClockclock1;没有调用构造函数静态对象staticClockclock3;调用无参构造函数一次,在main()之前全局对象Clockg_clock;//在函数之外调用无参构造函数一次,在main()之前拷贝构造函数是一种特殊的构造函数,参数有限制,必须是自身类的引用类型Clock(Clock&x);或Clock(constClock&x);//用常引用类型默认的拷贝构造函数:分别给数据成员赋值。拷贝构造函数被调用的典型情形:Clockb(a);//假设a是已定义的Clock对象拷贝构造函数被调用的三个场合①一个对象去初始化另一个对象(a是Clock对象)Clockb(a);或Clockb=a;或Clockb=Clock(a);②形参为对象的函数f(Clockx)被调用,在形实结合时实参————栈上的复制品③函数返回一个对象,Clockf(…){……returna;},在return时a————临时对象对象的初始化小结写法(b是Test对象)初始化方式Testa(5);用整参构造函数Testa(b);用拷贝构造函数,要求声明过对象bTesta=5;用整参构造函数,=不是赋值符Testa=b;用拷贝构造函数,要求声明过对象b,=不是赋值符Testa=Test(5);先用整参构造函数构造一个临时对象,然后用拷贝构造函数构造对象a,=不是赋值符Testa=Test(b);先用拷贝构造函数构造一个临时对象,再次用拷贝构造函数构造对象a,=不是赋值符注意:声明语句中的符号“=”不是赋值的意思,而是专门的初始化符号。对象初始化综合举例#includeiostreamusingnamespacestd;classTest{public:Test(){x=y=0;coutConstruct0endl;}Test(inta){x=y=a;coutConstruct1endl;}Test(Test&u){x=u.x;y=u.y;coutCopyconstructendl;}private:intx,y;};voidmain(){cout1--;Testa;cout2--;Testb(a);cout3--;Testc=Test(8);cout4--;Testd=a;cout5--;Teste=9;cout6--;e=9;cout7--;Testg=Test(a);}1--Construct02--Copyconstruct3--Construct1Copyconstruct4--Copyconstruct5--Construct16--Construct17--CopyconstructCopyconstruct析构函数1.类名前加~,不能指定返回类型,无参数,从而无重载的可能2.析构函数在对象的生存期结束时被自动调用3.对象数组在生存期结束时会分别调用每个元素的析构函数4..默认的析构函数:空函数体嵌套类(类的组合)一个对象可以用作另一个对象的成员,组合出一个嵌套类。类的组合描述的是一个类内嵌其它类的对象作为成员的情况,它们之间的关系是一种包含与被包含的关系。组合类B的对象内嵌A类对象嵌套类举例classA{public:voidSetA(inta,intb){x=a;y=b;}voidShowA(){coutx','yendl;}private:intx,y;};classB{public:voidSetB(inta,intb,intc){z=c;aaa.SetA(a,b);}voidShowB(){aaa.ShowA();coutzendl;}private:intz;Aaaa;};嵌套类的构造与析构•嵌套类的构造函数写法:必须在实现的时候写上传给内嵌成员的参数(初始化列表),形如类名::类名(形参表):内嵌对象1(形参1),…,内嵌对象n(形参n){……}•内嵌对象有无参构造函数时可以不用写初始化列表项。在类声明中不用写整个初始化列表,除非构造函数声明成隐式内联函数。•构造函数的调用顺序:先调用各内嵌对象成员的构造函数(按类声明中的顺序),再调用本类的构造函数•析构函数的调用顺序则相反。嵌套类的构造与析构举例classA{public:A(inta,intb):x(a),y(b){coutA构造了\n;}~A(){coutA析构了\n;}voidShowA(){coutx','yendl;}private:intx,y;};classB{public:B(inta,intb,intc):aaa(a,b){z=c;coutB构造了\n“;}~B(){coutB析构了\n;}voidShowB(){aaa.ShowA();coutzendl;}private:intz;Aaaa;};main(){Aobja;}运行输出什么?main(){Bobjb;}运行输出什么?main(){Aobja;Bobjb;}运行输出什么?前向引用声明*定义性声明和引用性声明(不完全的类声明、前向引用声明),两个类互相引用的时候classB;//引用性声明classA{public:voidf(Bb);};classB{//定义性声明public:voidg(Aa);};类和对象的图示标志Coad/Yourdon标记类对象UML(UnifiedModelingLanguage)类对象类名数据成员函数成员对象名数据成员函数成员类名属性操作()对象名:类名属性操作()关于UML的图•在UML的类图中,用位于最前面的+、-和#分别表示公有、私有和保护的成员。•在UML的类图中,函数成员的返回类型写冒号后面•UML的内容很丰富,还可以描述类之间的依赖(有调用关系时)、关联(有多重特征)、聚集(类的指针型组合)、组合(内嵌对象)、泛化(类的派生)等关系。还有注释图和描述动态过程的顺序图、协作图、活动图等。作业•习题3:一、二、三、四