4.2.2 实例化时间(2)
在某些时候,对于模板类的成员函数,即使在它依赖于模板参数的条件下,我们也可以提升这个函数。假设我们用下面独立的类Node来描述BSTree树中的节点:
- template<class T>
- class Node{
- T t;
- Node* preorder_successor;
- //...
- };
我们希望提供一个函数BSTree::thread,用于前序 线性化所给定的树-特别地,当函数BSTree::thread返回的时候,树中每个节点的preorder_successor域指向它的前序后继者,下面是BSTree::thread函数的伪代码: - template<class T>
- void BSTree::thread() {
- Node<T>* prev = 0;
- Node<T>* n = 0;
- for(树中前序的每个节点) {
- if(prev)
- prev->preorder_successor = n;
- prev = n;
- }
- if(n)
- n->preorder_successor = 0;
- }
thread函数的实际实现可能会使用树的前序遍历递归算法,而不是上面的for循环。而且从上面的代码可以看出:thread函数的代码实体依赖于模板参数T(在pre成员和n成员的声明语句中)。然而,从概念上讲,对树进行线性化并不依赖于树中节点存储值的类型;因此,只要再做一些工作,我们就应该可以提升thread函数。首先,让我们从一个非模板基类派生出模板类Node:- class Nodebase { //为了提升而设计的非模板类
- protected:
- Nodebase* preorder_successor;
- };
- template<class T>
- class Node : public Nodebase {
- T t;
- //...
- };
我们同时也提升了preorder_successor成员变量。现在我们就可以根据Nodebase类重写thread函数,来提升thread函数:
- class BSTreebase {
- public:
- void thread();
- //...
- };
- void BSTreebase::thread() {
- Nodebase* prev=0;
- Nodebase* n=0 7;
- //剩下的代码和原先在BSTree::thread中的代码一样
- //...
- }
3.指针容器
减少实例化代码数量的另一个技术就是提供指针容器(pointer container)。假设我们的程序库提供了一个List模板:
- template<class T>
- class List {
- public:
- T head() const;
- List<T> tail() const;
- Void insert(const T& t);
- //...
- };
List<T>是一个值的类型为T的链表;函数head在List不为空的前提下,返回List的第一个值;函数tail同样在List不为空的前提下,返回一个原先删除第一个值后的'List;函数insert将在List的表头插入值t。
例如,假设用户创建了一个List<inat>、一个List<String>、一个List<Widget*>和一个List<Blidget*>(其中Widget和Blidget是用户自己定义的类),并且对上面每个List都调用了head、tail和insert函数;那么,每个函数都将被实例化4次,总共对函数实例化了12次。在用户的程序里,一个被广泛使用的类(如List)可能会用不同的类型来进行实例化,同时也就必须实例化许多函数,最后导致生成许多(List)成员函数的代码。