构造函数和析构函数.ppt
《构造函数和析构函数.ppt》由会员分享,可在线阅读,更多相关《构造函数和析构函数.ppt(50页珍藏版)》请在三一办公上搜索。
1、第5章 构造和析构函数,构造函数和析构函数的引入带参构造函数和默认构造函数成员初始化列表拷贝构造函数对象的构造顺序再看new和delete,5.1 构造函数背景,与结构和其他基本数据类型的变量一样:定义一个全局对象会将其所占内存空间清0定义一个局部对象时,不会执行任何初始化动作,其数据成员的值完全依赖于堆栈上的情况。对象应该表达了现实世界中的相应实体,一旦建立对象,其每个数据成员理应有合理的初始值。,5.1 构造函数背景,struct Rectangledouble fWidth;double fHeight;,class Studentpublic:int GetAge()const;pri
2、vate:char m_strName100;int m_nAge;double m_fScore;,C语言使用下面的语法初始化结构变量:Rectangle r=10,20.0;C+中不能使用这种方法,因为某些数据成员可能不是公有成员。/错误:不能在类的作用/域外访问非公有数据成员Student stu=“aa”,10,90;为了避免破坏类的封装性,使用特殊的成员函数来负责对象初始化。,5.1 构造函数要点,与类同名的成员函数称为构造函数(Constructor,ctor),此函数在该类的对象被创建时会被自动调用,负责完成该对象的初始化工作。构造函数不能指定返回类型。每定义一个对象,该对象的c
3、tor被自动调用。Student s;此句背后的动作是首先为对象s分配内存,然后调用ctor初始化对象。,class Studentpublic:Student();int GetAge()const;private:char m_strName100;int m_nAge;double m_fScore;Student:Student()m_nAge=10;m_fScore=100;,5.1 构造函数要点,构造函数不能定义为const的,但是可以用来构造常量对象,这是因为只有当构造函数执行完毕后,对象的常量性才能够建立起来。Rectangle:Rectangle()const/错误的ctor
4、定义对于常量对象只能调用常成员函数的规则,构造函数是个例外。如果一个类对象item是另一个类Container的数据成员,则创建Container的对象时,会首先自动为item调用构造函数。换句话说,编译器会自动在Container的构造函数的函数体前插入对item构造函数的调用。首先调用对象成员的ctor,其次才是自身的ctor。演示 理解构造函数的调用时机,5.2 析构函数背景,一个对象的生存期结束(销毁)时可能需要做些清理工作。打开的文件需要关闭分配的堆内存需要释放如果清理工作对应的函数能够被自动调用,就会减少程序员的工作量,甚至出错的可能。可以使用析构函数(Destructor,dto
5、r)自动完成清理工作。,5.2 析构函数要点,析构函数名必须为加上类名。示例dtor是一类特殊的成员函数,它没有参数,不能重载,不能为其指定返回值。类中至多只有一个dtor。dtor在对象的生存期即将结束时由系统自动调用。析构函数返回后,对象结束其生存期。如果没有清理工作要做,则可以不在类中定义析构函数。【示例】析构函数,class Studentpublic:Student();/ctor Student();/dtor int GetAge()const;private:char m_strName100;int m_nAge;double m_fScore;,5.2 析构函数要点,dto
6、r不能定义为常成员函数,但是常量对象在析构的时候同样会调用dtor。Rectangle:Rectangle()const/错误的dtor定义对于常量对象只能调用常成员函数的规则,dtor是个例外。如果类中包含成员对象,在执行析构函数时将首先执行dtor的函数体,然后为类中的每个对象成员调用析构函数。换句话说,编译器会在类的dtor函数体之后插入对类中每个成员对象的dtor的调用。对dtor的调用顺序正好和对ctor的调用顺序相反。最先构造的对象最后被析构。演示 理解析构函数的调用时机,class Personpublic:Person()m_strName=new char20;/分配堆空间
7、Person()delete m_strName;/释放堆空间 void SetName(const char*name)strcpy(m_strName,name);private:char*m_strName;,5.3 构造函数重载,与dtor不同,ctor允许带参而且可以带不同的参数,ctor允许重载。教材P273页的例子MFC中的CString的类定义在一个构造函数中调用重载的另一个构造函数以简化编程的方法是错误的。因为构造函数只用于创建对象。这一点和普通重载函数不同。,Tdate:Tdate(int m,int d,int y).Tdate:Tdate(int d)/下面的语句只是创
8、建/了另一个对象,并且/很快结束生存期。Tdate(4,d,1995);,专门定义一个成员函数,然后所有的构造函数调用此成员函数即可。解决办法通过给参数设置默认值,可以将重载的构造函数合并为一个。示例,class Tdatepublic:Tdate(int m=4,d=22,y=2005);private:int month;int day;int year;Tdate:Tdate(int m/*=4*/,int d/*=22*/,int y/*=2005*/)month=m;day=d;year=y;cout month/day/year endl;,#include class Tdate
9、public:Tdate()Init(4,15,1995);Tdate(int d)Init(4,d,1995);Tdate(int m,int d)Init(m,d,1995);Tdate(int m,int d,int y)Init(m,d,y);protected:int month;int day;int year;void Init(int m,int d,int y)month=m;day=d;year=y;cout month/day/year endl;,5.4 默认(缺省)构造函数,默认构造函数(dctor):不需要用户指定实参就能被调用的构造函数。(教材上缺明确定义)Tda
10、te:Tdate()Rectangle:Rectangle(float w=0.0,float h=0.0);如果没有在类中定义任何ctor,则C+提供一个dctor,该dctor为无参构造函数,不作任何工作。类的数据成员如果为简单类型则不会被初始化,如果为其它类的对象则自动为其调用构造函数。,class Studentprivate:char name20;,等价于,class Studentpublic:Student()private:char name20;,5.4默认构造函数示例,class Studentpublic:Student(char*pName)strcpy(name,p
11、Name);Student()name0=0;private:char name20;void main(void)/错误:没有匹配的ctor Student s;,只要为类定义了一个带参的构造函数,C+就不再提供默认构造函数,如果还需要无参的构造函数,则必须显式定义。,5.5 使用参数初始化对象,Tdate adate;/调用默认构造函数(dctor)Tdate bdate(10);/OK,Tdate:Tdate(int d)等价于 Tdate bdate=Tdate(10);Tdate cdate(3,12);/OK,Tdate:Tdate(int m,int d)等价于Tdate cda
12、te=Tdate(3,12);Tdate ddate();/此句没有语法错误/Error:left of.GetYear must have class/struct/union type int iy=ddate.GetYear();编译器认为ddate是个函数声明。所以使用dctor构造对象时,对象名后面不能跟()。为什么Tdate bdate(10);不看作是函数声明?根据重载函数的匹配原则来决定调用哪个构造函数。,补充:函数声明和对象定义的判别,Tdate aa;Tdate aa();Tdate aa(1);Tdate aa(z=1);Tdate aa(int z);Tdate aa(
13、int z=1);判别上面的形式是函数声明还是对象定义的关键在于括号内的字符串能否被看作参数列表,如果能则一定是函数声明。,5.6 单参数构造函数(1),单参数构造函数是指只用一个参数即可以调用的构造函数。可以是只定义了一个参数的构造函数,可以是虽定义了多个参数但第一个参数以后的所有参数都有缺省值的ctor。当使用带一个参数的ctor构造对象时,有三种等价的写法。最后一种写法只适用于单参数构造函数。,class Rational/有理数类 public:Rational(int numerator=0,int denominator=1);,5.6 单参数构造函数(2),缺省情况下,单参数构造
14、函数可用于类型转换。重载函数的匹配原则:在严格匹配方式,经内部转换后匹配方式都失败后,将寻找通过用户定义的转换后参数匹配的函数并调用。单参数构造函数就是其中一种用户定义的转换。当同时存在多种可能的转换时,重载函数匹配失败,从而导致语法错误。单参数构造函数导致重载函数匹配失败的例子,class Apublic:A(char*);void f(A a);void main()/OK,构造A的一个无/名对象,然后调用f f(“yes?”);,void f(B b)void f(A a)void main()/Error:Ambiguous,二义性/Call f(A a)?or Call f(B a)
15、?f(“yes?”);,class Apublic:A(char*);class Bpublic:B(char*);,5.6 单参数构造函数(3),单参数ctor用于类型转换时极有可能导致意外的错误。演示使用关键字explicit可以抑制上述转换行为。使用explicit关键字后,必须显式的调用构造函数来初始化对象,也就是说不能再使用Tdate date=10;这样的构造对象方式;否则将导致编译错误。,class Apublic:explicit A(char*);void f(A a);void main()A a=“Hi”;/ERROR f(“yes?”);/ERROR,A a=A(“Hi
16、”);/OKf(A(“Yes?”);/OK,教材P325的错误,14.9第一段最后一句:“定义含一个参数的构造函数”应为“定义单参数构造函数”;倒数第二行“只会尝试含一个参数的构造函数”应为“只会尝试单参数构造函数”;void fn(Student否则会发生编译错误。,5.7 成员初始化列表背景,当一个对象是另一个类的成员时:Point3d aPoint;将自动调用成员m_point2d的默认构造函数。,/二维平面的一个点class Point2dpublic:Point2d(int x=0,int y=0)m_x=x;m_y=y;private:int m_x;int m_y;,/三维空间的
17、一个点class Point3dpublic:Point3d()m_z=0;private:Point2d m_point2d;int m_z;,5.7 成员初始化列表背景,Point3d point(1,2,3);需要在Point3d的构造函数中调用Point2d的非默认构造函数,应该怎么做?调用构造函数不可行,因为m_point2d已经构造过了。构造一个无名对象,赋给m_point2d,可行但是效率低。【演示】在Point3d的构造函数中构造了一个无名对象,赋给m_point2d,随后将无名对象析构。,/三维空间的一个点class Point3dpublic:Point3d()m_z=0;
18、Point3d(int x,int y,int z)/错误,构造函数不能显式调用 m_point2d.Point2d(x,y);m_z=z;private:Point2d m_point2d;int m_z;,/正确,但是效率低m_point2d=Point2d(x,y);,5.7 成员初始化列表,应使用成员初始化列表(member initialization list)完成上述工作。Point3d:Point3d(int x,int y,int z):m_point2d(x,y),m_z(z)成员初始化列表必须出现在构造函数参数列表结束(右括号)后和函数体之间,并且必须使用冒号。列表中对数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 构造 函数

链接地址:https://www.31ppt.com/p-6227603.html