一、类模板

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

(一)、类模板的定义

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

类模板、Stack的类模板实现(自定义链栈方式,自定义数组方式)的更多相关文章

  1. iptables详解(10):iptables自定义链

    前文中,我们一直在定义规则,准确的说,我们一直在iptables的默认链中定义规则,那么此处,我们就来了解一下自定义链. 你可能会问,iptables的默认链就已经能够满足我们了,为什么还需要自定义链 ...

  2. iptables 自定义链

    当默认链中的规则非常多时,不方便我们管理. 想象一下,如果INPUT链中存放了200条规则,这200条规则有针对httpd服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,假如,我们突 ...

  3. iptables详解(8)iptables自定义链

    自定义链存在的意义:对链进行分类 target可能是一个“动作“也可能是一个”自定义链” 1.新增自定义链. root@ubuntu:~# iptables -t filter -N IN_WEB#结 ...

  4. ZT 类模板Stack的实现 by vector

    *//*第3章 类模板 与函数相似,类也可以被一种或多种类型参数化.容器类就是一个具有这种特性的典型例子,它通常被用于管理某种特定类型的元素.只要使用类模板,你就可以实现容器类,而不需要确定容器中元素 ...

  5. C++标准库类模板(stack)和 队列(queue)

    在C++标准库(STL)中有栈和队列的类模板,因此可以直接使用 1.栈(stack):使用栈之前,要先包含头文件 : #include<stack> stack.push(elem); / ...

  6. C++ Templates (2.1 类模板Stack的实现 Implementation of Class Template Stack)

    返回完整目录 目录 2.1 类模板Stack的实现 Implementation of Class Template Stack 2.1.1 声明类模板 Declaration of Class Te ...

  7. 如何导出标准模板库(STL)类的实例化和包含STL类对象数据成员的类

    本文翻译自 https://support.microsoft.com/zh-cn/help/168958/how-to-export-an-instantiation-of-a-standard-t ...

  8. C++模板学习:函数模板、结构体模板、类模板

    C++模板:函数.结构体.类 模板实现 1.前言:(知道有模板这回事的童鞋请忽视) 普通函数.函数重载.模板函数 认识. //学过c的童鞋们一定都写过函数sum吧,当时是这样写的: int sum(i ...

  9. JAVASE(十一) 高级类特性: abstract 、模板模式、interface、内部类、枚举、注解

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1.关键字 abstract 1.1.abstract可以修饰:类,方法 1.2.abstract修饰方 ...

随机推荐

  1. 【张宴】PHP在金山游戏运营中的应用

    PPT下载地址1(国外服务器):http://blog.s135.com/attachment/201105/2011phptc_zy.zip PPT下载地址2(国内服务器):http://ishar ...

  2. 怎样教你牢记17个的Win7快捷键!

    常规快捷键在开始使用Win7中神奇的快捷键加速我们的电脑操作之前,先给大家介绍几个从Win2000到现在一直通用的“资源管理器”快捷键,权当作热身吧!Win+E: 打开“资源管理器”.Win+R: 打 ...

  3. Linux环境redis集群搭建

    集群后tomcat context.xml的配置 <!-- 集群配置--> <Valve className="com.radiadesign.catalina.sessi ...

  4. React的第一个例子

    准备: 官网:https://facebook.github.io/react/downloads.html Github地址:https://github.com/facebook/react 首先 ...

  5. Unity3D如何减少安装包大小

    译官方文档:http://docs.unity3d.com/Manual/ReducingFilesize.html PDF文档:http://www.rukawa.cn/Uploads/Attach ...

  6. thymleaf th:if标签

    1.概念 <table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOC ...

  7. Apache Mahout 简介 通过可伸缩、商业友好的机器学习来构建智能应用程序

    在信息时代,公司和个人的成功越来越依赖于迅速有效地将大量数据转化为可操作的信息.无论是每天处理数以千计的个人电子邮件消息,还是从海量博客文章中推测用户的意图,都需要使用一些工具来组织和增强数据. 这其 ...

  8. 类的const和非const成员函数的重载

    我们从一个例子说起,来看上一篇文章中的String类, 我们为它提供一个下标操作符([ ])以读写指定位置的字符(char). 只要了解过C++的操作符重载的语法,很快就可以写出下面这个[]操作符重载 ...

  9. C# 16位GUID

    摘自: http://www.cnblogs.com/lcwzj/archive/2009/04/16/1436992.html 当我们想要获得一个唯一的key的时候,通常会想到GUID.这个key非 ...

  10. [HNOI2002]营业额统计 Splay tree入门题

    题目连接:http://www.lydsy.com/JudgeOnline/problem.php?id=1588 1588: [HNOI2002]营业额统计 Time Limit: 5 Sec   ...