自定義一個簡單的迭代器(line_iterator)
STL是容器、迭代器、演算法三位一體的好東西,使用STL編寫的程式看起來非常簡潔。比如從cin輸入若干字串,每一字串佔一行,然後將這些字串按字典序排序並輸出到cout中,相關的程式碼如下所示:
-
/* 迭代器的使用
-
* created: btwsmile
-
* date: 2011-12-17
-
*
-
*/
-
#include<iostream>
-
#include<vector>
-
#include<string>
-
#include<iterator>
-
#include<algorithm>
-
using namespace std;
-
int main()
-
{
-
vector<string> v;
-
string temp;
-
while(getline(cin,temp))
-
{
-
v.push_back(temp);
-
}
-
sort(v.begin(),v.end());
-
copy(v.begin(),v.end(),ostream_iterator<string>(cout," "));
-
system("pause");
-
return 0;
-
}
包含的標頭檔案非常:
主函式中用到cin/cout以及getline,因此必須包含iostream;
主函式中用到vector<string>,因此必須包含vector和string;
主函式中用到ostream_iterator,因此必須包含iterator;
主函式還呼叫了sort和copy函式,因此必須包含algorithm。
除了iostream外,其它標頭檔案都是STL標頭檔案。vector和string是容器,iterator是迭代器,algorithm是演算法。
編譯執行此程式,結果如下所示:
-
you
-
are
-
the
-
apple
-
of
-
my
-
eye
-
^Z
-
apple are eye my of the you 請按任意鍵繼續. . .
如果想倒過來排,只要在把sort(v.begin(),v.end())改寫成sort(v.begin(),sort.end(),greater<string>())即可。
現在我們提出一個稍微高一點的要求,上面的程式不是將cout包裝到迭代器裡了嗎,能不能將cin也包裝到迭代器裡面呢?當然是可以,我們定義一個類來實現:
-
/* line_iterator.h
-
* created: btwsmile
-
* date: 2011-12-17
-
*
-
*/
-
class line_iterator
-
{
-
istream* in;
-
string line;
-
bool is_valid;
-
void read()
-
{
-
if(*in)
-
getline(*in,line);
-
is_valid = (*in) ? true : false;
-
}
-
public:
-
typedef input_iterator_tag iterator_category;
-
typedef string value_type;
-
typedef ptrdiff_t difference_type;
-
typedef const string* pointer;
-
typedef const string& reference;
-
reference operator*()
-
{
-
return line;
-
}
-
pointer operator->()
-
{
-
return &line;
-
}
-
line_iterator():in(&cin),is_valid(false)
-
{
-
}
-
line_iterator(istream& s):in(&s)
-
{
-
read();
-
}
-
line_iterator operator++()
-
{
-
read();
-
return *this;
-
}
-
line_iterator operator++(int)
-
{
-
line_iterator temp = *this;
-
read();
-
return temp;
-
}
-
bool operator==(const line_iterator& rhs)
-
{
-
if(in == rhs.in && is_valid == rhs.is_valid)
-
return true;
-
if(is_valid == false && rhs.is_valid == false)
-
return true;
-
return false;
-
}
-
bool operator!= (const line_iterator& rhs)
-
{
-
return !(*this == rhs);
-
}
-
};
程式碼比較長,看似很複雜,在解釋它之前先看看它怎麼使用:
-
/* 迭代器的使用 版本2
-
* created: btwsmile
-
* date: 2011-12-17
-
*
-
*/
-
#include<iostream>
-
#include<vector>
-
#include<string>
-
#include<iterator>
-
#include<algorithm>
-
using namespace std;
-
#include"line_iterator.h"
-
int main()
-
{
-
line_iterator iter(cin);
-
line_iterator end_of_file;
-
vector<string> v(iter,end_of_file);
-
sort(v.begin(),v.end());
-
copy(v.begin(),v.end(),ostream_iterator<string>(cout," "));
-
system("pause");
-
return 0;
-
}
毫不意外,執行這個新版的程式,結果與舊程式是一樣的。比較起來,新版的程式中看不到明顯地輸入語句。顯然這是我們自定義的line_iterator帶來的妙處。
新程式中的輸入是在哪裡實現的呢?請看vector<string> v(iter,end_of_file),用迭代器區間來構造vector,在這個構造方法內部隱含的一定有一個while迴圈,就是將字串從iter開始到end_of_file一個接一個的拷貝到vector v中。必然的,它將呼叫line_iterator的operator++、operator!=等操作符方法。而end_of_file看起來不跟任何變數相關,但是回頭看line_iterator的無參構造方法,你會發現它實際上還是跟標準輸入cin掛上了鉤。所以,在判斷有沒有到達輸入的尾端時,將比較is_valid標記。
line_iterator定義內部的其它成員同樣不可或缺,那些看似沒用的typedef,實際在於vector以及sort、copy等聯合工作的時候被頻繁使用到。想要搞懂它們就需要對iterator進行更深一步的學習了。