04737C++程序设计精华.docx

上传人:b****5 文档编号:28315947 上传时间:2023-07-10 格式:DOCX 页数:54 大小:124.27KB
下载 相关 举报
04737C++程序设计精华.docx_第1页
第1页 / 共54页
04737C++程序设计精华.docx_第2页
第2页 / 共54页
04737C++程序设计精华.docx_第3页
第3页 / 共54页
04737C++程序设计精华.docx_第4页
第4页 / 共54页
04737C++程序设计精华.docx_第5页
第5页 / 共54页
点击查看更多>>
下载资源
资源描述

04737C++程序设计精华.docx

《04737C++程序设计精华.docx》由会员分享,可在线阅读,更多相关《04737C++程序设计精华.docx(54页珍藏版)》请在冰豆网上搜索。

04737C++程序设计精华.docx

04737C++程序设计精华

04737C++程序设计精华

fghb

 

第一章认识C++的对象

1.1初识C++的函数和对象

一般称现实世界中客观存在的事物为对象。

用关键字const修饰的标识符是一类特殊的常量,称为符号常量,或const变量。

使用const允许编译器对其进行类型检查并可改善程序的可读性。

C++语言可以使用宏定义。

无参数的宏作为常量,而参数的宏则可以提供比函数更高的效率。

但预处理只是进行简单的文本代替而不进行语法检查,所以会存在一些问题。

因为被const修饰的变量的值在程序中不能被改变,所以在声明符号常量是,必须对符号常量进行初始化,除非这个变量使用extern修饰的外部变量。

C++语言预处理程序不是C++编译程序的一部分,它负责分析处理几种特殊的语句,这些语句被称为预处理语句。

顾名思义,预处理程序对这几种特殊语句的分析处理是在编译程序的其他部分之前进行的。

为了与一般的C++程序语句相区别,所有预处理语句都以位于行首的符号“#”开始。

预处理语句有3种,分别是宏定义、文件包含和条件编译。

预处理程序把所有出现的、被定义的名字全部替换成对应的“字符序列”。

#define中的名字与C++中的标识符有相同的形式,为了区别,往往用大写字母来表示(标识符用小写字母),这也适合const语句。

文件引用使用双引号还是尖括号,其含义并不一样。

采用尖括号引用系统提供的包含文件,C++编译系统将首先在C++系统设定的目录中寻找包含文件,如果没有找到,就到指定的目录中去寻找。

采用双引号引用自己定义的包含文件(一般都放在自己定义的指定目录中),这将通知C++编译器在用户当前的目录下或指定的目录下寻找包含文件。

指定的目录不必在同一个逻辑盘中。

8.程序运行结果

9.程序书写格式

1.2认识C++语言面向过程编程的特点

C++语言的标准模板库(StandardTempleteLibrary,STL)提供了与要操作的元素类型无关的算法,不仅使许多复杂问题迎刃而解,而且也将许多面向对象的程序设计问题转化成基于对象的面向过程编程。

1.2.1使用函数重载

C++允许为一个函数定义几个版本,从而使一个函数名具有多种功能,这称为函数重载。

1.2.2新的基本数据类型及其注意事项

void是无类型标识符,只能声明函数的返回值类型,不能声明变量。

C++语言还比C语言多了bool(布尔)型。

C++标准只限定int和short至少要有16位,而long至少32位,short不得长于int,int不得长于long。

地址运算符“&”用来取对象存储的首地址。

C++语言中的整数常量有4种类型:

十进制常量、长整型常量、八进制常量和十六进制常量,并用前缀和后缀进行分类标识。

1.2.3动态分配内存

在使用指针时,如果不使用对象地址初始化指针,可以自己给它分配地址。

对于值存储一个基本类型数据的指针,申请的方式如下:

new类型名[size]//申请可以存储size个该数据类型的对象

不再使用时,简单地使用“delete指针名”即可释放已经申请的存储空间。

1.2.4引用

别名的地址就是原来对象的地址,选定命名时使用“引用”运算符“&”,再选用数据类型与之配合。

引用的声明方式如下:

数据类型&别名=对象名;

