1. 程式人生 > >自定義一個簡單的迭代器(line_iterator)

自定義一個簡單的迭代器(line_iterator)

STL是容器、迭代器、演算法三位一體的好東西,使用STL編寫的程式看起來非常簡潔。比如從cin輸入若干字串,每一字串佔一行,然後將這些字串按字典序排序並輸出到cout中,相關的程式碼如下所示:

  1. /* 迭代器的使用

  2. * created: btwsmile

  3. * date: 2011-12-17

  4. *

  5. */

  6. #include<iostream>

  7. #include<vector>

  8. #include<string>

  9. #include<iterator>

  10. #include<algorithm>

  11. using namespace std;

  12. int main()

  13. {

  14. vector<string> v;

  15. string temp;

  16. while(getline(cin,temp))

  17. {

  18. v.push_back(temp);

  19. }

  20. sort(v.begin(),v.end());

  21. copy(v.begin(),v.end(),ostream_iterator<string>(cout," "));

  22. system("pause");

  23. return 0;

  24. }

包含的標頭檔案非常:

主函式中用到cin/cout以及getline,因此必須包含iostream;

主函式中用到vector<string>,因此必須包含vector和string;

主函式中用到ostream_iterator,因此必須包含iterator;

主函式還呼叫了sort和copy函式,因此必須包含algorithm。

除了iostream外,其它標頭檔案都是STL標頭檔案。vector和string是容器,iterator是迭代器,algorithm是演算法。

編譯執行此程式,結果如下所示:

  1. you

  2. are

  3. the

  4. apple

  5. of

  6. my

  7. eye

  8. ^Z

  9. apple are eye my of the you 請按任意鍵繼續. . .

如果想倒過來排,只要在把sort(v.begin(),v.end())改寫成sort(v.begin(),sort.end(),greater<string>())即可。

現在我們提出一個稍微高一點的要求,上面的程式不是將cout包裝到迭代器裡了嗎,能不能將cin也包裝到迭代器裡面呢?當然是可以,我們定義一個類來實現:

  1. /* line_iterator.h

  2. * created: btwsmile

  3. * date: 2011-12-17

  4. *

  5. */

  6. class line_iterator

  7. {

  8. istream* in;

  9. string line;

  10. bool is_valid;

  11. void read()

  12. {

  13. if(*in)

  14. getline(*in,line);

  15. is_valid = (*in) ? true : false;

  16. }

  17. public:

  18. typedef input_iterator_tag iterator_category;

  19. typedef string value_type;

  20. typedef ptrdiff_t difference_type;

  21. typedef const string* pointer;

  22. typedef const string& reference;

  23. reference operator*()

  24. {

  25. return line;

  26. }

  27. pointer operator->()

  28. {

  29. return &line;

  30. }

  31. line_iterator():in(&cin),is_valid(false)

  32. {

  33. }

  34. line_iterator(istream& s):in(&s)

  35. {

  36. read();

  37. }

  38. line_iterator operator++()

  39. {

  40. read();

  41. return *this;

  42. }

  43. line_iterator operator++(int)

  44. {

  45. line_iterator temp = *this;

  46. read();

  47. return temp;

  48. }

  49. bool operator==(const line_iterator& rhs)

  50. {

  51. if(in == rhs.in && is_valid == rhs.is_valid)

  52. return true;

  53. if(is_valid == false && rhs.is_valid == false)

  54. return true;

  55. return false;

  56. }

  57. bool operator!= (const line_iterator& rhs)

  58. {

  59. return !(*this == rhs);

  60. }

  61. };

程式碼比較長,看似很複雜,在解釋它之前先看看它怎麼使用:

  1. /* 迭代器的使用 版本2

  2. * created: btwsmile

  3. * date: 2011-12-17

  4. *

  5. */

  6. #include<iostream>

  7. #include<vector>

  8. #include<string>

  9. #include<iterator>

  10. #include<algorithm>

  11. using namespace std;

  12. #include"line_iterator.h"

  13. int main()

  14. {

  15. line_iterator iter(cin);

  16. line_iterator end_of_file;

  17. vector<string> v(iter,end_of_file);

  18. sort(v.begin(),v.end());

  19. copy(v.begin(),v.end(),ostream_iterator<string>(cout," "));

  20. system("pause");

  21. return 0;

  22. }

毫不意外,執行這個新版的程式,結果與舊程式是一樣的。比較起來,新版的程式中看不到明顯地輸入語句。顯然這是我們自定義的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進行更深一步的學習了。