1、第第9章章 关于类和对象的进一步说明关于类和对象的进一步说明9.1 构造函数构造函数n问题:前面是用成员函数来对对象中的数据成问题:前面是用成员函数来对对象中的数据成员赋初值的,如果对一个类定义了多个对象,员赋初值的,如果对一个类定义了多个对象,那么,程序就显得非常复杂烦琐。另外,类声那么,程序就显得非常复杂烦琐。另外,类声明中,也无法对对象的各数据成员赋值。明中,也无法对对象的各数据成员赋值。n解决方法:用构造函数对对象中的数据成员赋解决方法:用构造函数对对象中的数据成员赋初值。初值。class Time int num=0;char name=ab;char sex=f;class Stu
2、dent private:int num;char name20;char sex;public:void set()cinnumnamesex;void display()coutnum:numendl;coutname:nameendl;coutsex:sexhour;cinminute;cinsec;void Time show_time()couthour:minute:secendl;Time Time()hour=0;minute=0;sec=0;#include using namespace std;class Timepublic:Time();void set_time()
3、;void show_time();private:int hour;int minute;int sec;10 25 54 10:25:54 0:0:0对构造函数的说明对构造函数的说明(1)构造函数的定义可以写在类内,也可以在类外。构造函数的定义可以写在类内,也可以在类外。如果定义写在类外,则必须在类内声明构造函数如果定义写在类外,则必须在类内声明构造函数的原型,而且类外定义时要指明其所属的类。的原型,而且类外定义时要指明其所属的类。(2)在建立对象时系统自动执行构造函数,进行初在建立对象时系统自动执行构造函数,进行初始化,对各数据成员赋初值。始化,对各数据成员赋初值。(3)构造函数不需用户
4、调用,也不能被用户调用。构造函数不需用户调用,也不能被用户调用。它是由系统自动调用。它是由系统自动调用。(4)构造函数没有返回值,不能在定义构造函数时构造函数没有返回值,不能在定义构造函数时声明类型。(不能加声明类型。(不能加void)(5)在构造函数的函数体中不仅可以对数据成员在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其他语句。但是一般不赋初值,而且可以包含其他语句。但是一般不提倡在构造函数中加入与初始化无关的内容,提倡在构造函数中加入与初始化无关的内容,以保持程序的清晰。以保持程序的清晰。(6)如果用户自己没有定义构造函数,则如果用户自己没有定义构造函数,则C+系系统会自动
5、生成一个构造函数,只是这个构造函统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始数的函数体是空的,也没有参数,不执行初始化操作。化操作。9.1.3 带参数的构造函数带参数的构造函数前面的方法使每个对象都有同一初值,有时用户前面的方法使每个对象都有同一初值,有时用户希望对不同的对象赋予不同的值,可采用带参数希望对不同的对象赋予不同的值,可采用带参数的构造函数。的构造函数。构造函数首部格式:构造函数首部格式:构造函数名构造函数名(类型类型 1 形参形参1,类型,类型2 形参形参2,)定义对象的格式:定义对象的格式:类名类名 对象名对象名(实参实参1,实参,实参2,)
6、;在建立对象时,将实参数据传给构造函数的形参。在建立对象时,将实参数据传给构造函数的形参。例例9.2 9.2 有两个长方柱,其长、宽、高分别为:有两个长方柱,其长、宽、高分别为:(1)12,20,25(1)12,20,25;(2)10,14,20(2)10,14,20。求它们的体积。编一个基于对象的程序,在类中用。求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数。带参数的构造函数。#include using namespace std;class Boxpublic:Box(int,int,int);int volume();private:int height;int widt
7、h;int length;int main()Box box1(12,25,30);coutbox1.volume()endl;Box box2(15,30,21);coutbox2.volume()endl;return 0;int Box volume()return(height*width*length);90009450Box Box(int h,int w,int len)height=h;width=w;length=len;#include using namespace std;class Boxpublic:Box Box(int h,int w,int len):heig
8、ht(h),width(w),length(len)int volume();private:int height;int width;int length;int main()Box box1(12,25,30);coutbox1.volume()endl;Box box2(15,30,21);coutbox2.volume()endl;return 0;int Box volume()return(height*width*length);可以用参数初始化表对数据成员初始化可以用参数初始化表对数据成员初始化Box Box(int h,int w,int len)height=h;width
9、=w;length=len;9.1.5 构造函数的重载构造函数的重载n在一个类中可以定义多个构造函数,以便对类在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法,供用户选用。对象提供不同的初始化的方法,供用户选用。这些构造函数具有相同的名字,而参数的个数这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。这称为构造函数的重载。或参数的类型不相同。这称为构造函数的重载。当有多个构造函数时,调用哪一个构造函数由当有多个构造函数时,调用哪一个构造函数由系统根据实参来决定。系统根据实参来决定。#include using namespace std;class Boxpubli
10、c:Box();Box(int h,int w,int len):height(h),width(w),length(len)int volume();private:int height;int width;int length;Box Box()height=10;width=10;length=10;int main()Box box1;coutbox1.volume()endl;Box box2(15,30,25);coutbox2.volume()endl;return 0;int Box volume()return(height*width*length);100011250n说
11、明:说明:(1)调用构造函数时不必给出实参的构造函数,)调用构造函数时不必给出实参的构造函数,称为默认构造函数。显然,无参的构造函数属称为默认构造函数。显然,无参的构造函数属于默认构造函数。一个类只能有一个默认构造于默认构造函数。一个类只能有一个默认构造函数。函数。(2)尽管在一个类中可以包含多个构造函数,)尽管在一个类中可以包含多个构造函数,但是对于每一个对象来说,建立对象时只执行但是对于每一个对象来说,建立对象时只执行其中一个构造函数。其中一个构造函数。9.1.6 使用默认参数的构造函数使用默认参数的构造函数n构造函数中参数的值既可以通过实参传递,也构造函数中参数的值既可以通过实参传递,也
12、可以指定为某些默认值,即如果用户不指定实可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。参值,编译系统就使形参取默认值。#include using namespace std;class Boxpublic:Box(int h=10,int w=10,int len=10);int volume();private:int height;int width;int length;Box Box(int h,int w,int len)height=h;width=w;length=len;int Box volume()return(height*width*leng
13、th);int main()Box box1;coutbox1.volume()endl;Box box2(15);coutbox2.volume()endl;Box box3(15,30);coutbox3.volume()endl;Box box4(15,30,20);coutbox4.volume()endl;return 0;1000150045009000n说明:说明:(1)应该在声明构造函数时指定默认值,而不能应该在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。只在定义构造函数时指定默认值。(2)声明构造函数时,形参名可以省略。声明构造函数时,形参名可以省略。(3)
14、如果构造函数的全部参数都指定了默认值,如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参,也可则在定义对象时可以给一个或几个实参,也可以不给出实参。以不给出实参。(4)在一个类中定义了全部是默认参数的构造函在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。否则会出现数后,不能再定义重载构造函数。否则会出现歧义性。歧义性。9.2 析构函数析构函数n析构函数也是一个特殊的成员函数,它的作用与构造析构函数也是一个特殊的成员函数,它的作用与构造函数相反,它的名字是类名的前面加一个函数相反,它的名字是类名的前面加一个“”符号。符号。当对象的生命期结束时,会自动执行
15、析构函数。当对象的生命期结束时,会自动执行析构函数。n析构函数的作用并不是删除对象,而是在撤销对象占析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。被程序分配给新对象使用。n析构函数不返回任何值,没有函数类型,也没有函数析构函数不返回任何值,没有函数类型,也没有函数参数。因此它不能被重载。一个类可以有多个构造函参数。因此它不能被重载。一个类可以有多个构造函数,但只能有一个析构函数。数,但只能有一个析构函数。n实际上,析构函数的作用并不仅限于释放资源方面,实际上,析构函数的作用并不仅
16、限于释放资源方面,它还可以被用来执行它还可以被用来执行“用户希望在最后一次使用对象用户希望在最后一次使用对象之后所执行的任何操作之后所执行的任何操作”n如果用户没有定义析构函数,编译系统会自动如果用户没有定义析构函数,编译系统会自动生成一个析构函数,但该函数是一个空函数,生成一个析构函数,但该函数是一个空函数,什么操作都不进行。什么操作都不进行。#include#includeusing namespace std;class Student public:student(int n,string nam,char s)num=n;name=nam;sex=s;cout调用构造函数调用构造函数
17、.endl;Student()cout调用调用num析构函析构函数数.endl;void display()coutnumendl;coutnameendl;coutsexendl;private:int num;char name10;char sex;int main()Student stud1(10010,Wang_li,f);stud1.display();Student stud2(10011,Zhang_fun,m);stud2.display();return 0;调用构造函数调用构造函数10010 name:Wang_lisex:f调用构造函数调用构造函数10011 name
18、:Zhang_funsex:m调用调用10011析构函数析构函数调用调用10010析构函数析构函数9.3 调用构造函数和析构函数的顺序调用构造函数和析构函数的顺序n一般原则:一般原则:先构造的后析构,后构造的先析构。先构造的后析构,后构造的先析构。n并不是在任何情况下都是按这一原则处理的。对并不是在任何情况下都是按这一原则处理的。对象可以在不同的作用域中定义,可以有不同的存象可以在不同的作用域中定义,可以有不同的存储类别。这些会影响调用构造函数和析构函数的储类别。这些会影响调用构造函数和析构函数的时机。时机。9.4 对象数组对象数组n对象数组是指数组的每个元素都是同类的对象。对象数组是指数组的
19、每个元素都是同类的对象。假设已声明了假设已声明了Student类,定义类,定义stud数组,有数组,有50个元素:个元素:Student stud50;n在建立数组时,同样要调用构造函数。如果有在建立数组时,同样要调用构造函数。如果有50个个元素,需要调用元素,需要调用50次构造函数。次构造函数。n如果构造函数只有一个参数,在定义数组时可以直如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供实参。如:接在等号后面的花括号内提供实参。如:Student stud3=60,70,78;9.4 对象数组对象数组n如果构造函数有多个参数,定义对象数组时,在花如果构造函数有多个参数,
20、定义对象数组时,在花括号中分别写出构造函数并指定实参。括号中分别写出构造函数并指定实参。n在建立对象数组时,分别调用构造函数,对每个元在建立对象数组时,分别调用构造函数,对每个元素初始化。每一个元素的实参分别用括号包起来,素初始化。每一个元素的实参分别用括号包起来,对应构造函数的一组形参,不会混淆。对应构造函数的一组形参,不会混淆。Student stud3=Student(1001,18,87),Student(1002,19,76),Student(1003,18,72)例例9.6 9.6 对象数组的使用方法。对象数组的使用方法。#include using namespace std;c
21、lass Boxpublic:Box(int h=10,int w=12,int len=15):height(h),width(w),length(len)int volume();private:int height;int width;int length;int Box volume()return(height*width*length);int main()Box a3=Box(10,12,15),Box(15,18,20),Box(16,20,26);cout“a0体积体积:”a0.volume()endl;cout“a1体积体积:”a1.volume()endl;cout“a2
22、体积体积:”a2.volume()hourt1.hour(*pt).showtime()pt-showtime()t1.showtime()9.5.2 指向对象成员的指针指向对象成员的指针对象中的各成员也有地址。对象中的各成员也有地址。(1)指向对象数据成员的指针)指向对象数据成员的指针定义指向对象数据成员的指针变量的方法和定义定义指向对象数据成员的指针变量的方法和定义指向普通变量的指针变量方法相同。指向普通变量的指针变量方法相同。int*p1;p1=&t1.hour;cout*p1endl;(2)指向对象成员函数的指针)指向对象成员函数的指针n定义指向公用成员函数的指针变量的一般形式为:定义
23、指向公用成员函数的指针变量的一般形式为:返回值类型返回值类型(类名类名 *指针变量名指针变量名)(参数表列参数表列);为指针变量赋值的形式是:为指针变量赋值的形式是:指针变量名指针变量名=&类名类名 成员函数名成员函数名;访问指针变量所指向的函数形式是:访问指针变量所指向的函数形式是:(对象名对象名.*指针变量名指针变量名)(参数表列参数表列);#include using namespace std;class Timepublic:Time(int,int,int);int hour;int minute;int sec;void get_time();Time Time(int h,in
24、t m,int s)hour=h;minute=m;sec=s;void Time get_time()couthour”:”minute”:”secendl;int main()Time t1(10,13,56);int*p1=&t1.hour;cout*p1get_time();void(Time *p3)();p3=&Time get_time;(t1.*p3)();1010:13:5610:13:5610:13:569.5.3 this指针指针n 每个对象中的数据成员都分别占有存储空间,如每个对象中的数据成员都分别占有存储空间,如果对同一个类定义了果对同一个类定义了n个对象,则有个对象
25、,则有n组同样大小组同样大小的空间以存放的空间以存放n个对象中的数据成员。但是,不同个对象中的数据成员。但是,不同对象都调用同一个函数代码段。对象都调用同一个函数代码段。n问题:当不同对象的成员函数引用数据成员时,问题:当不同对象的成员函数引用数据成员时,怎么能保证引用的是所指定的对象的数据成员呢?怎么能保证引用的是所指定的对象的数据成员呢?解决方法:解决方法:this指针指针n在每一个成员函数中都包含一个特殊的指针,这在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,称为个指针的名字是固定的,称为this。它的值是当前。它的值是当前被调用的成员函数所在的对象的起始地址。被调用的
26、成员函数所在的对象的起始地址。int Box volume()return(height*width*length);int Box volume()return(this-height*this-width*this-length);假设假设a是是box类对象类对象当执行当执行a.volume()时,时,this=&aint Box volume()return(a.height*a.width*a.length);9.6 共用数据的保护共用数据的保护9.6.1 常对象常对象n在定义对象时指定对象为常对象。常对象必须要在定义对象时指定对象为常对象。常对象必须要有初值,如:有初值,如:Time
27、 const t1(12,34,46);这样,对象这样,对象t1中的所有数据成员的值都不能被修中的所有数据成员的值都不能被修改。改。n定义常对象的一般形式为定义常对象的一般形式为类名类名 const 对象名对象名(实参表列实参表列);const 类名类名 对象名对象名(实参表列实参表列);9.6.2 常对象成员常对象成员n可以将对象的成员声明为可以将对象的成员声明为const,包括常数据,包括常数据成员和常成员函数。成员和常成员函数。n常数据成员常数据成员:用关键字用关键字const来声明常数据成来声明常数据成员。常数据成员的值是不能改变的。只能通过员。常数据成员的值是不能改变的。只能通过构造
28、函数的参数初始化表对常数据成员进行初构造函数的参数初始化表对常数据成员进行初始化。始化。n常对象的数据成员都是常数据成员常对象的数据成员都是常数据成员,因此常对,因此常对象的构造函数只能用参数初始化表对常数据成象的构造函数只能用参数初始化表对常数据成员进行初始化。员进行初始化。const int hour;/声明声明hour为常数据成员为常数据成员Time Time(int h):hour(h)常成员函数常成员函数n将成员函数声明为常成员函数:将成员函数声明为常成员函数:void get_time()const;/注意注意const的位置在函数名和括号之后的位置在函数名和括号之后nconst是
29、函数类型的一部分,是函数类型的一部分,在声明函数和定义函在声明函数和定义函数时都要有该关键字,在调用时不必加数时都要有该关键字,在调用时不必加const。n常成员函数常成员函数可以引用可以引用const数据成员,也可以引用数据成员,也可以引用非非const的数据成员。但是都的数据成员。但是都不能修改它们。nconst数据成员可以被数据成员可以被const成员函数引用,也可成员函数引用,也可以被非以被非const的成员函数引用。的成员函数引用。n常对象中的成员函数不一定都是常成员函数常对象中的成员函数不一定都是常成员函数。常对。常对象只保证其数据成员是常数据成员。象只保证其数据成员是常数据成员。
30、怎样利用常成员函数呢?怎样利用常成员函数呢?n(1)如果在一个类中,有些数据成员的值允许改变,如果在一个类中,有些数据成员的值允许改变,另一些数据成员的值不允许改变,则可以将一部分数另一些数据成员的值不允许改变,则可以将一部分数据成员声明为据成员声明为const,以保证其值不被改变,可以用,以保证其值不被改变,可以用非非const的成员函数引用这些数据成员的值,并修改的成员函数引用这些数据成员的值,并修改非非const数据成员的值。数据成员的值。n(2)如果要求所有的数据成员的值都不允许改变,则如果要求所有的数据成员的值都不允许改变,则可以将所有的数据成员声明为可以将所有的数据成员声明为con
31、st,或将对象声明,或将对象声明为为const(常对象常对象),然后用,然后用const成员函数引用数据成成员函数引用数据成员,这样起到员,这样起到“双保险双保险”的作用,切实保证了数据成的作用,切实保证了数据成员不被修改。员不被修改。n(3)如果已定义了一个常对象,则只能调用其中的如果已定义了一个常对象,则只能调用其中的const成员函数,而不能调用非成员函数,而不能调用非const成员函数成员函数(不论这些函数不论这些函数是否会修改对象中的数据是否会修改对象中的数据)。这是为了保证数据的安全。这是为了保证数据的安全。n(4)当希望在调用函数时对象的值不被修改,就应当把形当希望在调用函数时对
32、象的值不被修改,就应当把形参定义为指向常对象的指针变量,同时用对象的地址作参定义为指向常对象的指针变量,同时用对象的地址作实参实参(对象可以是对象可以是const或非或非const型型)。如果要求该对象。如果要求该对象不仅在调用函数过程中不被改变,而且要求它在程序执不仅在调用函数过程中不被改变,而且要求它在程序执行过程中都不改变,则应把它定义为行过程中都不改变,则应把它定义为const型。型。9.6.3 指向对象的常指针指向对象的常指针n将指针变量声明为将指针变量声明为const型,这样指针值始终型,这样指针值始终保持为其初值,不能改变。如保持为其初值,不能改变。如注意:注意:指向对象的常指针
33、变量的值不能改变,指向对象的常指针变量的值不能改变,但可以改变其所指向对象但可以改变其所指向对象(如如t1)的值。的值。定义指向对象的常指针的一般形式为定义指向对象的常指针的一般形式为 类名类名*const 指针变量名;指针变量名;Time t1(10,12,15),t2;/定义对象定义对象Time*const ptr1;/const位置在指针变量名前面,规定位置在指针变量名前面,规定ptr1的值是常值的值是常值ptr1=&t1;/ptr1指向对象指向对象t1,此后不能再改变指向,此后不能再改变指向ptr1=&t2;/错误错误,ptr1不能改变指向不能改变指向9.6.4 指向常对象的指针变量指
34、向常对象的指针变量n定义指向常对象的指针变量的一般形式为定义指向常对象的指针变量的一般形式为 const 类型名类型名*指针变量名;指针变量名;例:例:const Time*ptr;说明说明ptr指向的指向的Time类对象是常对象,不能通过类对象是常对象,不能通过ptr来改变其值。来改变其值。注意:注意:(1)如果一个对象已被声明为常对象,只能用指向常对象的指如果一个对象已被声明为常对象,只能用指向常对象的指针变量指向它,而不能用一般的针变量指向它,而不能用一般的(指向非指向非const型对象的型对象的)指针变量指针变量去指向它。去指向它。(2)如果定义了一个指向常对象的指针变量,并使它指向一
35、个非如果定义了一个指向常对象的指针变量,并使它指向一个非const的对象,则其指向的对象是不能通过指针来改变的。的对象,则其指向的对象是不能通过指针来改变的。(3)如果定义了一个指向常对象的指针变量,是不能通过它改变如果定义了一个指向常对象的指针变量,是不能通过它改变所指向的对象的值的,但是指针变量本身的值是可以改变的。所指向的对象的值的,但是指针变量本身的值是可以改变的。9.6.5 对象的常引用对象的常引用n例例9.8 对象的常引用。对象的常引用。#include using namespace std;class Timepublic:Time(int,int,int);int hour;
36、int minute;int sec;Time Time(int h,int m,int s)hour=h;minute=m;sec=s;void fun(Time&t)/形参形参t是是Time类对象的引用类对象的引用 t.hour=18;int main()Time t1(10,13,56);fun(t1);coutt1.hourendl;return 0;以上程序修改了以上程序修改了t1的的hour成员成员的值。如果不希望在函数中修改的值。如果不希望在函数中修改实参实参t1的值,可以把引用变量的值,可以把引用变量t声明为声明为const(常引用常引用),函数原型函数原型为:为:void f
37、un(const Time&t);n在在C+面向对象程序设计中,经常用常指针和常引用作面向对象程序设计中,经常用常指针和常引用作函数参数。这样既能保证数据安全,使数据不能被随意函数参数。这样既能保证数据安全,使数据不能被随意修改。修改。形式形式含义含义Time const t1;t1是常对象,其值在任何情况下是常对象,其值在任何情况下都不能改变都不能改变void Time fun()constfun是是Time类中的常成员函数,类中的常成员函数,可以引用,但不能修改本类中的可以引用,但不能修改本类中的数据成员数据成员Time*const p;p是指向是指向Time对象的常指针,对象的常指针,p
38、的值的值(即即p的指向的指向)不能改变不能改变const Time*p;p是指向是指向Time类常对象的指针,类常对象的指针,其指向的类对象的值不能通过指其指向的类对象的值不能通过指针来改变针来改变9.7 对象的动态建立和释放对象的动态建立和释放n用前面介绍的方法定义的对象是静态的,在程用前面介绍的方法定义的对象是静态的,在程序运行过程中,对象所占的空间是不能随时释序运行过程中,对象所占的空间是不能随时释放的。但有时人们希望在需要用到对象时才建放的。但有时人们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用
39、。这样可它所占的内存空间以供别的数据使用。这样可提高内存空间的利用率。提高内存空间的利用率。n可以用可以用new运算符动态建立对象,用运算符动态建立对象,用delete运运算符撤销对象。算符撤销对象。n如果已经定义了一个如果已经定义了一个Box类,可以用下面的方法动类,可以用下面的方法动态地建立一个对象:态地建立一个对象:new boxn用用new运算符动态地分配内存后,将返回新对象的运算符动态地分配内存后,将返回新对象的起始地址。起始地址。n在程序中就可以通过在程序中就可以通过pt访问这个新建的对象。如访问这个新建的对象。如 Box*pt;/定义一个指向定义一个指向Box类对象的指针变量类对
40、象的指针变量 pt=new Box;/在在pt中存放了新建对象的起始地址中存放了新建对象的起始地址coutheight;/输出对象的输出对象的height成员成员coutvolume();/调用对象的调用对象的volume函数求体积函数求体积n允许在执行允许在执行new时,对新建立的对象进行初始化。时,对新建立的对象进行初始化。n不再需要使用由不再需要使用由new建立的对象时,可以用建立的对象时,可以用delete运算符予以释放。运算符予以释放。n在执行在执行delete运算符时,在释放内存空间之前,运算符时,在释放内存空间之前,自动调用析构函数自动调用析构函数,完成有关善后清理工作。,完成有
41、关善后清理工作。Box*pt=new Box(12,15,18);delete pt;/释放释放pt指向的内存空间指向的内存空间9.8 对象的赋值和复制对象的赋值和复制9.8.1 对象的赋值对象的赋值n如果对一个类定义了两个或多个对象,则这些如果对一个类定义了两个或多个对象,则这些同类的对象之间可以互相赋值同类的对象之间可以互相赋值,或者说,一个,或者说,一个对象的值可以赋给另一个同类的对象。这里所对象的值可以赋给另一个同类的对象。这里所指的对象的值是指对象中所有数据成员的值。指的对象的值是指对象中所有数据成员的值。n对象之间的赋值也是通过赋值运算符对象之间的赋值也是通过赋值运算符“=”进进行
42、的。对象赋值的一般形式为:行的。对象赋值的一般形式为:对象名对象名1=对象名对象名2;#include using namespace std;class Boxpublic:Box(int h=10,int w=10,int len=10);int volume();private:int height;int width;int length;Box Box(int h,int w,int len)height=h;width=w;length=len;int Box volume()return(height*width*length);int main()Box box1(15,30,
43、25),box2;coutbox1.volume()endl;box2=box1;coutbox2.volume()endl;return 0;1125011250对象的赋值只对其中的数据成员赋值,对象的赋值只对其中的数据成员赋值,而不对成员函数赋值。而不对成员函数赋值。9.8.2 对象的复制对象的复制例如:例如:Box box2(box1);作用是用已有的对象作用是用已有的对象box1去克隆出一个新对象去克隆出一个新对象box2。对象复制的一般形式为:对象复制的一般形式为:类名类名 对象对象2(对象对象1);用对象用对象1复制出对象复制出对象2。这实际上也是建立对象的语句,。这实际上也是建立
44、对象的语句,建立对象建立对象2。C+还提供另一种方便用户的复制形式,用赋值号代括还提供另一种方便用户的复制形式,用赋值号代括号,其形式是:号,其形式是:类名类名 对象名对象名1=对象名对象名2;如:如:Box box2=box1,box3=box1;n对象的赋值与复制的区别:对象的赋值与复制的区别:对象的赋值是对一个已经存在的对象赋值,因对象的赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。此必须先定义被赋值的对象,才能进行赋值。而对象的复制则是从无到有地建立一个新对象,而对象的复制则是从无到有地建立一个新对象,并使它与一个已有的对象完全相同并使它与一个已有的对象完全
45、相同(包括对象包括对象的结构和成员的值的结构和成员的值)。9.9 静态成员静态成员n在在c+中,可以将关键字中,可以将关键字static用于类的某成员,用于类的某成员,这样该成员就成为静态成员了。这样该成员就成为静态成员了。n静态成员包括:静态数据成员、静态成员函数。静态成员包括:静态数据成员、静态成员函数。一旦把类的某成员声明为静态,则无论这个类创一旦把类的某成员声明为静态,则无论这个类创建多少个对象都只有静态成员的一个拷贝,即静建多少个对象都只有静态成员的一个拷贝,即静态成员被类的所有对象共享。态成员被类的所有对象共享。9.9.1 静态数据成员静态数据成员class Boxpublic:i
46、nt volume();private:static int height;int width;int length;height为静态数据成员为静态数据成员,它为各对象所共有。即使有多个它为各对象所共有。即使有多个box对象,对象,height在内存中只占一份空间(而不是每个在内存中只占一份空间(而不是每个对象都分别为它保留一份空间)。对象都分别为它保留一份空间)。height的值对所有对的值对所有对象都是一样的,如果改变它的值,则各对象象都是一样的,如果改变它的值,则各对象height的值的值都同时改变了。都同时改变了。#include using namespace std;class
47、Boxpublic:Box(int,int);int volume();static int height;int width;int length;Box Box(int w,int len)width=w;length=len;int Box volume()return(height*width*length);int Box height=10;int main()Box a(15,20),b(20,30);couta.heightendl;coutb.heightendl;coutBox heightendl;couta.volume()endl;return 0;(1)(1)在一个
48、类中可以有一个或多个静态数在一个类中可以有一个或多个静态数据成员。静态数据成员不属于某一个对象,据成员。静态数据成员不属于某一个对象,在为对象所分配的空间中不包括静态数据在为对象所分配的空间中不包括静态数据成员所占的空间。静态数据成员是在所有成员所占的空间。静态数据成员是在所有对象之外单独开辟空间。只要在类中定义对象之外单独开辟空间。只要在类中定义了静态数据成员,即使不定义对象,也为了静态数据成员,即使不定义对象,也为静态数据成员分配空间。静态数据成员分配空间。(2)(2)静态数据成员可以初始化,但只能在静态数据成员可以初始化,但只能在类体外进行初始化。形式为:类体外进行初始化。形式为:数据类
49、型类名数据类型类名静态数据成员名静态数据成员名=初值;初值;(3)(3)静态数据成员既可以通过对象名引用,静态数据成员既可以通过对象名引用,也可以通过类名来引用。也可以通过类名来引用。(4)(4)静态数据成员是在程序编译时被分配静态数据成员是在程序编译时被分配空间的,到程序结束时才释放空间。空间的,到程序结束时才释放空间。n如果静态数据成员被定义为私有的,则不能在如果静态数据成员被定义为私有的,则不能在类外直接引用,而必须通过公用的成员函数引类外直接引用,而必须通过公用的成员函数引用。用。#include using namespace std;class Objcountprivate:in
50、t count;public:Objcount()count=0;void total()count+;int get()return count;int main()Objcount a1;a1.total();couta1.get()endl;Objcount a2;a2.total();couta2.get()endl;Objcount a3;a3.total();couta3.get()endl;return 0;111#include using namespace std;class Objcountprivate:static int count;public:Objcount(