C++从结构到类详解.ppt_第1页
C++从结构到类详解.ppt_第2页
C++从结构到类详解.ppt_第3页
C++从结构到类详解.ppt_第4页
C++从结构到类详解.ppt_第5页
已阅读5页,还剩102页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第2章 从结构到类,结构类型简称为结构(struct),结构不仅是构造类型的重要成员,也是类的前身。 C+中的结构与C中的结构已经发生了质的变化。本章首先使用结构编制一个C+的面向过程的典型程序,并通过实例简要说明结构如何向类变化,从而引入对象和类的知识。 然后介绍两个类,通过使用这两个类,进一步熟悉类和对象,为学习面向对象编程打下基础。,主要内容,2.1 结构的演化 2.2 从结构演变一个简单的类 2.3 C+面向对象程序设计特点 2.4 数据对象和数据类型 2.5 熟悉并使用类和对象 2.6 string对象数组与范型算法 2.7 结构化程序设计典型例题 2.8 活捉臭虫保平安,2.1 结

2、构的演化 结构由若干元素构成,C语言中称这些结构元素为结构成员,C+中称为数据成员。不过,能够做数据成员的不只是基本数据类型的变量,还可以是构造类型(数组、指针甚至是其他类型的结构)变量。 在C+中,定义结构变量时,可以省略关键字struct,而且C+的结构中可以有函数。其实,类确实是从结构演变而来,开始称为“带类的C”。这场革命就是从让结构含有函数开始的。 本节从结构引入类,然后练习如何使用系统提供的类,以便为设计类打下基础。,2.1.1 结构发生质的演变 1. 函数与数据共存 C+允许结构中可以定义函数,这些函数称为成员函数。如果将原来的结构成员称为数据成员的话,可以使用如下的形式描述:

3、struct 结构名 数据成员 成员函数 ;,可以像结构变量或指针使用结构成员那样,使用成员函数: 结构变量.成员函数 指向结构变量指针的名字 - 成员函数 假设为结构Point设计一个Setxy函数如下: void Setxy(double a, double b) x=a; y=b; 如果把域x和y称为结构的数据成员,则可以使用参数表中的a和b赋给结构变量的数据成员。假设有对象a,则语句: a.Setxy(12.5,14.5); 使结构变量a的a.x=125, a.y=14.5。,【例2.1】结构中使用成员函数的实例。 #include using namespace std; struc

4、t Point public: void Setxy(double a, double b) /成员函数,用来 /重新设置数据成员 x=a; y=b; void Display() /成员函数,按指定格式输出 /数据成员的值 coutxtyendl; private: double x, y; /数据成员 ;,void main( ) Point a,*p; /定义变量和指针变量 a.Setxy(10.6,18.5); /设置变量a的数据成员 a.Display(); /显示变量a的数据成员 p= 程序运行结果如下: 10.6 18.5 10.6 18.5 10.6 18.5,主程序中的变量是

5、通过结构的成员函数使用数据成员,但最后一条语句则是直接使用数据成员。这称作结构 Point的公有(public)性质。 2. 封装性 所谓封装性,就是限制存取权限(详见后面的2.3.3节)。如果在定义结构时,将数据成员使用private关键字定义,则产生封装性。 【例2.2】使结构具有封装性的实例。 #include using namespace std; struct Point private: double x, y; /数据成员,public: void Setxy(double a, double b) /成员函数 /用来重新设置数据成员 x=a; y=b; void Displa

6、y() /成员函数,按指定格式 /输出数据成员的值 coutxtyendl; ; 显然,没有使用private定义的成员函数,默认为public(也可以直接使用public)。这时,如果还使用【例2.1】的主程序,则其最后一条语句就出现编译错误。也就是说,私有的数据成员,必须通过公有的成员函数才能使用,这就称为数据的封装性。显然,没有使用private定义的成员函数,默认为public(也可以直接使用public)。,这时,如果还使用【例2.1】的主程序,则其最后一条语句就出现编译错误。也就是说,私有的数据成员,必须通过公有的成员函数才能使用,这就称为数据的封装性。其实,这就变成了具有类的性质

7、的结构。只是类使用关键字class定义,它默认的是private。确实,类当初就是从这种结构演变的。 2.1.2 使用构造函数初始化结构的对象 因为【例2.2】的程序使结构具有封装性,所以不能使用初始化列表初始化结构对象。为此,这里为结构Point设计两个专门用于初始化的函数。这两个函数具有相同的名字Point,其原型如下: Point(); Point(double,double); 从第1章的知识可知,这是函数重载。因为这里的函数名与结构同名,所以称为构造函数。构造函数专门用于初始化对象。,【例2.3】使用构造函数初始化对象的实例。 #include using namespace std

