1、第十章 构造函数和析构函数,10.1 构造函数,简单类型变量的初始化方法 int x=5; float y=10.0 数组的初始化 float a=10.5,11,21.0,30.0; char str=“China“; 结构体变量的初始化 struct ABC int x;int y; ABC sa=10,20;,10.1 构造函数,类对象(类变量)的初始化,class ABC public:int x,y;int a,b;void print()cout“x=“xendl;cout“y=“yendl;cout“a=“aendl;cout“b=“bendl; ;int main(int ar
2、gc, char* argv) int x;ABC sa=10,20;sa.print(); ,/结果 x=10 y=20 a=0 b=0,10.1 构造函数,类对象(类变量)的初始化,class ABC private:int x,y;public:int a,b;void print()cout“x=“xendl;cout“y=“yendl;cout“a=“aendl;cout“b=“bendl; ;int main(int argc, char* argv) int x;ABC sa=10,20;sa.print(); ,只要类定义中有私有成员(无论是数据成员还是函数成员),则无法直接初
3、始化对于类对象的初始化方法 构造函数,10.1.1 构造函数的定义及对象初始化,class ABC private:int x,y, a,b; public:ABC()x=0;y=0;a=0;b=0;ABC(int x1,int y1,int a1=100,int b1=100);int getx()return x;int gety()return y;int geta()return a;int getb()return b;void print(); ;,说明: 1.构造函数名与类名必须相同 2.构造函数不能有任何返回类型,包括void也不行 3.一个类可以定义多个构造函数构造函数的重载
4、 4.一般,构造函数总是定义成公有的,特殊情况下才定义成保护型,10.1.1 构造函数的定义及对象初始化,ABC: ABC(int x1,int y1,int a1,int b1) x=x1; y=y1; a=a1; b=b1;void ABC:print() cout“x=“getx()endl;cout“y=“gety()endl;cout“a=“geta()endl;cout“b=“getb()endl; ,说明: 5.构造函数既可以在类声明中定义,也可以在类声明外定义,10.1.1 构造函数的定义及对象初始化,void main() ABC sa1;/调用第一个构造函数,不能写成 AB
5、C sa1();ABC sa2(10,20); /调用第二个构造函数ABC sa3(100,200,300,400); /调用第二个构造函数cout“sa1中“endl;sa1.print();cout“sa2中“endl;sa2.print();cout“sa3中“endl;sa3.print(); ,说明:系统在生成类的对象时,自动调用该类的构造函数初始化对象,无需显式调用。,产生全局对象、静态对象和局部对象时调用构造函数的时机 (参考P221-223例10.5及解释),使用构造函数初始化,#include class dataclass private: int privatedata;
6、public: dataclass(int value);int publicdata;int publicmethod(void); dataclass:dataclass(int value) privatedata=value; int dataclass:publicmethod(void) return privatedata; void main() dataclass dataobject(1); dataobject.publicdata=2; cout“dataobject.publicdata=“dataobject.publicdata; cout“dataobject.
7、privatedata=“dataobject.publicmethod()n; ,10.1.3 构造函数和new运算符,定义类对象指针,然后用new运算符为类对象指针分配空间及初始化自动调用构造函数,class TD private:int x,y;public:TD(int x1,int y1)x=x1; y=y1;cout “调用构造函数TD(int,int)n “; TD()cout“调用构造函数TD()n“; void showXY() cout“x=“x“t“;cout“y=“yendl; ;,void main() TD *pd=new TD(5,10);/调用带参构造函数pd-
8、showXY();TD *p=new TD; /调用不带参构造函数p-showXY();delete pd;delete p; ,调用构造函数TD(int,int) x=5 y=10 调用构造函数TD() x=844586344 y=844586344,10.1.4 缺省构造函数,1.C+规定,每个类必须有一个构造函数,没有构造函数,就不能创建任何对象。 2.如果在定义类时没有定义任何构造函数,则C+自动生成一个缺省构造函数。其格式为:className:className() 即一个空的构造函数缺省构造函数只能有一个 3.只要一个类显式地定义了一个构造函数,则C+就不再提供默认的构造函数。也
9、就是说,如果为类定义了一个带参数的构造函数,但在编程中,还想使用无参数的构造函数,则必须自己定义。 4.当使用默认构造函数创建全局对象时,对象的数据成员的值默认取0;而使用默认构造函数创建局部对象时,对象的的数据成员的值是随机数; 5.要对对象的数据成员进行初始化,必须定义构造函数 6.定义类的对象时,系统必定调用构造函数对某个对象来说,构造函数必须唯一。,(1)在类中,若定义了没有参数的构造函数或各参数均有缺省值的构造函数,则此构造函数也可看成是缺省构造函数,缺省构造函数在一个类中只能有一个.(2)任意一种形式的构造函数必须唯一 (3)缺省构造函数的调用: 类名 对象名;,10.1.4 缺省
10、构造函数,#include class Q int x,y;public:Q(int a=0,int b=0)x=a;y=b;void p()coutxtyn; ; void main() cout “welcome your executive!n“; Q q;q.p();Q q1(50,100);q1.p();Q q2(500);q2.p(); cout“do you understand it?“; ,0 0,缺省的构造函数,50 100,500 0,50 100,10.1.4 缺省构造函数,class E private:int x,y;public:E(int a,int b)x=a
11、;y=b;void p()coutxt;coutyn; ;E e; /错误,为什么?,class Q private:int x,y;public:Q(int a=0,int b=0)x=a;y=b;Q();void p()coutxt;coutyn; ; Q q;/错误,为什么?,产生对象e时没有合适的构造函数可用,产生对象q时,有两个构造函数可用,不知用哪一个,Q qq();/什么意思? 说明了一个全局函数qq, 该函数返回值类型为类类型Q 当使用类的缺省构造函数创建一个对象时,对象名后不能带括号“()”Q qq,10.2 析构函数,class student private:char *
12、name; /.public:student(char *pnane) name=new char(12); student() delete name; ;,为什么要使用析构函数?,构造函数中分配了内存,析构函数中释放内存,在定义一个对象时要为对象分配存储空间; 在对象结束其生命期或作用域时,系统要收回对象所占的存储空间,即要撤消对象。 析构函数完成撤消对象的工作。,10.2.1 析构函数的定义,格式: className() /析构函数名/析构函数体,说明: 规定: 析构函数名必须与类名相同,并在其前面加上字符“” 析构函数不能有任何类型形式参数,void也不行,不能有任何返回类型,voi
13、d也不行。 析构函数是唯一的,不能重载。 析构函数在撤消对象时自动调用,10.2.2 不同存储类型调用构造函数及析构函数的时机,在定义对象时调用构造函数,撤消对象时调用析构函数 对不同存储类型的对象(全局对象,静态对象,局部对象),调用构造函数和析构函数的时机不同。,全局对象:程序执行时,调用构造函数,程序结束时调用析构函数; 局部对象(函数内定义):程序执行到定义对象的地方,调用构造函数,退出对象作用域时,调用析构函数; static定义的局部对象:首次执行对象的定义时,调用构造函数,程序结束时调用析构函数 new运算符生成的对象:用new产生对象时调用构造函数,用delete释放对象时,调
14、用析构函数,10.2.3 用delete运算符撤消对象数组,class Q private:int x,y; public:Q(int a=0,int b=0)x=a;y=b;cout“调用构造函数n“;Q()cout“调用析构函数n“; void p()coutxt;coutyn; ;,void main() Q *q=new Q2;cout“=n“; delete q;cout“退出主函数“; ,调用构造函数 调用构造函数 = 调用析构函数 调用析构函数 退出主函数,10.2.4 缺省的析构函数,如果在定义类时没有显式地定义析构函数,则C+自动生成一个缺省析构函数。其格式为:classNa
15、me:className() 即一个空的析构函数 如果在构造函数中利用new运算符分配了内存空间,则必须显式地定义析构函数来释放内存空间,10.4 实现类型转换的构造函数,4/8=? 4.0/8=?,4.0/8匹配了两个double类型数的除法,C+知道何时将8转换成double型,这是基本数据类型的转换。 对于用户自定义数据类型如何转换呢? 必须由用户告知 用户告知的方式就是定义一个含参数的构造函数。,10.4 实现类型转换的构造函数,如果有重载函数fn(char*),则调用fn(“Jenny“)马上匹配了事,但是由于没有这样的重载函数,所以C+试着对函数fn()的参数进行类型转换。 因为有
16、student(char *)这样的构造函数,又有fn(student &s)函数,于是fn(“Jenny“)便被认为是fn(student(“ Jenny “),最终予以匹配。 用构造函数把一种类型转换成另一种类型,这是C+面向对象的一个特性。,class student public:student(char *);/ void fn(student / ,10.4 使用隐含地实现类型转换的构造函数,class EX int x; public:EX(int a)x=a;cout“x=“x“t“调用了构造函数n“;EX()cout“调用了析构函数n“; ;void main() EX x1
17、(50);EX x2=100;x2=200;cout“主程序结束n“; ,x=50 调用了构造函数 x=100 调用了构造函数 x=200 调用了构造函数 调用了析构函数 主程序结束 调用了析构函数 调用了析构函数,10.4 显式地使用实现类型转换的构造函数,当构造函数有多个参数时,必须通过构造函数进行强制类型转换。 用构造函数进行强制类型转换的一般格式: classname(a1,a2,an) 其作用是调用对应的带有n个参数的构造函数,产生一个临时对象,用参数a1,a2,an 初始化该临时对象后,将该对象作为操作数参加运算。运算结束后,系统自动地撤消这个临时对象。,10.4 显式地使用实现类
18、型转换的构造函数,class EX int x,y; public:EX(int a, int b)x=a; y=b;coutx“t“ y “调用了构造函数n“;EX()cout“调用了析构函数n“; ;void main() EX x1(50,100);x1= EX (300,600);cout“主程序结束n“; ,50 100 调用了构造函数 300 600 调用了构造函数 调用了析构函数 主程序结束 调用了析构函数,10.3 拷贝构造函数,什么叫对象的拷贝? 制做一个对象的副本 什么时候需要对象拷贝? 以类对象作为函数参数传值调用时; 函数返回值为类对象; 用一个已定义的对象去初始化一个
19、新对象时;,10.3 拷贝构造函数,格式:className(className &c),class Q private:int x,y; public:Q(int a=0,int b=0)x=a;y=b;cout“调用构造函数n“; Q(Q ,调用构造函数 调用拷贝构造函数 调用拷贝构造函数 10 20 10 20 10 20 调用拷贝构造函数 调用析构函数 调用析构函数 调用析构函数 调用析构函数,void fun(Q q) ;void main() Q q1(10,20);Q q2=q1;Q q3(q2);q1.p();q2.p();q3.p();fun(q1); ,10.3 隐含的拷贝
20、构造函数,如果在定义类时没有定义一个复制数据成员的构造函数,则C+自动生成一个隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的复制。 其格式为:className:className(className,class Q private:int x,y; public:Q(int a=0,int b=0)x=a;y=b;cout“调用构造函数n“; Q()cout“调用析构函数n“; void p()coutxt;coutyn; ;,调用构造函数 10 20 10 20 10 20 调用析构函数 调用析构函数 调用析构函数 调用析构函数,void fun(Q q) ;void main(
21、) Q q1(10,20);Q q2=q1;Q q3(q2);q1.p();q2.p();q3.p();fun(q1); ,10.3隐含的拷贝构造函数,class Q private:int x,y;char *s; public:Q(int a=0,int b=0)x=a;y=b;s=“Great China “;cout“调用构造函数n“; Q()cout“调用析构函数n“; void p()coutxt;coutyn;coutsn; ;,void main() Q q1(10,20);Q q2=q1;Q q3(q2);q1.p();q2.p();q3.p(); ,调用构造函数 10 20
22、 Great China 10 20 Great China 10 20 Great China 调用析构函数 调用析构函数 调用析构函数,10.3隐含的拷贝构造函数,class Q private:int x,y;int *s; public:Q(int a=0,int b=0)x=a;y=b;s=new int5;cout“调用构造函数n“; Q() cout“调用析构函数n“; void sets() for(int i=0;i5;i+)si=i*i; void setp() for(int i=0;i5;i+)si=i+10; void p()coutxt;coutyn;for(int i=0;i5;i+)coutsi“ “;coutendl; ;,void fun(Q q) q.p(); ;void main() Q q1(10,20);Q q2=q1;q1.sets();q1.p();q2.setp() ;q2.p();fun(q1); ,调用构造函数 10 20 0 1 4 9 16 10 20 10 11 12 13 14 10 20 10 11 12 13 14 调用析构函数 调用析构函数 调用析构函数,