STL(Standard Template Library,标准模板库)是C++对泛型编程思想的实现,最早是惠普实验室开发的。在C/C++学习笔记(十)中已经初步有所介绍。STL是一种高效、泛型、可交互操作的软件组件。STL以迭代器(Iterators)和容器(Containers)为基础,是一种泛型算法(GenericAlgorithms)库,容器的存在使这些算法有东西可以操作。STL包含各种泛型算法(algorithms)、泛型指针(iterators)、泛型容器(containers)以及函数对象(function objects)。STL并非只是一些有用组件的集合,它是描述软件组件抽象需求条件的一个正规而有条理的架构。
STL广义上分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,在C++中实现模板函数和模板类首先用到的是泛型。这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。基于此,在学习stl之前有必要好好了解一下泛型。
泛型编程
泛型编程最初诞生于C++中,目的是为了实现C++的STL(标准模板库)。其语言支持机制就是模板(Templates)。模板的精神其实很简单:参数化类型。换句话说,把一个原本特定于某个类型的算法或类当中的类型信息抽掉,抽出来做成模板参数T,即以类型信息作为参数。
在大学的时候我们学习数学和一些算法的时候经常遇到很多公式之类的东西,例如f(n)=n*2,其实f(n)是一个与类型无关的算法,然而在用代码实现的时候却要经常来定义变量n的数据类型,虽然在c++中可以用重载来实现一个与数据类型有关的算法,但是那不可否认是一个非常繁琐的事情。更重要的是函数重载是静态编译,运行时占用过多内存。在此我们可以用C++的模板函数来表达通用型的函数,于是泛型就横空出世了。
C++模版函数
语法格式:
template <typename 模版参数列表…>
函数返回类型 函数名(形参列表…)
先看一个实例:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T add(T a,T b) //注意形参和返回类型
{
return a+b;
}
int _tmain(int argc, _TCHAR* argv[])
{
int num1=1, num2=2, sum=0;
sum=add(num1,num2); //用int匹配模版参数T,若sum,num1,num2类型不一致则无法匹配。
cout<<"sum="<<sum<<endl;
string str1="str1",str2="str12",str="";
str=add(str1,str2);
cout<<"str="<<str<<endl;
getchar();
return 0;
}
运行结果:
函数模板的特点:
1) 函数模板并不是真正的函数,它只是C++编译生成具体函数的一个模子。
2) 函数模板本身并不生成函数,实际生成的函数是替换函数模板的那个函数,比如上例中的add(sum1,sum2),这种替换是编译期就绑定的。
3) 函数模板不是只编译一份满足多重需要,而是为每一种替换它的函数编译一份。
4) 函数模板不允许自动类型转换。
5) 函数模板不可以设置默认模板实参。比如template <typename T=0>不可以。
C++模板类
语法格式:
template <class 模版参数列表…>
class 类名
{ //类体}
成员的实现…
看一个实例:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//类声明部分,有两个模板参数T1,T2
template <class T1, class T2 >
class A {
private:
int a;
T1 b; //成员变量也可以用模板参数
public:
int fun1(T1 x, int y );
T2 fun2(T1 x, T2 y);
};
//类实现部分
template <class T1, class T2 >
int A<T1,T2>:: fun1(T1 x, int y ){
//实现……
cout<<"fun1 T1="<<x<<endl;
cout<<"fun1 int="<<y<<endl;
return y*2;
}
template <class T1, class T2 >
T2 A<T1,T2>:: fun2(T1 x, T2 y) {
//实现……
cout<<"fun2 T1="<<x<<endl;
cout<<"fun2 T2="<<y<<endl;
return x+y;
}
int _tmain(int argc, _TCHAR* argv[])
{
int num1=1, num=0;
string str1="str1",str2="str12",str="";
A<string, string> a;
num=a.fun1(str1,num1);
str=a.fun2(str1,str2);
cout<<"num="<<num<<endl;
cout<<"str="<<str<<endl;
getchar();
return 0;
}
运行结果:
由上例可以看出, 类模板参数T1,T2对类的成员变量和成员函数均有效。在C++编程中,当你要实现的一个类的某些成员函数和成员变量的算法数据类型有关,可以考虑用类模板。C++版的数据结构算法大都用类模板实现。
模板类的特点:
1) 类模板不是真正的类,它只是C++编译器生成具体类的一个模子。
2) 类模板可以设置默认模板实参。