8、; struct Point private: double x, y; /数据成员 public: Point(); /无参数构造函数 Point(double a, double b) /具有两个参数的构造函数 x=a; y=b; void Setxy(double a, double b) /成员函数,用来重新设置数据成员 x=a; y=b;,void Display() /成员函数,按指定格式输出数据成员的值 coutxtyendl; ; void main( ) Point a; /定义对象a Point b(18.5 , 10.6); /定义对象b并赋初值 a.Setxy(10.6

9、,18.5); /设置变量a的数据成员 a.Display(); /显示变量a的数据成员 b.Display(); /显示变量b的数据成员 程序运行结果如下: 10.6 18.5 18.5 10.6,现在不要深究构造函数的原理,只要记住它的使用方法即可。一般形式为: 构造函数名 对象名(初始化参数); 程序在运行时,会自动完成初始化任务。例如语句 Point b(18.5 , 10.6); 使得a.x=18.5,a.y=10.6。,2.2 从结构演变一个简单的类,其实,使用关键字class代替struct,就是一个标准的类。 【例2.4】定义类的实例。 class Point private:

10、 double x, y; /类point的数据成员,public: Point(); /类Point的无参数构造函数 Point(double a, double b) /具有两个参数的构造函数 x=a; y=b; void Setxy(double a, double b) /成员函数,用来 /重新设置数据成员 num=a; score=b; void Display() /成员函数,按指定格 /式输出数据成员的值 coutxtyendl; ; 使用类产生对象的方式如结构一样,可以使用如下的主函数,将得到相同的运行结果。,void main( ) Point a; /定义类Point的对象

11、a Point b(18.5 , 10.6); /定义类Point的对象b并初始化 a.Setxy(10.6,18.5); /为对象a的数据成员赋值 a.Display(); /显示对象a的数据成员 b.Display(); /显示对象b的数据成员 程序运行结果如下: 10.6 18.5 18.5 10.6 可以将point类看作直角坐标系的点类,图2.1是point类的示意图。,图2.1 point类示意图,第1个方框中是类名,第2个方框中是坐标点的数据,称为属性(或称数据成员)。第3个方框中表示类所提供的具体操作方法,实际上是如何使用数据x和y,以实现预定功能的函数,这里称为成员函数。 用

12、point类产生对象a,而使用语句 a.set(10.6,18.5); 可以设置对象a的数据成员分别为10.6和18.5,也就是坐标点(10.6, 18.5),这就是一个具体的坐标点,即类point的一个对象。使用带参数构造函数 Point b(18.5 , 10.6); 则将其坐标初始化为(18.5, 10.6)的点对象b。,2.3 C+面向对象程序设计特点 面向对象的程序设计方法要求语言必须具备抽象、封装、继承和多态性等关键要素。 2.3.1 对象 称现实世界中客观存在的事物为对象,如前所述,整数是一个对象,平面上的点是一个对象,河流湖泊都是对象。复杂的对象可以由简单的对象组成,例如火车站

13、对象又包含售票处、行李房、信号灯、站台、铁轨和通信设施等对象。这些对象各自又由许多对象组成,对象各自完成特定的功能。总之,世界万物皆对象。 售票处有各种规格的车票,这些车票表示售票处的静态特征。它提供发售车票的功能(操作),表示了售票处的动态特征。,通过这种抽象归纳,C+可使用对象名、属性和操作三要素来描述对象。 对象名用来标识一个具体对象。用数据来表示对象的属性,一个属性就是描述对象静态特征的一个数据项。 操作是描述对象动态特征(行为)的一个函数序列(使用函数实现操作),也称为方法或服务。 数据称为数据成员,函数称为成员函数。 由此可见,C+中的对象是系统中用来描述客观事物的一个实体,是构成

14、系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的成员函数构成。对象结构如图2.2所示。,图2.2对象结构图,【例2.5】用简单对象表示平面上的A(3.5,6.4)和B(8.5,8.9)两个坐标点。可使用图2.3表示具体对象A和B的对象结构。,图2.3 具体对象A和B的结构图,图中含义解释如下: 对象名是“A”,A是一个点的对象。没有给对象A的属性赋值时,这只是个抽象名词。只有具有确定的属性值,才是一个具有确定位置的点。 图2.3中用x坐标和y坐标表示坐标点对象的静态属性(称为位置属性)。 假设x和y可以取实数值,C+中使用float标记它们是实数,不同属性值用来区分对象A和B。 假

