类属机制
在程序设计语言中,参与运算的所有对象的类型在编译时就可以确定,编译程序对类型进行严格的检查,于是可以在程序运行前就可以查出错误,提高了程序的可靠性。但是这样做同时有带来副作用。链表,堆栈,集合等常用数据结构在各种软件中都会用到,它们有可能存放各种类型的数据。
由于这类数据结构存放的元素类型不同,程序员不得不为每一种数据类型编写相似的程序代码。这样就增加了程序代码。如何解决这种类型的严格与灵活的问题,不同的语言采用了不同的方法。理想的方法是将数据类型作为类的参数,这种机制称为类属。
高版本的C++语言中均加入了类属机制。在C++中,类属被称为模板,模板按照其用途可分为函数模板和类模板两种类型。模板中的参数类型没有确定,只有经过实例化,变为一般的函数(C++称其为模板函数)或一般的类(C++称其为模板类),模板才有意义。
函数模板
函数模板是一种很有用的语言设施,它提供了描述通用操作的高级手段,这种机制可用一种抽象数据类型来设计一个通用的算法。
函数模板的一般性语法为:
template <class模板形参表>
返回值类型 函数名(模板函数形参表)
{
//函数体;
}
其中,模板形参表表示被替换的模板参数,各模板参数之间用“,”号分开。模板函数形参表表示函数所具有的参数,它不仅包含模板形参表的内容,而且还可具有一般的类型参数。
下面设计一个将任何类型的两个数值进行交换的函数Swap(x,y)。
C++属于强类型语言,它要求参数的类型在编译时必须确定。为了完成上面的要求,可以通过重载设计出Swap(x,y)

void Swap (int &.x,int &.y)
{
int t;
t=x;
x=y;
y=t;
}
void Swap (long &.x,long &.y)
{
long t;
t=x;
x=y;
y=t;
}
C++提供了另一种更高级的机制,即用函数模爆来解决这一问题。在函数模板中,类型本身可以作为一个参数。Swap(x,y)函数用函数模板可定义如下:
Swap.hpp
Template <class T>
Void swap (T &.x,T &.y)
{
T t;
T=x;
x=y;
y=t;
}
该定义说明,无论参数T是什么类型,函数Swap(x,y)都表示将T的两个变量(或对象)的值进行交换。函数Swap(T &.x,T &.y)是一个抽象的函数,在进行具体的数据交换之前必须将其参数T实例化为某个具体的类型,如或用户自定义的类等类型后,该函数才有意义。C++称其为函数模板,它代表了一类函数的家族。当用某个具体的类型将模板参数实例化后,该函数就变成了一个具体的函数。将T实例化的类型称为模板实参,用模板实参实例化函数模板得到的函数称为模板函数。
按函数模板的使用形式可将其分为两种方式。
一种为显式方式:
Swap( int&,int&);
Swap(long&,long&)
另一种为隐式方式:
int I=10,j=20;
Swap(I,j);
重载函数模板
同一般的函数一样,函数模板也可以重载。 例
//max.hpp
template <class TYPE>
TYPE max (TYPE a,TYPE b)
{
return ( a>b)? A,b;
}
template <class TYPE>
TYPE max (TYPE a,TYPE b,TYPE c)
}
TYPE t;
t= (a > b)? a,b;
return (t > c)? t,c;
}
一般地,这种重载是指参数的个数不同,而不是参数的类型不同。
C++中重载函数的调用次序为:
寻找一个参数完全匹配的函数,若找到,就调用之。
否则寻找一个函数模板,将其实例化产生一个匹配的模板函数,若找到,就调用之。
否则寻找重载函数中有无通过类型转换后产生参数匹配的函数,若有,则调用之。
类模板
与函数模板一样,在设计类时,也往往遇到仅由于类型不一样而不得不重复地设计出很多形式相象的类。基于同样的原因,C++引入了类模板机制。
类模板的一般性语法为:
template <class 模板形参表>
class 类模板名 {
// 类体;
};
其中,模板形参表同函数模板中的说明,类体中要用到这些模板参数。
类模板的成员函数的体外定义,每个前面都必须用与声明该类模板一样的
template <class 模板形参表> 加以声明。
类模板必须用类型参数将其实例化为具体的模板类后,才能用来生成对象。一般地,其形式可表示为:
类模板名 <类型实参表> 对象名 (值实参表);
其中,类型实参表表示将类模板实例化为一般的类时所用到的类型(包括系统固有的类型和用户自定义的类型),值实数表表示将该模板类实例化为对象时其构造函数所用到的变量。一个模板类可用来实例化多个模板类。
例] 栈类模板
//stack.hpp
template <class T>
class Stack{
private:
T*date;
Int top;
Int size;
int isEmpty ( ) {return (top < 0)? 1:0;}
Int isfull ( ) {return top==size}?1,0;}
Public:
Stack (int n) {date=new T[n]; size=n; top=0;}
~Stack ( ){delete []date;}
void pop(T n);
T push( );
};
Stack<T>中的push和pop成员函数的体外定义
//stack.cpp
//include <iostream.h>
//,stack.hpp”
template <class T>
void Stack<T>:,pop(T a)
{
if (isfull ( ) )
{
cout<<”stack overflow\n”;
return;
}
* (date+top++)=a;
return;
}
template <class T>
inline T Stack<T>:,push( )
{
if (isempty( ))
{
cout<<”stack underflow\n”;
}
return (* (date+top));
}
与函数模板不同,类模板必须进行显式的实例化声明。
综上所述,类模板机制允许用户定义一种具有相似行为的类的模式,它要求这些类具有相通的操作(包括内部操作和外部操作),并且要求这些操作的算法也是相同的。
类模板的友元
类模板的友元函数大致可分为三种情况一般的类模板友元函数:这种友元函数不包含任何类型的模板参数,定义和作用与一般类的情况一样。
封闭型的类模板友元函数:同模板类中的其他成员函数一样,该类的友元函数也包含模板参数。当用类型参数将类模板实例化为某个具体的模板类时,该类模板所包含的友元函数也将随之实例化,就如同一般的成员函数一样。
开放型的类模板友元函数:它的参数中包含了自己定义的函数模板的模板参数,而相关类模板的参数可以出现,也可以不出现。

template <class T1>
class a{
template class<class T2>
friend void foo(T2 vt2);
….
}
在这里,foo( )模板函数的任何一个实例化函数模板均是A<T1>模板类的任何一个类模板的友元;
同时,A<T1>模板类的任何一个类模板均是foo( )模板函数的任何一个函数模板的友元。这样在
A<T1>的类模板与foo( )的函数模板之间形成了一个多对多的对应关系。