一、类模板
类模板:将类定义中的数据类型参数化
类模板实际上是函数模板的推广,可以用相同的类模板来组建任意类型的对象集合
(一)、类模板的定义
template <类型形参表>
class <类名>
{ //类说明体 };
template <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数1>(形参表)
{ //成员函数定义体 }
template <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数2>(形参表)
{ //成员函数定义体 }
…
template <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数n>(形参表)
{ //成员函数定义体 }
(二)、使用类模板
类模板的实例化:用具体的数据类型替换模板的参数以得到具体的类(模板类)
模板类也可以实例化为对象
用下列方式创建类模板的实例:
类名 <类型实参表> 对象名称;
对于函数模板与类模板,模板参数并不局限于类型(类类型,基本类型,模板类实例),普通值也可以作为模板参数
二、Stack类的模板实现
在前面曾经分别使用C/C++实现了一个链栈,栈中只能放进int类型数据,现在使用模板来重新实现Stack,可以存放多种数据类型,分别使用自定义链栈方式以及自定义数组实现。
(一)、自定义链栈方式:
stack.h:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
/*************************************************************************
> File Name: stack.h > Author: Simba > Mail: dameng34@163.com > Created Time: 2012年11月03日 星期六 19时28分25秒 ************************************************************************/ #include<iostream> using namespace std; template < class T > class Node { //< >里面是模板参数,可以有多个,虽然T用class 声明,但可以是内建类型也可以是class类型 //模板的定义一般写在头文件里 public: Node(T invalue): m_Value(invalue), m_Next(NULL) {} ~Node(); T getValue() const { return m_Value; } void setValue(T value) { m_Value = value; } Node < T > *getNext() const { return m_Next; } void setNext(Node < T > *next) { m_Next = next; } private: T m_Value; Node < T > *m_Next; }; template < class T > Node < T >::~Node() { if (m_Next) { delete m_Next; //自动内存管理,接着找到m_Next指向的下一个结点,一直找到最后的一个结点 //故先释放最后一个结点(当然是最先压栈的结点),然后依次返回释放每一个途中的结点 } " deleted " << endl;
} template < class T > class Stack { public: Stack(): m_Head(NULL), m_Count(0) {} ~Stack() { delete m_Head; //自动内存管理 } void push(const T &t); T pop(); T top() const; int count() const; private: Node < T > *m_Head; int m_Count; }; template < class T > void Stack < T >::push(const T &value) { Node < T > *newNode = new Node < T > (value); newNode->setNext(m_Head); m_Head = newNode; ++m_Count; } template < class T > T Stack < T >::pop() { Node < T > *popped = m_Head; if (m_Head != NULL) { m_Head = m_Head->getNext(); T retval = popped->getValue(); popped->setNext(NULL); delete popped; --m_Count; return retval; } return 0; } template < class T > inline T Stack < T >::top() const //模板前缀template < class T > || 函数限定符inline 函数返回值T || //命名空间前缀 Stack < T > //一个类型 || 函数名(函数参数)const 限定符 { return m_Head->getValue(); } template < class T > inline int Stack < T >::count() const { return m_Count; } |
main.cpp:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include "stack.h"
int main(void) { Stack < int >intstack1, intstack2; int val; for (val = 0; val < 4; ++val) { intstack1.push(val); intstack2.push(2 * val); } while (intstack1.count()) { val = intstack1.pop(); cout << val << endl; } Stack < char >stringstack; stringstack.push('A'); stringstack.push('B'); stringstack.push('C'); char val2; while (stringstack.count()) { val2 = stringstack.pop(); cout << val2 << endl; } cout << "Now intstack2 will be destructed." << endl; return 0; } |
可以看到虽然intstack2 没有pop 出元素,但程序结束时,局部对象会被析构,调用析构函数,在析构函数内delete 头指针,顺藤摸瓜一直找到最后一个节点,即首先压栈的节点,依次返回释放掉。
(二)、自定义数组方式
Stack2.h:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
#ifndef _STACK2_H_
#define _STACK2_H_ #include <exception> template <typename T, int MAX_SIZE> class Stack2 { public: Stack2(); ~Stack2(); void Push(const T &elem); void Pop(); T &Top(); const T &Top() const; bool Empty() const; private: T *elems_; int top_; }; template <typename T, int MAX_SIZE> Stack2<T, MAX_SIZE>::Stack2() : top_(-1) { elems_ = new T[MAX_SIZE]; } template <typename T, int MAX_SIZE> Stack2<T, MAX_SIZE>::~Stack2() { delete[] elems_; } template <typename T, int MAX_SIZE> void Stack2<T, MAX_SIZE>::Push(const T &elem) { if (top_ + 1 >= MAX_SIZE) throw out_of_range("Stack2<>::Push() Stack2 full"); elems_[++top_] = elem; } template <typename T, int MAX_SIZE> void Stack2<T, MAX_SIZE>::Pop() { if (top_ + 1 == 0) throw out_of_range("Stack2<>::Push() Stack2 empty"); --top_; } template <typename T, int MAX_SIZE> T &Stack2<T, MAX_SIZE>::Top() { if (top_ + 1 == 0) throw out_of_range("Stack2<>::Push() Stack2 empty"); return elems_[top_]; } template <typename T, int MAX_SIZE> const T &Stack2<T, MAX_SIZE>::Top() const { if (top_ + 1 == 0) throw out_of_range("Stack2<>::Push() Stack2 empty"); return elems_[top_]; } template <typename T, int MAX_SIZE> bool Stack2<T, MAX_SIZE>::Empty() const { return top_ + 1 == 0; } #endif // _STACK2_H_ |
main.cpp:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include "Stack2.h"
#include <iostream> #include<string> using namespace std; int main(void) { Stack2<int, 5> s; s.Push(1); s.Push(2); s.Push(3); while (!s.Empty()) { cout << s.Top() << endl; s.Pop(); } return 0; } |
输出为 3 2 1
注意,用数组实现时pop 操作并没有删除元素的操作,只是移动了top 指针,下次push 的时候直接覆盖即可。再者因为实现了Top 返回栈顶元素,故pop 没有返回值。
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范