15、设暂且让点对象对外有显示属性值、设置属性值和移动位置等操作,这里分别使用成员函数display, setxy, move来实现这些操作。,2.3.2 抽象和类 抽象是一种从一般的观点看待事物的方法,即集中于事物的本质特征,而不是具体细节或具体实现。 面向对象鼓励程序员以抽象的观点看待程序,即程序是由一组抽象的对象组成的。 另外,又可以将一组对象的共同特征进一步抽象出来,从而形成“类”的概念。例如,从点A和B抽象出点的概念,这就是“点类”。 这个类的本质是具有两个坐标属性和对这两个属性值进行操作的方法。A和B的区别只是属性值的不同,其方法是相同的。例如,当它们使用移动位置的函数之后,点的位置属性

16、值将随之变化。 它们都从当前位置移到一个新位置,代表了新坐标处的点对象。通过分析一组对象(A和B),抽取公共的行为将其放入到一个类中,取名为Point类,并用图2.4的Point类模型表示它。,图2.4 类Point的结构图,它也由类名、一组属性和一组操作等3部分组成。类的属性只是性质的说明,对象的属性才是具体的数据。所以,图2.4的Point类只是表示类名是Point,它的点位置是两个实数,但还没有具体的位置。只有像本节A和B两点 那样,具有确定的属性值,才是Point类的具体对象,称它为类Point的一个实例。从图2.4可以推出图2.5所示的一般的“类”模型结构图。,图2.5 类模型的结构

17、图,抽象出这个类Point,就可以专心集中精力研究有关“点”的概念,如果再给它增加一个颜色属性,就可以知道这个类的所有对象都可以有颜色上的区别。无须再将注意力分散到有关任何一个具体点的坐标和颜色等细节中去。 又如大家非常熟悉的整数类,通过研究发现,它的属性是一个整数集合,它提供的基本操作是四则运算。8和9是两个整数对象,8+9是使用整数类提供的相加求和操作。 由此可见,类的概念来自于人们认识自然、认识社会的过程。在这一过程中,人们主要使用由特殊到一般的归纳法和由一般到特殊的演绎法。在归纳过程中,是从一个个具体的事物中把共同的特征抽取出来,形成一个一般的概念,这就是“归类”;在演绎的过程中,又把

18、同类的事物,根据不同的特征分成不同的小类,这又是“分类”。,对于一个具体的类,它有许多具体的个体,这些个体叫做“对象”。举个例子,“人”是一个类,具有“直立行走、会使用工具”等一些区别于其他事物的共同特征;而张三、李四、王五等一个个具体的人,就是“人”这个类的一个个“对象”,同一类的不同对象具有相同的行为方式(如张三和李四都能直立行走、会使用工具),不同类的对象具有不同的行为(例如张三能使用工具,坐标点A则不能使用工具)。 这种设计方法模仿了人们建立现实世界模型的方法,与人们认识客观事物的过程相一致,提高了编写程序的质量和可靠性。 不过,对已掌握了过程设计思想的程序员来说,则必须改变原来的思维

19、方法。 由此可见,一个对象是由一些属性和操作构成的。对象的属性和操作描述了对象的内部细节。类是具有相同的属性和操作的一组对象集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和操作两个主要部分。,这两个部分也是对象分类的依据,只有给出对象的属性和操作,才算对这个对象有了确切的认识和定义。 类的作用是定义对象。类和对象的关系如同一个模具与用这个模具铸造出来的铸造件之间的关系。类给出了属于该类的全部对象的抽象定义,而对象则是符合这种定义的实体。所以,C+中将对象称做类的一个实例。在程序中,每个对象需要有自己的存储空间以保存它们自己的属性值。所谓“一个类的所有对象具有相同的属性”,是指

20、属性的个数、名称、数据类型相同,各个对象的属性值则可以互不相同,并且随着程序的执行而变化。至于操作,则是所有对象共同使用它们的类定义中给出的操作代码,在C+中,每个操作是一个“成员函数”,在Smalltalk中则称为“方法”。我们说同类对象具有相同的属性和操作,是指它们的定义形式相同,而不是说每个对象的属性值都相同。,2.3.3 封装 举个简单的例子,电视机把各种部件都装在机箱里,遥控功能装在遥控器盒子中。用户通过遥控器操作电视机,既方便了用户,也保护了电视机。将类封装起来,也是为了保护类的安全,所谓安全,就是限制使用类的属性和操作。 按照面向对象的封装原则,一个对象的属性和操作是紧密结合的,