所谓“引用”就是将一个新标识符和一块已经存在的存储区域相关联。

因此,使用引用时没有分配新的存储区域,它本身并不是新的数据类型。

引用通常用于函数的参数表中或者作为函数的返回值。

对引用实质性的理解应抓住如下两点:

(1)引用实际上就是变量的别名,使用引用就如同直接使用变量一样。

引用与变量名在使用的形式上是完全一样的,引用只是作为一种标识对象的手段,不能直接声明对数组的引用,也不能声明引用的引用。

(2)引用的作用与指针有相似之处,它会对内存地址上存在的变量进行修改,但它不占用新的地址,从而节省开销。

1.2.5对指针使用const限定符

可以用const限定符强制改变访问权限。

1.左值和右值

左值是指某个对象的表达式。

2.指向常量的指针

指向常量的指针是在非常量指针声明前面使用const,例如:

constint*p;

它告诉编译器,“*p”是常量,不能将“*p”作为左值进行操作,即限定了“*p=”的操作,所以称为指向常量的指针。

3.常量指针

把const限定符放在*号的右边,是使指针本身称为一个const指针。

intx=5;

int*constp=&x;

不能改变p的指向,但可以通过间接引用运算符“*”改变其值,例如语句“*p=56;”将上面的x的值改变为56。

4.指向常量的常量指针

也可以声明指针和指向的对象都不能改动的“指向常量的常量指针”,这时必须要初始化指针。

例如:

intx=2;

constint*constp=&x;

告诉编译时,*p和p都是常量,都不能作为左值。

1.2.6泛型算法应用于普通数组

所谓泛型算法,就是提供的操作与元素的类型无关。

1.2.7数据的简单输入输出格式

C++提供了两种格式控制方式:

一种是使用ios_base类提供的接口;另一种是使用一种称为操控符的特殊函数,它的特点是可直接包含在输出和输入的表达式中,因此更为方便,不带形式参数的操控符定义在头文件中,带形式参数的操控符定义在头文件中。

使用它们时,一是要正确包含它们,二是只有与符号“<<”或“>>”连接时才起作用,三是无参数的操控符函数不能带有“()”号。

1.3程序的编辑、编译和运行的基本概念

用C++语言写成的程序称为源程序,源程序必须经过C++编译程序翻译成机器语言才能执行。

要得到一个用C++语言设计的、名为myapp.exe的可执行文件,其过程可分为如下几步:

(1)先使用编辑器编辑一个C++程序mycpp.cpp,又称其为C++的源程序。

(2)然后使用C++编译器对这个C++程序进行编译,产生文件mycpp.obj

(3)再使用连接程序(又称Link),将mycpp.obj变成mycpp.exe

所谓集成环境,就是将C++语言编辑、编译、连接和运行程序都集成到一个综合环境中。

第二章从结构到类的演变

2.1结构的演化

类是从结构演变而来,开始称为“带类的C”。

这种演变就是从让结构含有函数开始的。

2.1.1结构发生质的演变

1.函数与数据共享

2.封装性

2.1.2使用构造函数初始化结构对象

2.2从结构演变一个简单的类

2.3面向过程与面向对象

所谓“面向过程”,就是不必了解计算机的内部逻辑,而把精力主要集中在对如何求解问题的算法和过程的描述上,通过编写程序把解决问题的步骤告诉计算机。

所谓函数,就是模块的基本单位,是对处理问题的一种抽象。

结构化程序设计使用的是功能抽象,面向对象程序设计不仅能进行功能抽象,而且能进行数据抽象。

“对象”实际上是功能抽象和数据抽象的统一。

面向对象的程序设计方法不是以函数过程和数据结构为中心,而是以对象代表求解问题的中心环节。

他最求的是现实问题空间与软件系统解空间的近似和直接模拟。

软件开发是对给定问题求解的过程。

从认识论的角度看,可以归为两项主要的活动:

认识与描述。

软件开发者将被开发的整个业务范围称作“问题域”(problemdomain),“认识”就是在所要处理的问题域范围内,通过人的思维,对该问题域客观存在的事物以及对所要解决的问题产生正确的认识和理解,包括弄清事物的属性,行为及其彼此之间的关系并找出解决问题的方法。

