《面向对象C 第四章精选文档.ppt》由会员分享,可在线阅读,更多相关《面向对象C 第四章精选文档.ppt(108页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、面向对象面向对象C第四章第四章本讲稿第一页,共一百零八页4.1.1定义类定义类像枚举和结构一样,类也是一种用户自己构造的数像枚举和结构一样,类也是一种用户自己构造的数据类型并遵循据类型并遵循C+的规定。的规定。p类也要先声明后使用;类也要先声明后使用;p不管声明的内容是否相同,声明同一个名字的两个类是不管声明的内容是否相同,声明同一个名字的两个类是错误的,类是具有惟一标识符的实体;错误的,类是具有惟一标识符的实体;p在类中声明的任何成员不能使用在类中声明的任何成员不能使用extern、auto和和register关键字进行修饰;关键字进行修饰;p类中声明的变量属于该类,在某些情况下,变量可以被
2、类中声明的变量属于该类,在某些情况下,变量可以被该类的不同实例所共享。该类的不同实例所共享。p类和其他数据类型不同的是,组成这种类型的不仅可以类和其他数据类型不同的是,组成这种类型的不仅可以有数据,而且可以有对数据进行操作的函数,它们分别有数据,而且可以有对数据进行操作的函数,它们分别叫做类的数据成员和类的成员函数,而且不能在类声明叫做类的数据成员和类的成员函数,而且不能在类声明中对数据成员使用表达式进行中对数据成员使用表达式进行初始化初始化。本讲稿第二页,共一百零八页1.声明类声明类类是对一组性质相同对象的程序描述。在类是对一组性质相同对象的程序描述。在C+中声中声明类的一般形式为:明类的一
3、般形式为:class类名类名private:私有数据和函数私有数据和函数public:公有数据和函数公有数据和函数protected:保护数据和函数保护数据和函数;类声明以关键字类声明以关键字class开始,其后跟类名。类所声开始,其后跟类名。类所声明的内容用花括号括起来,右花括号后的分号作为类明的内容用花括号括起来,右花括号后的分号作为类声明语句的声明语句的结束标志结束标志。这一对花括号。这一对花括号“”之间的内之间的内容称为类体。容称为类体。本讲稿第三页,共一百零八页类中定义的数据和函数称为这个类的成员(数据成员类中定义的数据和函数称为这个类的成员(数据成员和成员函数)。和成员函数)。类成
4、员均具有一个属性,叫做访问权限,通过它类成员均具有一个属性,叫做访问权限,通过它前面的关键字来定义。关键字前面的关键字来定义。关键字private、public和和protected以后的成员的访问权限分别是私有、公有以后的成员的访问权限分别是私有、公有和保护的,把这些成员分别叫做私有成员、公有成员和保护的,把这些成员分别叫做私有成员、公有成员和保护成员。和保护成员。访问权限用于控制对象的某个成员在程序中的可访问访问权限用于控制对象的某个成员在程序中的可访问性,如果没有使用关键字,则所有成员默认声明为性,如果没有使用关键字,则所有成员默认声明为private权限。这些关键字的使用顺序和次数也都
5、是任意权限。这些关键字的使用顺序和次数也都是任意的。的。本讲稿第四页,共一百零八页【例【例4.1】描述点的描述点的Point类。类。classPoint/类名类名Pointprivate:/声明为私有访问权限声明为私有访问权限intx,y;/私有数据成员私有数据成员public:/声明为公有访问权限声明为公有访问权限voidSetxy(inta,intb);/无返回值的公有成员函数无返回值的公有成员函数voidMove(inta,intb);/无返回值的公有成员函数无返回值的公有成员函数voidDisplay();/无返回值的公有成员函数无返回值的公有成员函数intGetx();/返回值为返回
6、值为int的公有成员函数的公有成员函数intGety();/返回值为返回值为int的公有成员函数的公有成员函数;/类声明以分号结束类声明以分号结束x和和y是私有成员是私有成员Setxy、Display、Move、Getx和和Gety是公有成员是公有成员因为只是声明函数,所以可只给出函数原型。【例因为只是声明函数,所以可只给出函数原型。【例4.2】是其等效的声明】是其等效的声明方式。方式。本讲稿第五页,共一百零八页【例【例4.2】使用默认关键字及改变关键字顺序和次数的使用默认关键字及改变关键字顺序和次数的Point类。类。#includeusingnamespacestd;classPoint/
7、类名类名Pointintx;/默认私有数据成员默认私有数据成员public:/声明为公有访问权限声明为公有访问权限voidSetxy(int,int);/无返回值的公有成员函数的函数原型无返回值的公有成员函数的函数原型voidMove(int,int);/无返回值的公有成员函数的函数原型无返回值的公有成员函数的函数原型voidDisplay();/无返回值的公有成员函数的函数原型无返回值的公有成员函数的函数原型intGetx();/返回值为返回值为int的公有成员函数的函数原型的公有成员函数的函数原型intGety();/返回值为返回值为int的公有成员函数的函数原型的公有成员函数的函数原型p
8、rivate:/声明为私有访问权限声明为私有访问权限inty;/私有数据成员私有数据成员;/类定义以分号结束类定义以分号结束由此可见,成员函数声明的规则与第由此可见,成员函数声明的规则与第3章所述的函数声明规则相同。章所述的函数声明规则相同。本讲稿第六页,共一百零八页2.定义成员函数定义成员函数类中说明的成员函数用来对数据成员进行操作。类中说明的成员函数用来对数据成员进行操作。在类中只对这些成员函数进行了函数声明,还必须在在类中只对这些成员函数进行了函数声明,还必须在程序中实现这些成员函数。程序中实现这些成员函数。定义成员函数的一般形式为:定义成员函数的一般形式为:返回类型返回类型类名类名:成
9、员函数名(参数列表)成员函数名(参数列表)成员函数的函数体成员函数的函数体/内部实现内部实现其中其中“:”是是作用域运算符作用域运算符,“类名类名”是成员函数所是成员函数所属类的名字,属类的名字,“:”用于表明其后的成员函数是属于这个特用于表明其后的成员函数是属于这个特定的类。定的类。“类名类名:成员函数名成员函数名”的意思就是对属于的意思就是对属于“类名类名”的成员函数进行定义,而的成员函数进行定义,而“返回类型返回类型”则是这个成员函数返则是这个成员函数返回值的类型。回值的类型。本讲稿第七页,共一百零八页定义成员函数的函数体。例如定义成员函数的函数体。例如Setxy定义如下:定义如下:vo
10、idPoint:Setxy(inta,intb)x=a;y=b;定义定义Point的函数成员的函数成员Setxy(inta,intb),该成员带有两个整型参数,该成员带有两个整型参数,函数没有返回值函数没有返回值(void)。voidPoint:Move(inta,intb)x=x+a;y=y+b;voidPoint:Display()coutx,yendl;intPoint:Getx()returnx;intPoint:Gety()returny;本讲稿第八页,共一百零八页可以使用关键字可以使用关键字inline将成员函数定义为内联函数,例将成员函数定义为内联函数,例如:如:inlinein
11、tPoint:Getx()returnx;如果在声明类的同时,在类体内给出成员函数的定义,如果在声明类的同时,在类体内给出成员函数的定义,则则默认为默认为内联函数。例如在类中将声明内联函数。例如在类中将声明Getx的语句的语句“intGetx();”改为改为“intGetx()returnx;”,则,则Getx为内联函数。为内联函数。一般直接在类体内给出简单成员函数的定义。一般直接在类体内给出简单成员函数的定义。有些成员函数的实现方式不止一种,例如有些成员函数的实现方式不止一种,例如voidPoint:Display()coutGetx(),Gety()endl;是调用成员函数是调用成员函数G
12、etx()和和Gety()实现的,它们使用了实现的,它们使用了cout流,应在定义之前包含如下语句:流,应在定义之前包含如下语句:#includeusingnamespacestd;本讲稿第九页,共一百零八页3.数据成员的赋值数据成员的赋值不能在类体内给数据成员赋值,即下面的方法是错误的:不能在类体内给数据成员赋值,即下面的方法是错误的:ClassPointintx=25,y=56;当然,在类体外面就更不允许了。当然,在类体外面就更不允许了。数据成员的具体值是用来描述对象的属性的。只有产生了一个具体的对象,数据成员的具体值是用来描述对象的属性的。只有产生了一个具体的对象,这些数据值才有意义,所
13、以又称对象的初值或对象初始化。这些数据值才有意义,所以又称对象的初值或对象初始化。假设已经有了一个对象假设已经有了一个对象A,则可使用,则可使用“.”运算符调用成员函数运算符调用成员函数Setxy赋初值。例如:赋初值。例如:A.Setxy(25,56);将对象将对象A的数据成员的数据成员x和和y分别赋给分别赋给25和和56,即,即A.x=25,A.y=56。真正的初始化是使用与真正的初始化是使用与Point同名的构造函数同名的构造函数Point(int,int)实现的。产实现的。产生生Point对象的语句:对象的语句:PointA(25,56);本讲稿第十页,共一百零八页4.1.2使用类的对象
14、及指针使用类的对象及指针Point类是用户定义的一种类型,使用类是用户定义的一种类型,使用Point在程序中在程序中声明变量,具有声明变量,具有Point类的类型的变量被称为类的类型的变量被称为Point的的对象对象。只有产生类的对象,才能使用这些数据和成员函数。只有产生类的对象,才能使用这些数据和成员函数。类类Point不仅可以声明对象,还可以声明对象的引用和不仅可以声明对象,还可以声明对象的引用和对象的指针,语法与基本数据类型一样。对象的指针,语法与基本数据类型一样。PointA,B;/定义定义Point类型的对象类型的对象A和和BPoint*p=&A;/定义指向对象定义指向对象A的的Po
15、int类型的指针类型的指针Point&R=B;/定义定义R为为Point类型对象类型对象B的引用的引用本讲稿第十一页,共一百零八页对象和引用都使用运算符对象和引用都使用运算符“.”访问对象的成员,访问对象的成员,指针则使用指针则使用“-”运算符。例如:运算符。例如:A.Setxy(25,88);/为对象为对象A设置初值设置初值p-Display();/显示指针显示指针p所指对象所指对象A的数据成员的数据成员/A.x和和A.y之值之值R.Display();/显示对象显示对象B的数据成员的数据成员B.x和和B.y之值之值【例【例4.3】根据上面对】根据上面对Point类的定义,演示使用类的定义,
16、演示使用Point类的对象。类的对象。voidprint(Pointa)/使用使用Point的对象的对象a作为函数参数作为函数参数a.Display();/显示对象显示对象a的数据成员的值的数据成员的值voidmain()本讲稿第十二页,共一百零八页PointA,B;/声明对象声明对象A.Setxy(25,55);/为对象为对象A赋初值赋初值B=A;/B的数据成员取的数据成员取A的数据成员之值的数据成员之值A.Display();/显示显示A的数据成员的数据成员A.Move(-10,20);/移动移动Aprint(A);/等价于等价于A.Display();print(B);/等价于等价于B.
17、Display()coutA.Getx()endl;/只能使用只能使用A.Getx(),/不能使用不能使用A.x本例中的本例中的print函数使用函数使用Point的对象作为参数。的对象作为参数。C+推荐推荐使用下面的引用的形式:使用下面的引用的形式:voidprint(Point&a)/使用对象的引用做为函数参数使用对象的引用做为函数参数a.Display();/显示引用对象显示引用对象a的数据成员之值的数据成员之值本讲稿第十三页,共一百零八页对象对象A移动之后,对象移动之后,对象B仍为原来的值,所以输出如下:仍为原来的值,所以输出如下:25,55/原来的原来的A和和B15,75/新的新的A
18、25,55/原来的原来的B15/A.Getx()返回对象返回对象A的数据成员的数据成员x的之值的之值如果在如果在print函数或主函数里使用如下语句,则产生函数或主函数里使用如下语句,则产生错误:错误:coutA.x,A.y”运算符访问对象的成员,即:运算符访问对象的成员,即:对象指针名对象指针名-对象成员名对象成员名本讲稿第十八页,共一百零八页【例【例4.4】演示使用内联函数定义】演示使用内联函数定义Point类及使用类及使用Point类指针和引用的完整例子。类指针和引用的完整例子。#include/包含头文件包含头文件usingnamespacestd;/声明命名空间声明命名空间class
19、Point/使用内联函数定义类使用内联函数定义类Pointprivate:/声明为私有访问权限声明为私有访问权限intx,y;/私有数据成员私有数据成员public:/声明为公有访问权限声明为公有访问权限voidSetxy(inta,intb)/无返回值的内联公有成员函数无返回值的内联公有成员函数x=a;y=b;voidMove(inta,intb)/无返回值的内联公有成员函数无返回值的内联公有成员函数x=x+a;y=y+b;voidDisplay()/无返回值的内联公有成员函数无返回值的内联公有成员函数coutx,yDisplay();voidprint(Point&a)/类引用作为类引用作
20、为print函数的参数定义重载函数函数的参数定义重载函数a.Display();本讲稿第十九页,共一百零八页voidmain()/主函数主函数PointA,B,*p;/声明对象和指针声明对象和指针Point&RA=A;/声明对象声明对象RA引用对象引用对象AA.Setxy(25,55);/使用成员函数为对象使用成员函数为对象A赋值赋值B=A;/使用赋值运算符为对象使用赋值运算符为对象B赋值赋值p=&B;/类类Point的指针指向对象的指针指向对象Bp-Setxy(112,115);/使用指针调用函数使用指针调用函数Setxy/重新设置重新设置B的值的值print(p);/传递指针显示对象传递指
21、针显示对象B的属性的属性p-Display();/再次显示对象再次显示对象B的属性的属性RA.Move(-80,23);/引用对象引用对象RA调用调用Move函数函数print(A);/验证验证RA和和A同步变化同步变化print(&A);/直接传递直接传递A的地址作为指针参数的地址作为指针参数本讲稿第二十页,共一百零八页程序运行结果如下:程序运行结果如下:112,115112,115-55,78-55,78由此可见,使用对象和对象指针的效果一样。由此可见,使用对象和对象指针的效果一样。本讲稿第二十一页,共一百零八页4.1.4数据封装数据封装面向对象的程序设计,是通过为数据和代码建面向对象的程
22、序设计,是通过为数据和代码建立分块的内存区域,以便提供对程序进行模块化的立分块的内存区域,以便提供对程序进行模块化的一种程序设计方法,这些模块可以被用做样板,在一种程序设计方法,这些模块可以被用做样板,在需要时再建立其副本。根据这个定义,对象是计算需要时再建立其副本。根据这个定义,对象是计算机内存中的一块区域,通过将内存分块,每个模块机内存中的一块区域,通过将内存分块,每个模块(即对象即对象)在功能上保持相对独立。另外,定义也表在功能上保持相对独立。另外,定义也表明如下问题:明如下问题:这些这些内存块中不但存储数据,而且也存储代码,内存块中不但存储数据,而且也存储代码,这对保证对象是受保护的这
23、一点很重要。对象保护这对保证对象是受保护的这一点很重要。对象保护它自己不受未知的外部事件的影响,从而使自己的它自己不受未知的外部事件的影响,从而使自己的数据和功能不会因此遭到破坏。数据和功能不会因此遭到破坏。本讲稿第二十二页,共一百零八页这些内存块这些内存块的结构可被用做样板产生对象的更多的结构可被用做样板产生对象的更多副本。例如,一旦定义了一个窗口对象,只要内存副本。例如,一旦定义了一个窗口对象,只要内存允许,就可以建立许多这样的对象。允许,就可以建立许多这样的对象。在面向对象的程序中,对象的行为只有向对象在面向对象的程序中,对象的行为只有向对象发送消息才能引用,例如通过发送消息才能引用,例
24、如通过Display发出显示消息,发出显示消息,所以说面向对象是消息处理机制。面向对象就是将所以说面向对象是消息处理机制。面向对象就是将世界看成是由一组彼此相关并能相互通信的实体即世界看成是由一组彼此相关并能相互通信的实体即对象组成的。程序中的对象映射现实世界中的对象。对象组成的。程序中的对象映射现实世界中的对象。本讲稿第二十三页,共一百零八页C+对其对象的数据成员和成员函数的访问是通过访对其对象的数据成员和成员函数的访问是通过访问控制权限来限制的。问控制权限来限制的。private是限制类之外的函数的访问是限制类之外的函数的访问权。只要将数据成员或成员函数使用权。只要将数据成员或成员函数使用
25、private限定,就设定限定,就设定了一道防线。它还必须留下与外面打交道的接口,这通过了一道防线。它还必须留下与外面打交道的接口,这通过具有具有public权限的成员函数实现。权限的成员函数实现。在在C+中,数据封装是通过类来实现的。在类中指定了各中,数据封装是通过类来实现的。在类中指定了各成员的访问权限。一般情况下:成员的访问权限。一般情况下:将数据成员说明为私有的,以便隐藏数据;将数据成员说明为私有的,以便隐藏数据;将部分成员函数说明为公有的,用于提供外界和这个类将部分成员函数说明为公有的,用于提供外界和这个类的对象相互作用的接口(界面),从而使得其他函数的对象相互作用的接口(界面),从
26、而使得其他函数(例如(例如main函数)也可以访问和处理该类的对象。函数)也可以访问和处理该类的对象。对于那些仅是为支持公有函数的实现而不作为对象界面的成对于那些仅是为支持公有函数的实现而不作为对象界面的成员函数,也将它们说明为私有的。员函数,也将它们说明为私有的。本讲稿第二十四页,共一百零八页4.2构造函数构造函数建立一个对象时,对象的状态(数据成员建立一个对象时,对象的状态(数据成员的取值)是不确定的。为了使对象的状态确定,的取值)是不确定的。为了使对象的状态确定,必须对其进行正确的初始化。必须对其进行正确的初始化。C+有一个称为有一个称为构造函数的特殊成员函数,它可自动进行对象构造函数的
27、特殊成员函数,它可自动进行对象的初始化。的初始化。本讲稿第二十五页,共一百零八页4.2.1默认构造函数默认构造函数当没有为一个类定义任何构造函数的情况下,当没有为一个类定义任何构造函数的情况下,C+编编译器总要自动建立一个不带参数的构造函数。译器总要自动建立一个不带参数的构造函数。例如,如果在上面的例子中没有为例如,如果在上面的例子中没有为Point类定义任类定义任何构造函数,则何构造函数,则C+编译器要为它产生一个默认构造函编译器要为它产生一个默认构造函数,这个默认构造函数具有下面这种形式:数,这个默认构造函数具有下面这种形式:Point:Point()即它的函数体是空的。因此,当建立即它的
28、函数体是空的。因此,当建立Point类的一个对象类的一个对象时,对象的状态是不确定的,即没有被初始化。时,对象的状态是不确定的,即没有被初始化。本讲稿第二十六页,共一百零八页一旦程序定义了自己的构造函数,系统就不再提一旦程序定义了自己的构造函数,系统就不再提供这个默认构造函数供这个默认构造函数。如果程序员没有定义一个无参数的构造函数,如果程序员没有定义一个无参数的构造函数,但又声明了一个没有初始化的对象但又声明了一个没有初始化的对象(如如“PointA;”),则因系统已经不再提供默认构造函数,编译就会,则因系统已经不再提供默认构造函数,编译就会出错。出错。“默认默认”也称为也称为“缺省缺省”,
29、本书统一使用,本书统一使用“默认默认”。不带参数的构造函数又称作默认构造函数。不带参数的构造函数又称作默认构造函数。如果只声明对象数组(即不提供初值),因为如果只声明对象数组(即不提供初值),因为每个元素对象均需要调用一次默认构造函数来为自每个元素对象均需要调用一次默认构造函数来为自己初始化,所以必须要求有一个默认构造函数。己初始化,所以必须要求有一个默认构造函数。本讲稿第二十七页,共一百零八页4.2.2定义构造函数定义构造函数1.构造函数的定义和使用方法构造函数的定义和使用方法构造函数的作用是在对象被创建时使用特定的值构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象构造对象,
30、或者说将对象初始化初始化为一个特定的状态。为一个特定的状态。在对象创建时在对象创建时由系统自动调用由系统自动调用。如果程序中未声明,则系统自动产生出一个如果程序中未声明,则系统自动产生出一个默认形式默认形式的构造函数的构造函数允许为允许为内联内联函数、函数、重载重载函数、函数、带默认形参值带默认形参值的函数。的函数。本讲稿第二十八页,共一百零八页构造函数的特点构造函数的特点l构造函数名与类名相同;构造函数名与类名相同;l没有返回值;没有返回值;l定义在定义在public下;下;l构造函数由系统自动调用;构造函数由系统自动调用;l若不显式定义,系统自动生成一个不带参数的若不显式定义,系统自动生成
31、一个不带参数的构造函数;构造函数;l显式定义了构造函数后,默认的构造函数不起显式定义了构造函数后,默认的构造函数不起作用;作用;l构造函数可以重载;构造函数可以重载;本讲稿第二十九页,共一百零八页【例【例4.5】构造函数的定义和执行过程实例程序。构造函数的定义和执行过程实例程序。#includeusingnamespacestd;classPointprivate:intx,y;public:Point();/声明不带参数的构造函数声明不带参数的构造函数Point(int,int);/声明带声明带2个参数的构造函数个参数的构造函数;Point:Point():x(0),y(0)/定义不带参数的
32、构造函数定义不带参数的构造函数coutInitializingdefaultendl;/定义带定义带2个参数的构造函数个参数的构造函数Point:Point(inta,intb):x(a),y(b)coutInitializinga,bendl;本讲稿第三十页,共一百零八页voidmain()PointA;/使用不带参数的构造函数产生对象使用不带参数的构造函数产生对象APointB(15,25);/使用带参数的构造函数产生对象使用带参数的构造函数产生对象BPointc2;/使用不带参数的构造函数产生对象数组使用不带参数的构造函数产生对象数组CPointD2=Point(5,7),Point(8
33、,12);/使用带参数使用带参数/的构造函数产生对象数组的构造函数产生对象数组D本讲稿第三十一页,共一百零八页程序输出结果如下:程序输出结果如下:InitializingdefaultInitializing15,25InitializingdefaultInitializingdefaultInitializing5,7Initializing8,12程序中和程序中和Point类同名的两个成员函数是构造函数:一个不带类同名的两个成员函数是构造函数:一个不带参数,另一个带有参数,另一个带有2个参数。个参数。本讲稿第三十二页,共一百零八页构造函数可以通过构造函数的构造函数可以通过构造函数的初始化
34、列表初始化列表给其数给其数据成员赋值据成员赋值Point:Point(inta,intb):x(a),y(b)完成完成“x=a,y=b”的功能,它与下面的方法等价:的功能,它与下面的方法等价:Point:Point(int,intb)x=a;y=b;coutInitializinga,bendl;本讲稿第三十三页,共一百零八页l构造函数在类体里的声明形式如下:构造函数在类体里的声明形式如下:类名(形参类名(形参1,形参形参2,形参形参n););/可以没有形参可以没有形参l构造函数在类体外定义。可以使用初始化列表或者在构造构造函数在类体外定义。可以使用初始化列表或者在构造函数的函数体内定义数据成
35、员的初值。假设数据成员为函数的函数体内定义数据成员的初值。假设数据成员为x1,x2,xn,则有如下两种形式:则有如下两种形式:类名类名:类名(形参类名(形参1,形参形参2,形参形参n):x1(形参形参1),x2(形参形参2),xn(形参形参n)类名类名:类名(形参类名(形参1,形参形参2,形参形参n)x1=形参形参1;x2=形参形参2;xn=形参形参n;l构造函数的参数是无顺序排列,只要保证相互的对应顺构造函数的参数是无顺序排列,只要保证相互的对应顺序即可。可使用默认参数或重载。序即可。可使用默认参数或重载。本讲稿第三十四页,共一百零八页当声明一个外部对象时,外部对象只是引用在其他当声明一个外
36、部对象时,外部对象只是引用在其他地方声明的对象,程序并不为外部对象说明调用构造函地方声明的对象,程序并不为外部对象说明调用构造函数。如果是全局对象或静态对象,在数。如果是全局对象或静态对象,在main函数执行之函数执行之前要调用它们的构造函数,使用下面的主程序演示全局前要调用它们的构造函数,使用下面的主程序演示全局对象的情况:对象的情况:【例【例4.6】使用前面定义的】使用前面定义的Point类演示全局对象的例子。类演示全局对象的例子。Pointglobal(5,7);voidmain()coutEnteringmainandexitingmain“endl;程序在进入程序在进入main函数之
37、前先构造全局对象,输出函数之前先构造全局对象,输出“Initializing5,7”。进入主函数之后输出为:。进入主函数之后输出为:Enteringmainandexitingmain。本讲稿第三十五页,共一百零八页2.自动调用构造类成员函数自动调用构造类成员函数程序员不能在程序中显式地调用构造类成员函数,这程序员不能在程序中显式地调用构造类成员函数,这类函数是自动调用的。类函数是自动调用的。Pointa.Point(x,y);错误错误Pointa(x,y);。正确。正确编译系统会自动调用编译系统会自动调用Point(x,y)产生对象产生对象a并使用并使用x和和y将其正确地初始化。将其正确地初
38、始化。也不能在产生对象也不能在产生对象a之后,使用构造函数改变对象的属之后,使用构造函数改变对象的属性值。性值。a.Point(x,y);错误;错误如果要改变对象的属性值,需要设计专门的成员如果要改变对象的属性值,需要设计专门的成员函数,如使用函数,如使用a.Setxy(x,y)改变对象的属性值。改变对象的属性值。本讲稿第三十六页,共一百零八页4.2.3构造函数和运算符构造函数和运算符new运算符运算符new用于建立生存期可控的对象并返回这个对象的指用于建立生存期可控的对象并返回这个对象的指针。使用针。使用new建立动态对象的语法和建立动态变量的情况类似,建立动态对象的语法和建立动态变量的情况
39、类似,其不同点是其不同点是new和构造函数一同起作用。和构造函数一同起作用。【例【例4.7】使用前面的】使用前面的Point类演示类演示new运算符和构造函数的关系的运算符和构造函数的关系的例子。例子。voidmain()Point*ptr1=newPoint;Point*ptr2=newPoint(5,7);deleteptr1;deleteptr2;运行这个程序,程序的输出结果是:运行这个程序,程序的输出结果是:InitializingdefaultInitializing5,7本讲稿第三十七页,共一百零八页当使用当使用new建立一个动态对象时,建立一个动态对象时,new首先分配首先分配足
40、以保存足以保存Point类的一个对象所需要的内存,然后自动调类的一个对象所需要的内存,然后自动调用构造函数来初始化这块内存,再返回这个动态对象的用构造函数来初始化这块内存,再返回这个动态对象的地址。使用地址。使用new建立的动态对象在不用时必须用建立的动态对象在不用时必须用delete删除,以便释放所占空间。删除,以便释放所占空间。本讲稿第三十八页,共一百零八页4.2.4构造函数的默认参数构造函数的默认参数如果程序定义自己的有参数构造函数,又想使用如果程序定义自己的有参数构造函数,又想使用无参数形式的构造函数,解决的方法是将相应的构造无参数形式的构造函数,解决的方法是将相应的构造函数全部使用默
41、认参数设计。函数全部使用默认参数设计。本讲稿第三十九页,共一百零八页【例【例4.8】设计构造函数的默认参数。设计构造函数的默认参数。#includeusingnamespacestd;classPointprivate:intx,y;public:Point(int=0,int=0);/声明两个参数均为默认参数声明两个参数均为默认参数;Point:Point(inta,intb):x(a),y(b)/定义构造函数定义构造函数coutInitializinga,bendl;本讲稿第四十页,共一百零八页voidmain()PointA;/构造函数产生对象构造函数产生对象APointB(15,25)
42、;/构造函数产生对象构造函数产生对象BPointc2;/构造函数产生对象数组构造函数产生对象数组C声明构造函数原型时不需要给出参数名,即使用声明构造函数原型时不需要给出参数名,即使用“int=0,int=0”。程序输出如下:。程序输出如下:Initializing0,0Initializing15,25Initializing0,0Initializing0,0本讲稿第四十一页,共一百零八页4.2.5复制构造函数复制构造函数引用在类中一个很重要的用途是用在复制构造函数中。引用在类中一个很重要的用途是用在复制构造函数中。这是一类特殊而且重要的函数,通常用于使用已有的对象这是一类特殊而且重要的函数
43、,通常用于使用已有的对象来建立一个新对象。来建立一个新对象。浅拷贝浅拷贝就是普通的数值复制。在通常情况下,编译器建立就是普通的数值复制。在通常情况下,编译器建立一个一个默认默认复制构造函数,这个复制构造函数采用浅拷贝复制构造函数,这个复制构造函数采用浅拷贝来使用已有的对象来建立新对象,所以又直译为拷贝构来使用已有的对象来建立新对象,所以又直译为拷贝构造函数。造函数。本讲稿第四十二页,共一百零八页对类对类A而言,复制而言,复制(拷贝拷贝)构造函数的原型为:构造函数的原型为:A:A(A&)首先它是一个构造函数。首先它是一个构造函数。其次,它的参数有些特别,是引用类自己的对象,即用一其次,它的参数有
44、些特别,是引用类自己的对象,即用一个已有的对象来创建一个新对象。个已有的对象来创建一个新对象。为了不改变原有对象,更普通的形式是使用为了不改变原有对象,更普通的形式是使用const限定:限定:A:A(constA&)但如果存在指针时,是简单地将两个指针指向同一地但如果存在指针时,是简单地将两个指针指向同一地址还是指向不同的存储区域?简单的赋值可能使两个指针址还是指向不同的存储区域?简单的赋值可能使两个指针指向了同一块存储区域。当一个指针销毁后,另外一个指指向了同一块存储区域。当一个指针销毁后,另外一个指针指向了无效区域,访问这个指针可能会引起严重的错误。针指向了无效区域,访问这个指针可能会引起
45、严重的错误。本讲稿第四十三页,共一百零八页为了克服这样的缺点,需要为了克服这样的缺点,需要自定义自定义复制构造函数。复制构造函数。复制构造函数的原型为:复制构造函数的原型为:Point(Point&);/复制构造函数复制构造函数它的定义如下:它的定义如下:Point:Point(Point&t)x=t.x;y=t.y;这个成员函数具有特殊的作用:在使用该类的一个对象初始化这个成员函数具有特殊的作用:在使用该类的一个对象初始化该类的另一个对象时,调用这个函数该类的另一个对象时,调用这个函数(有时又称为复制初始化构造有时又称为复制初始化构造函数函数)。例如:。例如:Pointobj1(25,52)
46、;Pointobj2(obj1);/使用使用obj1的数据成员初始化的数据成员初始化obj2,/即数据成员为即数据成员为25和和52为了安全起见,推荐使用的原型为为了安全起见,推荐使用的原型为:Point(constPoint&)本讲稿第四十四页,共一百零八页4.3析构函数析构函数在对象消失时,使用析构函数释放由构造函在对象消失时,使用析构函数释放由构造函数分配的内存。数分配的内存。本讲稿第四十五页,共一百零八页4.3.1定义析构函数定义析构函数 它也是一种特殊的成员函数,执行与构造函它也是一种特殊的成员函数,执行与构造函数相反的操作,通常数相反的操作,通常用于撤消对象时的一些清理用于撤消对象
47、时的一些清理任务任务,如释放分配给对象的内存空间等。如释放分配给对象的内存空间等。具有一些特殊的性质具有一些特殊的性质:与类名相同,但前面必须加一个波浪号与类名相同,但前面必须加一个波浪号();();没有参数,也没有返回值,而且不能重载。因此没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数在一个类中只能有一个析构函数;当撤消对象时当撤消对象时,编译系统会自动地调用析构函数。编译系统会自动地调用析构函数。如果不显式定义,系统自动生成一个空的析构如果不显式定义,系统自动生成一个空的析构 函数函数本讲稿第四十六页,共一百零八页例如:例如:Point:Point()coutDes
48、tructorisactiveendl;使用下面的测试程序说明析构函数的作用:使用下面的测试程序说明析构函数的作用:voidmain()PointA(5,68);coutExitingmainendl;执行此程序,其输出是:执行此程序,其输出是:Initializing5,68/调用构造函数调用构造函数Exitingmain/主程序输出主程序输出Destructorisactive/自动调用析构函数自动调用析构函数当对象的生存期结束时,程序为这个对象调用析构函数,然后回收当对象的生存期结束时,程序为这个对象调用析构函数,然后回收这个对象占用的内存。这个对象占用的内存。全局对象和静态对象的析构函
49、数在程序运行结束之前调用。全局对象和静态对象的析构函数在程序运行结束之前调用。全局对象数组和静态对象数组的析构函数在程序结束之前被调用。全局对象数组和静态对象数组的析构函数在程序结束之前被调用。数组的每个元素调用一次析构函数。数组的每个元素调用一次析构函数。本讲稿第四十七页,共一百零八页4.3.2析构函数和运算符析构函数和运算符delete运算符运算符delete与析构函数一起工作。当使用运算符与析构函数一起工作。当使用运算符delete删除一个动态对象时,它首先为这个动态对象调用删除一个动态对象时,它首先为这个动态对象调用析构函数,然后再释放这个动态对象占用的内存,这和使析构函数,然后再释放
50、这个动态对象占用的内存,这和使用用new建立动态对象的过程正好相反。建立动态对象的过程正好相反。【例【例4.9】使用】使用Point类演示建立和释放一个动态对象数类演示建立和释放一个动态对象数组的例子。组的例子。#includeusingnamespacestd;classPointprivate:intx,y;本讲稿第四十八页,共一百零八页public:Point(int=0,int=0);/声明两个参数均为默认参数声明两个参数均为默认参数Point();/声明析构函数声明析构函数;Point:Point(inta,intb):x(a),y(b)/定义构造函数定义构造函数coutInitia