21、对象的属性只能由这个对象的操作来存取。对象的操作分为内部操作和外部操作。内部操作只供对象内部的其他操作使用,不对外提供。外部操作对外提供一个消息接口,通过这个接口接收对象外部的消息并为之提供操作(服务)。对象内部数据结构的这种不可访问性称为信息(数据)隐藏。数据封装给数据提供了与外界联系的标准接口,无论是谁,只有通过这些接口,使用规范的方式,才能访问这些数据。同时,由于程序员总是和接口打交道,因此就不必要了解数据的具体细节。简言之,封装就是把对象的属性和操作结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。,由此可见,封装要求一个对象应具备明确的功能,并具有接口以便和其他对象相互作用。同时

22、,对象的内部实现(代码和数据)是受保护的,外界不能访问它们。封装使得一个对象可以像一个部件一样用在各种程序中,而不用担心对象的功能受到影响。 数据封装一方面使得程序员在设计程序时可以专注于自己的对象,“各人自扫门前雪,莫管他人瓦上霜”,同时也切断了不同模块之间数据的非法使用,减少了出错的可能性。 在类中,封装是通过存取权限实现的,如将每个类的属性和操作分为私有的和公有的两种类型。对象的外部只能访问对象的公有部分,不能直接访问对象的私有部分。,2.3.4 继承 对象的另一个特点是继承。继承是一个对象可以获得另一个对象的特性的机制,它支持层次类这一概念,例如红香蕉苹果属于苹果类,而苹果类又属于水果

23、类。通过继承,低层的类只须定义特定于它的特征,而共享高层的类中的特征。 继承具有重要的实际意义,它简化了人们对事物的认识和描述。比如我们知道苹果可以吃,红香蕉继承苹果的特征,当然也可以吃。从“狗啃骨头”可知无论是黄狗黑狗或者花狗,它们都喜欢啃骨头。从“猫捉老鼠”可推知不管白猫还是黑猫,还是它们的子女,都继承捉老鼠的特长。俗语“老鼠生儿会打洞”,不正是使用了“继承”的概念吗?再如我们认识了轮船的特征之后,就知道客轮是轮船的特殊种类,它具有轮船的特征。当研究客轮时,只要把精力用于发现和描述客轮独有的那些特征即可。,2.3.5 多态性 不同的对象可以调用相同名称的函数,并可导致完全不同的行为的现象称

24、为多态性。利用多态性,程序中只须进行一般形式的函数调用,函数的实现细节留给接受函数调用的对象。这大大提高了我们解决复杂问题的能力。举个最简单的例子,将两个数“相加”,这两个数可以是整数或实数,将“+”看做一个特殊函数,则8+7和23.5+8.7都是使用“+”来完成两个数相加的功能,这就是“+”体现的多态性。由此可知,“-”、“*”和“/”也都具有这一特征,而且还可以自己定义这些运算符的功能(后面将会介绍如何实现这一称为运算符重载的方法)。类的多态性将更加精彩,这将留待第9章讨论,本章不再赘述。,2.4 数据对象和数据类型 各种语言之间的主要区别有3点:数据类型、操作类型以及控制操作的方法。控制

25、主要是指语言所提供的对数据序列进行操作的机制。本节仅从通用性角度,简单地考察程序设计语言中数据对象和数据类型的属性。,2.4.1 数据对象、变量和常量 一个数据对象就是能够存放和检索数据值的容器。数据对象有许多属性,最重要的属性是它的数据类型。这些属性决定数据对象可能存放的值的数目和类型,同时也决定了这些值的逻辑组织形式。 数据值可以是单个数值、字符,也可以是指向另一个数据对象的指针。数据对象通常存放在计算机内存中,而数据值则表现为比特流(二进制位)模式。图2.6是其示意图。,在程序中,对象存在是有时间性的,这个存在时间称为对象的生存期。在对象的生存期内,每个对象都可以用来保存数据值。如果一个

26、数据对象包含的数据值总是为一个数据单位所操作,则称这个数据对象是基本的。例如对象5总是被整数单位所操作,整数对象就是基本对象。如果是其他数据对象的集合,例如某个对象含有整数和实数两种基本数据对象,则可以用结构或类来实现它,C+中称这种对象为构造类型数据对象。 程序员显式(程序设计中将直截了当的明显方式称为显式)定义和命名的数据对象称为变量。简单变量是有名字的基本数据对象。通常认为变量的值通过赋值操作修改,即可以通过赋值改变数据对象的值。 也就是说,数据对象和值之间的对应关系在数据对象生存期中是可以改变的,这由程序员设计的程序决定。如果对象的名字与字母的大小写有关,称为大小写敏感,否则称为大小写

