欢迎光临散文网 会员登陆 & 注册

类模板机制

2023-03-23 22:10 作者:xhy2023  | 我要投稿

是对一批仅仅成员数据类型不同的类的抽象,程序员只要为这一批类所组成的整个类家族创建一个类模板,给出一套程序代码,就可以用来生成多种具体的类。

  • 类模板用于实现类所需数据的类型参数化。

  • 类模板在表示如数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响。

类模板基本语法举例:

模板的编译过程

  • 什么是编译单元:一个编译单元(translation unit)是指一个.cpp文件以及它所#include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,并且本身包含的就已经是二进制码,但是不一定能够执行,因为并不保证其中一定有main函数。

  • 什么是分离式编译:一个项目由若干个源文件共同实现,而每个源文件(.cpp)单独编译成目标文件(.obj),最后将所有目标文件连接起来形成单一的可执行文件的过程。

下面举一个例子来说明:

test.h文件内容如下:

test.cpp文件内容如下:

main.cpp文件内容如下:

test. cpp和main.cpp各自被编译成不同的.obj文件,在main.cpp中,调用了func函数,然而当编译器编译main.cpp时,它仅仅知道的只是main.cpp中所包含的test.h文件中的一个关于void func();的声明,所以,编译器将这里的f看作外部连接类型,func的实现代码实际存在于test.cpp所编译成的test.obj中。在main.obj中对f的调用只会生成一行call指令,链接器负责在其它的.obj中寻找func的实现代码,找到以后将call func这个指令的调用地址换成实际的func的函数进入点地址。然而,对于模板,模板函数的代码其实并不能直接编译成二进制代码,其中要有一个“实例化”的过程。举个例子(将模板的声明和实现分离):test.h文件内容如下:

test.cpp文件内容如下:

main.cpp文件内容如下:

编译器在#1处并不知道A<int>::f的定义,因为它不在test.h里面,于是编译器只好寄希望于链接器,希望它能够在其他.obj里面找到A<int>::func的实例,在本例中就是test.obj,然而,后者中真有A<int>::func的二进制代码吗?NO!!!因为C++标准明确表示,当一个模板不被用到的时侯它就不该被实例化出来,test.cpp中用到了A<int>::func了吗?没有!!所以实际上test.cpp编译出来的test.obj文件中关于A::f一行二进制代码也没有,于是链接器就傻眼了,只好给出一个链接错误。但是,如果在test.cpp中写一个函数,其中调用A<int>::func,则编译器会将其实例化出来,链接器就能够完成任务。

  • 模板的二次编译

  1. 非模板类在编译的时候就会被实例化出代码,但编译模板类则不是如此,C++标准明确表示当一个模板不被用到的时侯它就不该被实例化出来。

  2. 当编译到用模板类特例定义对象的代码时,如A<int> a; 此时编译器才会生成对应实例化类的二进制代码,即第二次编译。

  3. 第二次编译的时候如果该编译单元能访问到模板类的实现代码,则好说,否则只能等到链接,如果其它模块也没有实例化过该代码,则会链接出错。

  • 解决办法

  1. 模板类声明在test.h中,定义在main.cpp中,调用在main.cpp中,则能运行成功。

  2. 模板类声明在test.h中,定义在test.h中,调用在main.cpp中,则能运行成功,因为在预处理阶段会对头文件展开。


类模板机制的评论 (共 条)

分享到微博请遵守国家法律