在使用c++的时候,我们习惯于将类的定义声明在头文件中,即.h文件;将类函数的实现定义在源文件中,即.cpp文件。如果我们要提供的是一个动态库,那么这种方式更常用,使用动态库的时候,包含头文件,编译的时候链接动态库就可以了。
但是如果我们提供的是类模板,这种方式就不适用了,本文分析原因。
1模板类错误用法
如下是代码示例,t.h中声明了模板类Box,但是没有实现;t.cpp中实现了Box的每个函数。t.h和t.cpp通过命令g++ -fPIC --shared t.cpp -o libtemplate.so编译出动态库。main.cpp中使用了模板类,编译main.cpp的时候通过g++ main.cpp libtemplate.so链接动态库。
在编译的时候会报错,错误信息如下,提示没有Box<int>这个类,这是为什么呢?这是c++语言常用的使用方式啊,为什么编译会报错呢?
通过objdump -tT libtemplate.so查看动态库中的符号,发现动态库中没有模板类的任何信息,所以编译main的时候编译失败也可以解释了。但是,为什么动态库中没有模板类的任何信息呢,因为g++编译器在编译的时候只有遇到模板的实例,才会做真正的编译,如果只有一个模板,没有实例,编译器是不会编译的。
t.h
template <typename T>
class Box {
public:
// 构造函数
Box(T value);
// 获取值
T getValue() const;
// 设置值
void setValue(T value);
private:
T value_;
};
t.cpp
#include "t.h"
template <typename T>
Box<T>::Box(T value) : value_{value} {}
template <typename T>
T Box<T>::getValue() const {
return value_;
}
template <typename T>
void Box<T>::setValue(T value) {
value_ = value;
}
main.cpp
#include "t.h"
#include <iostream>
int main() {
Box<int> b{100};
std::cout << b.getValue() << std::endl;
return 0;
}
2模板类正确用法
在使用类模板的时候,在编译的时候要能找到类的实现才可以,找不到的类的实现,那么实例化就无从谈起,所以会编译失败。
一般在使用类模板的时候,类的实现和声明要放在同一个文件中。