C++模板的申明和定义
2015-09-02 14:53
162 查看
template <typename T> class CQTree { public: CQTree(); ~CQTree(); public: }; template <typename T> CQTree<T>::CQTree() { } template <typename T> CQTree<T>::~CQTree() { }
最近写代码,需要用到模板,果断将模板的申明和定义分别写到了.h和.cpp文件中,后来程序总是编译出错。后来查找原因,发现C++中模板和定义的实现最好写在同一.h文件中,其实以前就遇到过,好久没用了,居然忘记了,因此特此记录一番。
原因如下:
“通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明。因此,最好的办法就是将模板的声明和定义都放置在同一个.h文件中。这就是为什么所有的STL头文件都包含模板定义的原因。”[1]
"标准要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道 typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。"[1]
"《C++编程思想》第15章(第300页)说明了原因:
模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。"[2]
"对C++编译器而言,当调用函数的时候,编译器只需要看到函数的声明。当定义类类型的对象时,编译器只需要知道类的定义,而不需要知道类的实现代码。因此,因该将类的定义和函数声明放在头文件中,而普通函数和类成员函数的定义放在源文件中。
但在处理模板函数和类模板时,问题发生了变化。要进行实例化模板函数和类模板,要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道 typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。"[3]
[1] 任何时候都适用的20个C++技巧. http://www.uml.org.cn/c++/20112284.asp
[2] 为什么不能将类模板的声明与类模板函数实现分开写. http://blog.sina.com.cn/s/blog_684355870100jmjr.html
[3]类模板和模板函数连接出错处理. http://www.cppblog.com/kenny/archive/2011/04/23/144841.html
相关文章推荐
- C++读书笔记
- C++函数声明和定义深度解析
- C++内存管理
- c++10 Seattle Clang error
- C++ Builder XE8 安卓开发之使用ini文件保存数据
- C++中的头文件和源文件
- C/C++经典题解析
- 国外程序员整理的 C++ 资源大全
- 个人C++注释规范
- c语言中的字符数组与字符串
- C、C++和java中各种数据类型的长度
- C++11特性 - Smart Pointers 智能指针
- zk系列-c++下zookeeper使用实例
- C++11特性 - Smart Pointers 智能指针
- C 风格字符串,C++string类,MFC,CString类的区别。
- 数字组合
- C++类中包含string类型数据使用read和write实现文件读取和输出时遇到的问题
- C++builder XE10 终于支持类内变量初始化了
- C++ 友元函数
- C语言中查询进程信号是否被遮罩或搁置的简单方法