第十一讲 类与对象(二)
description
Transcript of 第十一讲 类与对象(二)
第十一讲 类与对象(二)11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
由关键字由关键字 staticstatic 修饰的类成员称为修饰的类成员称为类的类的静态成员静态成员。。
特点是不管这个类有多少个对象,特点是不管这个类有多少个对象,但其静态成员在但其静态成员在内存内存中中只有一个副只有一个副本本,这个副本被该类的全体对象共,这个副本被该类的全体对象共享。享。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
静态成员包括静态成员包括静态数据成员静态数据成员(成员变(成员变量)和量)和静态函数成员静态函数成员(成员函数)。(成员函数)。静态数据成员为该类全体对象共享。静态数据成员为该类全体对象共享。使用静态数据成员之前,必须在类说使用静态数据成员之前,必须在类说明体外对静态数据成员进行定义(明体外对静态数据成员进行定义(仅仅执行一次执行一次):):格式:格式: << 类型类型 ><>< 类名类名 >::<>::< 静态数据静态数据成员成员 >> == << 初值初值 >>当使用当使用 << 对象名对象名 >.<>.< 静态数据成员名静态数据成员名>> 时,时, << 对象名对象名 >> 和和 << 类名类名 >> 作用相作用相同同
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 1: 静态数据成员的实例#include<iostream.h> //P206class point { private: static float xcoord, ycoord; public: float getx() {return xcoord} //… }void main (void) { point p, q; //…}由于 xoord 是类 point 的静态数据成员, p 和 q 是 point 的对象,则在任何情况下 p.getx() 和 q.getx() 永远同时取相同值
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 2: 静态数据成员的实例#include<iostream.h> //P206class point { //… public: static float xcoord, ycoord; float getx() {return xcoord} //… }void main (void) { point p, q; //…}当 xoord 是公开静态数据成员时,p.getx() , q.getx() 和 point.getx() 等价。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
静态函数成员静态函数成员静态函数成员和一般函数成员的主静态函数成员和一般函数成员的主要区别是没有要区别是没有 thisthis 指针,因此通常指针,因此通常只处理类的只处理类的静态数据成员值静态数据成员值或者程或者程序的序的全局变量全局变量。。当使用静态函数成员访问类中非静当使用静态函数成员访问类中非静态成员时,必须借助态成员时,必须借助对象名对象名或者指或者指向对象的向对象的指针指针的函数参数。的函数参数。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 3: 静态函数成员的实例#include<iostream.h> //P206class point { static float xcoord, ycoord; public: static float gety(void) {return ycoord;} //… }void main (void) { point p, q; cout<<p::gety();//… }
由于 ycoord 是静态数据成员,所以 p::gety() 的执行和返回值都是确定的。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 4: 静态函数成员的实例#include<iostream.h> //P206class point { float xcoord, ycoord; public: static float gety(void) {return ycoord;} //… }void main (void) { point p, q; cout<<p::gety();//… }
由于 ycoord 不是静态数据成员,所以 p::gety() 将无确切含义。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 5: 静态函数成员的实例#include<iostream.h> //P206class point { float xcoord, ycoord; public: static float gety (point &ob) {return ob.ycoord;} //… }void main (void) { point p, q; cout<<point::gety(p);//… }
利用静态函数成员 gety() 得到点p 的 Y 轴坐标
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
使用关键字 const 修饰的类中成员被称为常量成员。常量成员包括常量数据成员和常量函数成员。常量数据成员常量数据成员在声明时不能被直接赋实值;而只能在声明类对象时,通过构造函数中的成员初始化列表来赋初值。对象初始化结束后,常量数据成员的值不能再被修改。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 6 :常量数据成员的实例class CC { int i; const int c1; // 私有常量数据成员 public: const int c2; // 公有常量数据成员 /* 成员初始化列表 c1(a),c2(b) 将实参 a 与 b 的值赋给 c1 和 c2*/ CC(int a, inb): c1(a),c2(b); i=c1; };…} 构造函数
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
/* 在类说明体外说明 CC 类对象 */CC cobj(4,7);cobj 的 3 个数据成员cobj.c1 4 ( 不可改变 )cobj.c2 7 ( 不可改变 ,可在类外被引用 )cobj.i 4 ( 私有数据成员,只能被类本身的成员函数改变 )
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
常量函数成员常量函数成员说明格式如下:< 类型说明符 >< 函数名 >( 参数表 ) const;const 是函数类型的一部分。此外,在该函数的实现部分也要加 const关键字。常量函数成员只能读取相应对象的内容,但不能修改。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 7 :常量函数成员的实例class CC { //P228 int me; public: int readme() const {return me;} // 常量函数成员 void writeme (int i) {me=i;} … };若常量函数成员中出现对该对象的任何写入或者修改将对系统检查视作出错。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
常量函数成员的作用当函数体规模较大,结构较复杂时为避免出现成员函数对对象内容进行错误修改,通常会将成员函数声明为常量函数成员,这就是使用常量函数成员的主要作用。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
友元概念为 C++ 语言所特有,一般在类说明体中出现,使用关键字 friend 。(1) 当 friend 出现在函数说明语句之前,则该函数是该类的友元函数。(2) 当 friend 出现在类名 B(位于类A的说明体中 ) 之前,则类 B是类 A的友元类。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 8: 友元函数和友元类的实例。 class A { … friend int f (int a);// 友元函数 … friend class B; // 友元类 …};
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
友元函数不能理解为类的函数成员;友元函数定义既可以在类说明体内,也可以类说明体之外。友元函数虽不是类的函数成员,当有权访问和调用类的所有私有成员和保护成员。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
友元函数和一般成员函数的区别友元函数必须在参数表中显式地列出参与运算的全部运算分量 ( 如类对象 ) 。友元函数的调用不通过类对象。成员函数总是以当前调用者对象为隐式的第一运算分量,当运算涉及的运算对象多于一个时,才在参数表中显式地列出。成员函数调用时必须通过类对象。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
友元类在类 A中说明的友元类 B:B可能是和 A无关的一个类。B要在 A的类说明体之外说明。B的任意函数成员都有权访问和调用 A的所有数据成员。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
友元类具有“单方向”和“不传递”等特点。单方向 : 若 claA具有友元类 claB,并不意味着 claB也具有友元类 claA。不传递 : 若 claA具有友元类 claB, claB具有友元类 claC ,并不意味着从 claC 可以直接存取claA的私有成员。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
友元的作用封闭和隐藏是面向对象程序设计的主要特征, C++ 语言也应具有这些特征。C++ 语言使用友元在局部打破封装和隐藏特性。友元概念类似于 goto语句,不宜多用。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 9: 复数类 complex 中的友元函数。 (P230-231)通过定义友元函数 addCom 和 outCom 来操作类 complex 的私有数据成员。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
C++ 语言中类之间主要有四种联系方式 :(1) 一个类的对象作为另一个类的成员。(2) 一个类的成员函数作为另一个类的友元函数。(3) 一个类的定义包含在另一个类的说明体中,即类的嵌套。(4) 一个类作为另一个类的派生类。
上节内容
下章内容
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
11.4.1 类的对象成员通过类说明体中的对象声明,可以指定类的数据成员是其它类的对象。这是一种最简单的类对象包含关系。类说明体中的对象声明不直接和对象的创建与初始化相联系,而是随所在类对象的创建同时创建。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
例 10: 类的对象成员的实例 (P233) class pixel { int x,y ; public: pixel() {x=0;y=0;} pixel(int x0, int y0) {x=x0; y=y0; } }class line { pixel start, end; //声明pixel 的对象 int color; public: line(int sx, int sy, int ex, int ey, int col): start(sx,xy), end(ex,ey) {color=col;};void main (void) {line line1(20,20,100,20,2), line2(20,20,20,100,1)} 在程序中创建 line 类的对象时,必须同时创建pixel 类的两个对象。
在 line 的构造函数中,通过成员初始化符表把参数传到对象成员的构造函数中。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
成员初始化符表的格式: :< 成员初始化符 >,…,< 成员初始化符 >成员初始化符 : < 对象成员 >< 初值表 > 当类中含有对象成员时,类的构造函数应包含成员初始化符表,负责为类中所含各对象成员进行初始化。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
当定义一个含有对象成员的类对象时,系统调用其构造函数。首先,按照初始化符表依次执行各对象成员的构造函数,完成对它们的初始化。其次,执行本类的构造函数体。系统调用本类析构函数时的执行顺序和上述顺序相反。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
除了声明类的对象成员之外,将指向对象的指针作为类的成员也是实现类对象包含关系的常用方法。此时,指针是类的一般数据成员,因此不用在类的构造函数中加入成员初始化符表,可以直接在构造函数中完成初始化。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
11.4.2 类的嵌套所谓类的嵌套指的是一个类的说明包含在另一个类的说明。应尽量避免使用类的嵌套 !
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
在自定义类中,可以通过两种方法实现运算符重载 :(1) 以类的公有成员函数方式 ;(2) 以类的友元方式 ;
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
(1) 以类的公有成员函数方式类成员函数可以处理与使用本类的私有成员。总以当前调用者对象 (*this)作为该成员函数的隐式第一运算分量。如果运算涉及多个运算对象,则须在参数表中显式列出其余运算对象。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
(2) 以类的友元方式友元函数可以处理与使用本类的私有成员。所有运算分量必须显式地在参数表中列出,并且这些运算分量中至少有一个用于说明该友元的类或是对该类的引用。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
两点说明 :(1) 一般来说,单目运算符重载常使用类的成员函数方式;而双目运算符重载常使用类的友元函数方式。(2) 运算符重载后,优先级、运算顺序 ( 结合性 ) 和运算分量个数都必须与系统中的原运算符相一致,而且不可自创新的运算符。
11.1 类的静态成员11.2 类的常量成员11.3 友元11.4 类之间的关系11.5 类中运算符重载
课堂自习P238 7.8.2 节。
作 业
思考题 : 11, 16, 22 (书面 )练习题 : 7, 8 (上机 )