概念了解
分离式编译
一个项目由若干个源文件共同实现,而每个源文件(.cpp)单独编译成目标文件(.obj),最后将所有目标文件连接起来形成单一的可执行文件(.exe)的过程。
编译过程
预处理–》编译–》汇编–》链接
- 预处理阶段
头文件展开、条件编译指令、宏替换 - 编译阶段
将第一步产生的文件同其他文件一起编译成汇编代码 - 汇编阶段
将汇编源码转换成可重定位目标文件 - 链接阶段
进行符号解析和重定位,将可重定位目标文件链接成可执行目标文件
模板
C++Primer中的定义:
模板是C++中泛型编程的基础。一个模板就是一个创建类或函数的蓝图或者说公式。
当使用一个vector这样的泛型类型,或者find这样的泛型函数时,我们提供足够的信息,将蓝图转换为特定的类或函数(实例化)。
这种转换发生在编译时。
我们可以捕捉到一个信息,使用的时候 对模板进行实例化,且发生在编译过程的编译阶段。
编译单元
在预处理阶段会进行头文件展开,通俗的理解就是.h+.cpp文件就是一个编译单元。
为什么模板不支持分离式编译
在编译阶段,每一个cpp文件都是相对独立的,并不知道另一个编译文件的存在,若存在外部调用,会在链接阶段进行重定位。
模板的实例化其实只能发生在本编译单元的调用。如果出现非本编译单元的模板调用,也就是分离式编译,只能等待链接时重定位,但是模板并没有实例化,所以会出现链接出错。
代码实例
模板函数声明在test.h中,定义在test.cpp中,调用在main.cpp中(链接出错)
模板函数声明在test.h中,定义在main.cpp中,调用在main.cpp中(运行成功)
模板函数声明在test.h中,定义在test.h中,调用在main.cpp中(运行成功,因为头文件会在预处理阶段对头文件展开)
总结
这个简单的链接出错问题,其实原因涉及到了很多方面,经过分析,其实能够加深对编译过程的理解。