|
1 | 1 | # 第二章 变量和基本类型 |
2 | 2 |
|
3 | | -## 基本算数类型 |
| 3 | +### 基本内置类型 |
4 | 4 |
|
5 | | -- `char`: 8bits |
6 | | -- `short`: 16bits |
7 | | -- `int`: 16bits (在32位机器中是32bits) |
8 | | -- `long`: 32bits |
9 | | -- `long long`: 64bits (是在C++11中新定义的) |
10 | | -- `float`:6位有效数字。 |
11 | | -- `double`:10位有效数字。 |
12 | | -- `long double`:10位有效数字。 |
| 5 | +**基本算数类型**: |
13 | 6 |
|
14 | | -## 如何选择类型 |
| 7 | +| 类型 | 含义 | 最小尺寸| |
| 8 | +|---|---|---| |
| 9 | +| `bool` | 布尔类型 | 8bits | |
| 10 | +| `char`| 字符 | 8bits | |
| 11 | +| `wchar_t` | 宽字符 | 16bits | |
| 12 | +| `char16_t` | Unicode字符 | 16bits | |
| 13 | +| `char32_t` | Unicode字符 | 32bits | |
| 14 | +| `short` | 短整型 | 16bits | |
| 15 | +| `int` | 整型 | 16bits (在32位机器中是32bits) | |
| 16 | +| `long` | 长整型 | 32bits | |
| 17 | +| `long long` | 长整型 | 64bits (是在C++11中新定义的) | |
| 18 | +| `float` | 单精度浮点数 | 6位有效数字 | |
| 19 | +| `double` | 双精度浮点数 | 10位有效数字 | |
| 20 | +| `long double` | 扩展精度浮点数 | 10位有效数字 | |
| 21 | + |
| 22 | + |
| 23 | +### 如何选择类型 |
15 | 24 |
|
16 | 25 | - 1.当明确知晓数值不可能是负数时,选用无符号类型; |
17 | 26 | - 2.使用`int`执行整数运算。一般`long`的大小和`int`一样,而`short`常常显得太小。除非超过了`int`的范围,选择`long long`。 |
18 | 27 | - 3.算术表达式中不要使用`char`或`bool`。 |
19 | 28 | - 4.浮点运算选用`double`。 |
20 | 29 |
|
21 | | -## 类型转换 |
| 30 | +### 类型转换 |
22 | 31 |
|
23 | 32 | - 非布尔型赋给布尔型,初始值为0则结果为false,否则为true。 |
24 | 33 | - 布尔型赋给非布尔型,初始值为false结果为0,初始值为true结果为1。 |
25 | 34 |
|
26 | | -## 左值和右值 |
| 35 | +### 字面值常量 |
27 | 36 |
|
28 | | -- **左值**(l-value)**可以**出现在赋值语句的左边或者右边,比如变量; |
29 | | -- **右值**(r-value)**只能**出现在赋值语句的右边,比如常量。 |
| 37 | +- 一个形如`42`的值被称作**字面值常量**(literal)。 |
| 38 | + - 整型和浮点型字面值。 |
| 39 | + - 字符和字符串字面值。 |
| 40 | + - 使用空格连接,继承自C。 |
| 41 | + - 字符字面值:单引号, `'a'` |
| 42 | + - 字符串字面值:双引号, `"Hello World""` |
| 43 | + - 转义序列。`\n`、`\t`等。 |
| 44 | + - 布尔字面值。`true`,`false`。 |
| 45 | + - 指针字面值。`nullptr` |
30 | 46 |
|
31 | | -## 字符串字面值 |
| 47 | +## 变量 |
32 | 48 |
|
33 | | -- 使用空格连接,继承自C。 |
34 | | -- 字符字面值:单引号, `'a'` |
35 | | -- 字符串字面值:双引号, `"Hello World""` |
| 49 | +**变量**提供一个**具名**的、可供程序操作的存储空间。 `C++`中**变量**和**对象**一般可以互换使用。 |
36 | 50 |
|
37 | | -## 初始化和赋值 |
| 51 | +### 变量定义(define) |
38 | 52 |
|
39 | | -- **对象的初始化**:定义时指定了初始值的对象成为是已初始化的。 |
40 | | -- **初始化不是赋值!**: |
| 53 | +- **定义形式**:类型说明符(type specifier) + 一个或多个变量名组成的列表。如`int sum = 0, value, units_sold = 0;` |
| 54 | +- **初始化**(initialize):对象在创建时获得了一个特定的值。 |
| 55 | + - **初始化不是赋值!**: |
41 | 56 | - 初始化 = 创建变量 + 赋予初始值 |
42 | 57 | - 赋值 = 擦除对象的当前值 + 用新值代替 |
43 | | -- 建议初始化每一个内置类型的变量。 |
44 | | -- **构造函数**:定义如何进行初始化的成员函数。 |
45 | | -- **列表初始化**:使用花括号 `{}` 中包含一系列相同类型的值。 |
46 | | -- 默认初始化:定义时没有指定初始值会被默认初始化;在函数体内部的内置类型变量将不会被初始化。 |
| 58 | + - **列表初始化**:使用花括号`{}`,如`int units_sold{0};` |
| 59 | + - 默认初始化:定义时没有指定初始值会被默认初始化;在函数体内部的内置类型变量将不会被初始化。 |
| 60 | + - 建议初始化每一个内置类型的变量。 |
47 | 61 |
|
48 | | -## 变量的定义和声明 |
| 62 | +### 变量的**声明**(declaration) vs **定义**(define) |
| 63 | + - 为了支持分离式编译,`C++`将声明和定义区分开。**声明**使得名字为程序所知。**定义**负责创建与名字关联的实体。 |
| 64 | + - **extern**:只是说明变量定义在其他地方。 |
| 65 | + - 只声明而不定义: 在变量名前添加关键字 `extern`,如`extern int i;`。但如果包含了初始值,就变成了定义:`extern double pi = 3.14;` |
| 66 | + - 变量只能被定义一次,但是可以多次声明。 |
| 67 | +- 名字的**作用域**(namescope) |
49 | 68 |
|
50 | | -- **变量的定义**:变量的定义用于**分配存储空间**,还可以**指定初始值**。 |
51 | | -- **变量的声明**:用于向程序表明变量的**类型和名字**。 |
52 | | -- **extern**:只是说明变量定义在其他地方。 |
53 | | -- 只声明而不定义: 在变量名钱添加关键字 `extern`,如`extern int i;` |
54 | | -- 变量只能被定义一次,但是可以多次声明。 |
| 69 | +## 左值和右值 |
| 70 | + |
| 71 | +- **左值**(l-value)**可以**出现在赋值语句的左边或者右边,比如变量; |
| 72 | +- **右值**(r-value)**只能**出现在赋值语句的右边,比如常量。 |
55 | 73 |
|
56 | | -## 引用 |
57 | 74 |
|
58 | | -- **引用**:引用是一个对象的别名,如`int &refVal = val;`。 |
| 75 | +## 复合类型 |
| 76 | + |
| 77 | +### 引用 |
| 78 | + |
| 79 | +- **引用**:引用是一个对象的别名,引用类型引用(refer to)另外一种类型。如`int &refVal = val;`。 |
59 | 80 | - 引用必须初始化。 |
60 | 81 | - 引用和它的初始值是**绑定bind**在一起的,而**不是拷贝**。 |
61 | 82 |
|
62 | | -## 指针 |
| 83 | +### 指针 |
63 | 84 |
|
64 | 85 | - 是一种 `"指向(point to)"`另外一种类型的复合类型。 |
65 | 86 | - **定义**指针类型: `int *ip1;`,**从右向左读**,`ip1`是指向`int`类型的指针。 |
66 | 87 | - 指针存放某个对象的**地址**。 |
67 | | -- 获取对象的地址: `int i=42; int *p = &i;`。 `&`是取地址符。 |
| 88 | +- 获取对象的地址: `int i=42; int *p = &i;`。 `&`是**取地址符**。 |
68 | 89 | - 指针的值的四种状态: |
69 | 90 | - 1.指向一个对象; |
70 | 91 | - 2.指向紧邻对象的下一个位置; |
|
75 | 96 | - `void*`指针可以存放**任意**对象的地址。 |
76 | 97 | - 其他指针类型必须要与所指对象**严格匹配**。 |
77 | 98 | - 两个指针相减的类型是`ptrdiff_t`。 |
| 99 | +- 建议:初始化所有指针。 |
78 | 100 |
|
79 | 101 | ## const限定符 |
80 | 102 |
|
81 | 103 | - 动机:希望定义一些不能被改变值的变量。 |
| 104 | + |
| 105 | +### 初始化和const |
82 | 106 | - const对象**必须初始化**,且**不能被改变**。 |
83 | 107 | - const变量默认不能被其他文件访问,非要访问,必须在指定const前加extern。 |
84 | | -- **reference to const**(对常量的引用):指向const对象的引用,如 `const int ival=1; const int &refVal = ival;`,可以读取但不能修改refVal。 |
| 108 | + |
| 109 | +### const的引用 |
| 110 | + |
| 111 | +- **reference to const**(对常量的引用):指向const对象的引用,如 `const int ival=1; const int &refVal = ival;`,可以读取但不能修改`refVal`。 |
| 112 | +- **临时量**(temporary)对象:当编译器需要一个空间来暂存表达式的求值结果时,临时创建的一个未命名的对象。 |
| 113 | +- 对临时量的引用是非法行为。 |
| 114 | + |
| 115 | +### 指针和const |
| 116 | + |
85 | 117 | - **pointer to const**(指向常量的指针):不能用于改变其所指对象的值, 如 `const double pi = 3.14; const double *cptr = π`。 |
86 | 118 | - **const pointer**:指针本身是常量,如 `int i = 0; int *const ptr = &i;` |
87 | | -- `顶层const`:指针本身是个常量 |
| 119 | + |
| 120 | +### 顶层const |
| 121 | + |
| 122 | +- `顶层const`:指针本身是个常量。 |
88 | 123 | - `底层const`:指针指向的对象是个常量。拷贝时严格要求相同的底层const资格。 |
| 124 | + |
| 125 | +### `constexpr`和常量表达式 |
| 126 | + |
89 | 127 | - 常量表达式:指值不会改变,且在编译过程中就能得到计算结果的表达式。 |
| 128 | +- `C++11`新标准规定,允许将变量声明为`constexpr`类型以便由编译器来验证变量的值是否是一个常量的表达式。 |
90 | 129 |
|
91 | 130 | ## 处理类型 |
92 | 131 |
|
93 | | -- 类型别名:使用**typedef**来定义类型的同义词。 `typedef double wages;` |
94 | | -- 别名声明(alias declaration): `using SI = Sales_item;`(C++11) |
95 | | -- **auto**类型说明符:让编译器**自动推断类型**。会忽略`顶层const`。(C++11) |
96 | | -- **decltype**:选择并返回操作数的**数据类型**。不会忽略`顶层const`。(C++11) |
| 132 | +### 类型别名 |
| 133 | + |
| 134 | +- 传统别名:使用**typedef**来定义类型的同义词。 `typedef double wages;` |
| 135 | +- 新标准别名:别名声明(alias declaration): `using SI = Sales_item;`(C++11) |
| 136 | + |
| 137 | +### auto类型说明符 |
| 138 | + |
| 139 | +- **auto**类型说明符:让编译器**自动推断类型**。 |
| 140 | +- `int i = 0, &r = i; auto a = r;` 推断`a`的类型是`int`。 |
| 141 | +- 会忽略`顶层const`。 |
| 142 | +- `const int ci = 1; const auto f = ci;`推断类型是`int`,需要自己加`const` |
| 143 | +- `C++11` |
| 144 | + |
| 145 | +### decltype类型指示符 |
| 146 | + |
| 147 | +- 从表达式的类型推断出要定义的变量的类型。 |
| 148 | +- **decltype**:选择并返回操作数的**数据类型**。 |
| 149 | +- `decltype(f()) sum = x;` 推断`sum`的类型是函数`f`的返回类型。 |
| 150 | +- 不会忽略`顶层const`。 |
| 151 | +- `C++11` |
| 152 | + |
| 153 | +## 自定义数据结构 |
| 154 | + |
| 155 | +### struct |
| 156 | + |
| 157 | +- 类可以以关键字`struct`开始,紧跟类名和类体。 |
| 158 | +- 类数据成员:类体定义类的成员。 |
| 159 | +- `C++11`:可以为类数据成员提供一个**类内初始值**(in-class initializer)。 |
| 160 | + |
| 161 | +### 编写自己的头文件 |
| 162 | + |
| 163 | +- 头文件通常包含哪些只能被定义一次的实体:类、`const`和`constexpr`变量。 |
| 164 | + |
| 165 | +预处理器概述: |
| 166 | + |
| 167 | +- **预处理器**(preprocessor):确保头文件多次包含仍能安全工作。 |
| 168 | +- 当预处理器看到`#include`标记时,会用指定的头文件内容代替`#include` |
| 169 | +- **头文件保护符**(header guard):头文件保护符依赖于预处理变量的状态:已定义和未定义。 |
| 170 | + |
| 171 | +```cpp |
| 172 | +#ifndef SALES_DATA_H |
| 173 | +#define SALES_DATA_H |
| 174 | +strct Sale_data{ |
| 175 | + ... |
| 176 | +} |
| 177 | +#endif |
| 178 | +``` |
0 commit comments