C++中模板函数及模板类的使用(下)

时间:2023-01-22 19:12:15

在使用模板类时,一般会将类定义及成员变量和成员函数的声明放在h头文件中,而将成员函数的定义放在cpp执行文件中。在编译程序时可能会出现如下错误提示

errorLNK2019: 无法解析的外部符号"public:void __thiscall Stack<int,10>::push(int)"(?push@?$Stack@H$09@@QAEXH@Z),该符号在函数_wmain中被引用

该错误提示的含义是编译器只找到了Stack模板类的push()成员函数的声明,而未能找到该成员函数的定义。产生该错误的原因是,在使用模板时,编译器必须能够访问定义模板的源代码当调用函数模板或类模板的成员函数的时候,编译器需要函数定义,需要那些通常放在源文件中的代码。而模板类的成员函数与普通类的成员函数不同,编译器不能从它对应的h头文件直接找到cpp执行文件。

标准C++为编译模板代码定义了两种模型。一种是“包含编译模型”,另外一种是“分别编译模型”。

1 包含编译模型

包含编译模型就是在h头文件中包含cpp执行文件。编译器在h头文件找到模板类成员函数声明的同时,就能够找到该函数的定义了。实现的方法为在在h头文件中的模板类定义之后加入对cpp执行文件的包含。

template<class T,int MAXSIZE>

class Stack{

.......
   };

#include"Stack.cpp"

在使用该模型进行模板编译时,添加了如上代码后,编译器会报如下错误

errorC2995: “voidStack<T,MAXSIZE>::push(T)”: 函数模板已经定义

主要原因是在h头文件中包含了cpp执行文件,对成员函数进行了定义;而cpp执行文件又包含在项目中,再次对成员函数进行了定义,所以会有“函数模板已经定义”的错误信息。可以将模板类对应的cpp执行文件从项目中移除,注意是“移除”而不是“删除”。

2 分别编译模型

分别编译模型就是告诉编译器去哪里找类模板成员函数的定义。通过export关键字实现。export关键字能够指明给定的定义可能会需要在其它文件中产生实例化。在一个程序中,一个模板只能定义为导出一次。在模板类对相应的cpp执行文件中,有如下代码

exporttemplate<typename T>

template<typename T> void Queue<T>::push(constT&)

{

.......

}