第--章━━构造函数和析构函数优秀文档.ppt

上传人:可**** 文档编号:91509129 上传时间:2023-05-27 格式:PPT 页数:41 大小:170.54KB
返回 下载 相关 举报
第--章━━构造函数和析构函数优秀文档.ppt_第1页
第1页 / 共41页
第--章━━构造函数和析构函数优秀文档.ppt_第2页
第2页 / 共41页
点击查看更多>>
资源描述

《第--章━━构造函数和析构函数优秀文档.ppt》由会员分享,可在线阅读,更多相关《第--章━━构造函数和析构函数优秀文档.ppt(41页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、C+程序设计程序设计第第5章章(2)构造函数和析构函数构造函数和析构函数1主要内容主要内容l对象的初始化对象的初始化l构造函数构造函数l默认的构造函数默认的构造函数lthis指针指针l对象的生存期和作用域对象的生存期和作用域l拷贝构造函数、默认拷贝构造函数拷贝构造函数、默认拷贝构造函数l析构函数析构函数l调用构造函数和析构函数的顺序调用构造函数和析构函数的顺序l实现类型转换的构造函数实现类型转换的构造函数对象赋值时的隐式调用(特殊情况)对象赋值时的隐式调用(特殊情况)l实现类型转换的构造函数实现类型转换的构造函数对象赋值时的显式调用(一般情况)对象赋值时的显式调用(一般情况)l对象成员对象成员

2、2对象的初始化对象的初始化使用初始化数据列表使用初始化数据列表l若类中所有的成员数据都为公有型,则定义对象时,允许若类中所有的成员数据都为公有型,则定义对象时,允许使用初始化数据列表使用初始化数据列表对其对其成员数据进行初始化,方法与结构体变量相同,用花括号将各成员数据的初值括起成员数据进行初始化,方法与结构体变量相同,用花括号将各成员数据的初值括起来赋给该对象。来赋给该对象。l若类中有成员数据为私有型或保护型,则定义对象时,不允许若类中有成员数据为私有型或保护型,则定义对象时,不允许使用初始化数据列表使用初始化数据列表对其初始化。对其初始化。【例】【例】(学生类、(学生类、初始化数据列表初始

3、化数据列表)#includeclass Student public:int id;char name 8 ;int score;void print()cout “学号学号:”id t;cout “姓名姓名:”name t;cout “成绩成绩:”score n;void main()Student s=111,“张军张军”,99 ;s.print();【例】【例】(学生类、初始化数据列表)(学生类、初始化数据列表)#includeclass Student int id;char name 8 ;int score;public:void print()cout “学号学号:”id t;c

4、out “姓名姓名:”name t;cout “成绩成绩:”score n;void main()Student s=111,“张军张军”,99 ;s.print();3对象的初始化对象的初始化使用构造函数使用构造函数l构造函数是类的成员函数,系统约定构造函数名必须与类名相同,构造函数的主要构造函数是类的成员函数,系统约定构造函数名必须与类名相同,构造函数的主要作用是初始化对象的成员数据。作用是初始化对象的成员数据。l上例程序中并没有显式调用构造函数上例程序中并没有显式调用构造函数Student(),而是在定义对象,而是在定义对象s时,由系统自动时,由系统自动调用构造函数调用构造函数Stude

5、nt()。【例】【例】(学生类、构造函数)(学生类、构造函数)#include#includeclass Student int id;char name 8 ;int score;public:Student(int i,char *na,int s)id=i;strcpy(name,na);score=s;void print()cout “学号学号:”id “t姓名姓名:”name “t成绩成绩:”score endl;void main()Student s(111,“张军张军”,99 );s.print();运行:运行:学号:学号:111 姓名:张军姓名:张军 成绩:成绩:99也可写

6、成:也可写成:char na 4构造函数构造函数l关于构造函数:关于构造函数:构造函数的主要作用是:定义对象时,初始化对象的成员数据。构造函数的主要作用是:定义对象时,初始化对象的成员数据。构造函数是类的成员函数,其函数名必须与类名相同,在定义构造函数时,不能指定构造函数是类的成员函数,其函数名必须与类名相同,在定义构造函数时,不能指定返回值类型,也不能指定返回值类型为返回值类型,也不能指定返回值类型为void。构造函数是在定义对象时由系统自动调用的。构造函数是在定义对象时由系统自动调用的。构造函数允许是重载函数、内联函数、带默认形参值的函数。构造函数允许是重载函数、内联函数、带默认形参值的函

7、数。若所声明的类是用于定义对象的,其构造函数必须是公有型。若所声明的类仅用于派若所声明的类是用于定义对象的,其构造函数必须是公有型。若所声明的类仅用于派生其它类,其构造函数可以是保护型。生其它类,其构造函数可以是保护型。定义对象时,系统根据对象名后面括号内给出的实参,自动调用相应的构造函数,定义对象时,系统根据对象名后面括号内给出的实参,自动调用相应的构造函数,完成该对象成员数据的初始化工作。完成该对象成员数据的初始化工作。若类中没有声明构造函数,则系统会自动产生一个默认的构造函数。若类中没有声明构造函数,则系统会自动产生一个默认的构造函数。5构造函数构造函数在在函数体中对各成员数据赋初值函数

8、体中对各成员数据赋初值构造函数构造函数在在函数头后面用函数头后面用成员初始化表成员初始化表对各成员数据赋初值对各成员数据赋初值#includeclass Clock int hour,minute,second;public:Clock(int h,int m,int s )hour=h;minute=m;second=s;void settime(int h,int m,int s )hour=h;minute=m;second=s;void showtime()cout hour “:”minute “:”second n;void main()Clock c(10,20,30);c.sh

9、owtime();运行:运行:10 :20 :30#includeclass Clock int hour,minute,second;public:Clock(int h,int m,int s ):hour(h),minute(m),second(s)void settime(int h,int m,int s )hour=h;minute=m;second=s;void showtime()cout hour “:”minute “:”second n;void main()Clock c(10,20,30);c.showtime();运行:运行:10 :20 :306【例】(时钟类、构

10、造函数重载)【例】(时钟类、构造函数重载)#includeclass Clock int hour,minute,second;public:Clock()hour=0;minute=0;second=0;cout “调用不带参的构造函数调用不带参的构造函数!n”;Clock(int h,int m,int s )hour=h;minute=m;second=s;cout “调用带调用带3个参的构造函数个参的构造函数!n”;void settime(int h,int m,int s )hour=h;minute=m;second=s;void showtime()cout hour “:”m

11、inute “:”second endl;void main()Clock c1,c2(10,20,30);c1.showtime();c2.showtime();c2.settime(8,50,20);c2.showtime();运行:运行:调用不带参的构造函数调用不带参的构造函数!(构构c1)调用带调用带3个参的构造函数个参的构造函数!(构构c2)0 :0 :010 :20 :308 :50 :20 7【例】(矩形类、带默认形参值的构造函数)【例】(矩形类、带默认形参值的构造函数)#include#includeclass Rectangle float left,top,right,bo

12、ttom;public:Rectangle(float L=0,float T=0 ,float R=0,float B=0 )left=L;top=T;right=R;bottom=B;void set(float L,float T,float R,float B )left=L;top=T;right=R;bottom=B;void print()cout “left=”left “ttop=”top t;cout “right=”right “tbottom=”bottom t;cout “面积面积=”fabs(right-left)*fabs(bottom-top)endl;void

13、 main()Rectangle r0;r0.print();Rectangle r1(10);r1.print();Rectangle r2(10,20);r2.print();Rectangle r3(10,20,30);r3.print();Rectangle r4(10,20,30,40);r4.print();r0.set(1,2,3,4);r0.print();运行:运行:left=0 top=0 right=0 bottom=0 面积面积=0left=10 top=0 right=0 bottom=0 面积面积=0left=10 top=20 right=0 bottom=0 面

14、积面积=200left=10 top=20 right=30 bottom=0 面积面积=400left=10 top=20 right=30 bottom=40 面积面积=400left=1 top=2 right=3 bottom=4 面积面积=4 (left,top)(right,bottom)8默认的构造函数默认的构造函数l若类中没有声明构造函数,系统会自动产生一个默认的构造函数,其格式为:若类中没有声明构造函数,系统会自动产生一个默认的构造函数,其格式为:类名类名:类名(类名()l系统给出的默认构造函数,其函数体为空,即什么事也没做。若定义对象时,调用系统给出的默认构造函数,其函数体

15、为空,即什么事也没做。若定义对象时,调用的是系统给出的默认构造函数,则什么事也没做,也不赋初值给对象的成员数据。的是系统给出的默认构造函数,则什么事也没做,也不赋初值给对象的成员数据。【例】(点类、类中没有声明构造函数)【例】(点类、类中没有声明构造函数)#includeclass Point float x,y;public:void print()cout “x=”x “ty=”y endl;Point p1;/全局对象全局对象void main()p1.print();Point p2;/auto局部对象局部对象 p2.print();static Point p3;/静态局部对象静态局

16、部对象 p3.print();运行:运行:x=0 y=0 x=-1.07374e+008 y=-1.07374e+008 x=0 y=0 xy (x,y)9默认的构造函数默认的构造函数l若类中已声明了构造函数,则编译系统就不会自动产生默认的构造函数。若类中已声明了构造函数,则编译系统就不会自动产生默认的构造函数。l不带形参的构造函数、或各个形参均有默认值的构造函数,也称为默认构造函数,不带形参的构造函数、或各个形参均有默认值的构造函数,也称为默认构造函数,而类中默认的构造函数只能有一个。而类中默认的构造函数只能有一个。运行:运行:x=0 y=0【例】(点类)【例】(点类)#includecla

17、ss Point float x,y;public:Point(float a=0,float b=0 )x=a,y=b;void print()cout “x=”x “ty=”y endl;void main()Point p;p.print();【例】(点类)【例】(点类)#includeclass Point float x,y;public:Point(float a,float b )x=a,y=b;void print()cout “x=”x “ty=”y endl;void main()Point p;p.print();编译错误编译错误!p:no appropriate def

18、ault constructor available10默认的构造函数默认的构造函数l定义对象时,若需要对其成员数据赋初值,则类中必须声明带形参的构造函数。定义对象时,若需要对其成员数据赋初值,则类中必须声明带形参的构造函数。l定义对象时,系统必定会自动调用相应的构造函数,而默认构造函数必须唯一。定义对象时,系统必定会自动调用相应的构造函数,而默认构造函数必须唯一。l定义对象时,若调用的是默认构造函数,则对象名后面不能带有括号和实参。定义对象时,若调用的是默认构造函数,则对象名后面不能带有括号和实参。【例】【例】Point p;Point p();但此句编译能通过,认为是函数但此句编译能通过,

19、认为是函数p()的原型声明。的原型声明。【例】(点类)【例】(点类)#includeclass Point float x,y;public:Point(float a=0,float b=0 )x=a,y=b;Point()cout “调用默认构造函数了调用默认构造函数了!n”;void print()cout “x=”x “ty=”y endl;void main()Point p;p.print();编译出错!编译出错!指出有两个默认构造函数,在产生对象指出有两个默认构造函数,在产生对象p时,存在二义性。时,存在二义性。11this指针指针成员函数中指向当前对象的指针成员函数中指向当前对

20、象的指针l同类的不同对象占据内存中的不同区域,大小一致,而其成员数据所保存的值可各同类的不同对象占据内存中的不同区域,大小一致,而其成员数据所保存的值可各不相同,但对各个对象的成员数据进行操作的成员函数,其代码都是一样的。不相同,但对各个对象的成员数据进行操作的成员函数,其代码都是一样的。l若同一个类定义了若同一个类定义了 n 个对象,则有个对象,则有 n 组同样大小的内存空间,来存放组同样大小的内存空间,来存放 n 个对象的成个对象的成员数据,但这员数据,但这 n 个对象都调用同一个成员函数的代码段。个对象都调用同一个成员函数的代码段。l当调用成员函数时,引用了成员数据,如何能保证引用的是所

21、指定对象的成员数据当调用成员函数时,引用了成员数据,如何能保证引用的是所指定对象的成员数据?由由this指针来保证成员函数引用的是当前对象的成员数据!指针来保证成员函数引用的是当前对象的成员数据!成成 员员 函函 数数 的的 代代 码码成员数据成员数据对象对象1成员数据成员数据对象对象2成员数据成员数据对象对象n 12this指针指针成员函数中指向当前对象的指针成员函数中指向当前对象的指针lthis指针:指针:类中的每一个成员函数(非静态成员函数),其内部都包含一个特殊的指针类中的每一个成员函数(非静态成员函数),其内部都包含一个特殊的指针 this指针,指针,this指针指向该成员函数当前所

22、操作的成员数据所属的对象。指针指向该成员函数当前所操作的成员数据所属的对象。成员函数中的成员函数中的this指针是指向当前对象的指针,其值为该成员函数当前所操作对象的指针是指向当前对象的指针,其值为该成员函数当前所操作对象的起始地址。在成员函数中要引用成员数据时,就按照起始地址。在成员函数中要引用成员数据时,就按照this指针的指向找到所操作对象指针的指向找到所操作对象的成员数据。的成员数据。当调用某对象的一个成员函数时,系统自动将该对象的地址传递给该成员函数的当调用某对象的一个成员函数时,系统自动将该对象的地址传递给该成员函数的this指针,然后该成员函数就按指针,然后该成员函数就按this

23、指针的指向去引用该对象的成员数据。指针的指向去引用该对象的成员数据。在成员函数的函数体中也可直接使用关键字在成员函数的函数体中也可直接使用关键字this来访问该指针。来访问该指针。13【例】(学生类、【例】(学生类、this指针)指针)#include#includeclass Student int id;char name 8 ;int score;public:Student(int i,char *na,int s )id=i;strcpy(name,na);score=s;cout “对象地址对象地址=”this “t调用构造函数了调用构造函数了!n”;void print()cou

24、t “学号学号:”id “t姓名姓名:”name “t成绩成绩:”score endl;void main()Student s1(111,“张军张军”,99 );Student s2(222,“王红王红”,88 );s1.print();s2.print();运行:运行:对象地址对象地址=0 x0012FF70 调用构造函数了!调用构造函数了!(构构s1)对象地址对象地址=0 x0012FF60 调用构造函数了!调用构造函数了!(构构s2)学号:学号:111 姓名:张军姓名:张军 成绩:成绩:99学号:学号:222 姓名:王红姓名:王红 成绩:成绩:88111张军张军99s1222王红王红8

25、8s2print()的的this指针指针14对象的生存期和作用域对象的生存期和作用域l对象的作用域和一般变量的作用域相同:对象的作用域和一般变量的作用域相同:在函数外定义的对象为全局对象,具有文件作用域。在函数外定义的对象为全局对象,具有文件作用域。在函数内、块内定义的对象为局部对象,具有块作用域。在函数内、块内定义的对象为局部对象,具有块作用域。l 对象的生存期也和一般变量的生存期相同:对象的生存期也和一般变量的生存期相同:全局全局对象对象、static静态局部静态局部对象对象存放在全局数据区(静态区),全局存放在全局数据区(静态区),全局对象对象在程序开始在程序开始运行时就在该区分配;运行

26、时就在该区分配;static静态局部静态局部对象对象在程序运行中第一次进入其作用域时在该在程序运行中第一次进入其作用域时在该区分配;二者都是直到程序运行结束才被释放。区分配;二者都是直到程序运行结束才被释放。auto局部局部对象对象存放在局部数据区(栈区),在程序运行到其作用域时在栈区分配,在存放在局部数据区(栈区),在程序运行到其作用域时在栈区分配,在离开其作用域时随即被释放。离开其作用域时随即被释放。15【例】【例】(矩形类、构造函数重载、全局对象、(矩形类、构造函数重载、全局对象、static局部对象、局部对象、auto局部对象)局部对象)#includeclass Rectangle

27、float left,top,right,bottom;public:Rectangle(float L,float T,float R,float B )left=L;top=T;right=R;bottom=B;cout “调用带调用带4个参的构造函数个参的构造函数!n”;Rectangle(float L,float T,float R )left=L;top=T;right=R;bottom=0;cout “调用带调用带3个参的构造函数个参的构造函数!n”;Rectangle(float L,float T )left=L;top=T;right=0;bottom=0;cout “调用

28、带调用带2个参的构造函数个参的构造函数!n”;Rectangle(float L )left=L;top=0;right=0;bottom=0;cout “调用带调用带1个参的构造函数个参的构造函数!n”;Rectangle()left=0;top=0;right=0;bottom=0;cout “调用不带参的构造函数调用不带参的构造函数!n”;void print()cout “left=”left “ttop=”top t;cout “right=”right “tbottom=”bottom endl;16void main()类名:类名(类名&对象名 )两对象非静态成员数据的依次拷贝

29、Line:Line()cout “对象地址=”(int)this “t调用线类析构了!n”;class Rectangle(析pb)#includeiostream.定义对象时,若需要对其成员数据赋初值,则类中必须声明带形参的构造函数。float x,y;void main()float x,y;int Length,Width;void main()10 20 调用构造函数了!cout “对象地址=”(int)this “t调用A类带参构造了!n”;【例】(点类、析构函数、调用构造函数和析构函数的顺序)y;cout “调用拷贝构造函数了!n”;fun(pb).Rectangle r4(2,3

30、,4,5);void f1()cout “进入函数进入函数f1了了!n”;static Rectangle r5(6,7,8);r5.print();Rectangle r6(1,9);r6.print();cout “退出函数退出函数f1了了!n”;void main()cout “进入主函数进入主函数main了了!n”;r4.print();f1();Rectangle r1(11,22);r1.print();Rectangle r2;r2.print();f1();cout “退出主函数退出主函数main了了!n”;Rectangle r3(9);运行:运行:调用带调用带4个参的构造函

31、数个参的构造函数!(构构r4)调用带调用带1个参的构造函数个参的构造函数!(构构r3)进入主函数进入主函数main了了!left=2 top=3 right=4 bottom=5进入函数进入函数f1了了!调用带调用带3个参的构造函数个参的构造函数!(构构r5)left=6 top=7 right=8 bottom=0调用带调用带2个参的构造函数个参的构造函数!(构构r6)left=1 top=9 right=0 bottom=0退出函数退出函数f1了了!调用带调用带2个参的构造函数个参的构造函数!(构构r1)left=11 top=22 right=0 bottom=0调用不带参的构造函数调用

32、不带参的构造函数!(构构r2)left=0 top=0 right=0 bottom=0进入函数进入函数f1了了!left=6 top=7 right=8 bottom=0调用带调用带2个参的构造函数个参的构造函数!(构构r6)left=1 top=9 right=0 bottom=0退出函数退出函数f1了了!退出主函数退出主函数main了了!17拷贝构造函数拷贝构造函数使用本类已有的一个对象来初始化本类的新对象使用本类已有的一个对象来初始化本类的新对象l拷贝构造函数的作用:拷贝构造函数的作用:用本类已有的一个对象来初始化本类的新对象,即完成对象用本类已有的一个对象来初始化本类的新对象,即完成

33、对象的拷贝,的拷贝,拷贝构造函数的形参必须是本类对象的引用,拷贝构造函数的形参必须是本类对象的引用,其格式为:其格式为:类名类名:类名(类名(类名类名&对象名对象名 )l定义对象时,若对象名后面括号内给出的实参是本类对象,或对象名后面等号右边定义对象时,若对象名后面括号内给出的实参是本类对象,或对象名后面等号右边给出的是本类对象,则要用本类给出的是本类对象,则要用本类已有的一个已有的一个对象来初始化本类的新对象,系统将自对象来初始化本类的新对象,系统将自动调用拷贝构造函数实现对象的拷贝。动调用拷贝构造函数实现对象的拷贝。【例】(点类、拷贝构造函数)【例】(点类、拷贝构造函数)#includec

34、lass Point float x,y;public:Point(float a=0,float b=0 )x=a,y=b;cout “调用带参构造了调用带参构造了!t”;Point(Point&p )x=p.x;y=p.y;cout “调用拷贝构造了调用拷贝构造了!t”;void print()cout “x=”x “ty=”y endl;void main()Point p1;p1.print();Point p2(10,20);p2.print();Point p3(p2);p3.print();Point p4=p2 ;p4.print();p1=p2;p1.print();运行:运

35、行:调用带参构造了!调用带参构造了!x=0 y=0 (构构p1)调用带参构造了!调用带参构造了!x=10 y=20 (构构p2)调用拷贝构造了!调用拷贝构造了!x=10 y=20 (构构p3)调用拷贝构造了!调用拷贝构造了!x=10 y=20 (构构p4)x=10 y=2018 float x,y;static Circle c3(10);c3.cout “对象地址=”(int)this “t调用B带参类构造了!n”;float x,y;void settime(int h,int m,int s )y;cout “调用拷贝构造函数了!n”;int x;Rectangle r3(10,20,3

36、0);r3.(x,y)对象地址=1245024 调用拷贝构造函数了!类中含有成员对象的构造函数定义:print();【例】(隐式调用:实现类型转换的构造函数)C(C&c):a1(c.void showtime()cout hour “:”minute “:”second n;print();默认的拷贝构造函数默认的拷贝构造函数l若类中没有声明拷贝构造函数,系统会自动产生一个默认的拷贝构造函数,完成对若类中没有声明拷贝构造函数,系统会自动产生一个默认的拷贝构造函数,完成对象的非静态成员数据的依次拷贝,其格式为:象的非静态成员数据的依次拷贝,其格式为:类名类名:类名(类名(类名类名&对象名对象名

37、)两对象非静态成员数据的依次拷贝两对象非静态成员数据的依次拷贝 l注意:定义对象时,若只要拷贝本类对象的部分成员数据,或者成员数据中有需要注意:定义对象时,若只要拷贝本类对象的部分成员数据,或者成员数据中有需要使用使用 new 运算符动态申请存储空间的,则必须在类中显式定义一个拷贝构造函数,运算符动态申请存储空间的,则必须在类中显式定义一个拷贝构造函数,以便正确实现对象成员数据的拷贝。以便正确实现对象成员数据的拷贝。【例】【例】(点类、默认的拷贝构造函数)(点类、默认的拷贝构造函数)#includeclass Point float x,y;public:Point(float a=0,flo

38、at b=0 )x=a,y=b;cout “调用带参构造函数了调用带参构造函数了!n”;void print()cout “x=”x “ty=”y endl;void main()Point p1(10,20);p1.print();Point p2(p1);p2.print();运行:运行:调用带参构造函数了!调用带参构造函数了!x=10 y=20 x=10 y=2019拷贝构造函数拷贝构造函数l当函数的形参为非引用类型的类对象时,属于值传递,在当函数的形参为非引用类型的类对象时,属于值传递,在C+中按值传递一个参数时,中按值传递一个参数时,会在被调函数中为形参对象分配一块内存空间,再把实参

39、对象的成员数据依次赋给会在被调函数中为形参对象分配一块内存空间,再把实参对象的成员数据依次赋给该形参对象各个成员数据,那么在创建该形参新对象时,系统会自动调用拷贝构造该形参对象各个成员数据,那么在创建该形参新对象时,系统会自动调用拷贝构造函数。函数。【例】【例】(点类、函数的形参为非引用类型的类对象)(点类、函数的形参为非引用类型的类对象)#includeclass Point float x,y;public:Point(float a=0,float b=0 )x=a,y=b;cout “调用带参构造函数了调用带参构造函数了!n”;Point(Point&p )x=p.x;y=p.y;co

40、ut “调用拷贝构造函数了调用拷贝构造函数了!n”;void print()cout “x=”x “ty=”y endl;void fun(Point p)/值传递,调用拷贝构造值传递,调用拷贝构造 Point pa=p;/创建创建pa时,调用拷贝构造时,调用拷贝构造 pa.print();void main()Point pb(10,50);pb.print();fun(pb);运行:运行:调用带参构造函数了!调用带参构造函数了!(构构pb)x=10 y=50调用拷贝构造函数了!调用拷贝构造函数了!(构形参构形参p)调用拷贝构造函数了!调用拷贝构造函数了!(构构pa)x=10 y=5020拷

41、贝构造函数拷贝构造函数l当函数的形参为引用类型的类对象时,属于引用传递,系统对引用类型的形参是不当函数的形参为引用类型的类对象时,属于引用传递,系统对引用类型的形参是不分配存储空间的,引用类型的形参对象与其相关联的实参对象使用的是同一个存储分配存储空间的,引用类型的形参对象与其相关联的实参对象使用的是同一个存储空间,是双向传递。请将下例与上例进行比较!空间,是双向传递。请将下例与上例进行比较!【例】【例】(点类、函数的形参为引用类型的类对象)(点类、函数的形参为引用类型的类对象)#includeclass Point float x,y;public:Point(float a=0,float

42、 b=0 )x=a,y=b;cout “调用带参构造函数了调用带参构造函数了!n”;Point(Point&p )x=p.x;y=p.y;cout “调用拷贝构造函数了调用拷贝构造函数了!n”;void print()cout “x=”x “ty=”y endl;void fun(Point&p)/引用传递引用传递 Point pa=p;/创建创建pa时,调用拷贝构造时,调用拷贝构造 pa.print();void main()Point pb(10,50);pb.print();fun(pb);运行:运行:调用带参构造函数了!调用带参构造函数了!(构构pb)x=10 y=50调用拷贝构造函数

43、了!调用拷贝构造函数了!(构构pa)x=10 y=5021拷贝构造函数拷贝构造函数l若函数的返回值是类对象,系统会自动调用拷贝构造函数。原因是:不能直接返回若函数的返回值是类对象,系统会自动调用拷贝构造函数。原因是:不能直接返回被调函数中的局部对象!局部对象在离开定义它的函数时就消亡了,不可能在返回被调函数中的局部对象!局部对象在离开定义它的函数时就消亡了,不可能在返回主调函数后继续生存,所以编译系统在处理这种情况时,会在主调函数中的调用处主调函数后继续生存,所以编译系统在处理这种情况时,会在主调函数中的调用处表达式域内创建一个无名临时对象,该临时对象的生存期仅在调用处表达式中。表达式域内创建

44、一个无名临时对象,该临时对象的生存期仅在调用处表达式中。【例】【例】(点类、函数的返回值是类对象)(点类、函数的返回值是类对象)#includeclass Point float x,y;public:Point(float a=0,float b=0 )x=a,y=b;cout “调用带参构造函数了调用带参构造函数了!n”;Point(Point&p )x=p.x;y=p.y;cout “调用拷贝构造函数了调用拷贝构造函数了!n”;void print()cout “x=”x “ty=”y endl;Point fun()Point pa(20,60);pa.print();return p

45、a ;/创建临时对象,调用拷贝构造创建临时对象,调用拷贝构造void main()fun().print();Point pb=fun();pb.print();运行:运行:调用带参构造函数了!调用带参构造函数了!(构构pa)x=20 y=60调用拷贝构造函数了!调用拷贝构造函数了!(构临时对象构临时对象)x=20 y=60调用带参构造函数了!调用带参构造函数了!(构构pa)x=20 y=60调用拷贝构造函数了!调用拷贝构造函数了!(构临时对象构临时对象)调用拷贝构造函数了!调用拷贝构造函数了!(构构pb)x=20 y=6022拷贝构造函数拷贝构造函数l若函数的返回值类型为类对象的引用,情况又

46、如何?请将下例与上例进行比较!特若函数的返回值类型为类对象的引用,情况又如何?请将下例与上例进行比较!特别要注意:局部对象在离开定义它的函数时就消亡了!别要注意:局部对象在离开定义它的函数时就消亡了!【例】【例】(点类、函数的返回值类型为类对象的引用)(点类、函数的返回值类型为类对象的引用)#includeclass Point float x,y;public:Point(float a=0,float b=0 )x=a,y=b;cout “调用带参构造函数了调用带参构造函数了!n”;Point(Point&p )x=p.x;y=p.y;cout “调用拷贝构造函数了调用拷贝构造函数了!n”

47、;void print()cout “x=”x “ty=”y endl;Point&fun()Point pa(20,60);pa.print();return pa;void main()Point pb=fun();pb.print();运行:运行:调用带参构造函数了!调用带参构造函数了!(构构pa)x=20 y=60调用拷贝构造函数了!调用拷贝构造函数了!(构构pb)【思考】【思考】(将(将fun()函数修改如下,结果又如何?)函数修改如下,结果又如何?)Point&fun()static Point pa(20,60);pa.print();return pa;运行:运行:调用带参构造

48、函数了!调用带参构造函数了!(构构pa)x=20 y=60调用拷贝构造函数了!调用拷贝构造函数了!(构构pb)x=20 y=6023拷贝构造函数拷贝构造函数l在定义拷贝构造函数时,务必将形参定义为本类对象的引用!在定义拷贝构造函数时,务必将形参定义为本类对象的引用!若把形参定义为本类若把形参定义为本类对象的非引用方式,那么创建新对象时,给出的实参对象作为参数传递给拷贝构造对象的非引用方式,那么创建新对象时,给出的实参对象作为参数传递给拷贝构造函数的形参,属于值传递,会引起无穷递归!因为函数的形参,属于值传递,会引起无穷递归!因为C+中按值传递一个参数时,会在中按值传递一个参数时,会在被调函数中

49、为形参对象分配一块内存空间,再把实参对象的成员数据赋给该形参对被调函数中为形参对象分配一块内存空间,再把实参对象的成员数据赋给该形参对象的成员数据,而在建立这个形参对象时,系统又会自动调用拷贝构造函数,这样象的成员数据,而在建立这个形参对象时,系统又会自动调用拷贝构造函数,这样由于给出的拷贝构造函数形参还是本类对象的非引用方式,则又会引入新一轮的调由于给出的拷贝构造函数形参还是本类对象的非引用方式,则又会引入新一轮的调用拷贝构造函数的过程,出现无穷递归!用拷贝构造函数的过程,出现无穷递归!l默认拷贝构造函数不适用的情况:默认拷贝构造函数不适用的情况:定义对象时,若只要拷贝本类对象的部分成员数定

50、义对象时,若只要拷贝本类对象的部分成员数据,或成员数据中有需要使用据,或成员数据中有需要使用new运算符动态申请存储空间的,都必须在类中显式运算符动态申请存储空间的,都必须在类中显式定义一个拷贝构造函数,以便正确实现对象成员数据的拷贝。定义一个拷贝构造函数,以便正确实现对象成员数据的拷贝。24析构函数析构函数l关于析构函数:关于析构函数:定义对象时,系统要为其分配存储空间;撤消对象时,系统要收回对象所占用的存储定义对象时,系统要为其分配存储空间;撤消对象时,系统要收回对象所占用的存储空间。空间。对象撤消前的清理工作由析构函数完成,析构函数的作用并不是撤消对象,而是在撤对象撤消前的清理工作由析构

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 教案示例

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