27、不敏感。C+是大小写敏感的语言。,常量是在生存期中被永久性地赋予一个值(或一些值)的有名字的数据对象。文字(文字常量)的名字恰好也表示了它的值(如以常量名25表示值为25的常量),即它们的名字和值是一个统一体。常量和值之间对应关系的实现是由编译器决定的。 一般常用如下几个特性描述数据对象: 1. 类型 类型是将数据对象和它可以取得数据值的集合联系起来,例如正的整数对象(无符号整数对象)的可取值范围是所有自然数的集合,字符对象的类型是人们所定义的字符集。 2. 存储位置 存储位置是内存中存放数据对象的具体位置,通常由编译器分配,程序员不能修改。例如一个整数对象或者字符对象存储在内存中的位置由编译

28、器决定,不仅不同的编译器可能有不同的分配方法,就是同一个编译器,也可能随版本的不同而异。,3. 值 值用来描述对象的属性,值的绑定通常是赋值操作的结果。例如使用赋值操作符“=”使一个整数对象的值为45,或者字符对象的值为字符集中的“B”。值为数字45的对象是整数对象,而值为字符“45”的,则是字符对象。 4. 名字 “名字”由声明建立,是程序中可被引用的对象名,例如整数对象a,通过“int a;”建立。字符对象c,则通过“char c;”建立。 5. 组件 组件含有一个或多个数据对象,本身也可含有组件。例如含有一个整数对象何一个字符对象的结构,就是一种组件。,2.4.2 数据类型 数据类型是一

29、个数据对象以及创建和操纵它们的操作集合所组成的类。每种语言都有构成该语言的基本数据类型,例如上述的整型和字符类型都是C+的基本类型之一。除此之外,也可以提供定义新数据类型的机制,例如数组等。一个数据类型规范的基本组件包括区别这个类型的数据对象的属性、这个类型的数据对象可能取的值以及定义这个类型的数据对象能提供的操作方法。 1. 属性 任何数据对象的基本属性(如数据类型和名)在生存期内不变。注意:某个属性的值和数据对象所含的值是不同的。例如当前整数对象a的值为5,整数对象的属性值不是5,而是整数集合。,2. 值 数据对象的类型决定了它可取的可能值的集合。基本数据类型定义的值的集合是一个有最小值和

30、最大值的有序集,并可以比较它们的大小。如整数类型包含的是整数集,这是一个有序集合。字符类型包含的是定义的字符集,可以是ASCII码字符集或者别的字符集,这些字符集也是一个有序集合。 3. 操作 为一个数据类型定义的操作的集合,决定了如何操纵该类型的数据对象,体现了数据对象的动态特征。作为语言定义一部分的操作称为基本操作,例如整数的四则运算,就是整数对象的基本操作。对于面向对象的C+而言,程序员还可以自己定义操作。,2.5 熟悉并使用类和对象 本节将介绍如何使用C+标准程序库提供的string类和complex类,目的是进一步了解类和对象的概念,为以 后自己编写类打下基础。,2.5.1 使用st

31、ring对象 C+标准程序库提供string类,string类可以像char那样定义一个字符串对象,但string类定义的对象不需要结束符“0”,而且可以使用string类提供的成员函数进行相应操作,例如求字符串的长度或取这个字符串的子串等。 实际上的string类很复杂,图2.7只给出本节例子所涉及的属性和部分操作。,图2.7 string类的简化图,从图2.7可见,它的属性是一个字符串str,同名函数string是构造函数,用来初始化字符串。其实,它有参数不同的几种构造函数,这里用string只是表示它有构造函数而已。 另外3个成员函数用来对属性str进行操作。成员函数find用来在str

32、字符串中检索所需要的子串;size成员函数计算并输出str存储的单词长度;substr成员函数,用来返回str字符串中的子串。详细使用方法见下面的实例。 在程序中可以使用string类定义存储字符串的对象。这些对象隶属于string类,因此还必须在程序中包含这个类的头文件,即使用语句 #include 因为C+将单引号用来标识单字符常量,双引号标识字符串常量,string需要的是字符串,所以string类的对象不能用单引号括起来的单个字符常量初始化,即语句,string str=A; 是错误的。 string str(A); 也是错误的。 可以使用双引号括起来的单个字符常量初始化,即下面语句均

