提前说明一下:
写类模版时把 <类型参数 >与 类名 看成一个整体 , 比较好理解;
比如 stack<int> 是一个类, stack<double> 是另一个类.
那么stack 呢?? 是一个用于生成类的模版,
即类模版是一个类的蓝图, 涉及到具体的类(stack<int>)则由编译器给我们生成;
如果看这些东西比较吃力, 建议先使用一下标准库的:vector, queue,stack 再学习模版
<这句话可以在看完模版后再回过头来看看>:
提前先说一下,全特化本质上就是一个实例,而部分特化还是一个模版;
每个类模版实例化的类都是一个独立的类:意思是可以随意添加任意成员变量与函数
首先1个常规的通用模版类:(具体化或特化 在下面介绍)
Stack.h
/*
Stack.h
类模版基本概念:
如果把类看成对象的蓝图 , 则类模版可看作类的蓝图;
template <typename T> 告诉编译器,你就按这个方式来生成这个类;
到时如果有Stack<int> si; 编译器就会给生成 Stack<int> 这个类 (类模版在使用时才会生成代码,所以常常把模版的声明与定义放在一起)
*把Stack<int> 看成一个整体,即Stack<int>是1个类, Stack是Stack<int>的模版;
如有Stack<double> 又会生成1个类,这些代码生成工作是编译器给咱作的.
下面的例子中,把成员函数都放到类外定义了, 如在类内定义则不需要加Stack::<T>, 直接使用Stack,就像常规类定义;
编写下面代码时,新手需时时注意一点,模版不是类,模版的目的是让编译器生成类. 所以
下面代码把 Stack<T> 看成是一个类,而不是Stack . 如果看T比较麻烦,可以想像Stack<int> ;
*/
/*
这是一个正常的类:
class Stack{};
模版类需要加一个模版头去声明一下: template <typename T>
(typename 表示类型名称是 T,T 表示一个类型,你就当成一个占位符就行了,那么 T 到底是什么类型呢? 由外部传入)
*/
//模版头,意思是下面这个类是一个模版.到时编译器将生成一个 Stack<XX> 类,例如Stack<int>;
template <typename T>
class Stack
{
private:
enum {MAX=10};
T * items;
int stackSize;
int top;
public:
//先介绍所有的成员函数在类外部定义的方式,类内定义与正常的类相同
explicit Stack(int ss = MAX);
Stack(const Stack &s);
~Stack();
Stack& operator= (const Stack &s);
bool isEmpty();
bool isFull();
bool push(const T& t);
bool pop(T& t);
void show() const;
};
template <typename T> //这里也必须写,暗示这是一个模版,不是一个类.除非定义在类内部.
Stack<T>::Stack(int ss) : top(0),stackSize(ss),items(0) //注意:Stack<T>:: 而不是Stack
{
items = new T[stackSize];
}
template <typename T> //注意所有的成员函数在类外部定义的时候都要额外添加模版头
Stack<T>::Stack(const Stack &s)
{
stackSize = s.stackSize;
top = s.top;
items = new T[stackSize];
for(int i = 0; i < top ; ++i)
items[i] = s.items[i];
}
template <typename T>
Stack<T>::~Stack()
{
if(items)
delete[] items;
}
template <typename T>
Stack<T>& Stack<T>::operator=(const Stack<T> & s) //函数参数Stack<T>& ,而不是Stack&.因为Stack是一个模版
{
if(this == &s)
return *this;
if(items)
delete[] items;
stackSize = s.stackSize;
top = s.top;
items = new T[stackSize];
for(int i =0 ; i < top ; ++i)
items[i] = s.items[i];
return *this;
}
template <typename T>
bool Stack<T>::isEmpty()
{
return top == 0;
}
template <typename T>
bool Stack<T>::isFull()
{
return top == MAX;
}
template <typename T>
bool Stack<T>::push(const T &t)
{
if(top < MAX)
{
items[top++] = t;
return true;
}
return false;
}
template <typename T>
bool Stack<T>::pop(T &t)
{
if(top > 0){
t = items[--top];
return true;
}
return false;
}
template <typename T>
void Stack<T>::show() const
{
for(int i = 0; i < top ; ++i)
std::cout << items[i] << std::endl;
}
以上需要注意的是:
每个成员函数的定义前都是 Stack<T>:: , 而不是Stack ; 同时每个成员函数上方都加了模版头 template<typename T>; (把template <typename T> 当成是1个参数列表)
原因是当加上了模版头template<typename T> 后, Stack已经是1个模版而不是类.
真正的类是编译给我们生成的, 何时生成呢?
比如 当使用了 Stack<string> 时 , 即生成了1个 Stack<string> 类;
如果函数在类内定义就简单很多了, 不需要再加Stack<T>:: 前缀, 也不需要在每个函数上放添加template <typename T>
此时:
Stack<int> si; 将生成一个类 class Stack<int>;
Stack<double> sd; 又生成一个类 class Stack<double>;
总之把<>内的类型参数列表与模版名Stack 看成一个整体会比较好理解模版生成的类;
再次强调 Stack 不是类,而是模版;
//main.cpp
//其他的方法就不测了.主要说明类模版
/*
编译器将实例化一个类;
注意Stack<int> 这种方式