c构造函数与析构函数.ppt

上传人:本田雅阁 文档编号:2090057 上传时间:2019-02-12 格式:PPT 页数:53 大小:299.01KB
返回 下载 相关 举报
c构造函数与析构函数.ppt_第1页
第1页 / 共53页
c构造函数与析构函数.ppt_第2页
第2页 / 共53页
c构造函数与析构函数.ppt_第3页
第3页 / 共53页
亲,该文档总共53页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《c构造函数与析构函数.ppt》由会员分享,可在线阅读,更多相关《c构造函数与析构函数.ppt(53页珍藏版)》请在三一文库上搜索。

1、第十章 构造函数和析构函数,构造函数和析构函数是在类体中说明的两种特殊的成员函数。,构造函数是在创建对象时,使用给定的值来将对象初始化。,析构函数的功能正好相反,是在系统释放对象前,对对象做一些善后工作。,构造函数是类的成员函数,系统约定构造函数名必须与类名相同。构造函数提供了初始化对象的一种简单的方法。,构造函数可以带参数、可以重载,同时没有返回值。,class A float x,y; public: A(float a,float b) x=a; y=b;/构造函数,初始化对象 float Sum(void) return x+y; void Set(float a,float b) x

2、=a; y=b; Print(void) cout“x=“xt“y=“yendl; ; void main(void) A a1(2.0, 3.0);/定义时调用构造函数初始化 A a2(1.0,2.0); a2.Set(10.0, 20.0); /利用成员函数重新为对象赋值 a1.Print(); a2.Print(); ,对构造函数,说明以下几点: 1.构造函数的函数名必须与类名相同。构造函数的主要作用是完成初始化对象的数据成员以及其它的初始化工作。 2. 在定义构造函数时,不能指定函数返回值的类型,也不能指定为void类型。 3. 一个类可以定义若干个构造函数。当定义多个构造函数时,必须

3、满足函数重载的原则。,4.构造函数可以指定参数的缺省值。,5.若定义的类要说明该类的对象时,构造函数必须是公有的成员函数。如果定义的类仅用于派生其它类时,则可将构造函数定义为保护的成员函数。,由于构造函数属于类的成员函数,它对私有数据成员、保护的数据成员和公有的数据成员均能进行初始化。,class A float x,y; public: A(float a, float b=10) x=a; y=b; A() x=0; y=0; void Print(void) coutxtyendl; ; void main(void) A a1, a2(20.0), a3(3.0, 7.0); a1.P

4、rint(); a2.Print(); a3.Print(); ,0 0 20 10 3 7,带缺省参数的构造函数,不带参数的构造函数,每一个对象必须要有相应的构造函数,每一个对象必须要有相应的构造函数,若没有显式定义构造函数,系统默认缺省的构造函数。,class A float x,y; public: A() void Print(void) coutxtyendl; ;,隐含的缺省的构造函数,A a1, a2;,只允许这样定义对象,对象开辟了空间,但没有初始化,对局部对象,静态对象,全局对象的初始化对于局部对象,每次定义对象时,都要调用构造函数。 对于静态对象,是在首次定义对象时,调用构

5、造函数的,且由于对象一直存在,只调用一次构造函数。 对于全局对象,是在main函数执行之前调用构造函数的。,class A int x,y; public: A(int a) x=a; cout“1n”; A(int a, int b) x=a,y=b;cout“2n”; ; A a1(3); void f(void) A b(2,3); void main(void) A a2(4,5); f(); f(); ,1,2,2,2,class A float x,y; public: A(float a, float b)x=a;y=b;cout“初始化自动局部对象n“; A() x=0; y=

6、0; cout“初始化静态局部对象n“; A(float a) x=a; y=0; cout“初始化全局对象n“; void Print(void) coutxtyendl; ; A a0(100.0);/定义全局对象 void f(void) cout“ 进入f()函数n“;A a2(1,2); static A a3; /初始化局部静态对象 void main(void) cout“进入main函数n“; A a1(3.0, 7.0);/定义局部自动对象 f(); f(); ,初始化全局对象,进入main函数,初始化自动局部对象,进入f()函数,初始化局部静态变量,进入f()函数,初始化自

