/ 写在前面 – 我热爱技术、热爱开源。我也相信开源能使技术变得更好、共享能使知识传播得更远。但是开源并不意味着某些商业机构/个人可以为了自身的利益而一味地索取,甚至直接剽窃大家曾为之辛勤付出的知识成果,所以本文未经允许,不得转载,谢谢/


这些基本概念,在我看来非常重要,当然,它们曾经也困扰了我非常长一段时间,所以,一定要搞清楚!

列表初始化 - p. 39

作为C++11新标准的一部分,用花括号来初始化变量得到了全面应用。这种初始化的形式被称为列表初始化(List Initialization)。现在,无论是初始化对象还是某些时候为对象赋新值,都可以使用这样一组由花括号括起来的初始值了。

以下4条语句都是正确的 - 定义一个名为 units_soldint 变量并初始化为 0

  1. int units_sold = 0;
  2. int units_sold = {0};
  3. int units_sold{0};
  4. 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 是声明的变量名。此时声明符就变复杂了,而不再像之前简单的声明语句——声明符其实就是变量名。此可谓复合类型,它基于基本数据类型得到更复杂的类型,并把它指定给变量。

❗ 引用即别名:引用并非对象,相反的,它只是为一个已经存在的 对象 所起的另外一个名字。

📕 关于引用,下面几点必须完全理解:

  1. 引用必须被初始化,否则会报错。
  2. 引用一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须被初始化。
  3. 引用即别名。
  4. 引用只能绑定在 对象 上。
  5. 因为引用本身不是一个对象,所以不能定义引用的引用。

要理解上面的第2点和第3点,把下面这段代码看明白就没问题了。当然,如果已经完全理解了上面几点,那么自己应该能准确预测这段代码的输出结果。

  1. #include <iostream>
  2. int main() {
  3. std::cout << "Initialization: " << std::endl;
  4. int ival1 = 111;
  5. int ival2 = 222;
  6. int &ref_ival1 = ival1;
  7. std::cout << "ival1: " << ival1 << std::endl;
  8. std::cout << "ival2: " << ival2 << std::endl;
  9. std::cout << "ref_ival1: " << ref_ival1 << std::endl;
  10. std::cout << std::endl;
  11. std::cout << "Execute: ref_ival1 = ival2; \nLet's see the result:" << std::endl;
  12. ref_ival1 = ival2;
  13. std::cout << "ival1: " << ival1 << std::endl;
  14. std::cout << "ival2: " << ival2 << std::endl;
  15. std::cout << "ref_ival1: " << ref_ival1 << std::endl;
  16. std::cout << std::endl;
  17. std::cout << "Execute: ival2 = 1024; \nLet's see the result:" << std::endl;
  18. ival2 = 1024;
  19. std::cout << "ival1: " << ival1 << std::endl;
  20. std::cout << "ival2: " << ival2 << std::endl;
  21. std::cout << "ref_ival1: " << ref_ival1 << std::endl;
  22. std::cout << std::endl;
  23. // Output:
  24. // -------
  25. // Initialization:
  26. // ival1: 111
  27. // ival2: 222
  28. // ref_ival1: 111
  29. //
  30. // Execute: ref_ival1 = ival2;
  31. // Let's see the result:
  32. // ival1: 222
  33. // ival2: 222
  34. // ref_ival1: 222
  35. //
  36. // Execute: ival2 = 1024;
  37. // Let's see the result:
  38. // ival1: 222
  39. // ival2: 1024
  40. // ref_ival1: 222
  41. //
  42. // -------
  43. return 0;
  44. }