第5章 对象和类.ppt
《第5章 对象和类.ppt》由会员分享,可在线阅读,更多相关《第5章 对象和类.ppt(177页珍藏版)》请在三一办公上搜索。
1、第5章 对象和类,5.1 类及其实例化5.2 类和对象的性质5.3 结构和联合5.4 构造函数5.5 析构函数5.6 综合例题,5.7 重载对象的赋值运算符5.8 对象成员的初始化5.9 类模板与标准模板库5.10 面向对象编程的文件规范实验习题,本章重点介绍在C+中定义类、建立和使用对象的方法。虽然同类对象在其数据成员的取值方面是不相同的,但可以共用相同的代码。类是对同类对象的描述,它不但描述了对象之间的公有接口,同时也给出了对象的内部实现(数据成员和成员函数)。,像构造枚举和结构一样,类也是一种用户自己构造的数据类型并遵循C+的规定。例如,类也要先声明后使用;不管声明的内容是否相同,声明同
2、一个名字的两个类是错误的,类是具有惟一标识符的实体;在类中声明的任何成员不能使用extern、auto和register关键字进行修饰;类中声明的变量属于该类,在某些情况下,变量可以被该类的不同实例所共享。,5.1 类及其实例化 5.1.1 定义类,类和其他数据类型不同的是,组成这种类型的不仅可以有数据,而且可以有对数据进行操作的函数,它们分别叫做类的数据成员和类的成员函数,而且不能在类声明中对数据成员使用表达式进行初始化。,1.声明类类是对一组性质相同对象的程序描述。在C+中声明类的一般形式为 class 类名 private:私有数据和函数 public:公有数据和函数 protected
3、:保护数据和函数;,类声明以关键字class开始,其后跟类名。类所声明的内容用花括号括起来,右花括号后的分号作为类声明语句的结束标志。这一对花括号“”之间的内容称为类体。类中定义的数据和函数称为这个类的成员(数据成员和成员函数)。类成员均具有一个属性,叫做访问权限,通过它前面的关键字来定义。顾名思义,关键字private、public和protected 以后的成员的访问权限分别是私有、公有和保护的,把这些成员分别叫做私有成员、公有成员和保护成员。访问权限用于控制对象的某个成员在程序中的可访问性,如果没有使用关键字,则所有成员默认声明为private权限。这些关键字的使用顺序和次数也都是任意的
4、。,【例5.1】描述点的Point类。class Point/类名Pointprivate:/声明为私有访问权限 int x,y;/私有数据成员public:/声明为公有访问权限 void Setxy(int a,int b);/无返回值的公有成员函数 void Move(int a,int b);/无返回值的公有成员函数 void Display();/无返回值的公有成员函数 int Getx();/返回值为int的公有成员函数 int Gety();/返回值为int的公有成员函数;/类声明以分号结束x和y是私有成员,Setxy、Display、Move、Getx和Gety是公有成员。因为只
5、是声明函数,所以可只给出函数原型。【例5.2】是其等效的声明方式。,【例5.2】使用默认关键字及改变关键字顺序和次数的Point类。class Point/类名Pointint x;/默认私有数据成员 public:/声明为公有访问权限/无返回值的公有成员函数Setxy的函数原型 void Setxy(int,int);/无返回值的公有成员函数Move的函数原型void Move(int,int);void Display();/无返回值的公有成员函数的函数原型int Getx();/返回值为int的公有成员函数的函数原型int Gety();/返回值为int的公有成员函数的函数原型,priv
6、ate:/声明为私有访问权限int y;/私有数据成员;/类定义以分号结束由此可见,成员函数声明的规则与第4章所述的函数声明规则相同。2.定义成员函数类中说明的成员函数用来对数据成员进行操作。例如,Point类的Setxy函数用来为该类的对象设置初始值,而当调用成员函数Getx时,则返回一个对象的数据成员x的值。在类中只对这些成员函数进行了函数声明,还必须在程序中实现这些成员函数。定义成员函数的一般形式为,返回类型 类名成员函数名(参数列表)成员函数的函数体/内部实现 其中“”是作用域运算符,“类名”是成员函数所属类的名字,“”用于表明其后的成员函数是属于这个特定的类。换言之,“类名成员函数名
7、”的意思就是对属于“类名”的成员函数进行定义,而“返回类型”则是这个成员函数返回值的类型。余下的工作就是定义成员函数的函数体。例如Setxy是类Point的成员函数,它没有返回值,则定义如下:void Point Setxy(int a,int b)x=a;y=b;,将“void PointSetxy(int a,int b)”理解为定义Point的函数成员Setxy(int a,int b),该成员带有两个整型参数,函数没有返回值(void)。按此方法,可写出其他几个成员函数的定义:void Point Move(int a,int b)x=x+a;y=y+b;void Point Disp
8、lay()coutx,yendl;int Point Getx()return x;int Point Gety()return y;,也可以使用关键字inline将成员函数定义为内联函数,例如:inline int Point Getx()return x;如果在声明类的同时,在类体内给出成员函数的定义,则默认为内联函数。例如在类中将声明Getx的语句“int Getx();”改为“int Getx()return x;”,则Getx为内联函数。一般直接在类体内给出简单成员函数的定义。有些成员函数的实现方式不止一种,例如void Point Display()coutGetx(),Gety(
9、)endl;,是调用成员函数Getx()和Gety()实现的,它们使用了cout流,应在定义之前包含如下语句:#include using namespace std;3.数据成员的赋值不能在类体内给数据成员赋值,即下面的方法是错误的:Class Point int x=25,y=56;,当然,在类体外面就更不允许了。数据成员的具体值是用来描述对象的属性的。只有产生了一个具体的对象,这些数据值才有意义,所以又称对象的初值或对象初始化。这跟简单数据类型的道理一样,int是整数类型,但需要声明整数对象之后才有意义,“int x=5;”使得整数对象x的值为5,只是类具有成员函数而已。假设已经有了一个
10、对象A,则可使用“.”运算符调用成员函数Setxy赋初值。例如:A.Setxy(25,56);,将对象A的数据成员x和y分别赋给25和56,即A.x=25,A.y=56。其实,真正的初始化是使用与Point同名的构造函数Point(int,int)实现的。在1.10.1节介绍使用string的对象str时,使用“string str(real is);”语句。按此推理,可以写出产生Point的对象的语句:Point A(25,56);这就是使用构造函数产生类的实例。不过,现在还没有定义构造函数Point(int,int),所以还不能使用这种方法。但可以看到数据封装的迹象了!,Point类是用户
11、定义的一种类型,Point类所说明的数据成员描述了对象的内部数据结构,对数据成员的访问通过类的成员函数来进行。使用Point在程序中声明变量,具有Point类的类型的变量被称为Point的对象。只有产生类的对象,才能使用这些数据和成员函数。类Point不仅可以声明对象,还可以声明对象的引用和对象的指针,语法与基本数据类型一样。Point A,B;/定义Point类型的对象A和BPoint*p=&A;/定义指向对象A的Point类型的指针Point&R=B;/定义R为Point类型对象B的引用,5.1.2 使用类的对象,对象和引用都使用运算符“.”访问对象的成员,指针则使用“-”运算符。例如:A
12、.Setxy(25,88);/为对象A设置初值R.Display();/显示对象B的数据成员/B.x和B.y之值p-Display();/显示指针p所指对象A的数据/成员A.x和A.y之值,【例5.3】根据上面对Point类的定义,演示使用Point类的对象。void print(Point a)/使用Point的对象a作为函数参数a.Display();/显示对象a的数据成员的值void main()Point A,B;/声明对象A.Setxy(25,55);/为对象A赋初值B=A;/B的数据成员取A的数据成员之值A.Display();/显示A的数据成员A.Move(-10,20);/移动
13、Aprint(A);/等价于A.Display();print(B);/等价于B.Display(),coutA.Getx()endl;/只能使用A.Getx(),不能使用A.x本例中的print函数使用Point的对象作为参数。C+推荐使用下面的引用的形式:void print(Point&a)/使用对象的引用作为函数参数a.Display();/显示引用对象a的数据成员之值对象A移动之后,对象B仍为原来的值,所以输出如下:25,55/原来的A和B 15,75/新的A 25,55/原来的B 15/A.Getx()返回对象A的数据成员x的值如果在print函数或主函数里使用如下语句,则产生错误
14、。coutA.x,A.yendl;/错误!,暂不涉及还没有介绍的保护成员,可以归纳出如下规律:类的成员函数可以直接使用自己类的私有成员(数据成员和成员函数);类外面的函数不能直接访问类的私有成员(数据成员和成员函数);类外面的函数只能通过类的对象使用该类的公有成员函数,例如print和main函数;对象A和B的成员函数的代码一样,不同对象的区别是属性的取值。,在程序运行时,通过为对象分配内存来创建对象。在创建对象时,使用类作为样板,故称对象为类的实例。从表5.1中可以看出,A和B两个对象占据内存中的不同区域。A的数据是A.x和A.y,而B的数据是B.x和B.y,它们各有表现自己的属性数据,但用
15、来操作数据的代码均是一样的,例如A.Getx()和B.Getx()的代码一样。为节省内存,在建立对象时,只分配用于保存数据的内存,代码为每个对象共享。类中定义的代码放在计算机内存的一个公用区中,供该类的所有对象共享。这只是C+编译器实现对象的一种方法,作为程序员仍要将对象理解为是由数据和代码组成的。正是由于类拥有这两类成员,才使得数据封装等思想得以实现。,表5.1 类Point的两个实例A和B,【例5.4】演示使用内联函数定义Point类及使用Point类指针和引用的完整例子。#include/包含头文件using namespace std;/声明命名空间class Point/使用内联函数
16、定义类Pointprivate:/声明为私有访问权限 int x,y;/私有数据成员public:/声明为公有访问权限 void Setxy(int a,int b)/无返回值的内联公有成员函数 x=a;y=b;void Move(int a,int b)/无返回值的内联公有成员函数 x=x+a;y=y+b;void Display()/无返回值的内联公有成员函数 coutx,yendl;,int Getx()return x;/返回值为int的内联公有成员函数 int Gety()return y;/返回值为int的内联公有成员函数;/类定义以分号结束void print(Point*a)/
17、类指针作为print函数的参数定义重载函数a-Display();void print(Point&a)/类引用作为print函数的参数定义重载函数a.Display();void main()/主函数 Point A,B,*p;/声明对象和指针 Point&RA=A;/声明对象RA引用对象A A.Setxy(25,55);/使用成员函数为对象A赋值,B=A;/使用赋值运算符为对象B赋值 p=&B;/类Point的指针指向对象B p-Setxy(112,115);/使用指针调用函数Setxy重新设置B的值 print(p);/传递指针显示对象B的属性 p-Display();/再次显示对象B的
18、属性 RA.Move(-80,23);/引用对象RA调用Move函数 print(A);/验证RA和A同步变化 print(&A);/直接传递A的地址作为指针参数程序运行结果如下:112,115112,115-55,78-55,78,面向对象的程序设计,是通过为数据和代码建立分块的内存区域,以便提供对程序进行模块化的一种程序设计方法,这些模块可以被用做样板,在需要时再建立其副本。根据这个定义,对象是计算机内存中的一块区域,通过将内存分块,每个模块(即对象)在功能上保持相对独立。另外,定义也表明如下问题。,5.1.3 数据封装,这些内存块中不但存储数据,而且也存储代码,这对保证对象受保护很重要。
19、只有对象中的代码才可以访问存储于这个对象中的数据,这清楚地限定了对象所具有的功能(即一个对象在一个软件系统中所能起到的作用),并使对象保护它自己不受未知的外部事件的影响,从而使自己的数据和功能不会因此遭到破坏。这些内存块的结构可被用做样板产生对象的更多副本。例如,一旦定义了一个窗口对象,只要内存允许,就可以建立许多这样的对象。在面向对象的程序中,对象的行为只有向对象发送消息才能引用,例如通过Display发出显示消息,所以说面向对象是消息处理机制。,对象之间只能通过成员函数调用实现相互通信。这样,对象之间的相互作用方式是仔细控制的,一个对象外部的代码就没有机会通过直接修改对象的内存区域妨碍对象
20、发挥其功能。当对象的一个函数被调用时,对象执行其内部的代码来响应这个调用,这就使对象呈现出一定的行为,即表现出该对象的功能。对象被视为能做出动作的实体,动作在对象相互作用时被激励,换句话说,对象就像在宿主计算机上拥有数据和代码,并能相互通信的具有特定功能的一台较小的计算机。,对象的这一特点导致了模拟现实世界的一种新型方法:面向对象就是将世界看成是由一组彼此相关并能相互通信的实体即对象组成的。程序中的对象映射现实世界中的对象。C+对其对象的数据成员和成员函数的访问是通过访问控制权限来限制的。可以试验一下,将【例5.1】中对数据成员x和y的声明改为public,就可以在主函数中直接使用语句“cou
21、tA.x;”输出A的数据成员x之值。这就取消了它的封装性。由此可见,private是限制类之外的函数的访问权。只要将数据成员或成员函数使用private限定,就设定了一道防线。不过,如果都在防线之内,这个类也就没有用处了。所以它还必须留下与外面打交道的接口,这通过具有public权限的成员函数实现(目前暂不涉及protected)。,由此可见,在C+中,数据封装是通过类来实现的。在类中指定了各成员的访问权限。一般情况下将数据成员说明为私有的,以便隐藏数据;而将部分成员函数说明为公有的,用于提供外界和这个类的对象相互作用的接口(界面),从而使得其他函数(例如main函数)也可以访问和处理该类的对
22、象。对于那些仅是为支持公有函数的实现而不作为对象界面的成员函数,也将它们说明为私有的。公有的成员函数是外界所能观察到(访问到)的对象界面,它们所表达的功能构成对象的功能,使同一个对象的功能能够在不同的软件系统中保持不变。,这样,当数据结构发生变化时,只需要修改少量的代码(类的成员函数的实现代码)就可以保证对象的功能不变。只要对象的功能保持不变,则公有的成员函数所形成的接口就不会发生变化。这样,对象内部实现所做的修改就不会影响使用该对象的软件系统。这就是面向对象程序设计使用数据封装为程序员的程序开发活动所带来的益处。在传统的 C 程序设计风格中,数据保存在数据结构中,然后生成函数来操作这些数据。
23、最后将此结构和函数放进源文件,单独编译,作为模块。这个方法的缺点是,即使该结构和函数是放在一起使用的,仍然可以不通过使用函数就能直接存取数据。C+使用封装的方法较好地解决了这个问题。,可以像第4章那样,对成员函数重载或使用默认参数。下面的例子演示了使用私有成员函数封装函数,并使用成员函数重载和默认参数。【例5.5】构造一个求4个正整数中最大者的类Max,并用主程序验证它的功能。class Max/声明类 private:/封装数据成员和成员函数int a,b,c,d;/数据成员int Maxi(int,int);/只允许类内部的成员函数调用,5.1.4 成员函数重载及默认参数,public:/
24、对外界的接口void Set(int,int,int,int);/设置对象初值int Maxi();/求最大值A3;/声明类的对象数组,定义结束/类中成员函数的实现int MaxMaxi(int x,int y)/求两个数的最大值return(xy)?x:y;void MaxSet(int x1,int x2,int x3=0,int x4=0)/使用两个默认参数a=x1;b=x2;c=x3;d=x4;int MaxMaxi()/求自己类中4个数的最大值 int x=Maxi(a,b);/x和y为Maxi()函数的局部整数对象 int y=Maxi(c,d);return Maxi(x,y);
25、,/主程序#includeusing namespace std;void main()A0.Set(12,45,76,89);/为数组对象A0置初值A1.Set(12,45,76);/为数组对象A1置初值A2.Set(12,45);/为数组对象A2置初值for(int i=0;i3;i+)/输出对象求值结果 coutAi.Maxi();,程序演示了可在声明类的同时也声明类的对象,这里是声明对象数组A,作用与在主程序里使用“Max A3;”语句相同。为了提高可读性,一般不在声明类时声明对象,这里只是为了演示它的性质。程序输出结果为:897645类中重载了函数Maxi,一个原型为Maxi(int
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第5章 对象和类 对象
链接地址:https://www.31ppt.com/p-2430474.html