《谭浩强C程序设计第四版.ppt》由会员分享,可在线阅读,更多相关《谭浩强C程序设计第四版.ppt(103页珍藏版)》请在金锄头文库上搜索。
1、第第7 7章章 类与对象类与对象 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象第第7 7章章 类与对象类与对象 1. 掌握类的定义,会根据需求设计类;2. 会根据类创建各种对象;3. 掌握对象的各种成员的使用方法; 4. 会设计构造函数与拷贝构造函数来初始化对象;理解其调用过程与顺序;5. 理解浅拷贝与深拷贝的概念;6. 掌握动态对象以及动态对象数组的建立与释放。7. 理解类的静态成员的概念;8. 理解友元函数与友元类的概念;9. 掌握常对象与常成员的使用;10.了解对象在内存中的分布情况。学习目标 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.1 类与对
2、象类与对象 在在面面向向过过程程的的结结构构化化程程序序设设计计中中,程程序序模模块块是是由由函函数数构构成成,函函数数将将对对数数据据处处理理的的语语句句放放在在函函数数体体内内,完完成成特特定定的的功功能,数据则通过函数参数传递进入函数体。能,数据则通过函数参数传递进入函数体。 在在面面向向对对象象的的程程序序设设计计中中,程程序序模模块块是是由由类类构构成成的的。类类是是对对逻逻辑辑上上相相关关的的函函数数与与数数据据的的封封装装,它它是是对对问问题题的的抽抽象象描描述。述。 面面向向对对象象的的程程序序设设计计方方法法就就是是运运用用面面向向对对象象的的观观点点来来对对现现实实世世界界
3、中中的的各各种种问问题题进进行行抽抽象象,然然后后用用计计算算机机程程序序来来描描述述并解决该问题,这种描述和处理是通过类与对象实现的。并解决该问题,这种描述和处理是通过类与对象实现的。 类类与与对象对象是是C+程序设计中最重要的概念程序设计中最重要的概念 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 每一个实体都是对象每一个实体都是对象,每个对象都属于一个特定每个对象都属于一个特定的类型。的类型。 在在C+中对象的类型称为类中对象的类型称为类(class)。类代表了类代表了某一批对象的共性和特征。类是对象的抽象,而对某一批对象的共性和特征。类是对象的抽象,而对象是类的具体实
4、例象是类的具体实例(instance)。正如同结构体类型正如同结构体类型和结构体变量的关系一样,人们先声明一个结构体和结构体变量的关系一样,人们先声明一个结构体类型,然后用它去定义结构体变量。同一个结构体类型,然后用它去定义结构体变量。同一个结构体类型可以定义出多个不同的结构体变量。类型可以定义出多个不同的结构体变量。结构体类型:结构体类型: struct Student int num;char name20;char sex;Student stud1,stud2; 类类:class Student int num; char name20; char sex; void display(
5、 ) coutnum:numendl; coutname:nameendl; coutsex:sexendl; ;Student stud1,stud2【例例7-1】 模拟时钟模拟时钟 分析:不管什么样的时钟分析:不管什么样的时钟, 也不管各种时钟是也不管各种时钟是如何运行的如何运行的, 它都具有时、分、秒它都具有时、分、秒3个属性。除了个属性。除了运行、显示时间的基本功能外,还有设置运行、显示时间的基本功能外,还有设置(调整调整)时时间、设置闹钟等功能。将时钟的这些属性与功能抽间、设置闹钟等功能。将时钟的这些属性与功能抽象出来,分别给出面向过程的程序与面向对象的程象出来,分别给出面向过程的程
6、序与面向对象的程序来实现对时钟的模拟。序来实现对时钟的模拟。 思考:二者有何不同?思考:二者有何不同?C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象* p7_1_b.cpp * 面向对象的时钟程序 */#include using namespace std;class Clock private: int H,M,S; public: void SetTime(int h,int m,int s) H=(h=0&h=0&m=0&s60)?s:0; void ShowTime() coutH:M:Sendl; ;void main(void) Clock MyClock; My
7、Clock.ShowTime(); MyClock.SetTime(8,30,30); MyClock.ShowTime();/* p7_1_a.cpp * 面向过程的时钟程序 */#include using namespace std;struct Clock int H,M,S;Clock MyClock;void SetTime(int H,int M,int S) MyClock.H=(H=0&H=0&M=0&S60)?S:0;void ShowTime() coutMyClock.H:; coutMyClock.M:; coutMyClock.Sendl;void main(voi
8、d) ShowTime();SetTime(8,30,30); ShowTime();123456789101112131415161718192021222324252627时钟程序时钟程序B时钟程序时钟程序A运行结果运行结果运行结果运行结果:0:0:0 -85893460:-85893460:-58934600:0:0 -85893460:-85893460:-58934608:30:30 8:30:30 8:30:308:30:30 F程序解释程序解释: :通过对上述两种方案的程序进行简单的观察,可以发现它们存在下面几点不同: 在程序A中,时钟数据用一个结构型的变量存储,对时钟数据的存取
9、通过函数实现。由于存 储时钟数据的是一个全局变量,在任何地方都可见,可以不通过函数单独存取时钟数据。 程序B中,只能通过类提供的函数操作时钟。 程序A中,数据与对数据操作相互独立,数据作为参数传递给函数。程序B中,数据与对数 据的操作构成一个整体。 程序A与程序B运行的初始结果不同。这是因为在程序A中,变量是全局的;在程序B中, 对 象(变量)MyClock是函数main()中的局部对象。全局变量与局部变量在没有初始化时,取初 值方式不同,这样造成了运行结果不同。将第23行移出main()外,使之变成全局对象后, 两程序结果完全相同。 在程序B中发现,一个以class开头的类似结构体的结构,将
10、时钟的数据与对数据进行处理 的函数包括在一起,这就是用C+实现的类。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.1.2 类的定义类的定义 class 类名 public: 公有数据成员或公有函数成员的定义; protected: 保护数据成员或保护函数成员的定义; private: 私有数据成员或私有函数成员的定义;; F说明说明: : 关键字class表明定义的是一个类; 类名是类的名称,应是一个合法的标识符; public、protected、private为存取控制属性存取控制属性(访问权限),用来控制对类的 成员的存取。如果前面没有标明访问权限,默认访问权限为默
11、认访问权限为privateprivate。 类的成员有数据成员与函数成员两类,类的数据成员和函数成员统称为类的 成员,类的数据成员数据成员一般用来描述该类对象的属性,称为属性属性;函数成员是描 述类行为,称作方法。函数成员由函数构成,这些作为类成员的函数因此也 叫成员函数成员函数。 简单讲,类是一个包含函数的结构体。因此,类的定义与结构类型的定义相似,其格式如下: C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.1.2 类的定义类的定义 例如:例7-1中定义了一个时钟类Clock。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 在在C+中也是先声明一个类类型
12、,然后用它去定义若干中也是先声明一个类类型,然后用它去定义若干个同类型的对象。对象就是类类型的一个变量。可以说类是个同类型的对象。对象就是类类型的一个变量。可以说类是对象的模板,是用来定义对象的一种抽象类型。对象的模板,是用来定义对象的一种抽象类型。 类是抽象的,不占用内存,而对象是具体的,占用存储类是抽象的,不占用内存,而对象是具体的,占用存储空间。在一开始时弄清对象和类的关系是十分重要的。空间。在一开始时弄清对象和类的关系是十分重要的。 类是用户自己指定的类型。如果程序中要用到类类型,类是用户自己指定的类型。如果程序中要用到类类型,必须自己根据需要进行声明,或者使用别人已设计好的类。必须自
13、己根据需要进行声明,或者使用别人已设计好的类。C+标准本身并不提供现成的类的名称、结构和内容。标准本身并不提供现成的类的名称、结构和内容。 在在C+中声明一个类类型和声明一个结构体类型是相似中声明一个类类型和声明一个结构体类型是相似的。的。1. 数据成员数据成员 类定义中的数据成员描述了类定义中的数据成员描述了类对象所包含的数据类型类对象所包含的数据类型,数据成员的类型可以是数据成员的类型可以是C+基本数据类型,也可以是构造数基本数据类型,也可以是构造数据类型。据类型。struct Record char name20; int score;class Team private: int nu
14、m; /基本数据类型 Record *p; /构造数据类型; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象class Team; /已定义的类已定义的类class Grade Team a; / 使用了已定义的类类型使用了已定义的类类型Grade *p; / 使用正在定义的类类型定义指针成员使用正在定义的类类型定义指针成员Grade &r; / 使用正在定义的类类型定义引用成员使用正在定义的类类型定义引用成员 Grade b; / 错误错误! 使用了未定义完的类使用了未定义完的类Record 定义变量定义变量; F注意注意: : 因为类只是一种类型,类中的数据成员不占内存空间
15、,因此在定义数据成员 时不能给数据成员赋初值。 类的数据成员除了可以使用前面讲述的C+类型外,还可以使用已定义完整的 类类型。 在正在定义的类中,由于该类型没有定义完整,所以不能定义该类类型的变 量,只能定义该类类型的指针成员以及该类类型的引用成员。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象2. 成员函数成员函数 作为类成员的成员函数描述了对类中的数据成员实施的操作。成员函数的定义、声明格式与非成员函数(全局函数)的格式相同。成员函数可以放在类中定义,也可以放在类外。放在类中定义的成员函数为内联(inline)函数。 Clock类中的成员函数就是放在类内定义的。 C+可以
16、在类内声明成员函数的原型,在类外定义函数体。这样做的好处是相当于在类内列了一个函数功能表,使我们对类的成员函数的功能一目了然,避免了在各个函数实现的大堆代码中查找函数的定义。在类中声明函数原型的方法与一般函数原型的声明一样,在类外定义函数体的格式如下: :是类的作用域分辨符作用域分辨符,用在此处,放在类名后成员函数前,表明后面的成员函数属于前面的那个类。返回值类型 类名 : 成员函数名(形参表) 函数体;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象Clock类中的成员函数可以在类中声明在类中声明:class Clock private: int H,M,S; public:
17、void SetTime(int h,int m,int s); /声明成员函数 void ShowTime(); /声明成员函数 ; 在类外实现在类外实现成员函数如下:void Clock:SetTime(int h,int m,int s) H=h,M=m,S=s; ; void Clock: ShowTime() coutH:M:Sendl; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 如果要将类外定义的成员函数编译成内联函数,可以在类外定义函数时,函数的返回类型前加上inline; 下面将ShowTime()定义成内联函数,与在类内定义成员函数的效果相同。inlin
18、e void Clock:ShowTime() coutH:M:S=0&h=0&m=0&s=0&h=0&m=0&s60)?s:0; 定义对象Clock MyClock;时,调用Clock(), 而Clock类没有Clock()函数,因而出错。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.2.2 析构函数析构函数 自然界万物都是有生有灭,程序中的对象也是一样。对象在定义时诞生,不同生存期的对象在不同的时期消失。在对象要消失时,通常有一些善后工作需要做, 例如:构造对象时,通过构造函数动态申请了一些内存单元,在对象消失之前就要释放这些内存单元。C+用什么来保证这些善后清除工作
19、的执行呢?答案是:析构函数析构函数。 析构函数析构函数(destructor)也译作拆构函数, 是在对象消失之前的瞬间自动调用的函数, 其形式是:构造函数名(类名)前加上一个逻辑非运算符,以示与构造函数相反。析构函数与构造函数的作用几乎正好相反,相当于“逆构造函数逆构造函数”。析构函数也是类的一个特殊的公有函数成员特殊的公有函数成员, C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 构造函数名构造函数名();();7.2.2 析构函数析构函数析构函数具有以下特点:析构函数没有任何参数,不能被重载不能被重载,但可以是虚函数但可以是虚函数,一个类只有一个类只有一个析构函数。一个析构
20、函数。析构函数没有返回值没有返回值。析构函数名与类名相同,但在类名前加上一个逻辑非运算符“”,以示与构造函数对比区别。析构函数一般由用户自己定义,在对象消失时由系统自动调用在对象消失时由系统自动调用,如果用户没有定义析构函数,系统将自动生成一个不做任何事的默认析构函数。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象F注意注意: :在对象消失时的清理工作并不是由析构函数完成,而是靠用户在析构函数中添加清理语句完成。 123456789101112131415/* p7_2.cpp * 构造函数与析构函数 */#include using namespace std;class C
21、lock private: int H,M,S; public: Clock(int h=0,int m=0,int s=0) H=h,M=m,S=s;coutconstructor:H:M:Sendl; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象161718192021222324252627 Clock() coutdestructor:H:M:Sendl; ;Clock C1(8,0,0);Clock C2(9,0,0);void main(void) Clock C3(10,0,0);Clock C4(11,0,0);运行结果运行结果运行结果运行结果:constru
22、ctor:8:0:0constructor:9:0:0constructor:10:0:0constructor:11:0:0destructor:11:0:0destructor:10:0:0 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象1234567891011121314151617181920 /* p7_3.cpp * 基本的字符串类 */#include using namespace std;class String private: char *Str; int len;public: void ShowStr() coutstring:Str,length:
23、lenendl; String()len=0;Str=NULL;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象21222324252627282930313233343536373839404142 String(const char *p) len=strlen(p);Str=new charlen+1;strcpy(Str,p); String() if (Str!=NULL) delete Str; Str=NULL; ;void main(void) char s=ABCDE;String s1(s);String s2(123456);s1.ShowStr();s2.
24、ShowStr(); 运行结果运行结果运行结果运行结果:string:ABCDE, length:5string:123456, length:6 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.2.3 拷贝构造函数拷贝构造函数 拷贝构造函数拷贝构造函数是与类名相同,形参是本类的对象的引用的函数,在用已存在对象初始化新建立对象时调用。 类的拷贝构造函数一般由用户定义,如果用户没有定义拷贝构造函数,系统就会自动生成一个默认函数,这个默认拷贝构造函数的功能是把初始值对象的每个数据成员的值依次复制到新建立的对象中。因此,也可以说是完成了同类对象的克隆(Clone)。这样得到的对象和
25、原对象具有完全相同的数据成员,即完全相同的属性。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 用户可以也可以根据实际问题的需要根据实际问题的需要定义特定的拷贝构造函数来改变缺省拷贝构造函数的行为,以实现同类对象之间数据成员的传递。如果用户自定义了拷贝构造函数,则在用一个类的对象初始化该类的另外一个对象时,自动调用自动调用自定义的拷贝构造函数。 定义一个拷贝构造函数的一般形式为: 拷贝构造函数在用类的一个对象去初始化该类的另一个对象时调用,以下三种情况相当于用一个已存在的对象去初始化新建立的对象, 此时, 调用拷贝构造函数: 当用类的一个对象去初始化该类的另一个对象时。 如果
26、函数的形参是类的对象,调用函数时,将对象作为函数实参传递给函数的形参时。 如果函数的返回值是类的对象,函数执行完成,将返回值返回时。类名(类名& & 对象名) ;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象12345678910111213141516171819/* p7_4.cpp * 构造拷贝构造函数 */#include using namespace std;class Clock private: int H,M,S; public: Clock(int h=0,int m=0,int s=0) H=h,M=m,S=s;coutconstructor:H:M:Se
27、ndl; Clock() coutdestructor:H:M:Sendl; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象20212223242526272829303132333435363738394041424344 Clock(Clock & p) coutcopy constructor,before call: H:M:Sendl; H=p.H; M=p.M; S=p.S; void ShowTime() coutH:M:S”运算符访问公有数对象指针名-数据成员名例如: Clock *Cp; Clock C1(8,0,0); Clock *Cp; Cp=&C1;
28、Cp-ShowTime();C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 类名 *对象指针名; 对象指针名-数据成员名 或: 对象指针名-成员函数名(参数表) 在C+中,对象指针可以作为成员函数的形参,一般而言,使用对象指针作为函数的参数要比使用对象作为函数的参数更普遍一些,因为使用对象指针作为函数的参数有如下两点好处:(1) 实现地址传递。实现地址传递。 通过在函数调用时将实参对象的地址传递给形参指针对象,使形参指针对象和实参对象指向同一内存地址,这样,对象指针所指向对象的改变也将同样影响着实参对象,从而实现信息的双向传递。(2) 使用对象指针效率高使用对象指针效率高 使用
29、对象指针传递的仅仅是对应实参对象的地址,并不需要实现对象之间的副本拷贝,这样就会减小时空开销,提高运行效率。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象123456789101112131415161718/* p7_6.cpp * 带时间加法的时钟类 */#include using namespace std;class Clock private: int H,M,S; public: void SetTime(int h,int m,int s) H=h,M=m,S=s; void ShowTime() coutH:M:SH+H+(Cp-M+M+(Cp-S+S)/60
30、)/60)%24; M=(Cp-M+M+(Cp-S+S)/60)%60; S=(Cp-S+S)%60;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象函数重载函数原型声明对象指针373839404142434445464748495051525354555657 void Clock:TimeAdd(int h,int m,int s) H=(h+H+(m+M+(s+S)/60)/60)%24; M=(m+M+(s+S)/60)%60; S=(s+S)%60;void Clock:TimeAdd(int s) H=(H+(M+(S+s)/60)/60)%24; M=(M+(S+s
31、)/60)%60; S=(S+s)%60;void main() Clock C1; Clock C2(8,20,20); C1.TimeAdd(4000); C1.ShowTime(); C2.TimeAdd(&C1); C2.ShowTime(); 运行结果运行结果运行结果运行结果:1:6:409:27:0 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象函数重载函数重载7.3.2 对象引用对象引用 对象引用对象引用就是对某类对象定义一个引用,其实质是通过将被引用对象的地址赋给引用对象,使二者指向同一内同一内存空间存空间,这样引用对象就成为了被引用对象的“别名别名”。 对象引
32、用的定义方法与基本数据类型变量引用的定义是一样的。定义一个对象引用,并同时指向一个对象的格式为: 类名 & & 对象引用名=被引用对象; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象F注意注意: :对象引用与被引用对象必须是同类型的。除非是作为函数参数与函数返回值,对象引用在定义时必须要初始化。定义一个对象引用并没有定义一个对象,所以不分配任何内存空间,不调用构造函数。对象引用的使用格式为: 例如: Clock C1(8,20,20); Clock & Cr=C1; /定义了C1的对象引用Cr。 Cr.ShowTime(); /通过对象引用使用对象的成员运行结果为: 8:20
33、:20C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.3.2 对象引用对象引用 对象引用名 . 数据成员名 或: 对象引用名 . 成员函数名(参数表)对象引用的优点: 对象引用通常用作函数的参数,它不仅具有对象指针的优点具有对象指针的优点,而且比对象指针更简洁,更方便,更直观比对象指针更简洁,更方便,更直观。将p7_6.cpp中添加如下函数: void Clock:TimeAdd(Clock & Cr) H=(Cr.H+H+(Cr.M+M+(Cr.S+S)/60)/60)%24;M=(Cr.M+M+(Cr.S+S)/60)%60; S=(Cr.S+S)%60; 将C2.Tim
34、eAdd(&C1); 替换为:C2.TimeAdd(C1); 运行结果与p7_6.cpp一样。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.3.2 对象引用对象引用 对象数组对象数组是以对象为元素的数组。对象数组的定义、赋值、引用与普通数组一样,只是数组元素与普通数组的数组元素不同。 对象数组定义格式如下: 其中,类名指出该数组元素所属的类,常量表达式给出某一维元素的个数。 与结构数组不同,对象数组初始化需要使用构造函数完成,以一个大小为n的一维数组一维数组为例,对象数组的初始化初始化格式如下:C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.3.3 对象数
35、组对象数组类名类名 对象数组名常量表达式n,., 常量表达式2常量表达式1; 数组名n= 构造函数(数据成员1初值,数据成员2初值,), 构造函数(数据成员1初值,数据成员2初值,), 构造函数(数据成员1初值,数据成员2初值,);F注意:注意:不带初始化表的对象数组,其初始化靠调用不带参数的构造函数完成。 以一个m维数组为例,对象数组元素的存取格式如下: C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 对象数组名下标表达式1 下标表达式2下标表达式m.数据成员名或: 对象数组名下标表达式1 下标表达式2下标表达式m.成员函数名(参数表) 【例例7-7】 计算一个班学生某门功课
36、的总评成绩。 分析分析: 首先设计一个类Score,这个类的数据成员为一个学生的学号、姓名、平时成绩、期末考试成绩,成员函数有求总评成绩、显示成绩。然后,定义一个对象数组对象数组存储一个班学生的成绩。最后,通过逐一调用数组元素的成员函数求每个学生的总评成绩。 123456789101112131415161718192021/* p7_7.cpp * 求一个班学生某门功课的总评成绩 */#includeusing namespace std;const int MaxN=100;const double Rate=0.6; /平时成绩比例class Score private:long No;
37、 /学号char *Name; /姓名int Peace; /平时成绩int Final; /期末考试成绩int Total; /总评成绩public: Score(long=0,char* = NULL,int=0,int=0,int=0); /构造函数void Count(); /计算总评成绩void ShowScore(); /显示成绩;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象22232425262728293031323334353637 Score:Score(long no,char *name,int peace,int final,int total) /
38、构造函数 No=no; Name=name; Peace=peace; Final=final; Total=total;void Score:Count() Total=Peace*Rate+Final*(1-Rate)+0.5;void Score:ShowScore() coutNotNametPeacetFinaltTotalendl;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象38394041424344454647484950void main() Score ClassScore13; Score ClassScore23=Score(200607001,Tom
39、,80,79), Score(200607002,John,90,85), Score(200607003,Wilson,70,55); for(int i=0;i3;i+) ClassScore2i.Count(); for(i=0;iShowTime(); /结果为0:0:0 Cp=new Clock(8,0,0); /建立动态对象,调用构造函数Clock(int,int,int) Cp-ShowTime(); /结果为8:0:0C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.3.4 动态对象动态对象F注意注意: : 函数体内的局部对象在函数调用时建立,在函数调用完后消失
40、;全局对象则在程序执行时建立,执行完成后才消失;这些对象在何时建立,何时消失是C+规定好了的,不是编程者能控制的。 在堆中建立的动态对象不能自动消失,需要使用delete语句删除对象,格式为: 在删除动态对象时,释放堆中的内存空间,在对象消失时,调用析构函数。 例如: delete Cp; /删除Cp指向的动态对象 动态对象的一个重要的使用方面是用动态对象组成动态对象数组,建立一个一维动态对象数组的格式为:删除一个动态对象数组的格式为: 在建立动态对象数组时,要调用构造函数,调用的次数与数组的大小相同;删除对象数组时,要调用析构函数,调用次数与数组的大小相同。 C+语语言言程程序序设设计计教教
41、程程第第7章章类类与与对对象象 delete 对象指针; 对象指针 = newnew 类名数组大小; delete 对象指针;将p7_7.cpp改为用动态对象数组实现如下:C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.3.4 动态对象动态对象 Score:SetScore(long no,char *name,int peace,int final,int total) No=no; Name=name; Peace=peace; Final=final; Total=total; 将p7_7.cpp改为用动态对象数组实现如下:C+语语言言程程序序设设计计教教程程第第7章章
42、类类与与对对象象SetScore()函数为动态数组设置初值。void main() Score * ClassScore; ClassScore=new Score 3; ClassScore0.SetScore(200607001,Tom,80,79), ClassScore1.SetScore(200607002,John,90,85), ClassScore2.SetScore(200607003,Wilson,70,55); for(int i=0;i3;i+) ClassScorei.Count(); for(i=0;iH=h, this-M=m, this-S=s; (* this
43、).H=h, (* this).M=m, (* this).S=s;/ 语句3、4、5是等效的为了与类的数据成员H、M、S区别,将SetTime的形参名设为h、m、s。如果使用this指针,就可以凭this指针区分本对象的数据成员与其他变量。 系统利用this指针明确指出成员函数当前操作的数据成员所属的对象。实际上,当一个对象调用其成员函数时,编译器先将该对象的地址赋给this指针,然后调用成员函数,这样成员函数对对象的数据成员进行操作时,就隐含隐含使用了this指针。 一般而言,通常不直接使用不直接使用this指针来引用对象成员,但在某些少数情况下,可以使用this指针,如:重载某些运算符以
44、实现对象的连续赋值等。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象1234/使用this指针重新设计重新设计的SetTime()成员函数如下: void Clock:SetTime (int H, int M, int S) this-H=H, this-M=M, this-S=S;F注意注意: :this指针不是调用对象的名称,而是指向调用对象的指针的名称。this的值不能改变,它总是指向当前调用对象。 7.3.6 对象组合对象组合 组合概念体现的是一种包含与被包含的关系,在语义上表现为“is part of”的关系,即在逻辑上A是B的一部分 。 在C+程序设计中,类的组合
45、用来描述一类复杂的对象,在类的定义中,它的某些属性,往往是另一个类的对象,而不是像整型、浮点型之类的简单数据类型,也就是“一个类内嵌其它类的对象作为成员”,将对象嵌入到类中的这样一种描述复杂类的方法,我们称之为“类的组合”,一个含有其他类对象的类称为组合类组合类,组合类的对象称为组合对象组合对象。 组合类定义的步骤为:先先定义成员类,再再定义组合类。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.3.6 对象组合对象组合【例例7-8】 计算某次火车的旅途时间。 分析分析:某次火车有车次、起点站、终点站、出发时间、到达时间。前面定义的Clock类正具有时间特性,因此,可以利用
46、Clock对象组合成一个火车旅途类TrainTrip。假定火车均为24小时内到达,旅途时间为到达时间减出发时间。 用空方框表示类,灰框表示对象,组合类可以表示为空框包含灰框。设计TrainTrip类的示意图与成员构成图如图7-4: C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象1234567891011121314151617181920/* p7_8.cpp * 计算火车旅途时间的组合类 */#include using namespace std;class Clock private: int H,M,S; public: void ShowTime() coutH:M:
47、SH=H, this-M=M, this-S=S; Clock(int H=0,int M=0,int S=0) this-H=H, this-M=M, this-S=S; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象Clock类232425262728293031323334353637383940int GetH() return H; int GetM() return M; int GetS() return S; ;class TrainTrip private: char *TrainNo; /车次 Clock StartTime; /出发时间 Clock End
48、Time; /到达时间public: TrainTrip(char * TrainNo, Clock S, Clock E) this-TrainNo=TrainNo; StartTime=S; EndTime=E; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象组合类4142434445464748495051525354555657585960 Clock TripTime() int tH,tM,tS; /临时存储小时、分、秒数 int carry=0; /借位 Clock tTime; /临时存储时间 (tS=EndTime.GetS()-StartTime.GetS(
49、)0?carry=0:tS+=60,carry=1; (tM=EndTime.GetM()-StartTime.GetM()-carry)0?carry=0:tM+=60,carry=1; (tH=EndTime.GetH()-StartTime.GetH()-carry)0?carry=0:tH+=24; tTime.SetTime(tH,tM,tS); return tTime; ;void main() Clock C1(8,10,10), C2(6,1,2); /定义Clock类的对象 Clock C3; /定义Clock类对象,存储结果 TrainTrip T1(K16,C1,C2)
50、; /定义TrainTrip对象 C3=T1.TripTime(); C3.ShowTime(); 运行结果运行结果运行结果运行结果:21:50:52 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象组合对象及其初始化 C+为组合对象提供了初始化机制:在定义组合类的构造函数,可以携带初始化表,其格式如下 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象组合类名(形参表):成员对象1(子形参表1),成员对象2(子形参表2), 成员对象初始化表 建立对象时,调用组合类的构造函数;在调用组合类的构造函数时,先调用各个成员对象的构造函数,成员对象的初值从初始化列表中取得。这
51、样,实际上是通过成员类的构造函数对成员对象进行初始化,初始化值在初始化表中提供。 为组合类定义了带初始化表的构造函数后,在建立组合对象同时为对象提供初值的格式如下:类名 对象名(实参表); C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象成员对象初始化表 123456789101112131415/使用初始化列表,将p7_8.cpp修改成p7_8a.cpp其中的构造函数修改如下: TrainTrip(char * TrainNo, int SH,int SM, int SS, int EH, int EM,int ES): EndTime(EH,EM,ES), StartTime
52、(SH,SM,SS) this-TrainNo=TrainNo; /定义组合对象的程序修改如下: void main() Clock C3; /定义Clock类对象,存储结果 TrainTrip T1(K16,8,10,10,6,1,2); /定义TrainTrip对象 C3=T1.TripTime(); C3.ShowTime(); F注意注意: : 初始化列表既不能决定是否调用成员对象的构造函数,也不能决定调用构造函数的顺序,成员对象调用顺序由成员对象定义的顺序决定。初始化列表只是提供调用成员对象构造函数的参数组合对象的构造函数组合对象的构造函数: 在定义一个组合类的对象时,不仅它自身的构
53、造函数将被调用,而且还将调用其成员对象的构造函数,调用先后顺序为: 成员对象按照在其组合类的声明中出现的次序,依次调用各自的构造函数, 而不是按初始化列表中的顺序。如果建立组合类的成员对象时没有指定对象的初始值,则自动调用默认的构造函数。 组合类对象调用组合类构造函数。 调用析构函数,析构函数的调用顺序与构造函数正好相反。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.4 静态成员静态成员 一个类对象的一个类对象的public成员可被本类的其他对象存取,即成员可被本类的其他对象存取,即可供所有对象使用,但是此类的每个对象都各自拥有一份,可供所有对象使用,但是此类的每个对象都
54、各自拥有一份,不存在真正意义上的不存在真正意义上的共享成员共享成员。所以,。所以,C+提供了静态成员,提供了静态成员,用以解决同一个类的不同对象之间数据成员和函数的用以解决同一个类的不同对象之间数据成员和函数的共享共享问问题。题。 静态成员的特点是:不管这个类创建了多少个对象,静态成员的特点是:不管这个类创建了多少个对象,其静态成员在内存中其静态成员在内存中只保留一份拷贝只保留一份拷贝,这个拷贝为该类的所,这个拷贝为该类的所有对象所共享。有对象所共享。 类的静态成员有两种:类的静态成员有两种:静态数据成员静态数据成员和和静态函数成员静态函数成员,下面分别对它们进行讨论下面分别对它们进行讨论 C
55、+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.4.1 静态数据成员静态数据成员静态数据成员:静态数据成员: 是类的数据成员的一种特例,采用static关键字来定义,属于类属性,每个类只有一个拷贝,由该类的所有对象共同维护和使用,从而实现了同类的不同对象之间的数据共享。 面向对象方法中还有类属性类属性(class attribute)的概念,类属性是描述类的所有对象的共同特征的一个数据项,对于任何对象实例,它的属性值是相同的,C+通过静态数据成员来实现类属性。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.4.1 静态数据成员静态数据成员 静态数据成员的定义分
56、为两个必不可少的部分:类内声静态数据成员的定义分为两个必不可少的部分:类内声明、类外初始化。明、类外初始化。 在类内,声明静态数据成员的格式为在类内,声明静态数据成员的格式为 :C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 数据类型 类名:静态数据成员名=初始值; static 数据类型 静态数据成员名; 在类外初始化的形式为:在类外初始化的形式为: 除了在初始化时可以在类外通过类对静态成员赋初值除了在初始化时可以在类外通过类对静态成员赋初值外,其他情况下对静态成员的存取规则与一般成员相同。外,其他情况下对静态成员的存取规则与一般成员相同。即:在类内可以任意存取;在类外,通过
57、对象只能访问即:在类内可以任意存取;在类外,通过对象只能访问存取属性为存取属性为public的成员。的成员。 7.4.1 静态数据成员静态数据成员C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象F对静态数据成员的定义与使用应注意对静态数据成员的定义与使用应注意 :静态数据成员的访问属性同普通数据成员一样,可以为public、private和protected。静态数据成员脱离具体对象而独立存在,其存储空间是独立分配的,不是任何对象存储空间的一部分,但逻辑上所有的对象都共享这一存储单元,所以对静态数据成员的任何操作都将影响共享这一存储单元的所有对象。静态数据成员是一种特殊的数据成员
58、,它表示类属性,而不是某个对象单独的属性,它在程序开始产生,在程序结束时消失。静态数据成员具有静态生存期。由于在类的定义中仅仅是对静态数据成员进行了引用性声明,因此必须在文件作用域的某个地方对静态数据成员进行定义并初始化,即应在类体外对静态数据成员进行初始化(静态数据成员的初始化与它的访问控制权限无关)。静态数据成员初始化时前面不加static关键字,以免与一般静态变量或对象混淆。由于静态数据成员是类的成员,因此在初始化时必须使用类作用域运算符:限定它所属的类。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象12345678class Student private: char
59、 *Name; int No; static int countS; ; /在类外对静态成员初始化如下:int Student:countS=0;例如: 我们对某学校不同学生的特性进行抽象,找出共性设计一个学生类Student,如果需要统计学生的总人数,可以在类外定义一个全局变量。但是类外的全局变量不受类存取控制的保护。因此可以将学生人数定义为静态成员,即学生类的类属性, 设计的Student类如下 :F注意注意: : 对静态数据成员的访问还可以通过类的成员函数来进行。 7.4.1 静态数据成员静态数据成员7.4.1 静态数据成员静态数据成员静态数据成员:静态数据成员: 是类的数据成员的一种特
60、例,采用static关键字来定义,属于类属性,每个类只有一个拷贝,由该类的所有对象共同维护和使用,从而实现了同类的不同对象之间的数据共享。 面向对象方法中还有类属性类属性(class attribute)的概念,类属性是描述类的所有对象的共同特征的一个数据项,对于任何对象实例,它的属性值是相同的,C+通过静态数据成员来实现类属性。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.4.2 静态成员函数静态成员函数 静态数据成员为类属性,在定义类后、建立对象前就存在。因此,在建立对象前不能通过成员函数存取静态数据成员。C+提供了静态成员函数,用来存取类的静态成员。 静态成员函数是用
61、关键字static声明的成员函数,它属于整个类而不属于类中的某个对象,是该类的所有对象共享的成员函数。 静态成员函数可以在类体内定义。也可以在类内声明为static,在类外定义。当在类外定义时,不能再使用static关键字作为前缀。 静态函数成员的调用形式有如下两种: (1) 通过类名调用静态成员函数; (2) 通过对象调用静态成员函数 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.4.1 静态数据成员静态数据成员 (1) 通过类名调用静态成员函数 静态函数成员为类的全体对象而不是部分对象服务,与类相联系而不与类的对象联系,因此访问静态函数成员时,可以直接使用类名。格式如下
62、:C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 对象. 静态成员函数 类名:静态成员函数; (2) 通过对象调用静态成员函数,格式为 :F注意注意: : 通过类名访问静态成员函数受静态成员函数访问权限的控制。 7.4.2 静态成员函数静态成员函数C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象F通过对象调用静态成员函数应注意:通过对象调用静态成员函数应注意: 通过对象访问静态成员函数的前提条件为对象已经建立。静态成员函数的访问权限同普通成员函数一样。静态成员函数也可以省略参数、使用默认形参值、以及进行重载。静态成员函数与普通成员函数在使用还有如下区别:由于静态成
63、员函数在类中只有一个拷贝(副本),因此它访问对象的成员时要受到一些限制:静态成员函数可以直接访问类中说明的静态成员,但不能直接访问类中的非静态成员;若要访问非静态成员时,必须通过参数传递的方式得到相应的对象,再通过对象来访问。由于静态成员是独立于类对象而存在的,因此静态成员没有this指针。 12345678910111213141516/* p7_9.cpp * 含有对象计数器的学生类 */#include using namespace std;class Student private: char *Name; int No; static int countS; public: sta
64、tic int GetCount() return countS; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象【例例7-9】 使用静态成员维护内存中Student类对象的个数(对象计数器)。 分析分析:为了维护内存中Student类对象的个数,除了定义一个静态数据成员存储类对象个数外,还要在所有可能建立对象、删除对象的场合记载对对象个数的修改。 静态数据成员静态成员函数1718192021222324252627282930313233343536 Student(char* =, int=0); Student(Student &); Student();Student:
65、Student(char * Name, int No) this-Name=new char strlen(Name)+1; strcpy(this-Name, Name); this-No=No; +countS; coutconstructing:Nameendl;Student:Student(Student & r) Name=new char strlen(r.Name)+1; strcpy(Name, r.Name); No=r.No; +countS; coutcopy constructing:r.Nameendl;C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象
66、象静态数据成员373839404142434445464748495051525354555657 Student:Student() coutdestructing:Nameendl; delete Name; -countS; int Student:countS=0;void main() coutStudent:GetCount()endl; /使用类调用静态成员函数 Student s1(Antony); /建立一个新对象 couts1.GetCount()endl; /通过对象调用静态成员函数 Student s2(s1); /利用已有对象建立一个新对象 couts1.GetCou
67、nt()endl; Student S32; /建立一个对象数组 coutStudent:GetCount()endl; Student *s4=new Student3; /建立一动态对象数组 coutStudent:GetCount()endl; delete s4; /删除动态对象数组 coutStudent:GetCount()endl; 运行结果运行结果运行结果运行结果:0constructing:Antony1copy constructing:Antony2constructing:constructing:4constructing:constructing:construct
68、ing:7destructing:destructing:destructing:4destructing:destructing:destructing:Antonydestructing:Antony C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.5 友元友元 数据隐藏给不同类和对象的成员函数之间,类的成员函数和类外的一般函数之间进行属性共享带来障碍,必须寻求一种方法使得类外的对象能够访问类中的私有成员,提高程序的效率。 为了解决这个问题,C+提出了使用友元友元作为实现这一要求的辅助手段。 友元不是类的成员,
69、但它可以访问类的任何成员(包括私有成员)。声明为友元的外界对象既可以是另一个类的成员函数,也可以是不属于任何类的一般的函数,称之为友元函数友元函数;友元也可以是整个的一个类,称之为友元类友元类。7.5.1 友元函数友元函数 友元函数友元函数是在类定义中由关键字friend修饰的非成员函数。其格式为 :C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 friend 返回类型 函数名(形参表) /函数体 注意注意: :友元函数的定义与成员函数一样,只是在类中用关键字friend予以说明。但友元函数是一个普通的函数,它不是本类的成员函数,因此在调用时不能通过对象调用。友元函数也可以在类
70、内声明,在类外定义。友元函数对类成员的存取与成员函数一样,可以直接存取类的任何存取控制属性的成员;可通过对象存取形参、函数体中该类类型对象的所有成员。private、protected、public访问权限与友员函数的声明无关,因此原则上,友元函数声明可以放在类体中任意部分,但为程序清晰,一般放在类体的后面。 1234567891011121314/* p7_10.cpp * 计算火车旅途时间的友元函数 */#include using namespace std;class Clock private: int H,M,S; public: void ShowTime() coutH:M:S
71、H=H, this-M=M, this-S=S; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象【例7-10】 使用友元函数计算某次火车的旅途时间。分析:为了简化问题,分别用两个Clock类对象表示某次火车出发时间、到达时间。假定火车均为24小时内到达,旅途时间为到达时间减出发时间。 1718192021222324252627282930313233 Clock(int H=0,int M=0,int S=0) this-H=H, this-M=M, this-S=S; friend Clock TripTime(Clock & StartTime, Clock & EndT
72、ime); ;Clock TripTime(Clock & StartTime, Clock & EndTime) int tH,tM,tS; /临时存储小时、分、秒数 int carry=0; /借位 Clock tTime; /临时存储时间 (tS=EndTime.S-StartTime.S)0?carry=0:tS=+60,carry=1; (tM=EndTime.M-StartTime.M-carry)0?carry=0:tM+=60,carry=1; (tH=EndTime.H-StartTime.H-carry)0?carry=0:tH+=24; tTime.SetTime(tH,
73、tM,tS); return tTime; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象友元函数34353637383940void main()Clock C1(8,10,10), C2(6,1,2); /定义Clock类的对象Clock C3; /定义Clock类对象,存储结果 C3=TripTime(C1,C2);C3.ShowTime(); C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象运行结果运行结果运行结果运行结果:21:50:5221:50:52 F说明说明: :在本例中,在Clock类体中设计了一个友元函数TripTime(), 它不是类的成员
74、函 数。但是,可以看到友元函数中通过对象名StartTime和EndTime直接访问了它 们的的私有数据 成员StartTime.H、StartTime.M、StartTime.S,这就是友元的关键所在。使用友元成员的好处是两个类可以某种方式相互合作、协同工作,共同完成某 一任务。 7.5.2 友元类友元类 友元除可以是函数外,还可以是类,如果一个类声明为另一个类的友元,则该类称为另一个类的友元类友元类。 若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的任何数据成员。 友元类的声明是在类名之前加上关键字friend来实现。声明A类为B类的友员类的格式如下: C+语
75、语言言程程序序设设计计教教程程第第7章章类类与与对对象象 class Bclass B friend class A; ; F注意注意: : 在声明A类为B类的友元类时,A类必须已经存在,但是如果A类又将B类声明为自己的友员类时,又会出现B类不存在的错误。 7.5.2 友元类友元类前向引用声明:前向引用声明: 当遇到两个类相互引用的情况时,必然有一个类在定义之前就将被引用,怎么办呢? 对此,C+专门规定了前前向向引引用用声声明明用以解决这类问题,前向引用声明是在引用未定义的类之前对该类进行声明,它只是为程序引入一个代表该类的标识符,类的具体定义可以在程序的其他地方进行。C+语语言言程程序序设设
76、计计教教程程第第7章章类类与与对对象象12345678910/前向引用声明示例class B; /前向引用声明 class A /A类的定义 public: /外部接口 void funA(B b); /以B类对象b为形参的成员函数 ; class B /B类的定义 public: /外部接口 void funB(A a); /以A类对象a为形参的成员函数 ; 12345678910111213/* p7_11.cpp * 计算火车旅途时间的友元类 */#include using namespace std;class TrainTrip; /前向引用声明class Clock privat
77、e: int H,M,S; public: void ShowTime() coutH:M:SH=H, this-M=M, this-S=S; Clock(int H=0,int M=0,int S=0) this-H=H, this-M=M, this-S=S; friend class TrainTrip; ;class TrainTrip private: char *TrainNo; /车次 Clock StartTime; /出发时间 Clock EndTime; /到达时间public: TrainTrip(char * TrainNo, Clock S, Clock E) thi
78、s-TrainNo=TrainNo; StartTime=S; EndTime=E; C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象363738394041424344454647484950515253545556 Clock TripTime() int tH,tM,tS; /临时存储小时、分、秒数int carry=0; /借位Clock tTime; /临时存储时间 (tS=EndTime.S-StartTime.S)0?carry=0:tS+=60,carry=1; (tM=EndTime.M-StartTime.M-carry)0?carry=0:tM+=60,ca
79、rry=1; (tH=EndTime.H-StartTime.H-carry)0?carry=0:tH+=24; tTime.SetTime(tH,tM,tS); return tTime; ;void main() Clock C1(8,10,10), C2(6,1,2); /定义Clock类的对象Clock C3; /定义Clock类对象,存储结果TrainTrip T1(K16,C1,C2); /定义TrainTrip对象 C3=T1.TripTime();C3.ShowTime(); 运行结果运行结果运行结果运行结果:21:50:52 C+语语言言程程序序设设计计教教程程第第7章章类类
80、与与对对象象7.5.2 友元类友元类C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象F友元关系具有以下性质:友元关系具有以下性质: 友元关系是不能传递不能传递的,B类是A类的友元,C类是B类的友元,C类和A类之间,如果没有声明,就没有任何友元关系,不能进行数据共享。友元关系是单向单向的,如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据。友元概念的引入,提高了数据的共享性共享性,加强了函数与函数之间,类与类之间的相互联系,大大提高程序的效率,这是友元的优点优点,但友元也破坏了数据隐蔽和数据封装破坏了数据隐蔽和数据
81、封装,导致程序的可维护性变差,给程序的重用和扩充埋下了深深的隐患,这是友元的缺点缺点。对友元的使用必须慎重必须慎重,要具体问题具体分析,在提高效率和增加共享之间把握好一个“度”,在共享和封装之间进行恰当的折衷平衡。 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象7.6 常对象与常成员常对象与常成员 由于常量是不可改变的,因此我们将“常”广泛用在C+中用来表示不可改变的量,如前面讲的常变量。不仅变量可以定义为常变量,对象、类的成员也可以定义为“常”。在程序中,我们有时候不允许修改某些特定的对象。如果某个对象不允许被修改,则该对象称为常对常对象象。C+用关键字const来定义常对象
82、。 const也可以用来限定类的数据成员和成员函数,分别称为类的常数据成员常数据成员和常成员函数常成员函数。C+中常对象、常数据成员、常成员函数的访问和调用各有其特别之处。 常对象和常成员概念的建立,明确规定了程序中各种对象的变与不变的界线变与不变的界线,从而进一步增强了C+程序的安安全性和可控性全性和可控性。 7.6.1 常对象常对象 C+编译器对常对象(const对象)的使用是极为苛刻的,它不允许常对象调用任何类的成员函数,而且常对象一旦定义,在其生存期内不允许改变,否则将导致编译错误。 常对象定义格式如下: C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 类型 const
83、 对象名; 或 const 类型 对象名;12345678910void main( ) const Clock C1(9,9,9); /定义常对象C1 Clock const C2(10,10,10); /定义常对象C2 Clock C3(11,11,11); / C1=C3; /错误!C1为常对象, 不能被赋值 / C1.ShowTime(); /错误!C1为常对象, 不能访问非常成员函数 C3. ShowTime(); / C1.SetTime(0,0,0); /错误!C1为常对象,不能被更新! 7.6.2 常数据成员常数据成员 使用const说明的数据成员称为常数据成员。常数据成员的定
84、义与一般常变量的定义方式相同,只是它的定义必须出现在类体中。 常数据成员同样也必须进行初始化,并且不能被更新不能被更新。但常数据成员的初始化只能通过构造函数的初始化列表进行。 常数据成员定义的格式如下 :C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象 数据类型 const 数据成员名;或 const 数据类型 数据成员名;1234567891011121314151617#includeusing namespace std;class A private: const int& r; /常引用数据成员 const int a; /常数据成员 static const int
85、b; /静态常数据成员public: A(int i):a(i),r(a) /常数据成员只能通过初始化列表来获得初值 coutconstructor!endl; ; void display() couta,b,r, 通过对象引用使用对象的成员要用操作符. 。 对象数组是以对象为元素的数组,对象数组的定义、赋值、引用与普通数组一样, 建立一个对象数组,相当于建立了多个对象,因此,多次调用构造函数。对象数组 初始化需要使用构造函数完成。C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象本章小结本章小结 建立动态对象使用语句new,动态对象一定要用语句delete删除。建立动态对象数组
86、 使用语句new,删除动态对象数组使用语句delete。 this指针是一个系统预定义的指向当前对象的指针,通过this指针可以访问对象的 成员。 组合类是含有类对象的类,组合类对象称为组合对象。定义组合对象时调用构造函 数的顺序为类中成员对象定义的顺序,子对象构造时初始值通过组合类构造函数的 成员对象初始化表提供。 静态数据成员是类的数据成员,独立于类存在。在类内定义,在类外初始化。静态 成员函数属于整个类,是该类的所有对象共享的成员函数。可通过类名、对象调用 静态成员函数访问静态函数成员。 友元函数不是类的成员,但它可以访问类的任何成员。一个类的友元类可以访问该 类的任何成员。 关键字const来定义的对象称为常对象,常对象的成员不允许被修改。使用const定 义的数据成员称为常数据成员,常数据成员不能被更新。在定义时使用const关键 字修饰的成员函数称为常成员函数,用于访问类的常对象。 各类对象在内存中的分布与以及生命周期与普通变量一样变量一样,一个类的所有 对象共有该类的成员函数,独享各自的数据成 C+语语言言程程序序设设计计教教程程第第7章章类类与与对对象象