2.1 基本内置类型
当赋给无符号类型一个超出它表示范围的数时,结果是初始值对表示数值总数取模后的余数:
字符和字符串字面值
'a'; //字符字面值
"Hello World!" //字符串字面值
字符串字面值的类型实际上是常量字符构成的数组。此外还包含一个空字符'\0'
。
2.2 变量
使用列表初始化,如果初始值存在丢失信息风险,那么编译器将不会执行:
默认初始化
2.2.2 变量声明和定义的关系
2.4 const 限定符
const
对象必须初始化。
默认状态下,const
对象仅在文件内有效。如果多个文件出现多个同名const
对象,其实等同于在各个文件定义独立的对象。但是如果想要定义一个const
对象实现通用,可以这样:
2.4.2 指针和 const
要想存放常量对象的地址,只能使用指向常量的指针:
const double pi = 3.14;
double* p = π //错误!
const double* p = π //正确!
const 指针
指针是对象,而引用不是,这就允许把指针本身定义为常量。常量指针必须初始化,而一旦初始化完成,它的值就不能再改变了(即它当中存放的地址)。将*****
放在**const**
前,表示指针是一个常量。
int pi = 4;
int *const ptr = π //表示ptr将一直指向pi
2.4.3 顶层 const 和底层 const
- 顶层 const:表示指针本身是常量,此外,顶层 const 还可用于其他任意类型(除指针外);
- 底层 const:表示指针所指对象是常量。
当对象执行拷贝操作时,常量是顶层 const 还是底层 const 有明显区别:
- 顶层 const 不受影响,执行拷贝操作并不会改变被拷贝对象的值,所以拷入和拷出对象是否是常量都无所谓;
- 底层 const 的限制不容忽视,当执行拷贝操作时,二者都必须具有相同的底层 const 资格,或者二者的数据类型能够转换,一般来说,non-const 可以转换为 const,反之不可: ```cpp int i = 0; const int ci = 42; const int p2 = &ci; //底层const const int const p3 = p2; //顶层const和底层const兼具 const int &r = ci; //用于引用的都是底层const
int p = p3; //错误!p3包含底层const,而p没有 p2 = p3; //正确!二者都有底层const属性 p2 = &i; //正确!int能转换为const int * int &r1 = ci; //错误!普通的int&不能绑定到int常量上 const int &r = ci; //正确!const int&可以绑定到int常量上
<a name="JlFcy"></a>
## 2.4.4 constexpr 和常量表达式
常量表达式指的是**值不会改变并且在编译期就能计算得到的结果。**<br />一个对象是不是**常量表达式**,**需要由数据类型和初始值共同决定**:
```cpp
const int max_file = 20; //是常量表达式
const int limit = max_file + 1; //是常量表达式
int staff_size = 27; //不是常量表达式
const int sz = get_size(); //不是常量表达式,由于函数,所以要在运行期才能获知
C++11允许将变量声明为constexpr
以便编译器验证变量的值是否是一个常量表达式。声明为**constexpr**
的值一定是一个常量,并且必须用常量表达式初始化:
constexpr int mf = 20;
constexpr limit = mf + 1;
constexpr sz = getsize(); //只有当getsize()是constexpr函数时才正确
字面值类型
算数类型、指针、引用都是字面值类型,自定义类行、IO库、string都不是字面值类型,也就不能定义为constexpr
。
被定义为constexpr
的指针,必须为**nullptr**
或 0 或者是存储于某个固定地址中的对象。(函数体内定义的变量一般并非存放在固定地址中,因此constexpr
指针不能指向函数体内定义的变量)
指针和 constexpr
如果一个指针被定义为constexpr
,那么这个constexpr
只对该指针有效,对指针所指对象无效。
2.5 处理类型
使用using
代替typedef
:
此处不能简单地替换,将pstring
替换为char*
,因为:
2.5.2 auto说明符
由于依赖推导,所以auto
变量必须有初值。
auto
在推导过程中忽略顶层**const**
。
2.5.3 decltype 类型指示符
使用decltype
时候,编译器只分析表达式并得到类型而不实际计算表达式值。所以如果调用decltype(func())
,实际上不会调用函数。