7、动局部对象,初始化自动局部对象,缺省的构造函数,在定义类时,若没有定义类的构造函数,则编译器自动产生一个缺省的构造函数,其格式为: className:className() 缺省的构造函数并不对所产生对象的数据成员赋初值;即新产生对象的数据成员的值是不确定的。,class A float x,y; public: A() /缺省的构造函数,编译器自动产生,可以不写 float Sum(void) return x+y; void Set(float a,float b) x=a; y=b; void Print(void) cout“x=“xt“y=“yendl; ; void main(v

8、oid) A a1,a2;/产生对象时,自动调用缺省的构造函数,不赋值 a1.Set (2.0,4.0); cout“a1: “; a1.Print (); cout“a1.sum=“a1.Sum ()endl; a2.Print();/打印随机值 ,关于缺省的构造函数,说明以下几点: 1、在定义类时,只要显式定义了一个类的构造函数,则编译器就不产生缺省的构造函数,2、所有的对象在定义时,必须调用构造函数,不存在没有构造函数的对象!,class A float x,y; public: A(float a,float b) x=a; y=b; void Print(void) coutxtye

9、ndl; ; void main(void) A a1; A a2(3.0,30.0); ,显式定义了构造函数,不产生缺省的构造函数,error,定义时,没有构造函数可供调用,3、在类中,若定义了没有参数的构造函数,或各参数均有缺省值的构造函数也称为缺省的构造函数,缺省的构造函数只能有一个。,4、产生对象时,系统必定要调用构造函数。所以任一对象的构造函数必须唯一。,class A float x,y; public: A(float a=10,float b=20) x=a; y=b; A() void Print(void) coutxtyendl; ; void main(void) A

10、a1; A a2(3.0,30.0); ,两个函数均为缺省的构造函数,两个构造函数均可供调用,构造函数不唯一,构造函数与new运算符,可以使用new运算符来动态地建立对象。建立时要自动调用构造函数,以便完成初始化对象的数据成员。最后返回这个动态对象的起始地址。,用new运算符产生的动态对象,在不再使用这种对象时,必须用delete运算符来释放对象所占用的存储空间。,用new建立类的对象时,可以使用参数初始化动态空间。,class A float x,y; public: A(float a, float b) x=a;y=b; A() x=0; y=0; void Print(void) co

11、utPrint(); pa2-Print(); delete pa1; /用delete释放空间 delete pa2; /用delete释放空间 ,5 0 0,析构函数,析构函数的作用与构造函数正好相反,是在对象的生命期结束时,释放系统为对象所分配的空间,即要撤消一个对象。,析构函数也是类的成员函数,定义析构函数的格式为: ClassName:ClassName( ) / 函数体; ,析构 函数的特点如下: 1、析构函数是成员函数,函数体可写在类体内,也可写在类体外。,2、析构函数是一个特殊的成员函数,函数名必须与类名相同,并在其前面加上字符“”,以便和构造函数名相区别。,3、析构函数不能带

12、有任何参数,不能有返回值,不指定函数类型。,在程序的执行过程中,当遇到某一对象的生存期结束时,系统自动调用析构函数,然后再收回为对象分配的存储空间。,4、一个类中,只能定义一个析构函数,析构函数不允许重载。,5、析构函数是在撤消对象时由系统自动调用的。,class A float x,y; public: A(float a,float b) x=a;y=b;cout“调用非缺省的构造函数n“; A() x=0; y=0; cout“调用缺省的构造函数n“ ; A() cout“调用析构函数n“; void Print(void) coutxtyendl; ; void main(void)

13、A a1; A a2(3.0,30.0); cout“退出主函数n“; ,调用缺省的构造函数,调用非缺省的构造函数,退出主函数,调用析构函数,调用析构函数,在程序的执行过程中,对象如果用new运算符开辟了空间,则在类中应该定义一个析构函数,并在析构函数中使用delete删除由new分配的内存空间。因为在撤消对象时,系统自动收回为对象所分配的存储空间,而不能自动收回由new分配的动态存储空间。,class Str char *Sp; int Length; public: Str(char *string) if(string) Length=strlen(string); Sp=new cha

14、rLength+1; strcpy(Sp,string); else Sp=0; void Show(void) coutSpendl; Str() if(Sp) delete Sp; ; void main(void) Str s1(“Study C+“); s1.Show(); ,在构造函数中将成员数据指针指向动态开辟的内存,用初值为开辟的内存赋值,析构函数,当释放对象时收回用new开辟的空间,string,Length=strlen(string);,Sp=new charLength+1;,Sp,new开辟的空间,strcpy(Sp,string);,用new运算符为对象分配动态存储空

15、间时,调用了构造函数,用delete删除这个空间时,调用了析构函数。当使用运算符delete删除一个由new动态产生的对象时,它首先调用该对象的析构函数,然后再释放这个对象占用的内存空间。,可以用new运算符为对象分配存储空间,如:,A *p; p=new A;,这时必须用delete才能释放这一空间。,delete p;,class A float x,y; public: A(float a, float b) x=a; y=b; coutPrint(); delete pa1; /调用析构函数 cout“退出main()函数n“; ,进入main()函数,调用了构造函数,3 5,调用了析

