第六章 以template进行编程
将template称为处方;
template 所接受的类型,系由template用户与使用时指定。
能根据用户指定的特定值或特定类型,自动产生一个函数或类。
以二叉树为例,二叉树包含两个class:
一个是BinaryTree,用以存储一个 ,指向根节点;提供的操作行为包括:插入(insert)、移除(remove)、搜寻(find)、清除(clear)、打印(print)
另一个是BTnode,用来存储节点实值,以及连接至左右两个子节点的链接。
6.1 被参数化的类型
class string_BTnode{
public:
//....
private:
string _val;
int _cnt;
string_BTnode *_lchild;
string_BTnode *_rchild;
}
但为了储存不同类型的数值,我们必须要为它实现不同的BTnode类,并取不同的名字。
怎么办?
template <typename valType>
class BTnode{
};
使用tmplate机制可以帮助我们将类定义中“与类型相关"和独立于类型之外的两部分分离开来。这样对树进行操作就不会随着处理的类型不同而有所不同。
针对每一种BTnode实际类型,对应的BinaryTree事例能够成为其friend。声明如下:
template <typename Type>
class BinaryTree; //前置声明
template <typename valType>
class BTnode{
friend class BinaryTree<valType>;
};
那么怎么通过class template实例化类呢?
在class template名称之后,紧接一个尖括号,其内放置一个实际类型(准备用来取代valType).
例如:
BTnode bti; //将valType绑定为int
6.2 Class Template的定义
template <typename elemType>
inline BinaryTree<elemType>::
BinaryTree():_root(0)
{}
这个member function的定义始于关键字template 和一个参数类表,然后便是函数定义本身,并带有关键字inline及class scope运算符。
inline 一词必须紧接在关键字template 和参数列表之后。
为什么第二次出现的BinaryTree名称就不需要限定?
因为在class scope 运算符出现之后BinaryTree,其后所有东西都被视为位于class定义范围之内。
6.3 Template类型参数的处理
将所有的template类型参数视为”class类型”来处理。这意味着我们会把它声明为一个const reference。
在constructor定义中,选择在member initilization list内为每个类型参数进行初始化操作:
template <typename valType>
inline BTnode<valType>::
BTnode(const valType &val)
:_val(val)
{
_cat =1;
_lchild = _rchild = 0;
}
6.4 实现一个class Template
以insert()为例:
template <typename elemType>
inline void
BinaryTree<elemType>::
insert(const elemType &elem)
{
if(! _root)
_root = new BTnode<elemType> (elem);
else _root->insert_value(elem);
}
6.5 一个以Function Template完成的Output运算符
template <typename elemType>
inline ostream&;
operator<<(ostream &os,const BinaryTree<elemType> &bt>
{
os << "Tree:" <<endl;
bt.print(os);
retun os;
}
6.6 常量表达式与默认参数值
可以使用常量表达式作为template参数
后期再进行补充。