模板的分离编译
分析为什么模板不支持分离编译?
首先,我们要弄清楚程序是怎么运行起来的,在《深入理解计算机系统》这本书上详细介绍了,在这里我简单的说一下。
大致要经过以下四步:
预处理:宏替换、头文件的展开、去掉注释、条件编译
编译:检查语法、生成汇编代码
汇编:汇编代码转化为机器码
链接:可执行程序
- 在实现分离编译的时候,我们通常在template.h中对在类中需要用到的函数进行声明,然后再template.cpp中对函数进行定义,在demp.cpp中进行实现和调用。
- 在demo.cpp中,调用了一些函数,然而当编译器编译demo.cpp时,它仅仅知道在所包含的头文件中有一个关于函数的声明,并不知道函数的定义。换句话说,编译器在这里将函数看作外部连接类型,认为函数实现代码在另外的.obj文件中(template.obj)。
- 在demo.obj中实际上是没有关于所调用函数的二进制代码的,这些代码实际存在于template.obj中。在demo.obj中对函数的调用只会生成相应的call指令。
- 我们知道,C++标准中规定了模板函数的代码并不会直接编译成二进制代码,必须在模板类实例化成对象之后,才会生成相应的二进制代码。 也就是说,如果你在demo.cpp文件中没有调用过函数,函数也就得不到实例化,从而demo.obj中也就没有关于template.cpp的任意一行二进制代码。所以, 分离编译的环境下,编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在。
当实现该模板的.cpp文件中没有用到模板的实例时,编译器懒得去实例化,所以,整个工程的.obj中就 找不到一行模板实例的二进制代码。
就会出现
链接错误
。
增量链接:
VC++中,在
非增量链接情况下
,当修改了c/c++文件后,将会重新生产整个obj文件;
在增量链接情况下, obj文件中为每个函数预留一部分空间, 编译链接时, 只是修改你修改过的函数
对应的代码, 其它二进制代码保持不
变。
我们该怎么处理这样的错误呢?
- 1、显示实例化。(一般不推荐)
- 2、 将声明和定义放到一个文件 “xxx.h” 里面。(推荐)