b917893200 发表于 2020-3-15 22:58

剖析类模板的声明和实现分离编译的后果

写程序的时候一般来说,我们在头文件里写类及其成员函数的声明,在cpp文件里写类的实现。
但是类模板有些不一样,我们通常是将声明与实现都放在一个头文件中。如果不这样做,我们看下面代码

#ifndef _FUNCTION_H
#define _FUNCTION_H
#include<iostream>
template<typename T> class A
{
        T value;
public:
        T GetValue();
        A(T t);
        A() = default;
};

#endif
这是类的声明部分代码,我们放在function.h中。

template<typename T> A<T>::A(T t) :value(t) {}
template<typename T> T A<T>::GetValue()
{
        return value;
}
这是function.cpp的代码。

#include<iostream>
#include"function.h"
using namespace std;
int main()
{
        A<int> a(5);
        cout << a.GetValue();
        return 0;
}
这是test.cpp,里面有我们的main函数,用以调用这个类的代码。
现在我们编译一下,

这个错误是发生在链接过程中的。一个c/cpp文件要经过预编译-编译-汇编三个过程,生成一个.o或。obj的目标文件,而一个exe文件就是多个.o(obj)文件合成而成。
为什么会出现这样的错误,我们到linux环境下测试。
首先我们利用g++ function.cpp -std=c++11指令将function文件编译。


可以看到并没有我们实现的函数,也就是编译器他是无法链接到的。
原因是我们的c/c++的编译机制是独立编译,也就是每个cpp独立编译,只有类实例化,模板才会实例化出相应的成员函数。
当编译main.cpp时,它实力化成A<int>类,然而,function.cpp此时并不可见,也就找不到相应的成员函数模板,就实例化不了模板函数。
当我们将function.cpp的实现放到function.h中,
g++ -S test.cpp -o test.s -std=c++1
vim test.s
看一看新编译的


可以看到已经成功实例化出一个模板函数,并链接。


总结:模板声明与实现都要放在同一文件内

页: [1]
查看完整版本: 剖析类模板的声明和实现分离编译的后果