类模板基础
语法:
template <typename Type>
- 每个模板类成员函数的前面都要加上
template <classType>
或template <typename Type>
,但如果在类声明中定义了方法(内联定义),则可以省略模板前缀和类限定符- 模板不是类和成员函数,而是
C++编译器指令
,说明了如何生成类和成员函数定义实例化(具体化):
模板的具体实现,eg:
处理string对象的栈类- 不能讲模板成员函数放在独立的实现文件中,由于模板不是函数,它们不能单独编译
- 模板必须与特定的模板实例化请求一起使用,应将
模板类的声明
以及模板成员函数
都放在一个.h的头文件
中,并在要使用这些模板的文件中包含该头文件
template <class Type> //或者 template <typename Type>
class Stack
{
private:
Type items[MAX];
public:
Stack();
bool push(const Type & item);
};
template <class Type>
Stack<Type>::Stack()
{
top = 0;
}
- 模板类的使用:
使用所需的具体类型替换泛型名:
eg:
Stack<string> colonels;
- 与常规的
函数模板
不同,类模板
必须显式提供所需的类型
- 表达式参数:
template <class T, int n>
,其中参数int n
,指定特殊的类型而不是用作泛型名,称为非类型参数
或表达式参数
- 表达式参数可以是
整型
、枚举
、引用
或指针
- 模板参数不能修改参数的值,也不能使用参数的地址,
n++
或&n
都是错误的- 实例化模板时,用作表达式参数的值必须是常量表达式
- 表达式参数的值不同将生成不同的独立的类声明
- 模板的多功能性:
- 可以将常规的类技术用于模板类
- 模板类可以用作
基类
,也可以用作组件类
,还可以用作其他模板的类型参数
- 模板类可以
递归
使用- 模板类可以使用多个
类型参数
,并且可以为类型参数提默认值
(1)可以为类模板类型参数提供默认值,但不能为函数模板提供默认值
(2)类模板
和函数模板
都可以为非参数类型提供默认值
类模板的具体化
具体化:
使用具体的类型生成类声明
- 分类:
隐式实例化
、显式实例化
、显式具体化
、部分具体化
- 隐式实例化:
实例化:
编译器使用通用模板提供的处方生成具体的类定义
隐式实例化:
声明一个或多个对象,指出所需的类型
来进行实例化
- 使用
隐式实例化
时,编译器在需要对象之前,不会生成类的隐式实例化
- 显式实例化:
显式实例化:
使用关键字template
并指出所需类型
来声明类时,编译器将生成类声明的显式实例化
(1)声明必须位于模板定义所在的名称空间
中
(2)显式具体化时,虽然没有创建类对象
,编译器也将生成类声明(包括方法定义)
- 显式具体化:
显式具体化:
用特定类型(用于替换模板中的泛型)的定义
(1)当具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本
(2)具体化类模板定义的格式:
template <> class Classname<specialized-type-name> {...};
- 部分具体化:
部分具体化:
部分限制模板的通用性- 如果指定所有的类型,则<>内将为空,将导致显式具体化
- 如果有多个模板可供选择,编译器将使用具体化程度最高的模板
- 也可以通过为
指针
提供特殊版本来具体化现有的模板部分具体化特性
能够设置各种限制
成员模板
- 模板可以用作
结构
、类
、或模板类
的成员- 模板函数或模板类做
成员
时,可以在类内声明类外定义
类模板作参数
类模板
还可以包含本身就是模板
的参数
模板类与友元
- 模板的友元分3类:
非模板友元
、约束模板友元
、非约束模板友元
非模板友元
非模板友元
:非模板友元函数本身不是模板函数- 必须为要使用的
友元
定义显式具体化
模板类的约束模板友元函数
模板类的约束模板友元函数:
友元函数本身成为模板
(1)在类定义的前面声明每个模板函数
(2)在函数中再次将模板声明为友元
(3)为友元提供模板定义
模板类的非约束模板友元函数
模板类的非约束模板友元函数:
(1)通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元
(2)对于非约束友元,友元模板类型参数与模板类类型参数是不同的
模板别名
- 可以使用
typedef
为模板具体化指定别名- 可使用
using =
为模板提供别名- C++11允许语法
using=
用于非模板,此时与typedef
等价