C++是在 C 语言基础上开发的一种集面向对象编程、泛型编程和过程化编程于一体的编程语言,是C语言的超集。本书是根据2003年的ISO/ANSI C++标准编写的,通过大量短小精悍的程序详细而全面地阐述了 C++的基本概念和技术,并专辟一章介绍了C++11新增的功能。
《C++ Primer Plus(第6版)中文版》分18章,分别介绍了C++程序的运行方式、基本数据类型、复合数据类型、循环和关系表达式、分支语句和逻辑运算符、函数重载和函数模板、内存模型和名称空间、类的设计和使用、多态、虚函数、动态内存分配、继承、代码重用、友元、异常处理技术、string类和标准模板库、输入/输出、C++11新增功能等内容。
《C++ Primer Plus(第6版)中文版》针对C++初学者,从C语言基础知识开始介绍,然后在此基础上详细阐述C++新增的特性,因此不要求读者有C语言方面的背景知识。《C++ Primer Plus(第6版)中文版》可作为高等院校教授C++课程的教材,也可供初学者自学C++时使用。
本章内容包括:
C++变量的命名规则。
C++内置的整型——unsigned long、long、unsigned int、int、unsigned short、
short、char、unsigned char、signed char 和 bool。
C++11 新增的整型:unsigned long long 和 long long。 表示各种整型的系统限制的 climits 文件。
各种整型的数字字面值(常量)。
使用 const 限定符来创建符号常量。
C++内置的浮点类型:float、double 和 long double。
表示各种浮点类型的系统限制的 cfloat 文件。
各种浮点类型的数字字面值。
C++的算术运算符。
自动类型转换。
强制类型转换。
面向对象编程(OOP)的本质是设计并扩展自己的数据类型。设计自己的数据类型就是让类型与数据 匹配。如果正确做到了这一点,将会发现以后使用数据时会容易得多。然而,在创建自己的类型之前,必须了解并理解 C++内置的类型,因为这些类型是创建自己类型的基本组件。
内置的 C++类型分两组:基本类型和复合类型。本章将介绍基本类型,即整数和浮点数。似乎只有两种类型,但 C++知道,没有任何一种整型和浮点型能够满足所有的编程要求,因此对于这两种数据,它提供了多种变体。第 4 章将介绍在基本类型的基础上创建的复合类型,包括数组、字符串、指针和结构。
当然,程序还需要一种标识存储的数据的方法,本章将介绍这样一种方法—使用变量;然后介绍如 何在 C++中进行算术运算;最后,介绍 C++如何将值从一种类型转换为另一种类型。
3.1 简单变量
程序必须记录 3 个基本属性:
信息将存储在哪里;
要存储什么值;
存储何种类型的信息
例如:
int braincount;
braincount 5;
这些语句告诉程序,它正在存储整数,并使用名称 braincount 来表示该整数的值(这里为 5)。实际上, 程序将找到一块能够存储整数的内存,将该内存单元标记为 braincount,并将 5 复制到该内存单元中;然 后,您可在程序中使用 braincount 来访问该内存单元。这些语句没有告诉您,这个值将存储在内存的什位置,但程序确实记录了这种信息。实际上,可以使用&运算符来检索 braincount 的内存地址。下一章介绍另一种标识数据的方法(使用指针)时,将介绍这个运算符。
3.1.1 变量名
必须遵循几种简单的 C++命名规则
在名称中只能使用字母字符、数字和下划线(_)。
名称的第一个字符不能是数字。
区分大写字符与小写字符。
不能将 C++关键字用作名称。
以两个下划线或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符。
C++对于名称的长度没有限制,名称中所有的字符都有意义,但有些平台有长度限制。
C++提供了一种灵活的标 准,它确保了最小长度(从 C 语言借鉴而来),如下所示:
short 至少 16 位;
int 至少与 short 一样长;
long 至少 32 位,且至少与 int 一样长;
long long 至少 64 位,且至少与 long 一样长
*位与字节
计算机内存的基本单元是位(bit)。可以将位看作电子开关,可以开,也可以关。关表示值 0,开表示值 1。8 位的内存块可以设置出 256 种不同的组合,因为每一位都可以有两种设置,所以 8 位的总组合数为 2×2×2×2×2×2×2×2,即 256。因此,8 位单元可以表示 0-255 或者-128 到 127。每增加一位,组合数便加倍。这意味着可以把 16 位单元设置成 65 536 个不同的值,把 32 位单元设置成 4 294 672 296个不同的值,把 64 位单元设置为 18 446 744 073 709 551 616 个不同的值。作为比较,unsigned long 存储不了地球上当前的人数和银河系的星星数,而 long long 能够。
字节(byte)通常指的是 8 位的内存单元。从这个意义上说,字节指的就是描述计算机内存量的度量单位,1KB 等于 1024 字节,1MB 等于 1024KB。然而,C++对字节的定义与此不同。C++字节由至少能够容纳实现的基本字符集的相邻位组成,也就是说,可能取值的数目必须等于或超过字符数目。在美国,基本字符集通常是 ASCII 和 EBCDIC 字符集,它们都可以用 8 位来容纳,所以在使用这两种字符集的系统中,C++字节通常包含 8 位。然而,国际编程可能需要使用更大的字符集,如 Unicode,因此有些实现可能使用16 位甚至 32 位的字节。有些人使用术语八位组(octet)表示 8 位字节。
3.1.4 无符号类型
前面介绍的 4 种整型都有一种不能存储负数值的无符号变体,其优点是可以增大变量能够存储的最大 值。例如,如果 short 表示的范围为−32768 到+32767,则无符号版本的表示范围为 0-65535。当然,仅当数值不会为负时才应使用无符号类型,如人口、粒数等。要创建无符号版本的基本整型,只需使用关键字 unsigned 来修改声明即可
整型溢出:
该程序将一个 short 变量(sam)和一个 unsigned short 变量(sue)分别设置为最大的 short 值,在我们的系统上,是 32767。然后,将这些变量的值都加 1。这对于 sue 来说没有什么问题,因为新值仍比无符号整数的最大值小得多;但 sam 的值从 32767 变成了−32768!同样,对于 sam,将其设置为 0 并减去 1,也不会有问题;但对于无符号变量 sue,将其设置为 0 并减去后,它变成了 65535。可以看出,这些整型变量的行为就像里程表。如果超越了限制,其值将为范围另一端的取值(参见图 3.1)。C++确保了无符号类型的这种行为;但 C++并不保证符号整型超越限制(上溢和下溢)时不出错,而这正是当前实现中最为常见的行为。
3.1.7 C++如何确定常量的类型
程序的声明将特定的整型变量的类型告诉了 C++编译器,但编译器是如何知道常量的类型呢?假设在程序中使用常量表示一个数字:程序将把 1492 存储为 int、long 还是其他整型呢?答案是,除非有理由存储为其他类型(如使用了特殊的后缀来表示特定的类型,或者值太大,不能存储为 int),否则 C++将整型常量存储为 int类型。
首先来看看后缀。后缀是放在数字常量后面的字母,用于表示类型。整数后面的 l 或 L 后缀表示该整 数为 long 常量,u 或 U 后缀表示 unsigned int 常量,ul(可以采用任何一种顺序,大写小写均可)表示 unsigned long 常量(由于小写 l 看上去像 1,因此应使用大写 L 作后缀)。例如,在 int 为 16 位、long 为 32 位的系统上,数字 22022 被存储为 int,占 16 位,数字 22022L 被存储为 long,占 32 位。同样,22022LU 和 22022UL都被存储为 unsigned long。C++11 提供了用于表示类型 long long 的后缀 ll 和 LL,还提供了用于表示类型 unsigned long long 的后缀 ull、Ull、uLL 和 ULL。
接下来考察长度。在 C++中,对十进制整数采用的规则,与十六进制和八进制稍微有些不同。对于不带后缀的十进制整数,将使用下面几种类型中能够存储该数的最小类型来表示:int、long 或 long long。
在 int 为 16 位、long 为 32 位的计算机系统上,20000 被表示为 int 类型,40000 被表示为 long 类型,3000000000 被表示为 long long 类型。对于不带后缀的十六进制或八进制整数,将使用下面几种类型中能够存储该数的最小类型来表示:int、unsigned int long、unsigned long、long long 或 unsigned long long。在将 40000 表示为 long 的计算机系统中,十六进制数 0x9C40(40000)将被表示为 unsigned int。这是因为十六进制常用来表示内存地址,而内存地址是没有符号的,因此,usigned int 比 long 更适合用来表示 16 位的地址。
3.3.1 书写浮点数
C++有两种书写浮点数的方式。
第一种是使用常用的标准小数点表示法:
即使小数部分为 0(如 8.0),小数点也将确保该数字以浮点格式(而不是整数格式)表示。(C++标准允许实现表示不同的区域;例如,提供了使用欧洲方法的机制,即将逗号而不是句点用作小数点。然而,这些选项控制的是数字在输入和输出中的外观,而不是数字在代码中的外观。)
第二种表示浮点值的方法叫做 E 表示法,其外观是像这样的:3.45E6,这指的是 3.45 与 1000000 相乘的结果;E6 指的是 10 的 6 次方,即 1 后面 6 个 0。因此,3.45E6 表示的是 3450000,6 被称为指数,3.45 被称为尾数。下面是一些例子
E 表示法确保数字以浮点格式存储,即使没有小数点。注意,既可以使用 E 也可以使用 e,指数可以是正数也可以是负数。(参见图 3.3。)然而,数字中不能有空格,因此 7.2 E6 是非法的。
指数为负数意味着除以 10 的乘方,而不是乘以 10 的乘方。因此,8.33E~4 表示 8.33/104 ,即 0.000833。 同样,电子质量 9.11e~31 kg表示 0.000000000000000000000000000000911 kg。可以按照自己喜欢的方式表示数字(911 在美国是报警电话,而电话信息通过电子传输,这是巧合还是科学阴谋呢?读者可以自己作出评判)。注意,−8.33E4 指的是−83300。前面的符号用于数值,而指数的符号用于缩放。
记住:d.dddE+n 指的是将小数点向右移 n 位,而 d.dddE~n 指的是将小数点向左移 n 位。之所以称为“浮点”,就是因为小数点可移动。
3.5 总结
C++的基本类型分为两组:一组由存储为整数的值组成,另一组由存储为浮点格式的值组成。整型之间通过存储值时使用的内存量及有无符号来区分。整型从最小到最大依次是:bool、char、signed char、unsigned char、short、unsigned short、int、unsigned int、long、unsigned long 以及 C++11 新增的 long long和 unsigned long long。还有一种 wchar_t 类型,它在这个序列中的位置取决于实现。C++11 新增了类型 char16_t 和 char32_t,它们的宽度足以分别存储 16 和 32 位的字符编码。C++确保了 char 足够大,能够存储系统基本字符集中的任何成员,而 wchar_t 则可以存储系统扩展字符集中的任意成员,short 至少为 16位,而 int 至少与 short 一样长,long 至少为 32 位,且至少和 int 一样长。确切的长度取决于实现。字符通过其数值编码来表示。I/O 系统决定了编码是被解释为字符还是数字。浮点类型可以表示小数值以及比整型能够表示的值大得多的值。3 种浮点类型分别是 float、double 和long double。C++确保 float 不比 double 长,而 double 不比 long double 长。通常,float 使用 32 位内存,double 使用 64 位,long double 使用 80 到 128 位。通过提供各种长度不同、有符号或无符号的类型,C++使程序员能够根据特定的数据要求选择合适的 类型。
C++使用运算符来提供对数字类型的算术运算:加、减、乘、除和求模。当两个运算符对同一个操作数进行操作时,C++的优先级和结合性规则可以确定先执行哪种操作。 对变量赋值、在运算中使用不同类型、使用强制类型转换时,C++将把值从一种类型转换为另一种类型。很多类型转换都是“安全的”,即可以在不损失和改变数据的情况下完成转换。例如,可以把 int 值转换为 long 值,而不会出现任何问题。对于其他一些转换,如将浮点类型转换为整型,则需要更加小心。开始,读者可能觉得大量的 C++基本类型有些多余,尤其是考虑到各种转换规则时。但是很可能最终将发现,某些时候,只有一种类型是需要的,此时您将感谢 C++提供了这种类型。
3.6 复习题
1.为什么 C++有多种整型?
2.声明与下述描述相符的变量。
a.short 整数,值为 80
b.unsigned int 整数,值为 42110
c.值为 3000000000 的整数
3.C++提供了什么措施来防止超出整型的范围?
4.33L 与 33 之间有什么区别?
5.下面两条 C++语句是否等价?
6.如何使用 C++来找出编码 88 表示的字符?指出至少两种方法。
7.将 long 值赋给 float 变量会导致舍入误差,将 long 值赋给 double 变量呢?将 long long 值赋给 double 变量呢?
8.下列 C++表达式的结果分别是多少?
9.假设 x1 和 x2 是两个 double 变量,您要将它们作为整数相加,再将结果赋给一个整型变量。请编写一条完成这项任务的 C++语句。如果要将它们作为 double 值相加并转换为 int 呢?
10.下面每条语句声明的变量都是什么类型?
3.7 编程练习
1.编写一个小程序,要求用户使用一个整数指出自己的身高(单位为英寸),然后将身高转换为英尺和英寸。该程序使用下划线字符来指示输入位置。另外,使用一个 const 符号常量来表示转换因子。
2.编写一个小程序,要求以几英尺几英寸的方式输入其身高,并以磅为单位输入其体重。(使用 3 个变量来存储这些信息。)该程序报告其 BMI(Body Mass Index,体重指数)。为了计算 BMI,该程序以英寸 的方式指出用户的身高(1 英尺为 12 英寸),并将以英寸为单位的身高转换为以米为单位的身高(1 英寸 =0.0254 米)。然后,将以磅为单位的体重转换为以千克为单位的体重(1 千克=2.2 磅)。最后,计算相应的BMI—体重(千克)除以身高(米)的平方。用符号常量表示各种转换因子。
3.编写一个程序,要求用户以度、分、秒的方式输入一个纬度,然后以度为单位显示该纬度。1 度为 60 分,1 分等于 60 秒,请以符号常量的方式表示这些值。对于每个输入值,应使用一个独立的变量存储它。
下面是该程序运行时的情况:
4.编写一个程序,要求用户以整数方式输入秒数(使用 long 或 long long 变量存储),然后以天、小时、分钟和秒的方式显示这段时间。使用符号常量来表示每天有多少小时、每小时有多少分钟以及每分钟 有多少秒。该程序的输出应与下面类似:
5.编写一个程序,要求用户输入全球当前的人口和美国当前的人口(或其他国家的人口)。将这些信息存储在 long long 变量中,并让程序显示美国(或其他国家)的人口占全球人口的百分比。该程序的输出应与下面类似:
6.编写一个程序,要求用户输入驱车里程(英里)和使用汽油量(加仑),然后指出汽车耗油量为一 加仑的里程。如果愿意,也可以让程序要求用户以公里为单位输入距离,并以升为单位输入汽油量,然后 指出欧洲风格的结果—即每 100 公里的耗油量(升)。
7.编写一个程序,要求用户按欧洲风格输入汽车的耗油量(每 100 公里消耗的汽油量(升)),然后将其转换为美国风格的耗油量—每加仑多少英里。注意,除了使用不同的单位计量外,美国方法(距离/燃料)与欧洲方法(燃料/距离)相反。100 公里等于 62.14 英里,1 加仑等于 3.875 升。因此,19mpg 大约 合 12.4l/100km,l27mpg 大约合 8.71/100km。