您的位置:首页 > 编程语言 > C语言/C++

c++面向对象编程(四)--模板

2016-07-06 15:41 375 查看
一、函数模板( Function templates)

1、

模板(Templates)使得我们可以生成通用的函数,这些函数能够接受任意数据类型的参

数,可返回任意类型的值,而不需要对所有可能的数据类型进行函数重载。这在一定

程度上实现了宏(macro)的作用。它们的原型定义可以是下面两种中的任何一个:
template <class identifier> function_declaration;

template <typename identifier> function_declaration

其实是一样的

生成一个模板,返回两个对象中较大的一个,我们可以这样写:
template <class GenericType>
GenericType GetMax (GenericType a, GenericType b) { return (a>b?a:b); }

调用模板

function <type> (parameters);

int x,y;
GetMax <int> (x,y);

通用数据类型的模板,叫做 GenericType。因此在其后面的函数中,GenericType 成为一个有效的数据类型,它被用来定义了两个参数 a和 b ,并被用作了函数 GetMax的返回值类型。

GenericType 仍没有代表任何具体的数据类型;当函数 GetMax 被调用的时候,我们可

以使用任何有效的数据类型来调用它。这个数据类型将被作为 pattern来代替函数中

GenericType 出现的地方。用一个类型 pattern来调用一个模板的方法如下:
on <type> (parameters);

这里是一个例子:

//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 被用作函数 GetMax 的参数,不需要说明<int>或

<long>,编译器也可以自动检测到传入的数据类型,因此,我们也可以这样写这个例子:

int i,j;
GetMax (i,j);

因为 i 和 j 都是 int 类型,编译器会自动假设我们想要函数按照 int进行调用。这种暗

示的方法更为有用,并产生同样的结果:

2、

我们也可以使得模板函数接受两种或两种以上类型的数据,例如

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);

如果我们要在类之外定义它的一个成员函数,我们必须在每一函数前面加 

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;

}

三、模板特殊化(Template specialization)
模板的特殊化是当模板中的 pattern有确定的类型时,模板有一个具体的实现。

例如假设我们的类模板 pair 包含一个取模计算(module operation)的函数,而我们希望这个函数只有当对象中存储的数据为整型(int)的时候才能工作,其他时候,我们需要这个函数总是返回 0。这可以通过下面的代码来实现:

//Template specialization

#include <iostream.h>

template <class T> 

class pair {
T value1, value2;

public:
pair (T first, T second){
value1=first;
value2=second;


T module () {return 0;}

};

template <>

class pair <int> {

int value1, value2;

public:
pair (int first, int second){
value1=first;
value2=second;
}
int module ();

};

template <>

int pair<int>::module() {
return value1%value2;

}

int main () {
pair <int> myints (100,75);
pair <float> myfloats (100.0,75.0);
cout << myints.module() << '\n';
cout << myfloats.module() << '\n';
return 0;

}

结果:

25
0

由上面的代码可以看到,模板特殊化由以下格式定义:
template <> class class_name <type>

这个特殊化本身也是模板定义的一部分,因此,我们必须在该定义开头写 template

<>。而且因为它确实为一个具体类型的特殊定义,通用数据类型在这里不能够使用,

所以第一对尖括号<> 内必须为空。在类名称后面,我们必须将这个特殊化中使用的

具体数据类型写在尖括号<>中。

当我们特殊化模板的一个数据类型的时候,同时还必须重新定义类的所有成员的特殊

化实现(如果你仔细看上面的例子,会发现我们不得不在特殊化的定义中包含它自己

的构造函数 constructor,虽然它与通用模板中的构造函数是一样的)。这样做的原因

就是特殊化不会继承通用模板的任何一个成员。

四、模板的参数值(Parameter values for templates)

除了模板参数前面跟关键字 class 或 typename 表示一个通用类型外,函数模板和类模

板还可以包含其它不是代表一个类型的参数,例如代表一个常数,这些通常是基本数

据类型的。例如,下面的例子定义了一个用来存储数组的类模板:

//array template

#include <iostream.h>

template <class T, int N>

class array {
T memblock
;

public:
void setmember (int x, T value);
T getmember (int x);

};

template <class T, int N>

void array<T,N>::setmember (int x, T value) {
memblock[x]=value;

}

template <class T, int N>

T array<T,N>::getmember (int x) {
return memblock[x];

}

int main () {
array <int,5> myints;
array <float,5> myfloats;
myints.setmember (0,100);
myfloats.setmember (3,3.1416);
cout << myints.getmember(0) << '\n';
cout << myfloats.getmember(3) << '\n';
return 0;



结果:

100
3.1416

我们也可以为模板参数设置默认值,就像为函数参数设置默认值一样。

下面是一些模板定义的例子:
template <class T> //最常用的:一个 class 参数。
template <class T, class U> //两个 class 参数


template <class T, int N> //一个 class 和一个整数。
template <class T = char> //有一个默认值。
template <int Tfunc (int)> //参数为一个函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: