C++采用模板实现栈的方法
今天又看了遍《effective C++》,手动实现了一下条款42中的栈,贴出来当博客的处女贴。
首先栈的声明如下,采用了模板传入类型,而栈的底层采用是个链表。
// stack.h
// by Chwen 2014-10-27 #include<stdio.h>
#include <stdlib.h>
#include <iostream> using namespace std; // 栈声明 template<typename T>
class Stack
{
public:
Stack();
~Stack(); void push(const T& node);
T Top();
void pop();
int size()const;
bool Empty() const;
void clear(); private:
struct StackNode
{
T data;
StackNode* next;
StackNode(const T& Newdata, StackNode* nextNode)
:data(Newdata),next(nextNode)
{}
};
StackNode * top;
// 防止默认拷贝和默认赋值
Stack(const Stack& rhs);
Stack& operator=(const Stack& rhs);
int mySize;
};
而对应的cpp实现如下:
// stack.cpp #include "stack.h"
using namespace std; // 栈实现 template<typename T>
Stack<T>::Stack()
:top(nullptr),mySize()
{ } template<typename T>
Stack<T>::~Stack()
{
clear();
} template<typename T>
void Stack<T>::push(const T& node)
{
top = new StackNode(node,top);
mySize ++;
} template<typename T>
T Stack<T>::Top()
{
if (Empty())
{
_DEBUG_ERROR("Error, stack is empty!");
}
return top->data;
} template<typename T>
void Stack<T>::pop()
{
if (Empty())
{
_DEBUG_ERROR("Error, stack is empty!");
}
StackNode* topOfStack = top;
top = top->next;
delete topOfStack;
topOfStack = nullptr;
mySize --;
return;
} template<typename T>
bool Stack<T>::Empty() const
{
return top == nullptr;
} template<typename T>
void Stack<T>::clear()
{
while (top)
{
StackNode* topOfStack = top;
top = top->next;
delete topOfStack; }
mySize = ;
}
template<typename T>
int Stack<T>::size()const
{
return mySize;
}
以上即是采用模板实现的栈的所有代码,可以实现栈的push, pop, top, clear 等操作。
以下写了一个简单的测试代码:
void funv()
{ Stack<int> s; for(int i = ; i < ; ++i)
{
s.push(i);
}
for(int j = s.size()- ; j >= ; --j)
{
cout<< "node: " << s.Top() <<endl;
s.pop();
} s.clear(); }
int main ()
{
funv();
getchar();
return 0;
}
之后effective C++指出了另一种更精巧的方式实现,即私有继承。
代码实现如下:
// stack.h
// by Chwen 2014-10-27
#include<stdio.h>
#include <stdlib.h>
#include <iostream> class commonStack
{
protected:
commonStack();
~commonStack(); void push(void* node);
void* Top();
void pop();
int size()const;
bool Empty() const;
void clear(); private:
struct StackNode
{
void* data;
StackNode* next;
StackNode(void* Newdata, StackNode* nextNode)
:data(Newdata),next(nextNode)
{}
}; StackNode * top;
// 防止默认拷贝和默认赋值
commonStack(const commonStack& rhs);
commonStack& operator=(const commonStack& rhs);
int mySize;
}; template <typename T>
class Stack:private commonStack
{
public:
void push(T * ty){commonStack::push(static_cast<void*>(ty));}
T* top(){return static_cast<T*>(commonStack::Top());}
void pop(){return commonStack::pop();}
int size(){return commonStack::size();}
bool Empty()const{ return commonStack::Empty(); }
void clear(){return commonStack::clear();} };
对应的cpp 如下:
#include "stack.h" using namespace std; commonStack::commonStack()
:top(nullptr),mySize()
{ } commonStack::~commonStack()
{
clear();
} void commonStack::push(void* node)
{
top = new StackNode(node,top);
mySize ++;
} void* commonStack::Top()
{
if (Empty())
{
_DEBUG_ERROR("Error, stack is empty!");
}
return top->data;
} void commonStack::pop()
{
if (Empty())
{
_DEBUG_ERROR("Error, stack is empty!");
}
StackNode* topOfStack = top;
top = top->next;
delete topOfStack;
topOfStack = nullptr;
mySize --;
return;
} bool commonStack::Empty() const
{
return top == nullptr;
} void commonStack::clear()
{
while (top)
{
StackNode* topOfStack = top;
top = top->next;
delete topOfStack; }
mySize = ;
} int commonStack::size()const
{
return mySize;
}
这里commonStack将原模板类的T改为了void*, 之后使用protected保护该类不会被其他不明群众调用,而是给出了一个模板接口类私有继承这个类,这样一来,既起到了保护作用,又在低损耗的情况下给出了方便易用的接口,巧夺天工的设计。
测试代码如下:
void funcInt()
{
int* a[];
for(int i = ; i < ; ++i)
{
a[i] = new int(i);
} Stack<int> s; for(int j = ; j < ; ++j)
{
s.push(a[j]);
} int k = s.size();
int* t = s.top();
s.pop();
if(s.Empty())
{
cout<<"empty"<<endl;
}
s.clear(); for(int i = ; i < ; ++i)
{
delete a[i] ;
} } void funcString()
{
string* str[];
for(int i = ; i < ; ++i)
{
str[i] = new string("a");
} Stack<string> s; for(int j = ; j < ; ++j)
{
s.push(str[j]);
} int k = s.size();
string* t = s.top();
s.pop();
if(s.Empty())
{
cout<<"empty"<<endl;
}
s.clear(); for(int i = ; i < ; ++i)
{
delete str[i] ;
}
} int main ()
{
funcInt();
funcString();
getchar();
return ;
}
测试代码没有输出,可以断点看数据。
之后我又去看了一眼STL对栈的实现,它默认使用deque作为栈的底层实现。
template<class _Ty,
class _Container = deque<_Ty> > class stack
{
// 栈实现
}
调用的时候直接std::stack<int> 即默认使用deque作为栈底层容器。
用户也可以指定其他方式,比如std::stack<int, std::list<int> >, 这样就使用了list作为栈的底层容器。
让我感到awesome的是STL实现的精巧和灵活性,居然是可指定底层的一种实现方法,太精巧了。回头再去看一下《STL源码剖析》。
只罗列了代码,没太详细的介绍原理,感兴趣的可以直接去看《effective C++》和《STL源码剖析》,以及STL的stack代码。
引用请注明出处,http://www.cnblogs.com/chwen/p/4055474.html 非常感谢,随时交流。
C++采用模板实现栈的方法的更多相关文章
- java内存管理(堆、栈、方法区)
java内存管理 简介 首先我们要了解我们为什么要学习java虚拟机的内存管理,不是java的gc垃圾回收机制都帮我们释放了内存了吗?但是在写程序的过程中却也往往因为不懂内存管理而造成了一些不容易察觉 ...
- JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存
Java 虚拟机可以看作一台抽象的计算机,如同真实的计算机,它也有自己的指令集和运行时内存区域. Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存(运行时内存区域)划分为若干个不同的数 ...
- 单链表的C++实现(采用模板类)
采用模板类实现的好处是,不用拘泥于特定的数据类型.就像活字印刷术,制定好模板,就可以批量印刷,比手抄要强多少倍! 此处不具体介绍泛型编程,还是着重叙述链表的定义和相关操作. 链表结构定义 定义单链表 ...
- (转) ThinkPHP模板自定义标签使用方法
这篇文章主要介绍了ThinkPHP模板自定义标签使用方法,需要的朋友可以参考下 转之--http://www.jb51.net/article/51584.htm 使用模板标签可以让网站前台开发 ...
- Angular 向组件传递模板的几种方法
最近在写一个日期选择器组件,为了满足将来可能出现的各种需求,所以需要能够高度的自定义组件的样式.为了达到这个目的,需要能够在日期选择器组件外控制每个日期格子内要显示的内容,比如,标上节假日之类的.这时 ...
- 简单了解下java中的堆、栈和方法区。
堆.栈.方法区 1,首先了解下java中的数据类型. ①java中的八大基本数据类型:boolean, char , byte, short, int, long , float , double. ...
- JVM内存结构之堆、栈、方法区以及直接内存、堆和栈区别
JVM内存结构之堆.栈.方法区以及直接内存.堆和栈区别 一. 理解JVM中堆与栈以及方法区 堆(heap):FIFO(队列优先,先进先出):二级缓存:*JVM中只有一个堆区被所有线程所共享:对象和数 ...
- ThinkPHP问题收集:模板中使用U方法时无法嵌套大括号,For标签,插入数据,新增的表字段缓存问题
ThinkPHP模板中使用U方法时无法嵌套大括号需要在control里面用U方法赋值给变量传到模版如:{:U('/Blog/comment/',array('id'=>$id)}$comment ...
- JVM,JMM,虚拟机栈,本地方法栈
JVM 虚拟机栈 本地方法栈:本地方法(使用native关键词修饰的方法,是由JVM底层用C,C++实现的),运行这部份代码使用的栈就是本地方法栈
随机推荐
- 在vs中连接sql的几种连接方式
sql身份验证:Data Source=.;Initial Catalog=DBName;UID=sa;Pwd=pwd windows身份验证:Data Source=.;Initial Catal ...
- CSS中.和#区别
一.问题来源 制作导航栏,参考别人的代码,发现的. 二.解析 2.1 概述 id:用来定义页面中大的样式,如栏目划分,顶部,正文,底部等:用#top的形式来定义: class:用来定义一些比较细节的样 ...
- bit和sbit的区别
1.bit和sbit都是C51扩展的变量类型. bit和int char之类的差不多,只不过char=8位, bit=1位而已.都是变量,编译器在编译过程中分配地址.除非你指定,否则这个地址是随机的. ...
- Xamarin.Forms Hello word
创建项目 XMD1右键->添加->新建项目 MDPage:MasterDetailPage 主窗体,导航与明细的布局窗体. 指定MenuPage.xaml 作为Master <?xm ...
- MySQL全连接(Full Join)实现,union和union all用法
MySQL本身不支持你所说的full join(全连接),但可以通过union来实现 ,下面是一个简单测试,可以看看: mysql> CREATE TABLE a(id int,name cha ...
- vs 2013调试的时候重启的解决方案
今天在用vs 2013 调试程序的时候,vs 总是莫名其妙的关闭,停止运行,泪蹦了..... 是什么原因呢? 以前的时候可是好好的啊,经过认真的思索,最近装过和vs 2013 相关的程序也只有 ref ...
- Oracle Dataguard三种保护模式
Oracle Dataguard提供了三种数据保护模式,在此分别总结一下三种数据保护模式的特点. 1.最大保护模式1)这种模式提供了最高级别的数据保护能力:2)要求至少一个物理备库收到重做日志后,主库 ...
- [oracle安装错误处理]ORA-00600: [keltnfy-ldmInit][46], [1], []
原博文:http://blog.itpub.net/519536/viewspace-614893/ 今天在部署一套10g Oracle(10.2.0.3版本)的过程中,偶遇ORA-00600: in ...
- iOS常用的开源类库
开发几个常用的开源类库及下载地址: 引用 1.json json编码解码 2.GTMBase64 base64编码解码 3.TouchXML xml解析 4.SFHFKeychainUtils 安全保 ...
- Android 适配
给定字体大小适配时应按照12sp,14sp,18sp,22sp 这几种字体的大小设置,以避免字体大小混乱12sp以上大小,14sp 18sp 22sp 字体首选大小,不要使用奇数.小数,否则会造成精度 ...