第一部分 基本语言
基本上所有的语言都提供下列特征:内置数据类型,表达式和语句,变量,控制结构,函数
C++是 静态类型语言,在编译时执行类型检查,C++提供了一组内置数据类型、操纵这些类型的操作符和一组少量的程序流控制语句,C++的表达能力是通过支持一些允许程序员定义新数据结构的机制来提升的,C++重要特征是类,程序员可以使用类自定义数据类型,类类型,C++标准库利用这些特征,实现了一个具有丰富类类型和相关函数的标准库
C++标准库 利用内置类型、自定义类类型,实现了一个 具有丰富类类型 和 相关函数 的标准库
第二章 变量和基本类型
类型是所有程序的基础,类型告诉我们 数据代表什么意思 以及可以对数据执行哪些操作
C++语言,定义了几种基本类型:字符型、整形、浮点型等,还提供了可用于自定义数据类型的机制,还能修改已有的类型以形成复合类型
2.1. 基本内置类型
C++定义了一组 表示整形、浮点型、单个字符和布尔型的 算术类型,另外还定义了一种称为void的特殊类型(通常作为无返回值函数的返回类型,void类型没有对应的值),C++标准规定了每个算术类型的最小存储空间,但它并不阻止编译器使用更大的存储空间
2.1.1 整形
表示整数、字符和布尔值的 算术类型 合称为整形
C++内置类型与其在计算机的存储器中的表示方式密切相关,让存储具有结构的最基本方法是用块处理存储,8位的块作为一个字节(byte),32位或4个字节作为一个字(word)
可以用地址表示从该地址开始的任何几个不同大小的位集合,要让地址的字节具有意义,必须知道存储在该地址的值得类型,一旦知道了该地址的类型,就知道了表示该类型的值需要多少位和如何解释这些位
short、int、long类型都表示整形值,存储空间的大小不同,short类型为半个机器字长,int类型为一个机器字长,long类型为一个或两个机器字长
bool类型表示真值true和false,可以将算术类型的任何值赋给bool对象,0值算术类型代表false,任何非0的值都代表true
除bool类型外,整形可以是带符号的,也可以是无符号的,整形int、 short、 long都默认为带符号型,如获得无符号型,则必须指定该类型为unsigned,和其他整形不同,char有三种不同的类型,普通char、unsigned char 和 signed char,但只有两种表示方式,可以使用 unsigned char 或 signed char表示char类型,表示方式由编译器而定
对于unsigned类型来说,编译器会将越界值对unsigned类型的可能取值数目求模,然后取所得值,比如8位的unsigned char,其取值范围从0到255,如果赋值超过这个范围的值,那么编译器将会取该值对256求模后的值,对于unsigned类型来说,负数总是超出其取值范围,把负值赋值给unsigned对象是完全合法的,其结果是 该负数 对该类型的取值个数 求模后的值
2.1.2 浮点型
float型保证6位有效数字,double至少可以保证10位有效数字,当计数元素时使用标准库定义的类型总是正确的,char类型通常用来存储字符而不用于计算,使用double类型基本上不会出错
2.2 字面值常量
字面值常量,称为 字面值 是因为只能用它的值称呼它,称为 常量 是因为它的值不能修改,每个字面值都有相应的 类型
2.2.1 整形字面值规则
定义字面值整数常量 可以使用三种进制中的任一种:十进制、八进制、十六进制,字面值整数常量 的 类型 默认为int或long类型,其精度类型决定于字面值,定义长整型时字面常量,应该使用大写字母L,小写的很容易和数值1混淆,定义unsigned类型,在数值后加字母U
2.2.2 浮点字面值规则
通常可以用十进制或者科学计数法来表示浮点字面值常量,使用科学计数法时,指数用E或e,默认的浮点字面值常量为double类型,数值的后面加F表示单精度,加 L 表示表示扩展精度(long double)
2.2.3 布尔字面值 和 字符字面值
单词true和false是布尔值的字面值,可打印的字符字面值,用一对单引号来定义,这些字面值都是char类型的,在字符字面值前加L能够得到 wchar_t类型的宽字符字面值
2.2.4 非打印字符的转义序列
不可打印字符和特殊字符都用转义字符书写
2.2.5 字符串字面值
字符串字面值是一串常量字符,字符串字面值常量用双引号括起来的零个或多个字符表示,为了兼容C语言,C++中所有的 字符串字面值都由编译器自动在末尾添加一个空字符, 字符串字面值的连接:在一行的末尾加一反斜线符号可将此行和下一行当作同一行处理,反斜线符号必须是该行的尾字符,
2.3 变量
C++是一门静态类型语言,在编译时会作类型检查,因此,程序中使用变量前必须先定义变量的类型
2.3.1 什么是变量
变量提供了程序可以操作的 有名字的存储区,C++程序员 常常把 变量称为"变量" 或 "对象"(object),左值:左值出现在赋值语句的左边或右边,右值:右值只能出现在赋值的右边,变量是左值,因此可以出现在赋值语句的左边,变量的值是当前存储在和该变量相关联的内存中的值,对象就是内存中具有类型的区域,计算左值表达式就会产生对象
2.3.2 变量名
变量名,即变量的标识符,可以由字母、数字、下划线组成,变量名必须以字母或下划线开头,并且区分大小写字母:C++中的标识符都是大小写敏感的
除了关键字,C++还保留了一些 用作各种操作符的替代名 (如 and),用于支持某些不支持标准C++操作符符号集的字符集,C++标准还保留了 一组标识符用于标准库,标识符不能包含二个连续的下划线,也不能以下划线开头后面紧跟字一个大写字母,有些标识符不能以下划线开头,
变量名的命名习惯:变量名一般用小写字母,标识符应使用能帮助记忆的名字,多个词的标识符,每个词之间加一个下划线或每个内嵌的第一个字母都大写
2.3.3 定义对象
每个定义都是以类型说明符开始,后面紧跟着以逗号分开的含有一个或多个说明符的列表,分号结束定义
C++支持两种初始化变量的形式:复制初始化( = )和直接初始化( () ),初始化不是赋值,指创建变量并给它赋初值,赋值 则是 擦除对象的当前值并用新值代替,初始化内置类型的对象只有一种方法:提供一个值,并把这个值复制到新定义的对象中,初始化类类型的变量,使用构造函数(直接初始化调用与实参匹配的构造函数,复制初始化总是调用复制构造函数)
2.3.4 变量初始化规则
内置类型变量是否自动初始化取决于变量定义的位置,在函数体外定义的内置类型变量都初始化成0,在函数体里定义的内置类型变量不进行自动初始化,建议每个内置类型的对象都要初始化
类通过定义一个或多个构造函数来控制 类对象的初始化,如果定义每个类的变量没有提供初始化式,这个类也可以定义初始化时的操作,它通过定义一个特殊的构造函数即 默认构造函数来实现,每个类最好有一个默认构造函数,没有默认构造函数的,每个定义都必须提供显式的初始化
2.3.5 变量的定义和声明
C++程序通常由许多文件组成,为了让多个文件访问相同的变量,C++区分了声明和定义
变量的定义,用于为变量分配存储空间,还可以为变量指定初始值,在一个程序中,变量必须且仅能定义一次,而且在使用变量之前必须定义或声明变量
声明用于向程序表明变量的类型和名字,定义也是声明,当定义变量时声明了它的类型和名字,可以通过使用extern关键字声明变量名而不定义它,不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern,extern声明不是定义,也不分配存储空间,它只是说明变量定义在程序的其他地方,如果声明有初始化,那么它可以被当作是定义,即使声明标记为extern,只有当extern声明位于函数外部时,才可以含有初始化式
任何在多个文件中使用的变量 都需要有与定义分离的声明,在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)
2.3.6 名字的作用域
用来区分名字的不同意义的上下文称为作用域,作用域是程序的一段区域,一个名称可以和不同作用域中的不同实体相关联,C++语言中,大多数作用域是用花括号来界定的,一般来说,名字从其声明点开始直到其声明所在的作用域结束处都是可见的
定义在所有函数外部的名字具有 全局作用域,定义在函数内部的具有 局部作用域,定义在语句中的,具有 语句作用域,定义咋全局作用域中的名字可以在局部作用域中使用,定义在全局作用域的名字和定义在函数的局部作用域中的名字可以在语句作用域中使用,局部变量屏蔽全局变量,C++还有两种不同级别的作用域,类作用域 和 命名空间作用域
2.3.7 在变量使用处定义变量
通常把一个对象定义在它首次使用的地方是一个很好的办法
2.4 const限定符
const限定符,把一个对象转换成一个常量,常量在定义后不能被修改,所以定义时必须初始化,如:const int bufSize = 512;
在全局作用域声明的 const 变量 是定义该对象的文件的 局部变量,此变量只存在于那个文件中,不能被其他文件访问,如果const变量前面加上 extern ,整个程序都可以访问,如 extern const int bufSize = 512;, 非const变量默认为extern, 要使const变量能够在其他的文件中访问,必须显式的指定它为extern
2.5 引用
引用就是对象的另一个名字,引用是一种复合类型,通过在变量名前添加&符号来定义,复合类型,是指用其他类型定义的类型 ,在引用的情况下,每一种引用类型都关联到某一其他类型,引用只是它绑定的对象的另外一个名字,当引用初始化后,只要该引用存在,它就保持绑定到初始化时指定的对象,不可能将引用绑定到另外一个对象
const 引用是指向const对象的引用,如:const int ival = 1024; const int &refVal = ival;,又如:const int &refVal = 1024;,const引用可以绑定到不同但相关的类型的对象 或 绑定到右值,将普通的引用绑定到const对象是不合法的,const的引用的意义,是,不能通过const引用修改其指向对象的值,const的引用可以指向非const对象
2.6 typedef名字
typedef可以用来定义类型的同义词,typedef名字可以用作类型说明符
2.7 枚举
枚举不但定义了整数常量集,而且还把它们聚集成组,枚举的定义包括关键字enum,其后是一个可选的枚举类型名,和一个用花括号括起来、用逗号分开的枚举成员列表,可以为一个或多个枚举成员提供初始值,用来初始化枚举成员的值必须是一个常量表达式,如:enum Weapon { ARROW = 1, SWORD, BOMB },常量表达式是编译器在编译时就能够计算出结果的 整形表达式,整形字面常量是常量表达式,枚举成员 可以初始化 枚举类型的对象,如:Weapon warriorWeapon = ARROW;
枚举成员值可以是不唯一的,不能改变枚举成员的值,枚举成员本身就是一个常量表达式,每个enum都定义一种唯一的类型,枚举类型的对象 的初始化或赋值,只能通过其枚举成员 或 同一枚举类型的其他对象 来进行
2.8 类类型
默认情况下,struct 的成员为public,而class的成员为private,类定义了该类型的对象包含的数据 和该类型对象可以执行的操作 ,类体可以为空,类体定义了组成该类型的数据和操作,这些操作和数据是类的一部分,也称为类的成员,操作是成员函数 ,而数据则称为数据成员
定义类时,通常先定义该类的接口,即该类所提供的操作
2.9 编写自己的头文件
2.9.1 设计自己的头文件
头文件为相关声明提供了一个集中存放的位置,头文件一般包含类的定义、extern变量的声明 和 函数的声明,头文件用于声明而不是用于定义,定义只可以出现一次,而声明可以出现多次,因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义,对于头文件不应该含有定义这一规则,有三个例外:头文件可以定义类、 值在编译时就已知道的const对象 和 inline函数,因为 const对象 默认为定义它的文件的局部变量,所以把它们的定义放到头文件中是合法的
2.9.2 预处理器的简单介绍
#include 指示只接受一个参数:头文件名,预处理器用指定的头文件的内容替代每个 #include
必须保证多次包含同一头文件不会引起该头文件定义的类和对象被 多次定义,使得头文件安全的通用做法,是使用预处理器定义 头文件保护符
如:
#ifndef SALESITEM_H
#define SALESITEM_H
//...
#endif
预处理器变量 的名字在程序中必须是唯一的,任何与预处理器变量相匹配的名字的使用都关联到该预处理器变量,为了避免名字冲突,预处理器变量经常用全大写字母表示,预处理器变量有两种状态:已定义或未定义:#define指示接受一个名字并定义该名字为预处理器变量,#ifndef指示检测指定的预处理器变量是否未定义,如果预处理器变量未定义,那么紧跟其后的所有指示都被处理,直到出现#endif
术语:access label(访问标号,如,public),arithmetic type(算术类型),direct-initialization(直接初始化),enumeration(枚举),enumerator(枚举成员),const reference(const引用),constant expression(常量表达式),escape sequence(转义字符),global scope(全局作用域),header guard(头文件保护符),implementation(实现),preprocessor(预处理器),liter constant(字面值常量),separate compilation(分别编译)