博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
类模板、Stack的类模板实现(自定义链栈方式,自定义数组方式)
阅读量:5961 次
发布时间:2019-06-19

本文共 5276 字,大约阅读时间需要 17 分钟。

一、类模板

类模板:将类定义中的数据类型参数化

类模板实际上是函数模板的推广,可以用相同的类模板来组建任意类型的对象集合

(一)、类模板的定义

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

你可能感兴趣的文章
Centos下基于Hadoop安装Spark(分布式)
查看>>
3D地图的定时高亮和点击事件(基于echarts)
查看>>
mysql开启binlog
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
Mysql 监视工具
查看>>
从前后端分离到GraphQL,携程如何用Node实现?\n
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>
博客搬家了
查看>>
Python中使用ElementTree解析xml
查看>>
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
查看>>
我的友情链接
查看>>
CentOS定时同步系统时间
查看>>
批量删除用户--Shell脚本
查看>>
Eclipse Java @Override 报错
查看>>
知道双字节码, 如何获取汉字 - 回复 "pinezhou" 的问题
查看>>
linux中cacti和nagios整合
查看>>