从零开始学C++之模板(二):类模板、Stack的类模板实现(自定义链栈方式,自定义数组方式)

转:http://blog.csdn.net/jnu_simba/article/details/9396347

一、类模板

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

(一)、类模板的定义

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指向的下一个结点,一直找到最后的一个结点
         //故先释放最后一个结点(当然是最先压栈的结点),然后依次返回释放每一个途中的结点
    }
    cout << m_Value <<  " 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< int5> 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++编程规范



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值