来自:http://www.iis.sinica.edu.tw/~kathy/vcstl/templates.htm
Introduction简介
许多C++程序常用像栈、队列、表等的数据结构。(举个例子)一个程序可能需要一个客户的队列(a queue of customers)和一个消息的队列(a queue of messages)。你可以很轻松的实现客户队列然后使用已有的代码来实现消息队列。随着程序的增长,现在又需要一个订单的队列(a queue of orders)。难道只有通过复制、粘贴、查找、替换来把一个消息队列转换成订单队列?需要对队列的实现作些改变啦!这不是一个简单的活,因为很多地方的代码大致相同。重新编码不是明智的方法,因为面向对象编程提倡程序的重用性。这看起来好像是要考虑怎样实现一个队列,不用复制代码就可以实现对任意类型数据的存储。怎么样实现呢?答案就是模板(templates)。
C++模板允许你实现一个带类型参数T的一个通用的队列Queue<T>。T可以被任意的实际类型所代替,如Queue<Customers>,C++会生成类Queue<Customers>。改变队列<Queue>的实现变得相对容易啦。只要模板的参数一改变,就能立即得到相应的类:Queue<Customers>, Queue<Messages>, Queue<Orders>。
若你想要构造一个对任意类型都通用的类如向量(vectors)、栈(stacks)、表(lists)、队列(queues)等,模板就非常有用。模板提供了一种与继承不同的重用代码的方式:重用对象代码。
C++提供两种模板:类模板和函数模板。使用函数模板可以写一个通用的函数,它能使用任意类型的参数。如:可以编写一个能用于任意类型参数的查找和排序函数。标准模板库(The Standard Template)的通用算法通过函数模板来实现的,容器是用类模板来实现的。
Class Templates 类模板
Implementing a class template实现一个类模板
一个类模板的定义像一个普通的类的定义,除了在前面加一个关键字:template。如:Stack栈的类模板的定义:
Template<class T>
class CStack{
public:
CStack(int = 10);
int push(const T&);
int pop(T&);
int isEmpty() const {return top == -1;}
int isFull() const {return top == size – 1;}
~CStack() {delete [] stackPtr;}
private:
int size; // number of elements on Stack.
int top;
T* stackPtr;
};
#endif //_STACK_H_
T是一个参数类型,它可以是任意类型。如:CStack<Token>,Token是一个用户定义的类。T不必是类类型。如:CStack<int>和CStack<Message*>也是有效的实例,尽管int 和Message*并不是“classes”。
Implementing class template member functions
实现类模板的成员函数
类模板的成员函数的实现与普通的类的成员函数据实现多多少少还是有些不同的。类模板的成员函数的声明和定义必须在一个头文件中。如下:
//B.H template <class t> class b { public: b() ; ~b() ; } ; |
// B.CPP #include "B.H" template <class t> b<t>::b() { } template <class t> b<t>::~b() { } |
//MAIN.CPP #include "B.H" void main() { b<int> bi ; b <float> bf ; } |
当编译B.CPP时,编译器同时有声明和定义。这是编译器不需要生成任何类的定义,因为没有实例。当编译Main.cpp时,有两个实例:template class B<int> 和B<float>。这时编译器只有声明(declarations)而没有定义(definition)。
当实现类模板的成员函数时,要在成员函数定义前面加上关键字template。以下为栈类的模板完整实现:
//constructor with the default size 10
template <class T>
Stack<T>::Stack(int s)
{
size = s > 0 && s < 1000 ? s : 10 ;
top = -1 ; // initialize stack
stackPtr = new T[size] ;
}
// push an element onto the Stack
template <class T>
int Stack<T>::push(const T& item)
{
if (!isFull())
{
stackPtr[++top] = item ;
return 1 ; // push successful
}
return 0 ; // push unsuccessful
}
// pop an element off the Stack
template <class T>
int Stack<T>::pop(T& popValue)
{
if (!isEmpty())
{
popValue = stackPtr[top--] ;
return 1 ; // pop successful
}
return 0 ; // pop unsuccessful
}
Using a class template使用类模板
使用一个类模板很简单。只需要把参数类型T换成想要的类型即可。This process is commonly known as “Instantiating a class”. 以下是一个使用栈模板的例子:
在先前的例子中我们实现了一个栈的模板。在上面的程序中我们把模板实例化了:stack of float(FloatStack)和stack of int(IntStack)。一旦类模板实例化后就能得到相应类型的对象,如fs和is。
FloatStack fs(5) ;
float f = 1.1 ;
cout << "Pushing elements onto fs" << endl ;
while (fs.push(f))
{
cout << f << ' ' ;
f += 1.1 ;
}
cout << endl << "Stack Full." << endl
<< endl << "Popping elements from fs" << endl ;
while (fs.pop(f))
cout << f << ' ' ;
cout << endl << "Stack Empty" << endl ;
cout << endl ;
IntStack is ;
int i = 1.1 ;
cout << "Pushing elements onto is" << endl ;
while (is.push(i))
{
cout << i << ' ' ;
i += 1 ;
}
cout << endl << "Stack Full" << endl
<< endl << "Popping elements from is" << endl ;
while (is.pop(i))
cout << i << ' ' ;
cout << endl << "Stack Empty" << endl ;
}
Program Output
Pushing elements onto fs
1.1 2.2 3.3 4.4 5.5
Stack Full.
Popping elements from fs
5.5 4.4 3.3 2.2 1.1
Stack Empty
Pushing elements onto is
1 2 3 4 5 6 7 8 9 10
Stack Full
Popping elements from is
10 9 8 7 6 5 4 3 2 1
Stack Empty