template<class T>
class CTpl
{
public:
CTpl();
virtual ~CTpl();
void Test(T t);
};
2.实现部分
// Tpl.cpp
#include "Tpl.h"
template<class T>
CTpl<T>::CTpl()
{
}
template<class T>
CTpl<T>::~CTpl()
{
}
template<class T>
void CTpl<T>::Test(T t)
{
}
3.习惯错误用法
// main.cpp
#include "Tpl.h"
int main()
{
CTpl<char> ts;
ts.Test(3);
return 0;
}
build时出现link错误
main.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall CTpl<char>::~CTpl<char>(void)" (??1?$CTpl@D@@UAE@XZ)
main.obj : error LNK2001: unresolved external symbol "public: void __thiscall CTpl<char>::Test(char)" (?Test@?$CTpl@D@@QAEXD@Z)
main.obj : error LNK2001: unresolved external symbol "public: __thiscall CTpl<char>::CTpl<char>(void)" (??0?$CTpl@D@@QAE@XZ)
这组错误信息和project中不加入Tpl.cpp的错误信息一样,即没有CTpl<char>的实现代码
我们把Tpl.cpp包涵到main.cpp中,问题解决
4.正确用法
// main.cpp
#include "tpl.cpp"
int main()
{
CTpl<char> ts;
ts.Test(3);
return 0;
}
5.总结
1.在使用以.h,.cpp分离实现模板类时,不能像使用普通类一样只简单的包涵.h头文件,应该在使用模板类的cpp文件中引入模板类相应的cpp文件
2.将模板类的声明与实现都放在.h中(在多个cpp中使用不同模板参数时可能会引起重复定义的编译错误)
《c++编程思想》中说:模板类定义很特殊,由template<...>定义的任何东西都意味着编译器在当时不为它分配内存空间,它一直处于等待状态,直到被一个模板实例告知,即模板参数是由编译器来替换的。
为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。有时,也可能为了满足特殊需要而要在独立的cpp中放置模板的实现。但大部分现在的编译器还不支持模板类的定义和实现分开
原因是模板的实例化,必须满足两个条件:
1。必须知道定义
2。必须知道类型参数
如果定义和声明不在同一文件中,则当使用时,因为没有定义会产生一个指向定义的引用,而在分析定义时,因为不知道类型参数,所以无法实例化。会产生链接错误。
template 机制称为 compile-time 多态 编译器在编译你的源文件时,若发现
keword template 会马上区找它的实现代码(想想c++怎么样找到它的source code?) 因此 大部分c++代码会把它的 template 实现代码 写在 头文件里
如果你想隐藏你的实现 可以考虑一下指针(本人不确定 这或许不行 本人以前没想过(很惭愧 没你善于考虑问题)),本人从楼上老兄那里得到了些灵感 待本人回家想想
如果把模板实现和定义分开,在模板类所在的编译单元里当然就不可能知道模板参数将是什么——int?char?甚至是用户自定义数据?——模板函数/类也就无从展开。很显然,相应的.o文件也就不可能包含所有这些实例代码。
只有把模板定义放到每一个引用它的地方,这样才可能完成展开——从这个意义上说,所谓模板定义其实应该算是模板声明,真正的定义是在你确认了模板类型参数之后(由编译器自动生成代码)。
不过,即便如此,为了避免和传统的.h .c使用习惯混淆,模板类所在的文件一般还是会用无扩展名或*.inc的格式命名。