关于模板类声明与实现分离(即声明放在.h文件,实现放在.cpp文件)的测试。
最近在写模板类的时候,分开编译模板声明和模板实现老实编译不过。看提示应该是链接不到实现的函数。
在网上查了一下,发现很多精辟的解释。
原来原因是模板的具体定义要在模板参数确定了之后才能实例化。
而在模板实例化的过程中(比如在main函数中,但只包含模板声明函数)。包含实例化的.cpp文件编译成.o文件,留了类函数的入口地址等待填充。
一般,包含普通函数的.cpp文件编译成.o文件时。函数是确定的,能编译成二进制代码。然后就有函数入口地址可以让链接程序填入调用了这个函数的.o文件中。
然后函数调用就成功了。
但是,对于模板类的实现。编译成.o文件时,仍然没有实例化。就是说模板类的实现函数不知道具体的模板函数是什么,不能实例化成一个真正的类型
(比如Vector<int> a ; //参数实例化成int,vector<int>为一个类型( 和内置类型double一样了 ))。但是没有实例化前,函数是不确定的。就是还没有编译成二进制文件。所以没有函数的入口地址提供。由于没有入口地址,链接程序在帮main函数找实例化成具体类型的模板找实现函数时找不到,就提示链接错误了。
既然知道哪里粗了问题,就可以解决问题了。解决的办法就是让实例化了模板的.cpp文件可以看到函数实现就行了。
这里有两个办法。
1、直接把函数声明和函数实现全部放在同一个.h文件里面。这样引用.h文件的时候,声明和实现都直接展开在实例化的.cpp文件里面
这样编译的时候就能找到函数的入口地址了。
2、函数声明和函数实现分开实现。在实例化模板的地方#include "xxx.cpp",即直接包含.cpp文件,这样也能找到函数入口。如我下面测试的一样。
其实,我之前看到一般文章有说,如果把声明和实现都放在同一个.h文件里面,在不同的.cpp文件里面以不同的参数实现模板的时候会
报重覆定义的错误。但是我没遇到过。如果以后发现再补充回来吧。
templateclass.h
#ifndef _TEM_H__
#define _TEM_H__
#include <iostream>
using namespace std;
template <class Elem>
class List {
private:
Elem data;
public:
List(Elem a ) {
data = a;
}
void print( void );
};
//#include "templateclass.cpp"
#endif
templateclass.cpp
#include "templateclass.h"
template <class Elem>
void List<Elem>::print( ) {
cout << data << endl;
}
double.cpp
#include "templateclass.h"
#include "templateclass.cpp"
void doubleprint( double para ) {
List<double> object( para );
object.print( );
}
#include "templateclass.h"
#include "templateclass.cpp"
void intprint( int para ) {
List<int> object( para );
object.print( );
}
//#include <iostream>
//using namespace std;
void doubleprint( double );
void intprint( int );
int main( int argc, char *argv[] ) {
doubleprint( 3.5 );
intprint( 19 );
return 0;
}
tao: double.o int.o mainfun.o templateclass.o
g++ -o tao double.o int.o mainfun.o templateclass.o
double.o: templateclass.h double.cpp
g++ -c double.cpp
int.o: templateclass.h int.cpp
g++ -c int.cpp
templateclass.o: templateclass.h templateclass.cpp
g++ -c templateclass.cpp
mainfun.o: double.cpp int.cpp mainfun.cpp
g++ -c mainfun.cpp
超通俗地解释模板分离编译