Templates⚓︎
约 841 个字 85 行代码 预计阅读时间 5 分钟
为什么需要模板?
设想一下:假如你有两个列表 X
和 Y
,它们需要相同的代码,但是存储元素的类型不同。这时,你也许会想到以下解决方案:
- 使用共同的基类
- 直接克隆代码:能够保证类型安全,但是不易管理(我的理解是很难确保一致性)
- 无类型列表:这样会产生类型不安全的问题
但这些方案似乎都不太好,所以我们引入了一种更优的方法:模板(template)。
模板:
- 重用源代码
- 泛型编程
- 使用类型作为类或函数定义中的参数
-
函数模板(function template)
- 例子:排序函数
- 模板函数(template function) 是函数模板的实例
- 参数不支持隐式的类型转换
-
类模板
- 例子:像栈、列表、队列等容器,其中栈的运算和栈里面项的类型无关
- 模板成员函数
模板的语法:
template
关键字用于引入模板class T
指明参数化的类型名称- 类可以是内建类型或用户定义的类型
- 这里也可以用
typename T
替代
- 在模板内部,使用
T
作为类型名称
模板的实例化(instantiation):从模板类 / 函数和模板参数重得到一个声明
- 类型被替代为模板
- 创建了新的函数体或类定义
- 语法错误、类型检查
- 专一化 (specialization):对于特定参数的模板版本
Function Templates⚓︎
例子:使用交换函数
函数重载规则:
- 先检查唯一的函数匹配
- 然后检查唯一的函数模板匹配
-
再对函数进行重载
函数实例化
- 编译器从传递给函数的实参中推断模板类型
-
可以显式实现,参数可以不在函数签名内(旧版编译器不支持这一行为)
Class Templates⚓︎
- 类型实现了对类的参数化
- 从被操作的类型中提取抽象操作
- 可能会定义类的无限集合
- 另一种重用方法
- 典型用法:容器类,比如
stack<int>
、list<Person&>
、queue<Job>
例子
template <class T>
class Vector {
public:
Vector(int);
~Vector();
Vector(const Vector&);
Vector& operator=(const Vector&);
T& operator[](int);
private:
T* m_elements;
int m_size;
};
Vector members
template <class T>
Vector<T>::Vector(int size) : m_size(size) {
m_elements = new T[m_size];
}
template <class T>
T& Vector<T>::operator[](int indx) {
if (indx < m_size && indx > 0) {
return m_elements[indx];
} else {
...
}
}
使用:
模板能用于多个类型,比如:
template< class Key, class Value>
class HashTable {
const Value& lookup(const Key&) const;
void install(const Key&, const Value&);
...
};
- 模板嵌套:本质上得到的是一个新类型
- 举例:
Vector< Vector< double *> > // note space > >
- 举例:
- 类型参数可以很复杂
- 举例:
Vector< int (*)(Vector<double>&, int)>
- 举例:
模板参数还可以是一个常量表达式,或者是无类型的参数
-
作为默认参数:
-
无类型参数:
template <class T, int bounds> T& FixedVector<T,bounds>::operator[]( int i ) { return elements[i]; // no error checking } // Usage FixedVector<int, 50> v1; FixedVector<int, 10*5> v2; FixedVector<int> v3; // uses default
- 嵌入 size 不是一个好主意
- 能够让代码更快
- 但使用起来更复杂
- 可能导致(甚至更多的)代码膨胀
模板和继承:
-
模板能够继承自非模板类
-
模板也可以继承自模板类
-
非模板类可继承自模板类
注
- 友元?
- 静态成员?
- 一般将模板的定义和声明放在头文件里
- 此时不会为该类分配存储空间
- 编译器 / 链接器有能够移除多定义的机制
在编写模板时:
- 从非模板的版本出发
- 建立一组良好的测试集,用于测量性能并进行调优
- 修改实现:考虑哪些类型需要被参数化
- 将非参数化的版本转换为模板:针对已建立的测试用例进行测试
评论区
如果大家有什么问题或想法,欢迎在下方留言~