文章目录
全部的实现代码放在了文章末尾
stack的模拟实现我采用了C++适配器模式
stack
的适配器一般是deque
,也可以是vector
或者list
因为stack是有特殊限制的线性表【只能在栈顶插入删除】,所以只要是线性结构并且可以高效的实现头或者尾的插入和删除的线性表,就都可以作为stack的适配器
什么是适配器模式?
适配器模式是一种设计模式,它允许将不兼容接口的类一起工作。
适配器模式通常用于以下情况:
- 希望使用一个类,但其接口与其他代码不兼容。
- 希望创建一个可重用的类,它能够将接口转换为其他接口。
- 希望使用第三方库或遗留代码,但其接口与其他代码不兼容。
适配器模式通常包括以下三个主要部分:
- 目标接口(Target):这是期望使用的接口,客户端代码只能与目标接口交互。
- 源接口(Adaptee):这是需要适配的类,其接口与目标接口不兼容。
- 适配器(Adapter):这是一个类,它实现了目标接口,并将调用转换为对源接口的调用。适配器将源接口的调用转换为目标接口的调用,使得客户端代码可以与目标接口交互。
可以类比我们生活中的家庭电源接口
和笔记本电脑充电口
与电源适配器
,它们之间也是一种适配器关系
笔记本电脑充电口
是上面提到的目标接口家庭电源接口
是上面提到的源接口电源适配器
是上面提到的适配器
笔记本电脑的充电口
是不能和家庭电源接口
直接连接进行充电的,因为笔记本电脑用的是直流电,而家庭电源输出的是交流电,所以要把交流电转换为直流电才能给笔记本电脑供电,而电源适配器
就能做到这一点
对应了上面提到的适配器模式解决的问题:
可以将不兼容接口的类一起工作
stack
准备工作
创建两个文件,一个头文件mystack.hpp
,一个源文件test.cpp
【因为模板的声明和定义不能
分处于不同的文件中,所以把成员函数的声明和定义放在了同一个文件mystack.hpp
中】
mystack.hpp:存放包含的头文件,命名空间的定义,成员函数和命名空间中的函数的定义
test.cpp:存放main函数,以及测试代码
包含头文件
iostream:用于输入输出
vector:提供vector类型的适配对象
deque: 提供deque类型的适配对象
定义命名空间
在文件mystack.hpp
中定义上一个命名空间mystack
把stack类和它的成员函数放进命名空间封装起来,防止与包含的头文件中的函数/变量重名的冲突问题
类的成员变量
只有一个,是适配器对象
默认成员函数
stack
类的四大默认成员函数:构造函数,拷贝构造函数,析构函数,赋值运算符重载,都不需要手动写
,使用编译器提供的默认的即可
因为编译器给的默认的这四大成员函数,都有一个特性:
如果类的成员变量是其他类实例化的对象
,调用本类的四大默认成员函数的时候,对其他类实例化的对象
进行操作时就可以自动调用
那个类自己的四大默认成员函数
empty
把stack的数据都存储在了适配器对象里面 所以判断适配器对象是否为空即可 bool empty()const { return _obj.empty(); }
size
把stack的数据都存储在了 适配器对象里面 所以适配器对象的size就是stack的size size_t size()const { return _obj.size(); }
top
统一把线性表(适配器类)的尾作为 栈顶 因为vector的头插,头删效率低,为了照顾它就把尾作为栈顶 所以back就是栈顶的数据 T& top() { return _obj.back(); } const修饰的对象,只能调用const修饰的成员函数 const T& top() const { return _obj.back(); }
push
统一把线性表(适配器类)的尾作为 栈顶 所以push,就是尾插 void push(const T& val) { _obj.push_back(val); }
pop
统一把线性表(适配器类)的尾作为 栈顶 所以pop,就是尾删 void pop() { _obj.pop_back(); }
全部代码
#include<iostream> #include<list> #include<vector> #include<deque> using namespace std; namespace mystack { //T是stack里面存储的数据的类型 //con是适配器类的类型 template<class T, class con = vector<T>> class stack { private: //使用适配器类类型创建 适配器对象 con _obj; public: //把stack的数据都存储在了适配器对象里面 //所以判断适配器对象是否为空即可 bool empty()const { return _obj.empty(); } //把stack的数据都存储在了适配器对象里面 //所以适配器对象的size就是stack的size size_t size()const { return _obj.size(); } //统一把线性表(适配器类)的尾作为 栈顶 //所以back就是栈顶的数据 T& top() { return _obj.back(); } //const修饰的对象,只能调用const修饰的成员函数 const T& top() const { return _obj.back(); } //统一把线性表(适配器类)的尾作为 栈顶 //所以push,就是尾插 void push(const T& val) { _obj.push_back(val); } //统一把线性表(适配器类)的尾作为 栈顶 //所以pop,就是尾删 void pop() { _obj.pop_back(); } }; }