模板的分离编译

模板为什么不支持分离编译
要了解这个问题,我们先来看一下程序在计算机中的执行过程,用一幅图简单说明。
这里写图片描述
在一个规范的C++文件中,我们通常把一个文件分为:文件声明,文件实现和文件测试三个部分。
在一般的编译环境中,.h文件的代码都会扩展到.cpp里面,然后编译器对.cpp文件编译形成.obj文件,.cpp以分离的方式编译完成后,经过连接器连接生成.exe文件。
我们来看一个例子:

test.h
#include<iostream>
using namespace std;
void fun();

test.cpp
#include"test.h"
void fun()
{}

main.cpp
#include"test.h"
int main()
{
    fun();
    system("pause");
    return 0;
}

在这个例子中,test.cpp和main.cpp分别被编译成各自不同的.obj文件,当编译器编译 main.cpp 时,它所仅仅知道的只是main.cpp中所包含的test.h文件中的一个关于void fun();的声明,所以,编译器将这里的 fun() 看作外部连接类型,即认为它的函数实现代码在另一个.obj文件中,本例也就是test.obj。因此 main.obj 中没有任何关于 f() 的代码。这些代码实际存在于test.cpp所编译成的test.obj中。main对fun()的调用只会生成一条call指令,因为main.obj中没有f()的实现代码。至于寻找 f() 的实现代码,那就是连接器的任务了。找到以后将call f这个指令的调用地址换成实际的f的函数进入点地址。需要注意的是:连接器实际上将工程里的.obj“连接”成了一个.exe文件。

再来看一个模板的例子

test.h
#include<iostream>
using namespace std;
template <class T>
class AA
{
public:
    void fun();
};

test.cpp
#include"test.h"
template<class T>

void AA<T>::fun()
{
    cout << "AA::fun()" << endl;
}

main.cpp
#include"test.h"
int main()
{
    AA<int> a;
    a.fun();
}

在这里,编译器会报错
这里写图片描述

模板仅在需要的时候才会实例化出来,所以,当编译器只看到模板的声明时,它不能实例化该模板,只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板的.cpp文件中没有用到模板的实例时,编译器并不会去实例化

猜你喜欢

转载自blog.csdn.net/wyn126/article/details/76733943