一、类模板

类模板:将类定义中的数据类型参数化
类模板实际上是函数模板的推广,可以用相同的类模板来组建任意类型的对象集合

(一)、类模板的定义

template  <类型形参表>
class  <类名>
{     //类说明体  };
template  <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数1>(形参表)
{     //成员函数定义体  }
template  <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数2>(形参表)
{     //成员函数定义体  }

template  <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数n>(形参表)
{     //成员函数定义体  }

(二)、使用类模板

类模板的实例化:用具体的数据类型替换模板的参数以得到具体的类(模板类)
模板类也可以实例化为对象
用下列方式创建类模板的实例:

类名 <类型实参表>  对象名称;

对于函数模板与类模板,模板参数并不局限于类型(类类型,基本类型,模板类实例),普通值也可以作为模板参数

二、Stack类的模板实现

前面曾经分别使用C/C++实现了一个链栈,栈中只能放进int类型数据,现在使用模板来重新实现Stack,可以存放多种数据类型,分别使用自定义链栈方式以及自定义数组实现。

(一)、自定义链栈方式:

stack.h:

 C++ Code 
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:

 C++ Code 
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:

 C++ Code 
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:

 C++ Code 
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++编程规范

最新文章

  1. UVA 10474
  2. Python-3 语法
  3. 将java类的泛型集合转换成json对象
  4. Scanner 与 Readable 的read()方法
  5. [VC6 console]调用API获取手机归属地
  6. 框架学习之道:PE框架简介
  7. [Usaco2008 Nov]Guarding the Farm 保卫牧场[DFS]
  8. 用websocket实现后台推送消息
  9. 2017PHP程序员的进阶之路
  10. Android版本分布数据源
  11. SpringJUnit4ClassRunner (单元测试)
  12. java:构造方法:无参构造/有参构造 this static关键字 静态变量 静态方法 代码块 封装 静态常量。
  13. [Swift]LeetCode911. 在线选举 | Online Election
  14. jQuery-使用hover(fn,fn)函数监听mouseover和mouseout两个事件
  15. Ubuntu java install &amp; config
  16. Spark学习笔记5:Spark集群架构
  17. Fn键
  18. jsp有哪些内置对象作用分别是什么 分别有什么方法?
  19. CMSIS-SVD Example (Schema Version 1.1)
  20. 从0开始 图论学习 邻接表 STL vector

热门文章

  1. UIColor和 同 CIColor 与 CGColor 之间的联系、转换
  2. JavaFX学习之Web
  3. eclipse.ini 文件使用说明
  4. Python中用MacFSEvents模块监视MacOS文件系统改变一例
  5. 【java】【mysql】存储微信表情emoji表情
  6. pm2-web
  7. System.Threading.Tasks并发和异步代码使用
  8. Navicat工具里的empty table和truncate table的区别
  9. XML 简单介绍
  10. linux shell的执行方式