33、是正确的: string str=A; string str(A); /也是正确的 如果string 的对象str的内容为“ab”,则str0=a,str1=b。 【例2.6】演示使用string对象及初始化的例子。,【例2.6】演示使用string对象及初始化的例子。 #include #include using namespace std; void main() string str1(We are here! ); string str2=Where are you? ; coutstr1; coutlength of the str1 is str1.size().endl; ,程

34、序中接收键盘输入的一个单词给string类的对象str1,这时就改变了对象str1的内容,假设输入“good”,则str1.size()的值为单词“good”的长度。下面是程序的输出结果: W!,We are here! W?,Where are you? please input a word: good length of the fine is 4. 程序中使用赋值运算符“=”对string类的对象进行初始化,这个动作是沿用C 语言的方法。因为string类的对象可以用一个字符串加以初始化,所以这种方式没有问题。程序中分别使用两种方法给string类的两个对象初始化。也可像下面这样,将它

35、们定义在同一行中: string str1(We are here! ),str2= Where are you? ;,这些对象都向外界提供许多能展现自己的“方法”。所谓方法,就是供这类对象使用的成员函数。例如size方法,就是用来输出对象的长度。对象使用自己的成员函数的方法是通过“.”运算符,格式如下: 对象名.成员函数 例如对象str1使用类string的size成员函数计算并输出单词的长度,其格式为: str1.size() string类还提供将两个字符串连接起来组成一个新字符串的能力。“+”号将其后的字符串连接到前一个字符串的后面,也可以与单个字符常量相加。例如语句 str=str

36、+ + str; 将原来的两个str 的内容用空格连起来,新内容为: We are here! We are here!,2.5.2 使用string类的典型成员函数实例 string对象是通过调用成员函数实现操作,从而提供对象的行为或消息传递的。成员函数size发送一个消息请求,它要求string对象返回字符串中字符的个数,这个成员函数不需要任何参数。对象调用成员函数的语法可表示如下: 对象名称.成员函数(参数(可供选择的消息内容) 例如string类提供的substr成员函数,用来返回字符串的子串。第1个参数是要截取子串在字符串中的位置,第2个参数是截取的长度。例如,要从对象str中截取“

37、are”,因为C+规定字符串的计数是从零开始的,所以“a”处于位置3,可用如下语句实现: string newstr=str.substr(3,3); 这时newstr的内容为“are”。给出的位置必须位于字符串中,否则出错。如果长度大于字符串的长度,则是可以的,它自动截取到末尾。例如下面语句:,string strnew=newstr.substr(2,8); 截取的内容为“e”,等同于语句“string strnew=newstr.substr(2,1);”。 成员函数find用来在主串中检索所需字符串。它有两个参数,格式如下: 对象名称.find(要查找的字符串,开始查找的位置); 该成

38、员函数返回查找到的字符串在主串的位置。例如: int i=str.find(are, 0 ); 表示从str字符串的位置0(起始位置)开始查找,结果为3。如果改从4开始,则查找到连接的第2个“are”,结果为16。如果让它从17处开始,则找不到,返回值为-1。如果不给位置参数,默认位置参数为0,即上述语句可写为 int i=str.find(are); string类还提供一个辅助功能,以便使用getline从流cin中读出输入的一行给string类的对象。,string InputLine; getline(cin, InputLine, n); cout your input: Input

39、Lineendl; 如果输入“I am here!”,则得到如下结果: your input: I am here! 【例2.7】演示将美国格式的日期转换为国际格式的例子。 美国使用月日年格式,例如May 28 , 2002。转为国际格式应为28 May 2002。这可以使用find检索,使用substr截取,然后再按要求重组。具体步骤如下:, 寻找月份。假设string类的Date对象存放美国日期,则下列语句 int i=Date.find(“ ”); /查找May与28之间的 /空格,i=3 string Month=Date.substr(0,i) ; /从0位置开始截取i /个字符(上

40、面求的i=3) 得到Month。 寻找日子。寻找“,”号,假设其位置为k。Day的起始位置应是i+1处,长度应是k-(i+1),则语句 string Day=Date.substr(i+1, k-i-1); 得到Day。 寻找年份。年份应从逗号处再计数2次(因逗号后面有一个空格),长度为4,也可使用比年的长度长的字符串的总长度,这由它的成员函数size提供。下面两种方法是等效的:,string Year = Date.substr(k + 2, Date.size() - 1); string Year = Date.substr(k + 2, 4); 按新格式拼装并输出。 下面是完整的程序及

41、运行结果: #include #include using namespace std; void main() cout Enter the date in American format (e.g., December 25, 2002) : ; string Date; getline(cin, Date, n);,int i = Date.find( ); string Month = Date.substr(0, i); int k = Date.find(,); string Day = Date.substr(i + 1, k - i - 1); string Year = Da

42、te.substr(k + 2, 4); string NewDate = Day + + Month + + Year; cout Original date: Date endl; cout Converted date: NewDate endl; 程序运行示范如下: Enter the date in American format (e.g., December 29, 1953) : May 28, 2002 Original date: May 28, 2002 Converted date: 28 May 2002,2.5.3 使用complex对象 C+标准程序库提供comp

43、lex 类定义复数对象。在程序中包含这个类的头文件: #include 复数(complex number)类需要两个初始值:实部和虚部,这需要借助构造函数初始化语法来实现多值处理。complex 类是一个模板类(template class),所谓模板,意思是说它可以定义多种数据类型的复数,例如实部和虚部的数据类型可以是整数,也可以是实数。这可以在complex后面使用“”加以说明。例如“”为整数,“”为实数,即: complex 对象名(实部值,虚部值); 也就是说,使用模板定义复数对象时,才指明数据成员的类型及其数值。例如: complex num1(2,3); /复数2+3i comp

44、lex num2(3.5, 4.5); /复数3.5+4.5i,complex的real和imag成员函数用来输出对象的实部和虚部的值。例如下面的语句输出浮点复数对象num2的实部和虚部: cout #include #include using namespace std; void main() complex num1(2,3); complex num2(3.5, 4.5);,string str1(real is ); string str2=image is ; coutstr1num1.real(),str2 num1.imag()endl; coutstr1num2.real(

45、),str2 num2.imag()endl; 程序的输出结果如下: real is 2,image is 3 real is 3.5,image is 4.5,2.5.4 使用对象小结 通过前面的程序可以看出,标准库提供的类都是经过抽象,代表一类对象的。例如,string类描述的是字符串特性,字符串有长度,可以对它进行运算或者检索。 string类有一个字符串,用这个字符串来描述string类的属性,这个属性又称为数据成员。换言之,string类具有一个用来描述对像静态性质的字符串,字符串的值可以区分不同的对象。例如str1的字符串的值为“We”,str2的字符串的值为“You”,则通过属性

