/ 写在前面 – 我热爱技术、热爱开源。我也相信开源能使技术变得更好、共享能使知识传播得更远。但是开源并不意味着某些商业机构/个人可以为了自身的利益而一味地索取,甚至直接剽窃大家曾为之辛勤付出的知识成果,所以本文未经允许,不得转载,谢谢。/
这些基本概念,在我看来非常重要,当然,它们曾经也困扰了我非常长一段时间,所以,一定要搞清楚!
列表初始化 - p. 39
作为C++11新标准的一部分,用花括号来初始化变量得到了全面应用。这种初始化的形式被称为列表初始化(List Initialization)。现在,无论是初始化对象还是某些时候为对象赋新值,都可以使用这样一组由花括号括起来的初始值了。
以下4条语句都是正确的 - 定义一个名为 units_sold
的 int
变量并初始化为 0
。
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
变量声明和定义的关系 - p. 41
任何包含了显式初始化的声明即成为定义。
如果想声明一个变量而非定义它,就在变量名前添加关键字 extern
,而且不要显式地初始化变量。
❗ 在函数体内部,如果试图初始化一个由 extern
关键字标记的变量,将引发错误。
要理解上面这一句话,就必须彻底搞懂初始化(Initialization)和赋值(Assignment)以及声明和定义的区别,参见p. 39, p. 41。
然后再搞懂声明(Declaration)做了些什么,而定义(Definition)又做了什么。变量声明规定了变量的类型和名字,在这一点上定义与之相同。但是除此之外,定义还申请存储空间,也可能会为变量赋一个初始值,即定义负责创建与名字关联的实体。
初始化只能进行一次,而赋值可以进行多次。
变量只能被定义一次,但是可以被多次声明。
复合类型 - p. 45
引用
C++语言有几种复合类型(Compound Type),这里介绍其中的两种:引用 和 指针 。
从编译原理的角度来看,或者说一种更通用的描述,一条声明语句由以下两部分组成:
- 一个 基本数据类型(Base Type)
- 紧随其后的一个 声明符(Declarator)列表
拿引用来举例,通过将 声明符 写成 &d
的 形式 来定义 引用类型 ,其中 d
是声明的变量名。此时声明符就变复杂了,而不再像之前简单的声明语句——声明符其实就是变量名。此可谓复合类型,它基于基本数据类型得到更复杂的类型,并把它指定给变量。
❗ 引用即别名:引用并非对象,相反的,它只是为一个已经存在的 对象 所起的另外一个名字。
📕 关于引用,下面几点必须完全理解:
- 引用必须被初始化,否则会报错。
- 引用一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须被初始化。
- 引用即别名。
- 引用只能绑定在 对象 上。
- 因为引用本身不是一个对象,所以不能定义引用的引用。
要理解上面的第2点和第3点,把下面这段代码看明白就没问题了。当然,如果已经完全理解了上面几点,那么自己应该能准确预测这段代码的输出结果。
#include <iostream>
int main() {
std::cout << "Initialization: " << std::endl;
int ival1 = 111;
int ival2 = 222;
int &ref_ival1 = ival1;
std::cout << "ival1: " << ival1 << std::endl;
std::cout << "ival2: " << ival2 << std::endl;
std::cout << "ref_ival1: " << ref_ival1 << std::endl;
std::cout << std::endl;
std::cout << "Execute: ref_ival1 = ival2; \nLet's see the result:" << std::endl;
ref_ival1 = ival2;
std::cout << "ival1: " << ival1 << std::endl;
std::cout << "ival2: " << ival2 << std::endl;
std::cout << "ref_ival1: " << ref_ival1 << std::endl;
std::cout << std::endl;
std::cout << "Execute: ival2 = 1024; \nLet's see the result:" << std::endl;
ival2 = 1024;
std::cout << "ival1: " << ival1 << std::endl;
std::cout << "ival2: " << ival2 << std::endl;
std::cout << "ref_ival1: " << ref_ival1 << std::endl;
std::cout << std::endl;
// Output:
// -------
// Initialization:
// ival1: 111
// ival2: 222
// ref_ival1: 111
//
// Execute: ref_ival1 = ival2;
// Let's see the result:
// ival1: 222
// ival2: 222
// ref_ival1: 222
//
// Execute: ival2 = 1024;
// Let's see the result:
// ival1: 222
// ival2: 1024
// ref_ival1: 222
//
// -------
return 0;
}