“描述”是指用一种语言把人们对问题域中事物的认识、对问题及其解决方法的认识描述出来。

最终的描述必须使用一种能够被机器读得懂的语言,即编程语言。

2.4C++面向对象程序设计的特点

和传统的程序设计方法相比,面向对象的程序设计具有抽象、封装、继承和多态性等关键要素。

2.4.1对象

C++可使用对象名、属性和操作三要素来描述对象。

2.4.2抽象和类

抽象是一种从一般的观点看待事物的方法,即集中于事物的本质特征,而不是具体细节或具体实现。

类的概念来自于人们认识自然、认识社会的过程。

在这一过程中,人们主要使用由特殊到一般的归纳法和由一般到特殊的演绎法。

在归纳的过程中,是从一个个具体的事物中把共同的特征抽取出来,形成一个一般的概念,这就是“归类”;在演绎的过程中,把同类事物,根据不同的特征分成不同的小类,这就是“分类”。

对于一个具体的类,它有许多具体的个体,这些个体叫做“对象”。

类的作用是定义对象。

所谓“一个类的所有对象具有相同的属性”,是指属性的个数、名称、数据类型相同,各个对象的属性值则可以互不相同,并且随着程序的执行而变化。

2.4.3封装

将类封装起来,也是为了保护类的安全。

所谓安全,就是限制使用类的属性和操作。

对象内部数据结构这种不可访问性称为信息(数据)隐藏。

封装就是把对象的属性和操作结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。

在类中,封装是通过存取权限实现的。

2.4.4继承

继承是一个类可以获得另一个类的特性的机制,继承支持层次概念。

通过继承,低层的类只须定义特定于它的特征,而共享高层的类中的特征。

2.4.5多态性

不同的对象可以调用相同名称的函数,但可导致完全不同的行为的现象称为多态性。

2.5使用类和对象

2.5.1使用string对象

所谓方法,书就是供这类对象使用的成员函数。

对象使用自己的成员函数的方法是通过“.”运算符,格式如下:

对象名.成员函数

2.5.2使用string类的典型成员函数实例

2.5.3使用complex对象

C++标准程序库提供complex类定义复数对象。

2.5.4使用对象小结

注意:

类是抽象出一类物质的共同特征,模板则是归纳出不同类型事物的共同操作。

2.6string对象数组与泛型算法

第3章函数和函数模板

3.1函数的参数及其传递方式

C语言函数参数的传递方式只有传值一种,传值又分为传变量值和传变量地址值两种情况。

比较复杂的是结构变量,结构变量的值是指结构域中所有的变量值。

在C++中,像int、float、double、char、bool等简单数据类型的变量,也是对象。

类对象一般都包括数据成员和成员函数,如果在C++沿用C语言的说法,则对象的值就是对象所有数据成员的值,约定参数传递中传递“对象值”是指对象的数据成员值,传递“对象地址值”是指对象的首地址值。

C++函数还可以使用传递对象的“引用”方式,即它的函数参数有两种传递方式:

传值和传引用。

传引用其实就是传对象的地址,所有也称传地址方式。

参数传递中不要混淆传地址值和传地址的区别。

传地址值传递的是值,不是地址;传地址传的是地址不是地址值。

传递对象地址值是使用对象指针做为参数;传递地址时使用对象引用作为参数。

3.1.1对象作为函数参数

将对象作为函数参数,是将实参对象的值传递给形参对象,这种传递是单向的。

形参拥有实参的备份,当在函数中改变形参的值时,改变的是这个备份中的值,不会影响原来实参的值。

3.1.2对象指针作为函数参数

将指向对象的指针作为函数参数,形参是对象指针(指针可以指向对象的地址),实参是对象的地址值。

注意:

不要非要在主程序里产生指针,然后再用指针作为参数。

函数原型参数的类型是指针,可以指针让它指向对象地址,即:

string*s1=&str1;

是完全正确的,使用&str1标识的是取对象str1的地址值,所以&str1直接作为参数即可。

3.1.3引用作为函数参数

可以使用“引用”作为函数的参数(引用形参)。

