类模板
大约 3 分钟
类模板
类模板
使用
使用
- 简概
- C++最初不支持模板,但模板被引入后一直在改进,因此有的编译器可能不支持所有特性
- 模板提供
参数化类型
(parameterized type)
- 使用场景
- 可以用于设计容器类(container calss)(如Stack、Queue等)
- 使用
- 和模板函数差不多,但稍复杂些
- 一方面,在class声明前加
template <typename T>
- 另一方面,所有的成员函数前加
template <typename T>
,并把作用域解析符前的类名
换成类名<T>
- 原理
- 和模板函数差不多
- 当定义类实例时,会根据
类名<T>
模板来生成不同的类声明和和类方法 - 因为是模板,所以可以不用(不会产生定义)也不能(模板不能单独编译)分离头文件和实现,实现要写在头文件中
- 类模板的函数模板区别
- 与函数模板不同,必须显式提供所需的类型而不能由参数类型来确定要生成那种函数
类型参数补充
- 类型参数
template <typename T>
中的T
是一个类型参数
(type parameter)- 这这意味着它类似于变量,
T
为可以修改名字的变量名,而赋值给它的是类型
- 非类型(non-type)参数或表达式(expression)参数
template <int n>
中的n
是一个非类型参数
(non-type parameter)或表达式参数
(expression parameter)- 比如
template <class T, int n>
可以替换为
- 类模板传参和构造函数传参区别(以创建数组为例)
vector
类型使用的是构造函数方法- 优点:通过new和delete管理堆内存,更方便
array
类型使用的是类模板传参方法- 优点:为自动变量维护内存栈,速度更快
- 缺点:会为不同长度的数组生成多个模板定义。如
Array<int, 2>;
、Array<int, 3>;
会生成两个定义
功能多样性 / 功能扩展
模板功能性多,可用作基类、组件类、还可用作其他模板的类型参数
- 可以递归使用模板
- 如
Array<Array<int,5>,10> twodee;
,这相当于二维数组int twodee[10][5];
- 如
- 可以使用多个类型参数
- 如
template <class T1, class T2>
- 如
- 默认类型模板参数
- 如
template <class T1, class T2=int> class A {...}
- 如
具体化、实例化
具体化
(specialization)和实例化
(instantiation)
写法和函数模板的不太同,主要原因可能是因为:
- 函数模板在圆括号的参数中写类型参数,而且会自动判别类型
- 类模板的原括号保留用作构造函数,使用尖括号,而且是显式写出类型
隐式实例化(implicit instantiation)
- 写法
- 举例:假如定义了
template <class T> class A {...}
,则当声明对象A<int> a;
时进行隐式实例化
- 举例:假如定义了
显式实例化(explicit instantiation)
- 写法
- 举例:假如定义了
template <class T> class A {...}
,则可以template class A<int>;
进行显式实例化
- 举例:假如定义了
显式具体化(explicit specialization)
简概
- 是特定类型(用于替换模板中的泛型)的定义
使用场景
- 需要为特殊类型实例化时,对模板进行修改,使其行为不同
写法
通用:
template <> class ClassName <specialized-type-name> {...};
或:
calss ClassName<specialized-type-name> {...};
(早期的写法)举例:
template <> class A <int> {...};
部分具体化(partial specialization)
- 简概
- 即限制模板的通用性
- 写法
- 举例:
template <class T1> class A <T1, int> {...};
,该语句将T2
具体化为int,但T1
保持不变
- 举例: