通常情况下,大型程序都是由多个源代码文件组成,这些文件可能共享一些数据,这涉及到如何编译的问题,本章对代码的编译做重点的介绍。
在有多个源文件时,先对这些文件进行编译,然后将它们链接成可执行的程序。单独编译是出于开发的效率,可移植性提出来的。首先了解一下背景,在大型项目下有多个源文件,若是每个程序都包含某个函数的定义,首先程序会显得冗余,修改起来比较麻烦;其次,要是进行修改,所有文件都需要重新编译一次。将一个程序放在多个文件中会有很多新的问题出现。因此C++开发人员提出了#include 来解决这个个问题,与其将结构声明加入到每一个文件中,不如将其放到头文件,要修改声明时,只需要在头文件修改即可。
因此可以将项目的文件大体分为3类:
1)头文件:包含结构声明和这些结构函数的原型;
2)源代码文件:包含与结构有关的函数的代码;
3)源代码文件:包含调用与结构相关的函数的代码;
对于头文件做一些额外的说明:
在大型项目中,可能会重复包含一个头文件,这样会使得“重复定义“的现象发生,为了提前预防这种状况,需要添加头文件保护,示例如下:
#ifndef _HEADER__
#define _HEADER__
……(statement)
#endif
这样就可以确保头文件在编译的过程中不会重复包含。
头文件包含内容如下:
1)函数原型;
2)使用#define或const定义的符号常量;
3)结构声明;
4)类声明;
5)模板声明;
6)内联函数
头文件做的活,基本上都是声明,提前告诉预编译器的变量大小,让编译器“做好准备”。书中给出了示例:coording.h,file1.cpp,file2.cpp。在头文件种声明了结构体,函数原型;
在file2.cpp中对coording.h声明的函数做出具体的实现,而file1.cpp一般是主函数,并会用到之前声明函数的调用。
下图展示了多个函数编译最终合成一个可执行程序的过程。

1)自动存储连续性:
一般指的是在函数体内部定义的变量,在执行完函数或者代码块时,他们使用的内存便会被释放。
2)静态存储持续性
在函数定义外定义的变量和使用关键词static定义的变量的存储持续性都为静态,在程序的整个运行过程都存在。
3)线程存储持续性
CPU可同时处理多个执行任务,让程序能够将计算放在可并行处理的不同线程中。
4)动态存储持续性
用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。
作用域描述了·名称在文件多大范围内可见。例如局部变量与全局变量。局部变量只能在函数中局部起作用,而全局变量在整个文件中都可以被使用。C++函数的作用域可以是整个类或者某个名称空间,但绝对不是局部的。
链接性描述了名称空间如何在不同单元间共享,链接性为外部的名称空间可以在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。
默认情况下,在函数中声明的函数参数和变量的存储持续性为自动,作用域为局部,没有链接性。

C++的静态存储变量提供了三种链接性:外部链接性(可在其他文件夹中访问),内部链接性(只能在当前文件夹中访问),无链接性(只能在当前函数或代码块中访问);不管链接性如何,这些变量在整个程序执行期间都是一直存在的。

