目录
2.1 基本内置类型
2.1.1 算术类型
C++ 标准规定了每个算术类型的最小存储空间,但它并不阻止编译器使用更大的存储空间
类型 | 含义 | 最小尺寸 |
---|---|---|
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位有效数字 |
带符号类型和无符号类型
- 当明确知道数值不可能为负数时,用无符号类型
- int执行整数运算,超过int表示范围的用long long
- 执行浮点数用double类型
2.1.2 类型转换
- 当赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数
- 当赋给有符号类型一个超出它表示范围的值时,结果是未定义的
2.1.3 字面值常量
数值20 | 进制 |
---|---|
20 | 十进制 |
024 | 八进制 |
0x14 | 十六进制 |
字符串字面值
如果两个字符串字面值位置紧邻且仅有空格、缩进、换行符分隔,则它们实际上是一个整体。
2.2 变量
2.2.1 变量定义
- 初始化不是赋值:初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新的值来代替
- 如果使用列表初始化且初始值存在丢失信息的风险,则编译器报错
- 定义于函数体内的内置类型的对象如果没有初始化,则其值未定义
2.2.2 变量声明和定义的关系
- 如果想声明一个变量而非定义它,就在变量名前添加关键字extern,而且不要显示地初始化变量
- 变量只能被定义一次,可以被多次声明
- 如果要在多个文件中使用同一个变量,就必须将定义和声明分开,变量的定义只能出现在一个文件中,其他用到该变量的文件必须对其进行声明,却不能重复定义
2.2.3 标识符
- 不能连续出现两个下划线,不能以下划线紧连大写字母开头
2.2.4 名字的作用域
- 作用域操作符::左侧为空时,即为全局作用域
2.3 复合类型
2.3.1 引用
引用为对象起了另外一个名字
- 引用非对象,引用是为一个已经存在的对象起的另外一个名字,由于引用不是一个对象,不能定义引用的引用
2.3.2 指针
- 指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象
- 指针无须定义时赋值,在块作用域(函数体)内定义的指针如果没有初始化,也将是不确定的值
- 取地址符&、解引用符*
- 建议初始化所有指针
- 赋值永远改变的是等号左侧的对象
- void* 指针可以存放任意对象的地址
- 指针类型必须要与所指对象严格匹配
int i = 42;
long *lp = &i; // 错误:类型不匹配
2.3.3 理解复合类型的声明
- 在同一条定义语句中,可以定义不同类型的变量(但基本数据类型只有一个)
//i是一个int型的数,p是一个int型指针,r是一个int型引用
int i = 1024, *p = &i, &r = i;
- 指向指针的指针
- 指向指针的引用:不能定义指向引用的指针,因为引用不是一个对象,但是可以存在对指针的引用
int *p;
int *&r = p; //r是一个对指针p的引用
2.4 const限定符
- 利用一个对象去初始化另外一个对象,则它们是不是const都无关紧要
- 如果想在多个文件之间共享const对象,必须在变量定义之前添加extern关键字
2.4.1 const的引用
const int ci = 1024;
const int &ri = ci; //注意必须加const
- 初始化常量引用允许任意表达式作为初始值
- 常量引用仅对引用可参与的操作做出了限定,对于引用本身是不是常量未作限定
- 非常量引用不能指向一个常量对象,但常量引用可以指向非常量对象
- 常量引用必须要初始化
2.4.2 指针与const
- 指向常量的指针与常量指针不同
- 指针本身是常量并不代表不能通过指针修改其所指向的对象的值,能否这样做完全依赖于其指向对象的类型。
- 常量对象的地址只能使用指向常量的指针来存放,但指向常量的指针可以存放非常量对象的地址
- 常量指针必须初始化,指向常量的指针不一定要初始化(这与常量引用不同)
2.4.3 顶层const
- 顶层 const 表示指针本身是个常量,底层 const(low-level const)表示指针所指的对象是一个常量。指针类型既可以是顶层 const 也可以是底层 const。
- 顶层 const 没有影响。拷贝操作不会改变被拷贝对象的值,因此拷入和拷出的对象是否是常量无关紧要。
int i = 0;
int *const p1 = &i; // 不能改变p1的值,这是一个顶层const
const int ci = 42; // 不能改变ci的值,这是一个顶层const
const int *p2 = &ci; // 允许改变p2的值,这是一个底层const
const int *const p3 = p2; // 靠右的const是顶层const,靠左的是底层const
const int &r = ci; // 用于声明引用的const都是底层const
i = ci; // ok: 拷贝ci的值,ci是一个顶层const,对此操作无影响,注意是拷贝时可以,初始化时不可以
p2 = p3; // ok: p2和p3指向的对象类型相同,p3顶层const的部分不影响
- 底层const的限制不能忽视。拷入和拷出的对象必须具有相同的底层 const 资格。或者两个对象的数据类型可以相互转换。一般来说,非常量可以转换成常量,反之则不行。
int *p = p3; // error: p3包含底层const的定义,而p没有
p2 = p3; // ok: p2和p3都是底层const
p2 = &i; // ok: int*能转换成const int*
int &r = ci; // error: 普通的int&不能绑定到int常量上
const int &r2 = i; // ok: const int&可以绑定到一个普通int上
2.4.4 constexpr和常量表达式
- C++11允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。
- 指针和引用都能定义成 constexpr,但是初始值受到严格限制。constexpr 指针的初始值必须是0、nullptr 或者是存储在某个固定地址中的对象。函数体内定义的普通变量一般并非存放在固定地址中,因此 constexpr 指针不能指向这样的变量。相反,函数体外定义的变量地址固定不变,可以用来初始化 constexpr 指针。
- 在 constexpr 声明中如果定义了一个指针,限定符 constexpr 仅对指针本身有效,与指针所指的对象无关。
const int *p = nullptr; // p是一个指向整型常量的指针
constexpr int *q = nullptr; // q是一个指向整数的常量指针
- 与其他常量指针类似, constexpr 指针既可以指向常量也可以指向一个非常量
2.5 处理类型
2.5.1 类型别名
- 使用关键字 typedef 定义类型别名。
typedef double wages; // wages是double的同义词
typedef wages base, *p; // base是double的同义词,p是double*的同义词
- 使用关键字 using 进行别名声明,作用是把等号左侧的名字规定成等号右侧类型的别名
using SI = Sales_item; // SI是Sales item的同义词
2.5.2 auto类型说明符
- auto 类型说明符,能让编译器自动分析表达式所属的类型。auto 定义的变量必须有初始值
- 使用 auto 也能在一条语句中声明多个变量。因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样
- auto 一般会忽略顶层 const,同时底层 const 则会保留下来。
- 设置类型为 auto 的引用时,原来的初始化规则仍然适用,初始值中的顶层常量属性仍然保留。
auto &g = ci; // g是一个整型常量引用,绑定到ci
auto &h = 42; // error: 不能为非常量引用绑定字面值
const auto &j = 42; // ok: 可以为常量引用绑定字面值
const auto f = ci; // ci是int类型,f是const int类型
- 注意auto是根据=号右边的数据类型推断=号左边的数据类型
2.5.3 decltype类型指示符
- decltype 类型指示符,作用是选择并返回操作数的数据类型,此过程中编译器不实际计算表达式的值。
- decltype 处理顶层 const 和引用的方式与 auto 有些不同,如果 decltype 使用的表达式是一个变量,则 decltype 返回该变量的类型
- decltype 和 auto 的另一处重要区别是,decltype 的结果类型与表达式形式密切相关。注意:如果 decltype 使用的是一个不加括号的变量,则得到的结果就是该变量的类型;如果给变量加上了一层或多层括号,则 decltype 会得到引用类型,因为变量是一种可以作为赋值语句左值的特殊表达式。
// decltype的表达式如果是加上了括号的变量,结果将是引用
decltype ((i)) d; // 错误:d是int&,必须初始化
decltype (i) e; // 正确:e是一个(未初始化的)int
decltype(*p) c; // *p是int型,而c是int&类型
- decltype((var)) 的结果永远是引用,而 decltype(var) 的结果只有当 var 本身是一个引用时才会是引用。
- 赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。也就是说,如果 i 是 int,则表达式 i=x 的类型是 int&
int a = 3, b = 4;
decltype(a) c = a;
decltype(a = b) d = a; // 注意d是int&类型
2.6 自定义数据结构
- C++11 规定可以为类的数据成员(data member)提供一个类内初始值(in-class initializer)。创建对象时,类内初始值将用于初始化数据成员,没有初始值的成员将被默认初始化。
- 类定义的最后应该加上分号。
- 头文件(header file)通常包含那些只能被定义一次的实体,如类、const和constexpr变量。