类模板
1,类模板的定义
类模板是公共逻辑的抽象,通常用来作为容器或者行为的封装。
一般定义格式:
template<typename T1,typename T2,...>
//template是定义模板的关键字,T1,T2类模板的类型参数,一个类模板中可以定义多个类型参数。
//typename表示其后的参数名代表任意类型。类名前的class表明类的声明
class 类名
{
类体
};
例:定义一个堆栈类模板Stack
#include<iostream>
#incldue<ctime>
using namespace std;
template<typename T>
class Stack
{
public:
Stack(int size=5):mTop(0),mSize(size)
{
mpStack=new T[mSize];
}
~Stack()
{
delete[]mStack;
mStack=NULL;
}
Stack(const Stack<T>&src):mTop(src.mTop),mSize(src.mSize)
{
mStack=new T[mSize];
for(int i=0;i<mSize;i++)
{
mStack[i]=src.mStack[i];
}
}
Stack<T>&operator=(const Stack<T>&src)
{
if(this==&src)
{
return*this;
}
delete[]mStack;
mStack=NULL;
mTop=src.mTop;
mSize=src.mSize;
mStack=new T[mSize];
for(int i=0;i<mSize;i++)
{
mStack[i]=src.mStack[i];
}
}
void push(const T&val);
void pop():
T top(){return mStack[mTop-1];}
bool full()const{ return mTop==mSize;}
bool empty()const {return mTop==0;}
private:
T*mpStack;
int mTop;
int mSize;
void reSize()
{
T*temp=new T[mSize*2];
for(int i=0;i<mSize;i++)
{
temp[i]=mStack[i];
}
delete[]mStack;
mStack=temp;
mSize*=2;
}
};
template<typename T>
void Stack<T>::push(const T&val)
{
if(full())
{
reSize();
}
mStack[mTop++]=val;
}
template<typename T>
void Stack<T>::pop()
{
if(empty())
{
returnl
}
mTop--;
}
说明:
(1)类模板中的成员函数即可以在类模板内定义,也可以在类模板外定义。在类模板内部定义成员函数的方法与普通类成员函数的定义方法相同。但是在类模板外定义成员函数时,必须采用以下方法:
template<模板参数列表>
返回值类型 类名<模板参数名表>::成员函数名(参数列表)
{…};
例如上述Stack中的push成员方法的定义:
template
void Stack::push(const T&val)
{…}
(2)类模板的成员函数的定义必须与类模板的定义在同一个文件中。因为类模板的定义不同于类的定义,编译器无法通过一般手段找到类模板成员函数的代码,只有将它与类模板定义放在一起,才能保证类模板的正常运行。一般放入一个 .h 头文件中。
2,类模板的实例化
用模板定义对象形式如下:
类模板名<实际类型名表>对象名;
类模板名<实际类型名表>对象名(构造函数实参表)
例:上述栈对象的实例化:
int main()
{
//类模板的选择性实例化
sTack<int>stack1;
for(int i=0;i<10;i++)
{
stack1.push(i);
}
while(!stack1.empty())
{
int top=stack1.top();
cout<<top<<" ";
stack1.pop();
}
sTack<char>stack2;
char str[]="abcdefg";
for(int i=0;i<strlen(str);i++)
{
stack1.push(str[i]);
}
while(!stack1.empty())
{
char top=stack1.top();
cout<<top<<" ";
stack1.pop();
}
}
3,类模板参数
(1)非类型参数
与函数模板的模板参数一样,类模板的模板参数中也可以出现非类型参数,对于上述的堆栈类模板Stack,也可以不定义一个int型常变量mSize来指定栈的容量大小,而修改为一个非类型参数。
修改后的堆栈类模板Stack定义如下:
#include<iostream>
using namespace std;
template <typename T,int mSize>
class Stack
{
public:
Stack():mTop(0)
{
mpStack=new T[mSize];
}
~Stack()
{
delete[]mStack;
mStack=NULL;
}
Stack(const Stack<T>&src):mTop(src.mTop),mSize(src.mSize)
{
mStack=new T[mSize];
for(int i=0;i<mSize;i++)
{
mStack[i]=src.mStack[i];
}
}
Stack<T>&operator=(const Stack<T>&src)
{
if(this==&src)
{
return*this;
}
delete[]mStack;
mStack=NULL;
mTop=src.mTop;
mSize=src.mSize;
mStack=new T[mSize];
for(int i=0;i<mSize;i++)
{
mStack[i]=src.mStack[i];
}
}
void push(const T&val);
void pop():
T top(){return mStack[mTop-1];}
bool full()const{ return mTop==mSize;}
bool empty()const {return mTop==0;}
private:
T*mpStack;
int mTop;
void reSize()
{
T*temp=new T[mSize*2];
for(int i=0;i<mSize;i++)
{
temp[i]=mStack[i];
}
delete[]mStack;
mStack=temp;
mSize*=2;
}
};
template<typename T>
void Stack<T>::push(const T&val)
{
if(full())
{
reSize();
}
mStack[mTop++]=val;
}
template<typename T>
void Stack<T>::pop()
{
if(empty())
{
returnl
}
mTop--;
}
当需要这个模板的一个实例时,必须为非类型参数mSize限时提供一个编译时常数值:
Stack<int,10>stack1;
(2)默认模板参数
在类模板中,可以为模板参数提供默认值,但是在函数模板中不行
例:
template <typename T,int mSize=10>
class Stack
{
public:
...
private:
T*mpStack;
int mTop;
void reSize()
{...}
};
说明:默认的模板参数,只能被定义一次;
指定默认值的模板参数必须放在模板形参表的右端,负责出错
template<typename T1,typename T2,typename T3=double,int N=100>//正确
template<typename T1,typename T2=double,typename T3,int N=100>//错误
可以为所有的模板参数提供默认值,但在声明一个实例时必须使用一对空的尖括号
template <typename T,int mSize=10>
class Stack
{
public:
...
private:
T*mpStack;
int mTop;
void reSize()
{...}
};
Stack<>stack1; //same as Stack<int ,10>