C++容器适配器的概念与示例
SouLinya 人气:0一. 什么是适配器与容器适配器?
适配器是一种设计模式(设计模式是一套被反复使用的,多数人知晓的,经过分类编目的,代码设计经验的总结),该种模式将一个类的接口转换成用户需要的另外一个接口。
举个例子:在日常生活中,当手机没电了,我们需要给手机充电,给手机充电的方式很多,可以插到电源上,也可以用充电宝,还可以直接连着电脑充。而我们并不关心用什么给它充电,我们关心的只是能否给手机充上电。适配器充当的角色就是 给手机充电的接口,它会将不同大小的电压转化成适合给手机充电的电压。容器适配器的概念可以结合这个例子理解,它以 某种容器作为底层结构,改变其接口,使它符合该容器的特性。
容器适配器:以某种已有的既定容器作为底层结构,在其基础上进一步地进行封装接口函数。使其可以满足某种特性。
下面将介绍三个用到容器适配器的结构:stack栈,queue队列,priority_queue优先级队列,通过这三个结构,我们可以更好的理解容器适配器的用途。
二. 理解容器适配器
STL的六大组件
我们可以看出虽然stack,queue,priority_queue中也可以存放数据,但在STL中并没有将其划分在容器的行列,而是将其称为容器配接器,这是因为stack,queue,priority_queue只是对其它容器的接口进行了包装,STL中stack和queue默认使用deque,priority_queue默认使用vector作为容器。我们现在来看看它们的底层接口和实现
stack的模拟实现
知道了容器适配器后,stack的模拟实现就简单了,我们只需要调用指定容器deque的各个成员函数即可实现stack的各个函数接口。
底层实现代码如下:stack底层利用deque双端队列进行包装,需要更改成多参数模板,最便利的一点就是,stack的底层函数的实现可以直接调用容器的函数接口,不需要自己再一步步实现。
namespace nn //命名空间域:防止命名冲突 { //多参数模板 template<class T, class Container = std::deque<T>>//可以明显看出stack配接器的底层容器是deque双端队列,后面会介绍 class stack { public: //元素入栈 void push(const T& x) { _con.push_back(x); } //元素出栈 void pop() { _con.pop_back(); } //获取栈顶元素 T& top() { return _con.back(); } const T& top() const//const修饰 { return _con.back(); } //获取栈中有效元素个数 size_t size() const { return _con.size(); } //判断栈是否为空 bool empty() const { return _con.empty(); } //交换两个栈中的数据 void swap(stack<T, Container>& st)//注意stack<T,Container>才是类型,加引用,别名,减少拷贝 { _con.swap(st._con);//调用deque的算法swap } private: //deque<T> _con底层 Container _con;//将一个类的接口转换成用户需要的另一种接口,即利用deque容器转换成stack配接器 }; }
queue的模拟实现
同样的方式,我们也是通过调用所指定容器的各个成员函数来实现queue的。
底层实现代码如下:
namespace nn //防止命名冲突 { template<class T, class Container = std::deque<T>> class queue { public: //队尾入队列 void push(const T& x) { _con.push_back(x); } //队头出队列 void pop() { _con.pop_front(); } //获取队头元素 T& front() { return _con.front(); } const T& front() const { return _con.front(); } //获取队尾元素 T& back() { return _con.back(); } const T& back() const { return _con.back(); } //获取队列中有效元素个数 size_t size() const { return _con.size(); } //判断队列是否为空 bool empty() const { return _con.empty(); } //交换两个队列中的数据 void swap(queue<T, Container>& q) { _con.swap(q._con); } private: Container _con;//deque<T> _con; }; }
思考stack 和 queue 是否存在迭代器?
stack 和 queue 都不具备迭代器, 因为两者都不具备遍历走访功能,所以自然不需要设计迭代器
stack 和 queue可以以哪些容器作为底层容器?
实际上stack使用vector作为底层容器也是可以的,queue使用deque双端队列+list带头双向循环链表作为底层容器也是可以的。
但是deque在设计上相比于list和vector,作为stack,queue的底层结构更优。
底层容器如何传进去?
作为模板参数传入template<class T,class Container = deque<T>>
,用了默认参数(缺省参数)
加载全部内容