关于模板的更多的内容,参见以下链接:
C++——成员模板
C++——友元模板
C++——函数模板
前言:STL(模板库)的一个重要特点是数据结构和算法的分离。这种分离使得STL确实非常通用。
STL另一个重要特性是它不是面向对象的。STL主要依赖于模板。这使得STL的组件具有广泛通用性的底层特征。由于STL是基于模板的,内联函数的使用使得生成的代码短小高效。STL是ANSIISO C++标准中最新的也是极具革命性的一部分。 STL包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法,为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
从实现层次看,整个STL是以模板作为基石的。
STL的背后蕴含着泛型化程序设计(GP)的思想,在这种思想里,大部分基本算法被抽象、被泛化,独立于与之对应的数据结构,用于以相同或相近的方式处理各种不同情形。“泛型化”是根据英语翻译过来的,以笔者的理解,称为“普通”更恰当。
在ISO/IEC 14882:2003(E)中, 类模板的英文定义是:“A class template defines the layout and operation for an unbounded set of related types.”较恰当的中文翻译应该是:对于一些非紧密相关的数据类型,类模板定义了它们共同的设计(类的结构)和操作(子函数)等。
template <类型参数表>
class 类模板名{
...
成员函数和成员变量
...
};
其中,类型参数表的写法如下:
class类塑参数1, class类型参数2, ...
其中,类模板中的成员函数放到类模板定义外面写时的语法如下:
template <类型参数表>
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
...
}
其中,用类模板定义对象的写法如下:
类模板名<真实类型参数表> 对象名(构造函数实际参数表);
如果类模板有无参构造函数,那么也可以使用如下写法:
类模板名 <真实类型参数表> 对象名;
类模板仅仅是模板。如何使用模板就涉及类模板的实例化问题。模板实例化一般指使用模板类和模板参数生成一个类声明的过程。
模板可以使用较短的源代码定义生成出代码,是非常强有力的程序开发方法。使用时要避免大量几乎相同的函数定义胀破存储器。
模板的具体形式在第2点已经说明,是:
template < class Type >
相关的例子,如:list、map、stack等。
在实例化过程中,需要声明一个类型为模板类的对象,即使用所需的具体类型替换通用类型名。例如:
list<int> mylist;
stack<int> mystack;
提示: 类模板实例化,说白了就是怎样使用类模板生成类,这样才能使用生成的类定义对象。本节没有大篇幅地讲述类模板的抽象知识,而是通过讲道理的形式,对类模板的功能等加以阐述。之后直接给出实例形式,很好地避免了读者开始学习就掉入抽象的模板理论中。
下面的例子说明了类模板的用法:
#include
#include
#include
using namespace std;
void mysleep(int second) //自己编写的延时函数
{
clock_t st;
st = clock() ;
while (clock() -st<second*CLOCKS_ PER SEC);
}
void main ()
{
int count=5;
float number=0.0;
list<int> mylist; //对list模板类进行实例化,list
cout<<"请任意输入5个数字:"<<endl;
while (count--)
{
cin>>number;
mylist.push back (number); //将输入数据压入列表list
}
list<int>::iterator iter;
for(iter=mylist.begin();iter!=mylist.end();iter++) //输出列表 list的元素
cout<<*iter<<" ,";
cout<<endl ;
return;
}
类模板的成员函数可以被类模板实例化产生的类所拥有。每个类模板都拥有自己相应的成员函数,这些函数可以被模板的实例调用。
类模板中成员函数也是用模板实现的,当使用时必须将其实例化。具体形式如下:
- 必须以关键字template 开头;
- 必须指出是哪个类的成员;
- 类名必须包含模板形参。
例如:
template <class T> ret-type Queue::<T>::member-name
对于Queue类的destroy()函数,其定义源代码为(摘自《C++Primer中文版》第4版814页):
template <class Type> void Queue<Type>::destroy ()
{
while (!empty())
pop();
}
对于vector的insert()函数,其定义源代码为(摘自《STL 源码剖析》第124页):
template <class T, class Alloc>
void vector<T,Alloc>::insert(iterator position,size_type n, const T&x)
{
.......
}
在C++中,类的成员变量被声明为static型,意味着它为该类的所有实例所共享,即当某个类的实例修改了该静态成员变量,其修改值为该类的其他所有实例所见。下面用例子详细说明静态成员的使用方法。
如果类模板中有成员被声明为static型,例如:
template <class T> //声明下面是一个类模板
class BClass
{
public:
static int count; //静态成员变量
static long size; //静态成员变量
public:
static long GetSize() { //静态成员函数
return size;
}
static int GetCount() { //静态成员函数
return count;
}
};
在上述代码中,BClass 作为类模板的名称,count 和size 是类模板的成员变量,GetSize()和GetCount()是类模板的成员函数。
如果在程序中需要使用类模板的成员变量,必须在程序中类外部对该static静态成员进行定义。例如:
template <class T> int BClass<T>::count=0;
template <class T> long BClass<T>::size=2;
如果在程序中需要使用类模板的成员函数,必须在程序中使用类模板创建对象,进而使用对象访问该成员函数;或者使用类模板的作用域操作符直接访问成员函数。例如:
BClass<int> myO;
cnt = my0.GetCount();
nsize = myO.GetSize();
完整的使用静态成员的示例如下:
#include
using namespace std;
template <class T>
class BClass
{
public:
static int count;
static long size;
public:
static long GetSize(){
return size;
}
static int GetCount(){
return count;
}
}
template <class T> int BClass<T>::count=0; //在类模板外部定义类模板的静态成员变量count
template <class T> long BClass<T>::size=2; //在类模板外部定义类模板的静态成员变量size
void main()
{
int cnt;
long nsize;
BClass<int> myO;
myO.count = 2;
myO.size = 3;
cnt = myO.GetCount();
nsize = myO.GetSize();
cout<<cnt<<","<<nsize<<endl;
}
输出结果:2,3
类模板的静态成员函数可以通过类模板定义对象或作用域操作符的形式调用;而类模板的静态成员变量必须在程序中(类外部)声明。