C++ 接配器(Adapter)总结

Posted j1ac

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 接配器(Adapter)总结相关的知识,希望对你有一定的参考价值。

近日在看《STL源码解析》,STL里面一大堆泛型编程的确是非常巧妙,不过由于时间有限,我还是只能更加专注于日常使用比较多的一些知识。

Adapter是我在最开始使用STL Container的时候就听到的一个词,一直以来没有比较深入的了解,借着这次学习STL源码,在这里总结一下:

 

首先是Adapter的定义,《Design Patterns》中对于Adapter的定义我觉得真的十分准确:将一个Class的接口转换成另一个Class的接口,使原本因接口不兼容而不能合作的Class可以一起运作。这很直接就能让我想到日常生活中常见的Adapter:电源适配器。同样的,其实两者的作用也差不多。

 

STL里面主要有两种接配器(Adapter):容器接配器(Container Adapter)和迭代器接配器(Iterator Adapter),下面举几个例子了解一下这两类主要的Adapter:

 

Container Adapter:

  最常用的容器接配器无非是queue和stack,从意义上来说,他们为底层的容器提供了一层包装,使得底层的容器只表现出这些接配器所定义的数据结构的功能。

这里假设底层容器是deque,双向开口,而且两端插入删除都能够实现O(1)的时间复杂的。当作为queue进行包装的时候deque就会封闭一端的插入操作,封闭另一端的删除操作,使得整个deque表现出FIFO的特性,在作为stack的时候同理。

  可以看到Container Adapter做到的功能很直观,也很好理解,只是对于容器的一层包装,改变了数据结构的接口的同时方便了我们对其的理解和使用。

 

Iterator Adapter(#include<iterator>)

  迭代器接配器是我原先并不是很熟悉的,对于STL中iterator的使用我可能最多的也就是begin(),end(),const_iterator,rbegin()等等,而在这里我要讲的Iterator Adapter主要有三种,分别是insert iterator,reverse iterator,iostream iterator。

 

  首先是insert iterator。从定义上来讲,它的作用是将一般迭代器的赋值(assign)操作转变为插入(insert)操作。理解了这句话也就理解了insert iterator的本质。

下图显示的是STL里面insert iterator的主要用法:

技术分享图片

  这三种形式的最大区别无非就是使用Adapter之后元素插入的位置了。

  先来一段最简单的测试代码:

 1 #include<iostream>
 2 #include<iterator>
 3 #include<vector>
 4 using namespace std;
 5 
 6 int main(){
 7     vector<int> data={6,2,3,4,5,9};
 8     for(int i = 0;i<10;++i){
 9         *back_inserter(data)=i;
10     }
11 
12     for(auto j:data) cout<<j<<" ";
13     cout<<endl;
14     return 0;
15 }
输出结果:6 2 3 4 5 9 0 1 2 3 4 5 6 7 8 9

可以看到,我们依然可以把经过Iterator Adapter修饰之后的结果当成是一种迭代器,依然可以用*符号,但不同的是当你对它进行赋值的时候,它将自动进行insert操作。使用原书中的描述应该更好:

技术分享图片

也就是说在insert iterator的封装下,该iterator只是将assign操作变成了push_back,push_front,insert,而其他操作++,--,*全部返回原先的iterator

 这也就能够解释copy函数的时候进行复制的底层实现了,在每复制一个值后的++对insert iterator并不起作用,只有赋值assign会起到相关操作。

当使用copy函数的时候:

 1 #include<iostream>
 2 #include<iterator>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int main(){
 8     vector<int> data={6,2,3,4,5,9};
 9     vector<int> res={2,1,1};
10     copy(data.begin(),data.end(),back_inserter(res));
11     for(auto j:res) cout<<j<<" ";
12     cout<<endl;
13     return 0;
14 }
输出结果:2 1 1 6 2 3 4 5 9

copy的时候每次都是从res的末尾插入一个数字并进行copy,而不像copy本义中只存在的赋值而已。

 

  reverse iterator:

  显然作用是使得iterator方向相反,常和rbegin,rend一起使用,比如:

 1 #include<iostream>
 2 #include<iterator>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int main(){
 8     vector<int> data={6,2,3,4,5,9};
 9     vector<int>::reverse_iterator it = data.rbegin();
10     for(;it!=data.rend();++it) cout<<*it;
11     cout<<endl;
12     return 0;
13 }
输出:954326

  iostream iterator:

  这种Adapter将iterator和输入输出流(可以是文件流)相关联,经常和copy函数联合使用:

 1 #include <iostream>     // std::cout
 2 #include <iterator>     // std::ostream_iterator
 3 #include <vector>       // std::vector
 4 #include <algorithm>    // std::copy
 5 
 6 int main () {
 7   std::vector<int> myvector;
 8   for (int i=1; i<10; ++i) myvector.push_back(i*10);
 9 
10   std::ostream_iterator<int> out_it (std::cout,", ");
11   std::copy ( myvector.begin(), myvector.end(), out_it );
12   return 0;
13 }
输出:10, 20, 30, 40, 50, 60, 70, 80, 90,

 

从上面的例子中可以看到,接配器(Adapter)在STL中有着重要作用,其和copy等常用函数关系紧密,同样可以和输入输出等操作进行结合。  

参考:《STL源码剖析》

  http://www.cplusplus.com/reference/iterator/ostream_iterator/

 

以上是关于C++ 接配器(Adapter)总结的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式之接口型模式总结

设计模式学习总结适配器模式(Adapter)

从适配器访问片段

适配器项目单击“从片段”

打造万能Adapter(适配器)——适用于ListViewGridListView

从适配器 RecyclerView 打开片段