一、.普通函数不需要分离编译而模版函数需要分离编译
1、对于普通函数:vodi Fun()
在Fun.h文件中声明如下:
void Fun();
在Fun.cpp中定义如下:
#include"Fun.h"
void Fun()
{
cout << "Fun()" << endl;
}
测试用例如下:
#include"Fun.h"
void TestFun()
{
Fun();
}
这个时候并不会产生什么错误,运行结果如下:
2、对于模版函数void TemplateFun(const T&x)
在TemplateFun.h文件中声明如下:
template<class T>
void TemplateFun(const T&x);
在TemplateFun.cpp中定义如下:
#include"TemplateFun.h"
template<class T>
void TemplateFun(const T&x)
{
cout << "TemplateFun()" << endl;
}
测试用例如下:
#include"TemplateFun.h"
void TestTemplateFun()
{
TemplateFun(1);
}
这个时候程序会报一个链接错误,只是拿到了函数的声明,而拿不到函数的定义
二、程序的编译与执行的四个阶段
以下同过一张图来直观的描述出来:
三、链接错误产生的原因
c++在调用外部函数的,在编译是其实只是用一条jmp跳转指令代替这个调用代码,例如jmp 0xABCDEFG,这个地址可能是任意的,然而关键是这个地址上有一行指令来进行真正的call f动作,也就是说,跳转的地址是一条真正的调用指令call
但是call的地址是一个任意的无效地址,因为在编译阶段,本单元是不知道其他单元函数的地址的,于是这个无效的地址的修正是放在链接阶段,链接器根据调用函数单元的符号表,修改该无效地址。
这样问题就来了。因为模版仅在需要的时候才会具体实例化出来。在编写的模版.h文件中没有具体的定义,仅仅只有其声明,因此编译次单元的时候不会生成相应的函数二进制代码,这就导致了在链接阶段会在其他调用模版 单元函数的是报错,编译器给出一个链接错误
四。解决办法
1、方法一:
在模板头文件 xxx.h 里面显示实例化->模板类的定义后面添加 template class SeqList<int >; 一般不推荐这种方法,一方面老编译器可能不支持,另一方面实例化依赖调用者。(不推荐)
2、方法二:
将声明和定义放到一个文件 "xxx.hpp" 里面,推荐使用这种方法。
五。模版的优缺点
1、优点:
(1)模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生。(2)增强了代码的灵活性。
2、缺点:
(1)模板让代码变得凌乱复杂,不易维护,编译代码时间变长。(2)出现模板编译错误时,错误信息非常凌乱,不易定位错误。