这时函数并没有对形参对象初始化,即没有指定形参对象是哪个对象的别名。

在函数调用是,实参对象名传给形参对象名,形参对象名就成为实参对象名的别名。

实参对象和形参对象代表同一个对象,所以改变形参对象的值就是改变实参对象的值。

实际上,在虚实结合时是把实参对象的地址传给形参对象,使形参对象的地址取实参对象的地址,从而使形参对象和实参对象共享同一个单元。

这就是地址传递方式。

通过使用引用参数,一个函数可以修改另外一个函数内的变量。

因为引用对象不是一个独立的对象,不单独占用内存单元,而对象指针要另外开辟内存单元(其内容是地址),所以传引用比传指针更好。

注意:

虽然系统向形参传递的是实参的地址而不是实参的值,但实参必须使用对象名。

3.14默认参数

默认参数就是不要求程序员设定该参数,而由编译器在需要时给该参数赋默认值。

当程序员需要传递特殊值时,必须显式地指明。

默认参数是在函数原型中说明的,默认参数可以多于1个,但必须放在参数序列的后部。

如果一个默认参数需要指明一个特定值,则在其之前所有的参数都必须赋值。

3.1.5使用const保护数据

用const修饰传递参数,意思是通知函数,它只能使用参数而无权修改它。

这主要是为了提高系统的自身安全。

C++中普遍采用这种方法。

3.2深入讨论函数返回值

C++函数的返回值类型可以是除数组以外的任何类型。

非void类型的函数必须向调用者返回一个值。

数组只能返回地址。

当函数返回值是指针或引用对象时,需要特别注意:

函数返回所指的对象必须继续存在,因此不能将函数内部的局部对象作为函数的返回值。

3.2.1返回引用的函数

函数可以返回一个引用,将函数说明为返回一个引用的主要目的是为了将该函数用在赋值运算符的左边。

函数原型的表示方法如下:

数据类型&函数名(参数列表);

3.2.2返回指针的函数

函数的返回值可以是存储某种类型数据的内存地址,称这种函数为指针函数。

它们的一般定义形式如下:

类型标识符*函数名(参数列表);

在C++中,除了内存分配失败之外,new不会返回空指针,并且没有任何对象的地址为零。

指针所指向的对象的生存期不应低于该指针的生存期。

3.2.3返回对象的函数

3.2.4函数返回值作为函数的参数

如果用函数返回值作为另一个函数的参数,这个返回值必须与参数类型一致。

3.3内联函数

使用关键字inline说明的函数称内联函数。

在C++中,除具有循环语句、switch语句的函数不能说明为内联函数外,其他函数都可以说明为内联函数。

使用内联函数能加快程序执行速度,但如果函数体语句多,则会增加程序代码的大小。

使用小的内联函数在代码速度和大小上可以取得折衷,其他情况下取决于程序员是追求代码速度,还是追求代码的规模。

由于编译器必须知道内联函数的函数体,才能进行内联替换,因此,内联函数必须在程序中第一次调用此函数的语句出现之前定义。

3.4函数重载和默认参数

函数重载可以使一个函数名具有多种功能,即具有“多种形态”,这种特性称为多态性。

C++的多态性又被直观地称为“一个名字,多个函数”。

源代码只指明函数调用,而不说明具体调用哪个函数。

编译器的这种连接方式称为动态联编或迟后联编。

在动态联编中,直到程序运行才能确定调用哪个函数(动态联编需要虚函数的支持)。

如果编译器在编译时,能根据源代码调用固定的函数标识符,并用物理地址代替它们,这就称为静态联编或先期联编。

静态联编是在程序被编译时进行的。

使用默认参数,就不能对少于参数个数的函数进行重载。

另外,仅有函数返回值不同也是区分不了重载函数的。

当使用默认参数设计类的构造函数时,要特别注意这一问题。

3.5函数模板

1.引入函数模版

由于函数在设计时没有使用实际的类型,而是使用虚拟的类型参数,故其灵活性得到加强。

当用实际的类型来实例化这种函数时,就好像按照模版来制造新的函数一样,所以称这种函数为函数模板。

