C++模板的声明和定义为什么不能分写在.h与.cpp文件中

一般情况下,编写一个类一般将头文件(.h文件)和源文件(.cpp文件)进行分离。.h文件定义类和函数,.cpp文件中进行函数的实现, 然后提供给其他.cpp文件调用。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明

模板定义很特殊,由template<…>处理的任何东西都意味着编译器在当时不为它分配存储空间(没有具体的函数时不会对模板实例化),它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。

由于C++是独立编译,例如a.cpp、b.cpp、c.cpp三个文件,先独立编译成三个独立的目标文件,即a.o、b.o、c.o,然后再通过链接器链接起来,生成可执行文件。

在编译时,a.cpp发现一个函数调用,在当前文件找不到函数定义,则在函数位置生成符号,在链接时,再寻找这个函数。

模板类是两次编译。第一次编译时只对模板进行编译,不生成具体函数,在调用时才生成具体函数。为什么不能在第一次编译就生成具体函数呢?请看下图(取自vector模板源码迭代器“+”的定义和声明):

标准要求编译器(VS、GCC)在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道“typename” 实参是什么类型呢?因此模板的实例化与定义体必须放到同一翻译单元中。

所以,最好的办法就是将模板的声明和定义都放置在同一个.h文件中。这同时也是为什么所有的STL头文件都包含模板定义的原因。

posted @ 2021-07-28 21:25  Jcpeng_std  阅读(1578)  评论(0编辑  收藏  举报