第10章构造函数和析构函数#includeiostream.hclassComplex{doubleReal,Imag;public:voidSetCom(doublea,doubleb){Real=a;Imag=b;}};voidmain(){Complexa,b;a.SetCom(1.0,2.0);b.SetCom(2.0,3.0);}构造函数:在说明(产生)一个对象时自动被调用,所以一般用以初始化一个对象。{Complexa(1.0,2.0);Complexb(2.0,3.0);}10.1.1构造函数的定义构造函数的一些问题:•构造函数名字必须与类名相同;•不能指定函数返回值,也不能指定为void类型;•构造函数可带参数,可不带参数,也可指定参数的缺省值;•构造函数可重载;•在定义对象时,在对象名后加上一对括号后并不表示定义对象,也不表示要调用不带参数的构造函数,而表示一个不带参数的函数,它的返回值为指定类的对象;•静态对象首次创建后不再重新产生。#includeiostream.hclassComplex{doubleReal,Imag;public:Complex(doublea,doubleb){Real=a;Imag=b;}Complex(){Real=0;Imag=0;}};voidmain(){Complexa(1.0,2.0);Complexb,c();}10.1.2默认构造函数默认构造函数:在定义类时,若没有定义类的构造函数,则编译器自动产生一个默认构造函数,该函数什么事也不做;在定义类时,若定义了类的构造函数,则编译器就不产生默认构造函数;在类中,若定义了没有参数的构造函数,或各参数均有缺省值的构造函数也称为默认构造函数,默认构造函数只能有一个;产生对象时,系统必定要调用构造函数,所以任一对象的构造函数必须唯一。10.2析构函数析构函数:在一个对象消亡时被调用,因此常用来做善后工作,比如对象保持的动态空间的释放等。类变量消亡:在变量退出其作用域时全局:程序结束局部:退出定义的分程序通过new得到的对象,用delete运算时。10.2析构函数析构函数的一些问题:析构函数名字必须与类名相同,并在其前面加字符“~”;不能指定函数返回值,也不能指定为void类型;不可带参数;不允许重载;用delete运算释放一个对象会调用析构函数;在类变量消亡时,总要调用一个析构函数。#includestring.h#includeiostream.hclassPerson{char*name;public:Person(char*s){name=newchar[strlen(s)+1];strcpy(name,s);}voidGetName(char*s){strcpy(s,name);}~Person(){deletename;}voidmain(){Personx(张三),y(李四);}10.2析构函数10.3.1拷贝构造函数格式:ClassName::ClassName(ClassName&)作用:一般用于完成类变量间的拷贝。隐含拷贝构造函数:对没有定义构造函数的类,系统隐含有一个默认拷贝构造函数,功能是完成拷贝。10.3.1拷贝构造函数调用拷贝构造函数的情况:用说明语句来创建一个对象时,用一个已有对象来初始化新建对象;调用函数时,用传值调用方式,把对象作为实参传递给形参;函数中返回一个对象。#includestring.h#includeiostream.hclassS{char*ptr;public:S(char*p){if(!p)ptr=NULL;else{ptr=newchar[strlen(p)+1];strcpy(ptr,p);}}~S(){deleteptr;}};voidmain(){Ss1(abcdef);}Ss2=s1;//Ss2(s1);s1ptrAbcdef\0ptrs2ptrs2Abcdef\0S(S&);S::S(S&a){if(a.ptr==NULL)ptr=NULL;else{ptr=newchar[strlen(a.ptr)+1];strcpy(ptr,a.ptr);}}#includestring.h#includeiostream.hclassPerson{char*name;public:Person(char*s){name=newchar[strlen(s)+1];strcpy(name,s);}voidGetName(char*s){strcpy(s,name);}~Person(){deletename;}voidCopy(Persons){if(name!=NULL)deletename;name=newchar[strlen(s.name)+1];strcpy(name,s.name);}};voidmain(){Personx(张三),y(李四);y.Copy(x);}s前的&不能省,当采用类对象值传递时,会自动调用拷贝构造函数,函数结束前,自动调用析构函数类Person对象x成员函数Copy的工作空间类Person对象x的内容张三‘\0’做x的值复制程序执行出错!10.3.2赋值操作函数当同类对象之间执行赋值操作时,调用赋值操作函数。赋值操作函数的一般格式:类名&类名::operator=(const类名&对象名){…//赋值操作函数体return*this;}若类中没有显式定义赋值操作函数,编译器自动生成一个公有的赋值操作函数,复制每个非静态数据成员。#includestring.h#includeiostream.hclassS{char*ptr;public:S(char*p=NULL){if(!p)ptr=NULL;else{ptr=newchar[strlen(p)+1];strcpy(ptr,p);}}~S(){deleteptr;}S(S&a){if(a.ptr==NULL)ptr=NULL;else{ptr=newchar[strlen(a.ptr)+1];strcpy(ptr,a.ptr);}}};voidmain(){Ss1(abcdef);Ss3=s1,s2;s3.show();s2=s3;s2.show();}s1ptrAbcdef\0s3ptrAbcdef\0s2ptr此处增加下面的成员函数:S&operator=(constS&a){if(ptr)deletptr;if(a.ptr==NULL)ptr=NULL;else{ptr=newchar[strlen(a.ptr)+1];strcpy(ptr,a.ptr);}return*this;}s2.oprator=(s3);#includeiostream.hclassEx1{intx;public:Ex1(inta){x=a;cout“x=”x”调用了构造函数!endl;}~Ex1(){cout调用了析构函数!endl;}};voidmain(){Ex1x1(50);Ex1x2=100;x2=200;}结果输出:X=50调用了构造函数!X=100调用了构造函数!X=200调用了构造函数!调用了析构函数!调用了析构函数!调用了析构函数!等同于x2(100)的写法,条件是构造函数的形参只有一个的情况下x=200;的实际效果:(内部转换成如下的操作){Ex1tmp(200);x2=tmp;}当构造函数只有一个参数时,才能象以上这样使用。10.3.3单参构造函数#includeiostream.hclassEx2{intx,y;public:Ex2(inta,intb){x=a;y=b;cout“x=”x“y=”y“调用了构造函数!endl;}~Ex2(){cout调用了析构函数!endl;}};voidmain(){Ex2x1(50,100);x1=Ex2(300,600);}输出结果:x=50y=100调用了构造函数!x=300y=600调用了构造函数!调用了析构函数!调用了析构函数!内部处理为:{Ex2tmp(300,600);x1=tmp;}构造函数有多个参数的情况:10.4复合函数与成员对象在定义一个新类时,可把一个已定义类的对象作为该类的成员。产生这新定义类的对象时,也要对它的对象成员进行初始化,且只能通过这新类的构造函数来对它的所有数据成员初始化。要对对象成员进行初始化,必须通过调用其对象成员的构造函数来实现。10.4复合函数与成员对象新类构造函数形式为:类名::类名(参数表):c1(参数表),…,cn(参数表){函数体;}注意:c1..cn的次序可任意,但习惯上按说明次序定义。当类自己不需要构造函数而其对象成员需构造初始化,则自己必须有一个构造函数,不能依赖于缺省的构造函数。#includeiostream.hclassA{intx,y;public:A(inta,intb){x=a;y=b;}};classB{intLength,Width;public:B(inta,intb){Length=a;Width=b;}};classC{intr,High;Aa1;Bb1;public:C(inta,intb,intc,intd,inte,intf):a1(e,f),b1(c,d){r=a;High=b;}};例:当建立类C的对象时,先调用各个对象成员的构造函数(对对象成员的构造函数的调用顺序取决于这些对象成员在类中说明的顺序),初始化相应的对象成员,然后才执行类C的构造函数,初始化类C中的其它成员;析构函数的调用顺序与构造函数正好相反。voidmain(void){Cc1(25,35,45,55,65,100);}三维坐标中的一条直线的可通过该直线的两个端点的坐标(x1,y1,z1)和(x2,y2,z2)来描述。定义一个类,实现坐标数据的初始化,输出端点的坐标和直线的长度。10.4复合函数与成员对象#includeiostream.h#includemath.hclassPoint{doublex,y,z;public:Point(doublea=0,doubleb=0,doublec=0){x=a;y=b;z=c;}voidSet(doublea,doubleb,doublec){Point(a,b,c);}voidPrint(){coutx=xy=yz=zendl;};doubleDistance(Point&t){doubler;r=(x-t.x)*(x-t.x)+(y-t.y)*(y-t.y)+(z-t.z)*(z-t.z);returnsqrt(r);}};classLine{Pointx1,x2;public:Line(doublea1,doubleb1,doublec1,doublea2,doubleb2,doublec2):x1(a1,b1,c1),x2(a2,b2,c2){}doubleLenth(){returnx1.Distance(x2);}voidPrintLine(){coutLineendl;x1.Print();x2.Print();}};voidmain(){Linel1(1,2,3,4,5,6);Linel2(2,3,4,8,9,10);l1.PrintLine();l2.PrintLine();coutLenth1=l1.Lenth()endl;coutLenth2=l2.Lenth()endl;}Line:x=1y=2z=3x=4y=5z=6Line:x=2y=3z=4x=8y=9z=10Lenth1=5.19615Lenth2=10.3923对象数组就是一类对象的一个有序集合,数组中所有元素是同一类的对象。一维对象数组的定义:类型数组名[常量