VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > C/C++语言编程 >
  • C++教程之模板(Templates)

 

模板(Templates)

模板(Templates)是ANSI-C++ 标准中新引入的概念。如果你使用的 C++ 编译器不符合这个标准,则你很可能不能使用模板。
 
 

函数模板( Function templates)

模板(Templates)使得我们可以生成通用的函数,这些函数能够接受任意数据类型的参数,可返回任意类型的值,而不需要对所有可能的数据类型进行函数重载。这在一定程度上实现了宏(macro)的作用。它们的原型定义可以是下面两种中的任何一个:
template <class identifier> function_declaration;
template <typename identifier> function_declaration;
上面两种原型定义的不同之处在关键字class 或 typename的使用。它们实际是完全等价的,因为两种表达的意思和执行都一模一样。
例如,要生成一个模板,返回两个对象中较大的一个,我们可以这样写:
template <class GenericType>
GenericType GetMax (GenericType a, GenericType b) { return (a>b?a:b); }
在第一行声明中,我们已经生成了一个通用数据类型的模板,叫做GenericType。因此在其后面的函数中,GenericType 成为一个有效的数据类型,它被用来定义了两个参数a和 b ,并被用作了函数GetMax的返回值类型。
GenericType 仍没有代表任何具体的数据类型;当函数 GetMax 被调用的时候,我们可以使用任何有效的数据类型来调用它。这个数据类型将被作为pattern来代替函数中GenericType 出现的地方。用一个类型pattern来调用一个模板的方法如下:
function <type> (parameters);
例如,要调用GetMax 来比较两个int类型的整数可以这样写:
int x,y;
GetMax <int> (x,y);
因此,GetMax 的调用就好像所有的GenericType 出现的地方都用int 来代替一样。
这里是一个例子:
// function template
#include <iostream.h>
template <class T> T GetMax (T a, T b) {
    T result;
    result = (a>b)? a : b;
    return (result);
}
int main () {
    int i=5, j=6, k;
    long l=10, m=5, n;
    k=GetMax(i,j);
    n=GetMax(l,m);
    cout << k << endl;
    cout << n << endl;
    return 0;
}
6
10
(在这个例子中,我们将通用数据类型命名为T 而不是 GenericType ,因为T短一些,并且它是模板更为通用的标示之一,虽然使用任何有效的标示符都是可以的。)
在上面的例子中,我们对同样的函数GetMax()使用了两种参数类型:int 和 long,而只写了一种函数的实现,也就是说我们写了一个函数的模板,用了两种不同的pattern来调用它。
如你所见,在我们的模板函数 GetMax() 里,类型 T 可以被用来声明新的对象
T result;
result 是一个T类型的对象, 就像a 和 b一样,也就是说,它们都是同一类型的,这种类型就是当我们调用模板函数时写在尖括号<> 中的类型。
在这个具体的例子中,通用类型 T 被用作函数GetMax 的参数,不需要说明<int>或 <long>,编译器也可以自动检测到传入的数据类型,因此,我们也可以这样写这个例子:
int i,j;
GetMax (i,j);
因为i 和j 都是int 类型,编译器会自动假设我们想要函数按照int进行调用。这种暗示的方法更为有用,并产生同样的结果:
// function template II
#include <iostream.h>
template <class T> T GetMax (T a, T b) {
    return (a>b?a:b);
}
int main () {
    int i=5, j=6, k;
    long l=10, m=5, n;
    k=GetMax(i,j);
    n=GetMax(l,m);
    cout << k << endl;
    cout << n << endl;
    return 0;
}
6
10
注意在这个例子的main() 中我们如何调用模板函数GetMax() 而没有在括号<>中指明具体数据类型的。编译器自动决定每一个调用需要什么数据类型。
因为我们的模板函数只包括一种数据类型 (class T), 而且它的两个参数都是同一种类型,我们不能够用两个不同类型的参数来调用它:
int i;
long l;
k = GetMax (i,l);
上面的调用就是不对的,因为我们的函数等待的是两个同种类型的参数。
我们也可以使得模板函数接受两种或两种以上类型的数据,例如:
template <class T>
T GetMin (T a, U b) { return (a<b?a:b); }
在这个例子中,我们的模板函数 GetMin() 接受两个不同类型的参数,并返回一个与第一个参数同类型的对象。在这种定义下,我们可以这样调用该函数:
int i,j;
long l;
i = GetMin <int, long> (j,l);
或者,简单的用
i = GetMin (j,l);
虽然 j 和 l 是不同的类型。
 

类模板(Class templates)

我们也可以定义类模板(class templates),使得一个类可以有基于通用类型的成员,而不需要在类生成的时候定义具体的数据类型,例如:
template <class T>
class pair {
    T values [2];
public:
    pair (T first, T second) {
        values[0]=first;
        values[1]=second;
    }
};
上面我们定义的类可以用来存储两个任意类型的元素。例如,如果我们想要定义该类的一个对象,用来存储两个整型数据115 和 36 ,我们可以这样写:
pair<int> myobject (115, 36);
我们同时可以用这个类来生成另一个对象用来存储任何其他类型数据,例如:
pair<float> myfloats (3.0, 2.18);
在上面的例子中,类的唯一一个成员函数已经被inline 定义。如果我们要在类之外定义它的一个成员函数,我们必须在每一函数前面加template <... >。
// class templates
#include <iostream.h>
template <class T> class pair {
     T value1, value2;
public:
    pair (T first, T second) {
        value1=first;
        value2=second;
    }
    T getmax ();
};

template <class T>
T pair::getmax (){
    T retval;
    retval = value1>value2? value1 : value2;
    return retval;
}

int main () {
    pair myobject (100, 75);
    cout << myobject.getmax();
    return 0;
}
100
注意成员函数getmax 是怎样开始定义的:
template <class T>
T pair::getmax ()
所有写 T 的地方都是必需的,每次你定义模板类的成员函数的时候都需要遵循类似的格式(这里第二个T表示函数返回值的类型,这个根据需要可能会有变化)。
相关教程