16、构函数,退出main()函数,不同存储类型的对象调用构造函数及析构函数,1、对于全局定义的对象(在函数外定义的对象),在程序开始执行时,调用构造函数;到程序结束时,调用析构函数。,2、对于局部定义的对象(在函数内定义的对象),当程序执行到定义对象的地方时,调用构造函数;在退出对象的作用域时,调用析构函数。,3、用static定义的局部对象,在首次到达对象的定义时调用构造函数;到程序结束时,调用析构函数,4、对于用new运算符动态生成的对象,在产生对象时调用构造函数,只有使用delete运算符来释放对象时,才调用析构函数。若不使用delete来撤消动态生成的对象,程序结束时,对象仍存在,并占用相

17、应的存储空间,即系统不能自动地调用析构函数来撤消动态生成的对象。,class A float x,y; public: A(float a, float b)x=a;y=b;cout“初始化自动局部对象n“; A() x=0; y=0; cout“初始化静态局部对象n“; A(float a) x=a; y=0; cout“初始化全局对象n“; A() cout“调用析构函数”endl; ; A a0(100.0);/定义全局对象 void f(void) cout“ 进入f()函数n“; A ab(10.0, 20.0);/定义局部自动对象 static A a3; /初始化局部静态对象 v

18、oid main(void) cout“进入main函数n“; f(); f(); ,初始化全局对象,进入main函数,初始化自动局部对象,进入f()函数,初始化静态局部对象,进入f()函数,初始化自动局部对象,调用析构函数,调用析构函数,调用析构函数,调用析构函数,举例:建立一个类NUM,求指定数据范围内的所有素数。 如: 定义类NUM的对象test,查找范围为100200,正确的输出结果: num=21 101 103 107 109 113 127 131 ,动态构造及析构对象数组,用new运算符来动态生成对象数组时,自动调用构造函数,而用delete运算符来释放p1所指向的对象数组占用

19、的存储空间时,在指针变量的前面必须加上 , 才能将数组元素所占用的空间全部释放。否则,只释放第0个元素所占用的空间。,pa1=new A3; . delete pa1;,class A float x,y; public: A(float a=0, float b=0)x=a; y=b;cout“调用了构造函数n“; void Print(void) coutxtyendl; A() cout“调用了析构函数n“; ; void main(void) cout“进入main()函数n“; A *pa1; pa1=new A3;/开辟数组空间 cout“n完成开辟数组空间nn“; delete

20、pa1; /必须用删除开辟的空间 cout“退出main()函数n“; ,进入main()函数,调用了构造函数,调用了构造函数,调用了构造函数,完成开辟数组空间,调用了析构函数,调用了析构函数,调用了析构函数,退出main()函数,缺省的析构函数,若在类的定义中没有显式地定义析构函数时,则编译器自动地产生一个缺省的析构函数,其格式为: ClassName:ClassName() ;,任何对象都必须有构造函数和析构函数,但在撤消对象时,要释放对象的数据成员用new运算符分配的动态空间时,必须显式地定义析构函数。,实现类型转换的构造函数,同类型的对象可以相互赋值,相当于类中的数据成员相互赋值; 如

21、果直接将数据赋给对象,所赋入的数据需要强制类型转换,这种转换需要调用构造函数。,class A float x,y; public: A(float a,float b) x=a;y=b;cout“调用构造函数n“; A() cout“调用析构函数n“; void Print(void) coutxtyendl; ; void main(void) A a1(1.0, 10.0); a1.Print(); a1=A(3.0 , 30.0); a1.Print(); cout“退出主函数n“; ,调用构造函数,产生临时对象,初始化并赋值后立即释放,1 10,调用构造函数,调用析构函数,3 30,

22、退出主函数,调用析构函数,注意:当构造函数只有一个参数时,可以用= 强制赋值。,class B float x; public: B(float a) x=a; cout“调用构造函数n“; B() cout“调用析构函数n“; void Print(void) coutxendl; ; void main(void) B b1(1.0) ; b1.Print(); B b2=100; b2.Print(); b1=10; b1.Print(); cout“退出主函数n“; ,调用构造函数,单参数可以这样赋值,1,调用构造函数,100,调用构造函数,调用析构函数,10,退出主函数,调用析构函数