静态变量的初始化有零初始化,表达式初始化与动态初始化。
链接性为外部的变量通常简称为外部变量,他们的存储持续性为静态,作用域为整个文件。书中给出了示例,在一个文件中定义了一个变量,另一个文件想要使用他时只需要extern这个变量即可。
将static限定符用于作用域为整个文件的变量,该变量的链接性是内部的。在多个文件中,这样的声明就很有意义,例如:链接为内部的变量只能在其所属的文件中使用;但常规外部变量具有外部链接性,即可以在其他文件中使用。
书中给出了twofile1.cpp,twofile2.cpp,通过给出不同变量的地址,观察变量是否还保持一致。
这种变量是这样创建的,将static限定符用于在代码块中定义的变量;在代码块中使用static,将使得局部变量的存储持续性转化为静态的。如果初始化了局部静态变量,则程序只在启动的时刻进行一次初始化,书中给出了示例代码。
C++关键字提供了有关存储的信息,包括cv限定符,mutable,const,前两个与硬件相关,着重讲一下const限定符。默认情况下,全局变量的链接性为外部的,但是const全局变量的链接性为内部的,在变量前加上了const关键字,就像使用了static说明符一样。
函数也具备链接性,所有函数的存储持续性默认为静态的,所以函数在程序执行期间都一直存在。默认情况下,函数的链接性为外部的,即可以在文件间共享;但是若是在函数前加上static,将函数的链接性设置为内部的,使之只能在一个文件中使用。
链接程序要求每个不同的函数都有不同的符号名。在C++中,同一个名称可能对应多个函数,必须将这些函数翻译为不同的符号名称。
通常编译器使用三块独立的内存:静态变量,自动变量,动态存储。在C++中由new分配的内存称为动态内存,由new分配的内存将一直保留在内存中,直到使用delete运算符将其释放掉。
1)使用new运算符初始化
a.为内置的标量类型分配存储空间并初始化
例子:int *pi = new int(6) //一个指向6的整型数值的一个指针*pi
b.初始化结构体
例子:struct where{double x,double y,double z};
where* one = new where{1.0,2.0,3.0}; //声明一个one的指针指向这个结构体
2)new失败时
以前new找不到请求的内存量返回一个空指针,现在会引发异常std::bad_alloc。
3)new:运算符,函数和替换函数
分配函数与释放函数
new和new[]对应的delete和delete[],书中给出了示例。
4)定位new运算符
new负责在堆中找到一个足以能够满足要求的内存块。new还有一种变体,称为定位new运算符,它让您能够指定要使用的位置。书中给出了示例的代码。
下面是对代码块的补充说明:
pd1 = new double[N]; //use heap
pd2 = new (buffer) doubkle [N]; //use buffer array
起始地址:
常规new将指针放在很远的位置,若是重新进行赋值,地址也会进行更改;而定位new运算符不一样,他每次赋值的地址都是从buffer的起始地址进行的。
是否使用delete:
常规new运算符要是想从最初的地址进行重新赋值,可以先delete[]一下,因为delete用来释放指向常规new运算符分配的堆内存;而定位new运算符,buffer指定的内存是静态内存,用delete无法进行删除。
名称可以是变量,函数,结构,枚举,类以及类和结构的成员,随着项目的增大,名称内相互冲突的可能性也将增加,例如多个厂商都定义了list,但定义的方式不兼容,这种冲突被称为名称空间问题。C++为了解决这类问题提供了名称空间工具,以便更好地控制名称的作用域。
首先介绍一些术语,声明区域,作用域和潜在作用域。
声明区域:可以在其中声明的区域;
作用域:变量对程序而言可见的范围被称为作用域;
潜在作用域:变量可能在这片区域被另一个嵌套声明区域中声明的同名变量隐藏;


1)using声明和using编译指令
using声明使得特定的标识符可用,using编译指令使得整个名称空间可用。
2)using编译指令和using声明的比较
出于安全性考虑,一般来说尽量使用using声明,因为他只导入指定的名称,如果他有局部变量发生冲突,编译器会发出指示;而直接使用using编译指令,遇到上述情况,局部变量会直接覆盖名称空间的版本,编译过程中而不发出指示,这样代码在执行过程中就可能会出现问题。
3)名称空间的其它特性
a.可以将名称空间的声明进行嵌套;
b.可以在名称空间内进行using编译指令和using声明;
4)可以通过省略名称空间的名称来创建未命名的名称空间,这种操作为链接性为内部的静态变量提供了一种替代。
书中给出了代码示例说明名称空间的一些特性。
书中给出了使用名称空间的指导原则。

使用名称空间的最终目的是简化大型项目的管理工作。
本章介绍了程序中变量,函数的存储型,链接性。讲述了动态分配内存的两种方法;讲述了名称空间的特性,以及如何使用名称空间。
5.1 《C++ Primer Plus》