将函数模版与某个具体数据类型连用,就产生了模板函数,又称这个过程为函数模板实例化,这种形式就是类型参数化。

2.函数模板的参数

对于一个默认调用,能从函数参数推断出模板参数的能力是其中最关键的一环。

要想省去显式调用的麻烦,条件是由这个调用的函数参数表能够惟一地标识出模板参数的一个集合。

3.使用显式规则和关键字typename

C++专门定义一个仅仅用在模板中的关键字typename,它的用途之一是代替template参数列表中的关键字class。

第4章类和对象

4.1类及其实例化

对象就是一类物体的实例,将一组对象的共同特征抽象出来,从而形成“类”的概念。

4.1.1定义类

像C语言构造结构一样,类也是一种用户自己构造的数据类型并遵循C++的规定。

类要先声明后使用,不管声明内容是否相同,声明同一个名字的两个类是错误的,类是具有惟一标识符的实体;在类中声明的任何成员不能使用extern、auto和register关键字进行修饰;类中声明的变量属于该类,在某些情况下,变量也可以被该类的不同实例所共享。

类和其他数据类型不同的是,组成这种类型的不仅可以有数据,而且可以有对数据进行操作的函数,他们分别叫做类的数据成员和类的成员函数,而且不能在类声明中对数据成员使用表达式进行初始化。

1.类声明

类声明以关键字class开始,其后跟类名。

类所声明的内容用花括号括起来,右花括号后的分号作为类关键字声明语句的结束标志。

这一对花括号之间的内容称为类体;

访问权限用于控制对象的某个成员在程序中的可访问性,如果没有使用关键字,则所有成员默认声明为private权限。

2.定义成员函数

类中声明的成员函数用来对数据成员进行操作,还必须在程序中实现这些成员函数。

定义成员函数的一般形式如下:

返回类型类名:

成员函数名(参数列表)

{

成员函数的函数体//内部实现

}

其中“:

”是作用域运算符,“类名”是成员函数所属类的名字,“:

”用于表名其后的成员函数是属于这个特定的类。

换言之,“类名:

成员函数名”的意思就是对属于“类名”的成员函数进行定义,而“返回类型”则是这个成员函数返回值的类型。

也可以使用关键字inline将成员函数定义为内联函数。

如果在声明类的同时,在类体内给出成员函数的定义,则默认为内联函数。

3.数据成员的赋值

不能在类体内给数据成员赋值。

在类体外就更不允许了。

数据成员的具体值是用来描述对象的属性的。

只有产生了一个具体的对象,这些数据值才有意义。

如果在产生对象时就使对象的数据成员具有指定值,则称为对象的初始化。

4.1.2使用类的对象

对象和引用都使用运算符“.”访问对象的成员,指针则使用“->”运算符。

暂不涉及还没有介绍的保护成员,可以归纳出如下规律:

(1)类的成员函数可以直接使用自己类的私有成员(数据成员和成员函数)

(2)类外面的函数不能直接访问类的私有成员(数据成员和成员函数)

(3)类外面的函数只能通过类的对象使用该类的公有成员函数。

在程序运行时,通过为对象分配内存来创建对象。

在创建对象时,使用类作为样板,故称对象为类的实例。

定义类对象指针的语法如下:

类名*对象指针名;

对象指针名=对象的地址;

也可以直接进行初始化。

类名*对象指针名=对象的地址;

类对象的指针可以通过“->”运算符访问对象的成员,即:

对象指针名->对象成员名

4.1.3数据封装

面向对象的程序设计是通过为数据和代码建立分块的内存区域,以便提供对程序进行模块化的一种程序设计方法,这些模块可以被用做样板,在需要时在建立其副本。

根据这个定义,对象是计算机内存中的一块区域,通过将内存分块,每个模块(即对象)在功能上保持相对独立。

对象被视为能做出动作的实体,对象使用这些动作完成相互之间的作用。

换句话说,对象就像在宿主计算机上拥有数据和代码并能相互通信的具有特定功能的一台较小的计算机。

4.2构造函数

C++有称为构造函数的特殊成员函数,它可自动进行对象的初始化。

