2.1 基本内置类型
包含算术类型和空类型(void)
2.1.1 算术类型
带符号类型和无符号类型
除布尔型和字符型外,其他整形可划分为带符号和无符号两种
字符被划分为char、signed char 和unsigned char
2.1.2 类型转换
含有无符号类型的表达式
2.1.3 字面值常量
形如42的值被称作字面值常量,每个字面值常量对应一种数据类型,字面值常量的形式和值决定了它的数据类型
整形和浮点型字面值
整形字面值具体的数据类型由它的值和符号决定,默认十进制字面值是带符号数,类型是int,long和long long中尺寸最小的那个,八进制和十六进制是能容纳其数值的int\unsinged int\long\unsinged long\long long 中尺寸最小者。
浮点型字面值默认为double
字符和字符串字面值
字符串字面值实际是由常量字符构成的数组
转义序列
两类字符程序员不能直接使用:
- 不可打印的字符:如退格或其他控制字符
- C++语言中特殊含义的字符:单引号,双引号等
在上述两种情况下需要使用转义序列:
指定字面值的类型
** 布尔字面值和指针字面值**
true和false是布尔类型的字面值
nullptr是指针字面值
2.2 变量
变量提供一个具名的,可供程序操作的存储空间,C++中,变量和对象一般可互换使用。
2.2.1 变量定义
对象是指一块能存储数据并具有某种类型的内存空间。
初始值
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值代替
列表初始化
列表初始化是指用花括号初始化变量
默认初始化
内置类型定义在函数体外被初始化为0;定义在函数体内将不被初始化,此时试图拷贝或其他形式访问此类值将引发错误,建议初始化每一个内置类型的变量。
类类型各自决定其初始化对象的方式,以及是否允许不初始化就定义对象也由类自己决定,类类型未显示初始化,其值由类确定。
2.2.2 变量声明和定义的关系
为了允许把程序拆分成多个逻辑部分来编写,C++语言支持分离式编译机制,为了实现这个功能,C++语言将声明和定义区分开来,声明使得名字为程序所知,定义负责创建与名字相关联的实体。
2.2.3 标识符
变量命名规范
变量名一般小写,用户自定义类名首字母大写
2.2.4 名字的作用域
同一名字在不同作用于中可能指向不同的实体,作用域以花括号分隔
建议当第一次使用变量时再定义它
嵌套的作用域
局部变量覆盖全局变量
2.3 复合类型
2.3.1 引用
引用为对象起了另外一个名字,引用和变量的初始值会绑定在一起,而不是将变量的初始值拷贝给引用
引用即别名
引用并非对象,相反,它只是为一个已经存在的对象所起的另外一个名字
引用本身不是一个对象,所以不能定义引用的引用
引用的定义
一个变量允许定义多个引用
引用只能绑定对象,而不能域字面值或者表达式的值绑定在一起
2.3.2 指针
- 指针与引用类似,实现了对其他对象的间接访问
- 不同在于指针本身就是一个对象,允许赋值和拷贝,切无需在定义时赋初值
获取对象的地址
用取地址符&
指针类型需要与它所指向的对象严格匹配
指针值
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针,没有指向任何对象
- 无效指针,上述情况之外的其他值
利用指针访问对象
如果指针指向对象,可使用解引用符*来访问该对象
空指针
几个生成空指针的方法:
将int变量直接赋值给指针是错误的操作
赋值和指针
是对指针的操作还是对指针所指向的对象的操作
其他指针操作
指针合法,就可以用于if等条件表达式中,指针值是0,条件取false
void*指针
可用于存放任意对象的地址,但我们不能直接操作void*所指向的对象,因为我们不知道它指向的对象的类型
2.3.3 理解复合类型的声明
定义多个变量
错误观点认为类型修饰符(*或&)作用于本次定义的全部变量
指向指针的指针
一般来说声明符中修饰符的个数并没有限制,当多个修饰符连写在一起时,按照其逻辑关系详加解释即可。以指针为例,允许指向指针的指针
通过一次或多次解引用可以得到指针或者访问最原始的对象
指向指针的引用
无指向引用的指针,但存在指针的引用
2.4 const 限定符
const对变量的类型加以限定,防止其不经意地被改变
const对象一旦创建,其值不能再改变
初始化和const
可以用变量初始化const 变量,可以用const变量执行任何不改变其值的操作
默认状态下,const对象仅在当前文件内有效
多个文件出现同名的const变量,等同于不同文件中分别定义了独立的变量
如果想再一个文件中定义const对象,而在其他多个文件中使用它,解决方法是对于const变量不管是声明还是定义都添加extern关键字,这样之定义一次就可以了
2.4.1 const的引用
不允许通过const引用改变const对象的值
初始化和对const的引用
引用的类型必须与其所引用对象的类型一致,但是有两个例外
- 初始化常量引用时允许用任意表达式作为初始值,
为了确保ri绑定一个整数,编译器将上述代码变为如下形式:
这种情况下,ri绑定了一个临时量对象。
当ri不是常量时,如果执行上面的初始化,C++将把这种行为归为非法,因为通过ri只能改变临时量的值而无法改变所引用对象的值。
对const的引用可能引用一个并非const的对象
常量引用的对象可以不是常量,此时不能通过常量引用改变其值,但可以通过其他途径改变其值。
2.4.2 指针和const
指向常量的指针不能用于改变其所指向对象的值,要想存放常量对象的地址,只能使用指向常量的指针。
指针类型必须与所指向的对象的类型一致,但有两个例外:
- 允许指向常量的指针指向一个非常量对象
- 和常量引用一样,指向常量的指针可以指向非常量对象,只是无法通过该指针改变非常量对象的值。
const指针
常量指针必须初始化且一经初始化就不能改变,*放在const关键字之前用以说明指针是一个常量,不变的是指针本身而非指向的那个值。
弄清这些声明的含义最行之有效的方法是从右向左阅读。
指针本身是一个常量并不意味着不能通过指针修改其所指向的对象的值,如curErr
2.4.3 顶层const
顶层const表示指针本身是一个常量,而底层const表示指针所指的对象是一个常量。
指针类型既可以是顶层const,也可以是底层const
当执行对象的拷贝操作时,const是顶层还是底层区别明显,其中顶层const不受什么影响。
另一方面,底层const的限制不能忽视,当执行对象的拷贝操作时,考入和考出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换,一般来说,非常量可以转化成常量,反之不行
2.4.4 constexpr和常量表达式
常量表达式是指在编译过程就能得到计算结果的表达式
constexpr变量
在一个复杂系统中,很难分别一个初始值到底是不是常量表达式,C++11新标准规定,允许将变量声明为constexpr类型一遍由编译器来验证变量的值是否是一个常量表达式
字面值类型
常量表达式的值在编译时得到,因此对声明constexpr时用到的类型必须有所限制,将算术类型,引用和指针等简单的类型成为字面值类型,而自定义类不属于字面值类型。
指针和constexpr
constexpr声明定义了一个指针,限定符constwxpr仅仅对针织有效,与指针所指的对象无关。
与其他常量指针类似,constexpr既可以指向常量也可以指向非常量。
2.5 处理类型
2.5.1 类型别名
两种方法定义类型别名:
- 关键字typedef
- 别名声明
类型别名和类型名等价
指针、常量和类型别名
2.5.2 auto类型说明符
由auto类型说明符定义的变量能让编译器通过初始值推断变量的类型
使用auto在一条语句中声明多个变量:
复合类型、常量和auto
2.5.3 decltype类型指示符
有时候希望从表达式的累心推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。
declype和引用
2.6 自定义数据结构
2.6.1 定义Sales_data类型
一般不建议将类的定义和变量的定义放在一起
2.6.2 使用Sales_data类
添加两个Sales_data对象
Sales_data对象对入数据
输出两个Sales_data对象的和
2.6.3 编写自己的头文件
类一般不定义在函数体内部,通常被定义在头文件中,而且类所在的头文件的名字应该与类的名字一样。
预处理器概述
确保头文件多次包含仍能安全工作的常用技术是预处理器