C++ Primer 笔记,主要基于书籍《C++ Primer (5th Edition)》,仅补充些笔者需要记录的知识。
1. 开始
写入 endl
或换行符的效果是结束当前行,并将设备关联的缓冲区(buffer)中内容刷到设备中,保证到目前程序产生的输出均真正写入输入流中,而非仅停留在内存中等待写入流。
2. 变量和基本类型
2.1 基本内置类型
2.1.3. 字面值常量
字符和字符串字面值(string literal)
如果两个字符串字面值位置紧邻且仅由空格、缩进和换行符分隔,则它们实际是一个整体。当字符串字面值较长,写在一行不合适时,可采取此方式。
// 分多行书写的字符串字面值
std::cout << "a really, really long string literal "
"that spans two lines" << std::endl;
转义序列 (escape sequence)
对于泛化的转义序列:
- 如果反斜杠
\
后面跟着的八进制数字超过3个,只有前3个数字与\
构成转义序列。 - 相反,
\x
要用到后面跟着的所有数字。例如,”\x1234”
表示一个16位的字符,该字符由这4个十六进制数所对应的比特唯一确定。
指定字面值的类型
字符和字符串字面值 | ||
前缀 | 含义 | 类型 |
u | Unicode 16 字符 | char16_t |
U | Unicode 32 字符 | char32_t |
L | 宽字符 e.g. L’a’ | wchar_t |
u8 | UTF-8(仅用于字符串字面常量)e.g. u8”hi!” | char |
整型字面值 | |
后缀 | 最小匹配类型 |
u or U | unsigned |
l or L | long |
ll or LL | long long |
浮点型字面值 | |
后缀 | 类型 |
f or F | float |
l or L | long double |
2.2. 变量
2.2.1. 变量定义
列表初始化(list initialization)
对于 int 变量初始化为 0,有四种语句可以实现:
int i = 0;
int i = {0};
int i(0);
int i{0};
作为C++11新标准的一部分,花括号初始化变量得到全面应用,称为列表初始化,在初始化对象或者某些时候为对象赋新值均可使用。
当用于内置类型的变量时,有个特点:如果使用列表初始化,且初始值存在丢失信息的风险,则编译器将报错:
long double ld =3.1415926536;
int a{ld}, b = {ld}; // 错误:转换未执行,因为存在丢失信息的危险
int c(ld), d = ld; // 正确:转换执行,且确实丢失部分值
2.2.2. 变量声明和定义的关系
C++语言支持分离式编译(separate compilation)机制,允许程序分割为若干个可被独立编译的文件。
为了支持分离式编译,C++将声明和定义区分开。声明(declaration)使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。而定义(definition)负责创建与名字关联的实体。
变量声明规定了类型和名字,定义在这一点与之相同。但定义还申请存储空间,也可能会为变量赋一个初始值。
如果想声明而非定义,在变量名前添加关键字 extern
,而且不要显式地初始化变量:
extern int i; // 声明 i 而非定义 i
int j; // 声明并定义 j
extern double pi = 3.1416; // 定义
任何包含了显式初始化的声明即成为定义。
在函数体内部,若试图初始化一个由 extern
关键字标记的变量,将引发错误。
变量的定义必须出现在且只能出现在一个文件中。
C++是一种静态类型(statically typed)语言,含义是在编译阶段检查类型,该过程称为类型检查(type checking)。
2.2.4. 名字的作用域
可以使用作用域操作符 ::
来覆盖默认的作用域规则,全局作用域本身没有名字,所以当作用域操作符左侧为空时,在全局作用域中获取右侧名字对应的变量。