初始化和赋值是不同的操作,当C++语言预先定义的初始化和赋值操作不能满足程序的要求时,程序员可以定义自己的初始化和赋值操作。

4.2.1默认构造函数

当没有为一个类定义任何构造函数的情况下,C++编译器总要自动建立一个不带参数的构造函数。

4.2.2定义构造函数

1.构造函数的定义和使用方法

构造函数的名字应与类名同名。

并在定义构造函数时不能指定返回类型,即使void类型也不可以。

当声明一个外部对象时,外部对象只是引用在其他地方声明的对象,程序并不为外部对象说明调用构造函数。

如果是全局对象,在main函数执行之前要调用它们的构造函数。

2.自动调用构造函数

程序员不能在程序中显式地调用构造函数,构造函数是自动调用的。

例如构造一个Point类的对象a,不能写成“Pointa.Point(x,y);”,只能写成“Pointa(x,y);”。

编译系统会自动调用Point(x,y)产生对象a并使用x和y将其正确地初始化。

可以设计多个构造函数,编译系统根据对象产生的方法调用相应的构造函数,构造函数是在产生对象的同时初始化对象的。

4.2.3构造函数和预算符new

运算符new用于建立生存期可控的对象,new返回这个对象的指针。

由于类名被视为一个类型名,因此,使用new建立动态对象的语法和建立动态变量的语法类似,其不同点是new和构造函数一起使用。

使用new建立的动态对象只能用delete删除,以便释放所占空间。

应养成及时释放不再使用的内存空间的习惯。

4.2.4构造函数的默认参数

如果程序定义自己的有参数构造函数,又想使用无参数形式的构造函数,解决的方法时间相应的构造函数全部使用默认的参数设计。

4.2.5复制构造函数

引用在类中一个很重要的用途是用在复制构造函数中。

一是一类特殊而且重要的函数,通常用于使用已有的对象来建立一个新对象。

在通常情况下,编译器建立一个默认复制构造函数,默认复制构造函数采用拷贝方式使用已有的对象来建立新对象,所以又直译为拷贝构造函数。

程序员可以自己定义复制构造函数,对类A而言,复制构造函数的原型如下:

A:

:

A(A&)

从这个函数原型来看,首先它是一个构造函数,因为这毕竟是在创造一个新对象。

其次,他的参数有些特别,是引用类自己的对象,即用一个已有的对象来建立新对象。

使用引用是从程序的执行效率角度考虑的。

为了不改变原有对象,更普通的形式是像下面这样使用const限定:

A:

:

A(constA&)

像调用构造函数一样,如果自定义了复制构造函数,编译器只调用程序员为它设计的赋值构造函数。

在C++中,在一个类中定义的成员函数可以访问该类任何对象的私有成员。

4.3析构函数

在对象消失时,应使用析构函数释放由构造函数分配的内存。

构造函数、赋值构造函数和析构函数是构造型成员函数的基本成员,应深刻理解他们的作用并熟练掌握其设计方法。

4.3.1定义析构函数

因为调用析构函数也是由编译器来完成的,所以编译器必须总能知道应调用哪个函数。

最容易、也最符合逻辑的方法是指定这个函数的名称与类名一样。

为了与析构函数区分,在析构函数的前面加上一个“~”号(仍然称析构函数与类同名)。

在定义析构函数时,不能指定任何返回类型,即使指定void类型返回类型也不行。

析构函数也不能指定参数,但是可以显示地说明参数为void,即形如A:

~A(void)。

从函数重载的角度分析,一个类也只能定义一个析构函数且不能指明参数,以便编译系统自动调用。

析构函数在对象的生存期结束时被自动调用。

当对象的生存期结束时,程序为这个对象调用析构函数,然后回收这个对象占用的内存。

全局对象和静态对象的析构函数在程序运行结束之前调用。

类的对象数组的每个元素调用一次析构函数。

全局对象数组的析构函数在程序结束之前被调用。

4.3.2析构函数与运算符delete

运算符delete与析构函数一起工作。

当使用运算符delete删除一个动态对象时,他首先为这个动态对象调用析构函数,然后再释放这个

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1