46、值可以区分对象str1和str2。为了对这个字符串进行操作,还需要一系列的操作方法。用函数实现这些方法,又称这些函数为成员函数。例如使用size成员函数获得字符串的长度。数据成员(属性)和成员函数(方法)代表了字符串一类事物的特征。使用的一般方法如下:,#include / 包含它的头部文件 string str1; / 定义这个类的一个对象str1 str=This is a string; / 给对象str1赋值 coutstr1; / 使用对象str1 string str2(“This is a str2”); / 定义这个类的 /另一个对象str2 coutstr2.size();

47、/ 使用对象str2的成员 /函数size输出字符串长度 可以先定义对象,然后给它赋值(str1);也可以在定义对象的同时初始化对象(str2),如果要使用对象的成员函数,则用“.”运算符,例如: coutstr1.size(); /使用对象str1的成员函数size /输出字符串str1的长度,通过前面的程序可以看出,标准库提供的类都是经过抽象,代表一类对象的。例如,string类描述的是字符串特性,字符串有长度,可以对它进行运算或者检索。换言之,string类具有描述字符串性质的的数据成员(属性),以及对字符串进行操作的一系列成员函数(方法)。它们代表了字符串一类事物的特征。同理,复数类可

48、以抽象为具有实部和虚部的数据成员,以及能对复数进行基本操作的成员函数。与string不同的是,定义复数类时与数据成员的类型无关,当定义复数类的对象时才指定实部和虚部的数据类型。这就像做了一副浇铸勺子的模子,可使用铁、铝和铜等不同金属液体,浇铸出不同材料的勺子。具体浇铸出的是哪一种材料,由浇铸材料决定。它不是抽象出一类物质的共同特征,而是归纳出不同类型事物的共同操作,称之为类模板。,2.6 string对象数组与范型算法 第1.4.4节介绍的范型算法同样适合string类,但string对象之间可以直接赋值,所以更为简单。需要注意的是,不要将1.4.4节介绍的find函数与string本身的成员

49、函数混淆。另外,string类还有一个swap成员函数,用来交换两个对象的属性。假设有两个string类的对象str1和str2,下面两种调用方式是等效的: str1.swap(str2); str2.swap(str1); 【例2.9】演示string对象的例子。 #include #include #include using namespace std; void main(), string str1=we are here!,str2=str1; reverse( /逆向输出 这里使用str1初始化str2(与str2=str1等效),是为了在保证复制时,str2能有足够的空间存储s

