C++基础
1. 变量和基本类型
1.1 基本数据类型
1.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位有效数字 |
带符号类型和无符号类型
除去布尔类型和扩展的字符型之外,其他整形可以划分为带符号的(signed)和无符号的(unsigned)两种。带符号的类型可以表示正数,负数和0,无符号类型则仅能表示大于等于0的值。
类型int,short,long和long long默认都是带符号的,通过在这些类型名前添加unsigned就可以得到无符号类型。
与其他整形不同,字符型被分为了三种:char,signed char和unsigned char。尽管字符型由三种,但是字符的表现形式却只有两种:带符号的和无符号的。类型char实际上会表现为上述两种形式种的一种,具体是哪种由编译器决定。
1.1.2 类型转换
当我们把一个非布尔类型的算术值赋给布尔类型时,初始值为0则结果为false,否则结果为true;
当我们把一个布尔值赋给非布尔类型时,初始值为false则结果为0,初始值为true则结果为1;
当我们把一个浮点数赋给整数类型时,结果值将仅保留浮点数中小数点之前的部分;
当我们把一个整数值赋给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,精度可能有损失;
当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数;
当我们赋给带符号类型一个超出它表示范围的值时,结果时未知的。
1.1.3 字面值常量
整形和浮点型字面值
默认情况下,十进制字面值是带符号数,八进制和十六进制字面值即可能是带符号的也可能是无符号的:
20 /* 十进制 */
024 /* 八进制 */
0x14 /* 十六进制 */
默认情况下,浮点型字面值是一个double:
3.14159
3.14159E0
0.
0e0
.001
字符和字符串字面值
字符串字面值的类型实际上是由常量字符构成的数组,编译器在每个字符串的结尾处添加一个空字符(‘\0’),因此字符串字面值的实际长度要比它的内容多1;
'a' // 字符字面值
"Hello World! // 字符串字面值
转义序列
转义序列均以反斜线作为开始,C++语言规定的转义序列包括:
换行符 \n | 横向制表符 \t | 报警(响铃)符 \a |
---|
纵向制表符 \v | 退格符 \b | 双引号 " | 反斜线 \ | 问号 ? | 单引号 ’ | 回车符 \r | 进纸符 \f | |
1.2 变量
变量提供一个具名的,可供程序操作的存储空间,一般来说变量和对象可以互换使用;
1.2.1 变量定义
初始值
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代;
列表初始化
int units_sold = 0;`
int units_sold = {0};`
int units_sold{0};`
int units_sold(0);
默认初始化
如果定义变量时没有指定初始值,则变量被默认初始化,默认值由变量类型决定,同事定义变量的位置也会对此有影响;
1.2.2 变量声明和定义的关系
C++语言支持分离式编译机制,该机制允许将程序分割成若干个文件,每个文件可被独立编译;
为了支持分离式编译,C++语言将声明和定义区分开来。声明使得名字为程序所知,而定义负责创建与名字关联的实体;
extern int i; // 声明 i 而非定义 i`
int j; // 声明并定义j
1.2.3 标识符
C++的标识符由字母,数字和下划线组成,其中必须以字母或下划线开头,长度没有限制,但是对大小写字母敏感;
1.2.4 名字的作用域
同一个名字如果出现在程序的不同位置,也可能指向的是不同的实体。一般来说,在对象第一次使用的地方附件定义它是一种好的选择,因为这样做有助于更容易地找到变量的定义。
1.3 复合类型
复合类型是指基于其他类型定义的类型,C++语言有几种复合类型,包括引用和指针;
1.3.1 引用
C++11 新增一种引用:所谓的右值引用,这种引用主要用于内置类。严格来说当我们使用术语引用时,指的其实是左值引用;
引用(reference)为对象起了另外一个名字,引用类型引用另外一种类型;
为引用赋值,实际上是把值赋给了与引用绑定的对象上;获取引用值,实际上是获取了与引用绑定的对象的值;
int ival = 1024;
int &refVal = ival; // refVal指向ival(是ival的另一个名字)
int &refVal2; // 报错:引用必须被初始化
1.3.1 指针
指针是指向另外一种类型的复合类型,与引用类似,指针也实现了对其他对象的间接访问,然而指针与引用相比又有很多不同点:
其一,指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象;
其二,指针无须在定义时赋值;
获取对象的地址
int ival = 42;
int *p = &ival; // p存放变量ival的地址,或者说p是指向变量ival的指针
利用指针访问对象
int ival = 42;
int *p = &ival; // p存放着变量ival的地址,或者说p是指向变量ival的指针
cout << *p; // 由符号 * 得到指针p所指向的对象,输出42
空指针
空指针不指向任何对象,在试图使用一个指针之前代码可以首先检查它是否为空;
得到空指针最直接的办法就是用字面值nullptr 来初始化指针,这也是C++11新标准引入的一种方法,它可以被转换成任意其他的指针类型;
int *p1 = nullptr; // 等价于int *p1 = 0;
int *p2 = 0; // 直接将p2初始化为字面常量0
// 需要首先#include cstdlib
int *p3 = NULL; // 等价于int *p3 = 0;
void*指针
void*指针是一种特殊的指针类型,可用于存放任意对象的地址。不能直接操作void * 指针所指向的对象,因为我们并不知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。
double obj = 3.14, *pd = obj; // 正确:void * 能存放任意类型对象的地址
void *pv = &obj; // obj可以是任意类型的对象
pv = pd; // pv可以存放任意类型的指针
指向指针的指针
int ival = 1024;
int *p = &ival; // pi指向一个int型的数
int **ppi = π // ppi指向一个int型的指针
指向指针的引用
引用本身不是一个对象,因此不能定义指向引用的指针,但是指针是对象,所以存在对指针的引用,
int i = 42;
int *p; // p是一个int型指针
int *&r = p; // r是一个对指针p的引用
r = &i; // r引用了一个指针,因此给r赋值&i就是令p指向i
*r = 0; // 解引用r得到i,也就是p指向的对象,将i的值改为0
1.4 const限定符
初始化const
const int i = get_size(); // 正确:运行时初始化
const int j = 42; // 正确:编译时初始化
const int k; // 错误:k是一个未经初始化的常量
constexpr和常量表达式
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式,显然字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
constexpr变量
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式;声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
constexpr int mf = 20; // 20是常量表达式
constexpr int limit = mf + 1; // mf + 1是常量表达式
constexpr int sz = size(); // 只有当size是一个constexpr函数时,才是一条正确的声明语句
1.5 处理类型
1.5.1 类型别名
有两种方法可用于定义类型别名,传统的方法是使用关键字typedef:
typedef double wages; // wages是double的同义词
typedef wages base, *p; // base是double的同义词,p是double*的同义词
新标准规定了一种新的方法,使用别名声明来定义类型的别名
using SI = Sales_item; // SI是Sales_item的同义词
1.5.2 auto类型说明符
C++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。auto让编译器通过初始值来推算变量的类型
auto i = 0, *p = &i; // 正确:i是整数,p是整形指针
auto sz = 0, pi = 3.14 // 错误:sz和pi的类型不一致
1.5.3 decltype类型指示符
C++11新标准引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
decltype(f()) sum = x; // sum的类型就是函数f的返回类型
|