23、,调用析构函数,b1=B(10),产生一个临时对象,完成拷贝功能的构造函数,可以在定义一个对象的时候用另一个对象为其初始化,即构造函数的参数是另一个对象的引用,这种构造函数常为完成拷贝功能的构造函数。,完成拷贝功能的构造函数的一般格式为: ClassName:ClassName(ClassName &) / 函数体完成对应数据成员的赋值 ,class A float x,y; public: A(float a=0, float b=0)x=a; y=b; A(A ;,void main(void) A a1(1.0,2.0); A a2(a1); ,形参必须是同类型对象的引用,实参是同类型的

24、对象,class A float x,y; public: A(float a=0, float b=0)x=a; y=b; cout“调用了构造函数n“; A(A ,调用了构造函数 调用了完成拷贝功能的构造函数 1 2 1 2 调用了析构函数 调用了析构函数,用已有的对象中的数据为新创建的对象赋值,如果没有定义完成拷贝功能的构造函数,编译器自动生成一个隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的拷贝。,A:A(A ,隐含的构造函数,class A float x,y; public: A(float a=0, float b=0)x=a; y=b; cout“调用了构造函数n“;

25、 void Print(void) coutxtyendl; A() cout“调用了析构函数n“; ; void main(void) A a1(1.0,2.0); A a2(a1); A a3=a1;/可以这样赋值 a1.Print(); a2.Print(); a3.Print(); ,调用了构造函数 1 2 1 2 1 2 调用了析构函数 调用了析构函数 调用了析构函数,隐含了拷贝的构造函数,由编译器为每个类产生的这种隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的拷贝。,但是,当类中的数据成员中使用new运算符,动态地申请存储空间进行赋初值时,必须在类中显式地定义一个完成拷贝

26、功能的构造函数,以便正确实现数据成员的复制。,class Str int Length; char *Sp; public: Str(char *string) if(string)Length=strlen(string); Sp=new charLength+1; strcpy(Sp,string); else Sp=0; void Show(void)coutSpendl; Str() if(Sp) delete Sp; ; void main(void) Str s1(“Study C+“); Str s2(s1); s1.Show (); s2.Show (); ,隐含的拷贝构造函数

27、为: Str:Str(Str ,s1.Sp,s2.Sp,new开辟的空间,同一空间释放两次,造成运行错误。,在这种情况下,必须要定义完成拷贝功能的构造函数。,Str:Str(Str ,s1.Sp,原来s1开辟的空间,s2.Sp,拷贝函数中用new开辟的空间,构造函数与对象成员,对类A的对象初始化的同时还要对其成员数据类B的对象进行初始化,所以,类A的构造函数中要调用类B的构造函数。,class B ;,class A int x , y; B b1,b2; ;,在类A中包含类B的对象,class A float x,y; public: A(int a,int b) x=a;y=b; void

28、 Show() cout “x=“xt“y=“yn; ; class C float z; A a1;/类C的数据成员为类A 的对象a1 public: C(int a,int b,int c):a1(b, c) z=a;/类C的对象初始化 void Show()cout “z=“an; a1.Show(); ; void main(void) C c1(1, 2, 3 ); /对类C的对象初始化 c1.Show(); ,在类C中调用类A的成员函数,利用类A的构造函数对类A的对象初始化,a1,A,C,a1(b, c),ClassName:ClassName(args):c1(args1),cn

29、(agrsn) /对其它成员的初始化 初始化对象成员的参数(实参)可以是表达式。,也可以仅对部分对象成员进行初始化。,class A float x,y; public: A(int a,int b) x=a;y=b; void Show() cout “x=“xt“y=“yn; ; class B float x1,y1; public: B(int a, int b) x1=a; y1=b; void Show() cout“x1=“x1t“y=“yn; ; class C float z; A a1; B b1; public: C(int a,int b,int c,int d, in

30、t e):a1(a+b, c) ,b1(a,d) z=e; void Show()cout “z=“an; a1.Show();b1.Show(); ; void main(void) C c1(1, 2, 3 ,4,5); /对类C的对象初始化 ,对象初始化的参数可以是表达式,对对象成员的构造函数的调用顺序取决于这些对象成员在类中说明的顺序,与它们在成员初始化列表中的顺序无关。 当建立类ClassName的对象时,先调用各个对象成员的构造函数,初始化相应的对象成员,然后才执行类ClassName的构造函数,初始化类ClassName中的其它成员。析构函数的调用顺序与构造函数正好相反。,cla

31、ss A float x; public: A(int a) x=a; cout“调用了A的构造函数n”; A()cout“调用了A的析构函数n”; ; class B float y; public: B(int a) y=a; cout“调用了B的构造函数n”; B()cout“调用了B的析构函数n”; ; class C float z; B b1; A a1; public: C(int a,int b,int c): a1(a),b1(b)z=c;cout“调用了C的构造函数n”; C()cout“调用了C的析构函数n”; ; void main(void) C c1(1,2,3); ,调用了B的构造函数,调用了A的构造函数,调用了C的构造函数,调用了C的析构函数,调用了A的析构函数,调用了B的析构函数,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1