50、tr1。另外要注意ostream_iterator的数据类型是char,不是string。输出结果如下:,!ereh era ew !ereh era ew we are here! string是系统提供的类,当然就有其特殊性质。其实,string类提供了一对用来指示其元素位置的基本成员函数:指示第一元素的begin( )和指示结束的标记end( )。它们标示要进行迭代的元素空间。如果begin不等于end,算法便会首先作用于begin所指元素,并将begin前进一个位置,然后作用于当前的begin所指元素身上,如此继续进行,直到begin等于end为止,所以它们是元素存在的半开区间begi

51、n,end)。,图2.8是str1和迭代区间示意图。 str1.begin()指示第1个元素 str.end()指示最后一个元素之后的结束位置 有了这两个成员函数,就可以用它们表示迭代区间。 【例2.10】是演示string对象使用成员函数表示迭代区间的例子。,【例2.10】演示string对象使用成员函数表示迭代区间的例子。 #include #include #include #include using namespace std; void main() string str1=wearehere!,str2(str1); /使用str1 /初始化str2 reverse(str1.b

52、egin(),str1.end(); /字符串元 /素逆向 coutstr1endl;,copy(str1.begin(),str1.end(),str2.begin(); /原样 /复制到str2,要求str2更够容纳 sort(str1.begin(),str1.end(); /默认升幂排序 cout(cout); /输出逆向后 /的部分内容 coutendl;,sort(str1.begin(),str1.end(), greater(); /降幂排序 coutstr1endl; /输出排序后的字串str1 str1.swap(str2); /互相交换内容 coutstr1 str2en

53、dl; cout(*find(str1.begin(),str1.end(),e)=e) /注意不是成员函数find (*find(str1.begin(),str1.end(),O)=O) endl; 程序输出结果如下:,!ereheraew !aeeeehrrw !ereheraew wrrheeeea! eeeehr wrrheeeea! wreeeehra! wrrheeeea! 1 0 虽然可以声明string类的数组,但只能对数组分量使用范型算法,不能对整个数组使用范型算法。不过swap成员函数可以用来交换两个数组分量。【例2.11】是演示string对象数组的例子。,【例2.11

54、】演示string对象数组的例子。 #include #include #include using namespace std; void main() string str=We are here!, Where are you?,welcome!; for( int i=0;i(cout);,coutendl; str0.swap (str2); str0.swap(str1); for(i=0; i3;i+) coutstriendl; 除非输出部分内容,否则使用coutstri的方法更方便。程序输出结果如下: We are here! Where are you? welcome!

55、Where are you? welcome! We are here!,2.7 结构化程序设计典型例题 顺序结构是最简单而基本的结构,它是顺序执行各个语句。C+语言的结构化程序设计的语句称为程序控制结构,又可分为控制循环和控制选择(选择结构)。程序控制语句是用来描述语句的执行条件与执行顺序的语句。C+语言的控制语句有: if( )else 条件语句 for( ) 循环语句 while( ) 循环语句 dowhile( ) 循环语句 continue 结束本次循环语句 break 中止循环或 switch语句 switch 多分支选择语句 goto 转移语句 return 从函数返回语句 以上

56、9种语句中的括号( )表示其中是一个条件, 表示内嵌的语句。例如一条if( )else的具体语句可写成:,if ( x y )z = x; elsez = y; 因为这些与C语言的一样,所以不再赘述。本节主要使用string类进行编程,目的是既复习巩固程序控制结构,又熟悉类和对象的使用方法。 【例2.12】条件运算符表达式类型不同的例子。 #include #include using namespace std; void main( ) int x(0); string str1(通过), str2=没通过,str;,cinx; str=(x59?str1:str2); /使用条件运算符表

57、达式 coutstrendl; 条件运算符表达式中的表达式1是整型,其他两个为string。当输入大于59时,程序输出“通过”,否则输出“没通过”。 【例2.13】使用if语句嵌套形式的例子。 这个程序使用嵌套形式的if语句,程序根据学生的考分,来划分成绩的优秀(10085)、良好(84 75) 、及格(74 60)、不及格(59 0 )。 假定考分变量为score,则其程序如下所示:,#include #include using namespace std; void main( ) int score=0; string grade; coutscore; if ( score84 ) grade=优秀; else if ( score75 ) grade=良好; else if ( score59 ) grade=及格; else grade=不及格; coutscore分为gradeendl; ,运行实例: 成绩score:84 84分为良好 【例2.14】从键盘接收输入,用Ctrl+Z键

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论