6、【C++ STL】適配器

1、基本概念

    適配器, 在STL中扮演着轉換器的角色,本質上是一種設計模式,用於將一種接口轉換成另一種接口,從而是原本不兼容的接口能夠很好地一起運作。適配器不提供迭代器。

2、基本類型

根據目標接口的類型,適配器可分爲以下幾類:

    (1) 改變容器的接口,稱爲容器適配器
    (2)改變迭代器的接口,稱爲迭代器適配器
    (3)改變仿函數的接口,稱爲仿函數適配器

3、容器適配器

    容器的適配器有stack、queue、priority_queue,是在容器deque的基礎進行了一些特定的約束,因而本質上並不屬於容器,而是容器的適配器。

4、迭代器適配器

    STL提供了很多應用於迭代器的適配器,主要有:有back_insert_iterator, front_insert_iterator, inser_iterator, reverse_iterator, istream_iterator, ostream_iterator, istreambuf_iterator, ostreambuf_iterator等等,下面介紹集中主要的迭代器適配器:

(1)insert iterators

    這種迭代器,可以將迭代器的賦值操作轉變爲插入操作。根據功能的不同,還分爲用於尾端插入的back_insert_iterator,用於頭端插入的front_insert_iterator,用於任意位置插入的insert_iterator。示例如下:

ostream_iterator<int> outline(cout," "); //輸出迭代器的適配器

int ia[] = {0,1,2,3,4,5}; 
deque<int> id(ia,ia+6); 
copy(id.begin(),id.end(),outline);//0 1 2 3 4 5 
cout<<endl; 

copy(ia+1,ia+2,front_inserter(id)); 
copy(id.begin(),id.end(),outline);//1 0 1 2 3 4 5 
cout<<endl;
 
copy(ia+3,ia+4,back_inserter(id)); 
copy(id.begin(),id.end(),outline);//1 0 1 2 3 4 5 3 
cout<<endl; 

deque<int>::iterator iter = find(id.begin(),id.end(),5); 
copy(ia+0,ia+3,inserter(id,iter)); 
copy(id.begin(),id.end(),outline);//1 0 1 2 3 4 0 1 2 5 3 
cout<<endl;

(2)reserve iterators

    這種迭代器,將一般迭代器的行進方向進行逆轉,可以很好地應用於從容器尾端開始的算法。示例如下:

    copy(id.rbegin(),id.rend(),outline);//3 5 2 1 0 4 3 2 1 0 1
    cout<<endl;

(3)iostream iterators

    這種迭代器,將自己綁定一個iostream對象身上,從而獲得輸入輸出的功能。示例如下:

ostream_iterator<int> outline(cout," "); 

int ia[] = {0,1,2,3,4,5}; 
deque<int> id(ia,ia+6); 

copy(id.begin(),id.end(),outline);//0 1 2 3 4 5 
cout<<endl;
5、仿函數適配器

    仿函數適配器,相比於其他適配器更加地靈活,可以自由地組合適配。目前提供的適配操作包括以下這些:

(1)聯結(bind)

    通過bind,我們仿函數與參數進行綁定,可實現算法所需的條件判斷功能,例如判斷小於12的元素時,可使用bind2nd(less(),12),就可以達到目的。

(2)否定(negate)

    這裏就是取反的操作,例如not1(bind2nd(less(),12)),就可判斷不小於12的元素。

(3)組合(compose)

    當算法的判斷條件需要進行一些複雜的數學運算時,即可採用這種適配操作。例如對每個元素v進行(v+2)*3操作,就可表示爲compose1(bind2nd(multiplies(),3),bind2nd(plus(),2))。

(4)一般函數適配器

    一般函數可以當做仿函數供STL算法使用,但無配接能力,需要將其包裝成仿函數,其原理就是在仿函數的運算符()內執行其所包裝的函數即可。

(5)成員函數適配器

    這裏將成員函數包裝成仿函數,從而可使用成員函數搭配各種泛型算法。當容器內存儲的是對象的實體時,需使用mem_fun_ref進行適配;當容器內存儲的是對象的指針時,需使用mem_fun進行適配。

    仿函數適配器的作用,就是將我們需要的東西包裝成仿函數,已達到算法泛化的目的,測試示例如下:

void print(int i) 
{ 
    cout<<i<<" "; 
} 
class Int 
{ 
public: 
    explicit Int(int i):m_i(i) { } 
    ~Int() { } 
    void print1() 
    { 
        cout<<"["<<m_i<<"] "; 
    } 
    
private: 
    int m_i; 
}; 

int ia2[] = {2,21,12,7,19,23}; 
vector<int> iv(ia2,ia2+6); 
cout<<count_if(iv.begin(),iv.end(),not1(bind2nd(less<int>(),12)));//4 
cout<<endl; 

for_each(iv.begin(),iv.end(),print);//2 21 12 7 19 23 
cout<<endl; 

for_each(iv.begin(),iv.end(),ptr_fun(print));//2 21 12 7 19 23 
cout<<endl; 

Int t1(3),t2(7),t3(20),t4(14),t5(68); 
vector<Int> Iv; 
Iv.push_back(t1); 
Iv.push_back(t2); 
Iv.push_back(t3); 
Iv.push_back(t4); 
Iv.push_back(t5); //當容器中存放的是對象實體的時候用mem_fun_ref 
for_each(Iv.begin(),Iv.end(),mem_fun_ref(&Int::print1));//[3] [7] [20] [14] [68] 
cout<<endl; 

vector<Int*> Iv2; 
Iv2.push_back(&t1); 
Iv2.push_back(&t2); 
Iv2.push_back(&t3); 
Iv2.push_back(&t4); 
Iv2.push_back(&t5); 

//當容器中存放的是對象的指針的時候用mem_fun 
for_each(Iv2.begin(),Iv2.end(),mem_fun(&Int::print1));//[3] [7] [20] [14] [68] 
cout<<endl;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章