2 变量和基本类型
2.1 基本内置类型
c++包含了一套包括算术类型和空类型在内的基本数据类型。其中算术类型包含了字符、整型数和布尔值和浮点数。空类型不对应具体的值。
2.1.1 算术类型
算术类型分为两类:整型(包括字符和布尔类型在内)和浮点型
类型 | 含义 | 最小尺寸 |
---|---|---|
bool | 布尔类型 | 未定义 |
char | 字符 | 8位 |
wchar_t | 宽字符 | 16位 |
char16_t | Unicode字符 | 16位 |
char32_t | Unicode字符 | 32位 |
short | 短整型 | 16位 |
int | 整型 | 16位 |
long | 长整型 | 32位 |
long long | 长整型 | 64位 |
float | 单精度浮点数 | 6位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
带符号类型和无符号类型
2.1.2 类型转换
含有无符号类型的表达式
1.当一个无符号的数与另外一个数(包括有符号数和无符号数),结果是所的结果的模
2.使用无符号数来进行循环时,有可能造成死循环
3.切勿混用带符号和无符号数
2.1.3 字面值常量
整型和浮点数
1.整型字面值的具体的数据类型由它的值和符号决定。默认情况下,十进制字面值是带符号数,是int,long,long long 中尺寸最小的那个,一般为int
2.八进制和十六进制既可能是带符号也可能是无符号的。八进制和十六进制字面值的类型是能容纳其数值的int,unsigned int,long,unsigned long,long long 和unsigned long long 中的尺寸最小者。
3.short没有对应的字面值
4.默认的浮点型字面值是一个double
字符和字符串字面值
1.字符串字面值的类型实际上是由常量字符组成的数组,编译器在每个字符串的结尾处加一个' '字符
2.如果两个字符串位置紧邻且由空格、缩进和换行分隔
转义序列
指定字面值的类型
前缀 | 含义 | 类型 |
---|---|---|
u | Unicode16字符 | char16_t |
U | Unicdoe32字符 | char32_t |
L | 宽字符 | wchar_t |
u8 | UTF-8(仅用于字符串字面常量) | char |
布尔字面值和指针字面值
1.布尔类型的字面值是true和false
2.nullptr是指针字面值
2.2 变量
2.2.1变量定义
初始值
1.在c++中初始化和赋值是两个完全不同的操作
列表初始化
1.列表初始化用于内置类型的变量且存在丢失信息的风险时,编译器会报错
默认初始化
1.如果定义变量没有被指定初值,则变量被默认初始化,默认值由变量类型决定
2.如果变量定义于函数之外,则被初始化为0;定义在函数体内置类型变量将不被初始化
2.2.2 变量声明和定义的关系
1.c++将声明和定义分离开来。声明使得名字为程序所知;定义负责创建与名字关联的实体
2.如果想声明一个变量而非定义它,那么需要在变量名前加extern,而且不要显式地初始化变量。
2.2.3 标识符
c++的标识符由字母、数字和下划线组成,其中必须以字母或者下划线开头,标识符长度没有限制,但是对大小写字母敏感。
变量命名规范
2.2.4 名字的作用域
嵌套的作用域
2.3 复合类型
2.3.1 引用
- 引用必须初始化。一旦初始化完成,引用将和它的初始值一直邦定在一起
引用即别名
引用的定义
- 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
2.3.2 指针
指针和引用的区别:
- 指针本身就是一个对象,允许对指针赋值和拷贝,指针的声明周期内可以指向几个不同的对象
- 指针无须在定义时赋初始值
获取对象的地址 取地址符&
指针值
利用指针访问对象 *
空指针 nullptr
赋值和指针
其他指针操作
void*指针
void* 是一种特殊的指针类型,可以用于存放任意对象的地址。
2.3.3 理解复合类型的声明
指向指针的指针
指向指针的引用
2.4 const限定符
const对象一旦创建后其值就不能再改变,所以必须初始化。
初始化和const
默认状态下,const对象仅在文件内有效
为了在多个文件中共享const变量,解决办法是不管声明还是定义都添加extern关键字
2.4.1 const 的引用
初始化和对const的引用
引用的第一种例外情况,初始化常量引用允许使用任意表达式作为初始值,只要该表达式的结果能够转换成引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值。
对const的引用可能引用一个并非const的对象
2.4.2 指针和const
1.指向常量的指针不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针
2.指向常量的指针可以指向非常量对象
const指针
1.常量指针必须初始化,而且一旦初始化完成,它的值就不能变化了
2.4.3 顶层const
1.顶层const 表示指针本身是个常量;底层const表示指针所指向的对象是一个常量
2.当执行对象的拷贝操作时,常量是顶层const还是底层const区别明显。其中,顶层const不受什么影响;另一方面,底层const的限制不能忽视。当执行对象的拷贝操作时,拷入和拷出的对象具有相同的底层const资格,或者两个对象的数据类型能够进行转换。一般来说,非常量可以转换成常量
3.用于声明引用的const都是底层const
2.4.4 constexpr和常量表达式
- 常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。
constexpr常量
- constexpr变量一定是个常量,而且必须用产量表达式初始化
字面值类型
1.算术类型、引用和指针都属于字面值类型;自定义类型、IO库、string类型则不属于字面值类型
指针和constexpr
2.5 处理类型
2.5.1 类型别名
1.传统的方法是 typedef
2.别名声明 using
指针、常量和类型别名
如果某个类型别名指代的是复合类型或常量,那么把它用到声明语句就会产生意想不到的后果。
typedef char* pstring;
const pstring cstr;//这里定义的实际上是一个常量指针,而不是一个指向指向常量的指针
2.5.2 auto类型说明符
1.auto在一条语句中声明多个变量时,该语句中所有变量的初始基本数据类型都必须一样。
复合类型、常量和auto
auto的一些规则:
1.当引用被用作初始值时,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型
2.auto一般会忽略掉顶层const(常量指针),同时底层const 则会保留下来
3.如果希望推断出auto类型是一个顶层const,则需要明确指出,如const auto f = ci;
4.设置一个类型为auto的引用是,初始值中的顶层常量属性仍然保留。和往常一样,如果我们给初始值绑定一个引用,则此时的常量(坑人呢,这个常量指的是绑定引用的常量而不是初始值的常量)就不是顶层常量了
2.5.3 decltype类型指示符 选择并返回操作数的数据类型
1.如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)
decltype和引用
1.如果decltype使用的表达不是一个变量,则decltype返回表达式结果对应的类型。如果表达式返回一个引用类型时,则该表达式结果对象需要作为赋值语句的左值,必须初始化。
2.如果表达式的内容是解引用操作,返回的类型得到引用类型。
3.decltype 返回的类型与表达式的形式密切相关,如果decltype使用了一个加上括号的变量,则会返回对应的引用类型;如果使用的是不加括号的类型,则会将其当作一个表达式。
2.6 自定义数据结构
2.6.1 定义Sales_data类型
类数据成员
2.6.2 使用Sales_data类
2.6.3 编写自己的头文件
预处理概述
8.1 io类
- iostream
- fstream
- sstream
8.1.1 IO对象无拷贝或赋值
- 不能拷贝IO对象,因此不能将形参或者返回类型设置为流类型。进行IO操作的类型通常以引用的方式传递和返回流
- 读写IO会改变其状态,因此传递和返回的引用不能是const的
8.1.2 条件状态
IO库的条件状态
条件状态 | 描述 |
---|---|
strm::iostate | strm 是一种IO类型。iostate是一种机器相关的类型,提供了表达条件状态的完整功能 |
strm::badbit | strm::badbit用来指出流已崩溃 |
strm::failbit | strm::failbit用来指出一个IO操作失效了 |
strm::eofbit | strm::eofbit用来指出流到达了文件结束 |
strm::goodbit | strm::goodbit用来之后粗流未处于错误状态,此值保证为0 |
一个流一旦发生错误,其上后续的IO操作就会失败。因此需要在使用流之前检查它是否处于良好状态,最简单的办法是将它当作条件来使用
查询流的状态
管理条件状态
8.1.3 管理输出缓冲
导致缓冲刷新的原因有很多:
- 程序正常结束,作为main函数或者return操作的一部分,缓冲刷新被执行
- 缓冲区满时,需要刷新缓冲
- 可以使用endl等操作符来显式刷新缓冲区
- 每个输出操作之后,可以用操作符unitbuf 设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的
- 一个输出流可能被关联到另外一个流。当读写被关联的流是,关联到的流会被刷新
刷新输出缓冲区
- endl:输出一个换行,并刷新
- flush:刷新缓冲区
- ends:输出一个空字符,并刷新缓冲区
unitbuf 操纵符
- unitbuf:所有输出操作后都会立即刷新缓冲区
- nounitbuf 回到正常的缓冲方式
关联输入和输出流
tie():返回指向输出流的指针,如果本对象当前关联到一个输出流,那么返回这个流的指针
tie(&ostream)将本对象关联到一个ostream
8.2文件输入输出
fstream 特有的操作
特性 | 描述 |
---|---|
fstream fstrm; | 创建一个未绑定的文件流,fstream 是头文件中定义的一个类型 |
fstream fstrm(s); | 创建一个fstream 打开名为s的文件。s可以是string类型的,或者是一个指向c风格字符串的指针。这些构造函数都是explicit的,默认的文件模式依赖于fstream的类型 |
fstream fstrm(s,mode); | 以指定mode打开文件 |
fstrm.open(s) | 打开名为s的文件,并将文件与fstrm绑定。s可以是一个string 或者一个指向c风格字符串的指针。默认的文件mode依赖于fstram的指针 |
fstrm.close() | 关闭与fstrm绑定的文件。返回void |
fstrm.is_open() | 返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭 |