目錄
- 1. 什么時候需要使用自定義的迭代器?
- 常見、基本的陣列型別
- STL 容器
- 自定義資料型別
- 2. 開始撰寫自定義迭代器之前需要思考的問題
- 3. 如何撰寫及實作自定義型別的迭代器?
1. 什么時候需要使用自定義的迭代器?
常見、基本的陣列型別
-
對于常見、基本的陣列型別,如:
int、char,我們可以簡單地使用下標來進行遍歷:int array[5] = {1,2,3,4,5}; // 方法1:使用下標遍歷 for (int ind = 0; ind < 5; ++ind) { cout << array[ind] << " "; }也可以使用范圍來進行遍歷,達到和使用下標同樣的遍歷效果:
// 方法2:使用范圍遍歷 for (int &n: array) { cout << n << " "; }
回到頂部
STL 容器
-
對于 STL 容器來說,如:
vector、list,我們同樣也可以使用下標和范圍來進行遍歷:vector<int> vec = {1,2,3,4,5}; // 方法1:使用下標遍歷 for (int ind = 0; ind < vec.size(); ++ind) { cout << vec[ind] << " "; } // 方法2:使用范圍遍歷 for (int &n: vec) { cout << n << " "; }除了以上兩種方法,STL 容器還可以使用迭代器(iterator)進行遍歷:
vector<int>::iterator iter; // 方法3:使用迭代器遍歷 // .begin() 是指向 vector 首元素的位置的迭代器 // .end() 是指向 vector 最后一個元素的位置的下一個位置的迭代器 for (iter = vec.begin(); iter != vec.end(); ++iter) { cout << *iter << " "; }
回到頂部
自定義資料型別
-
下面給出一個簡單的自定義類:
class Group { private: vector<vector<int>> students_marks; ...... }其中,
students_marks是一個用來記錄學生若干次的分數的 vector,students_marks[0]也是一個 vector,用來記錄第一個學生的分數,其中students_marks[0][0]表示第一個學生的第一個分數, -
如果要對
students_marks進行遍歷,由于不存在vector<int>型別的迭代器,因此方法2和方法3無法使用,只能使用下標遍歷法:// 定義一個函式,用來輸出 vector 中所有元素 void printvec(vector<int> &vec) { for(int ind = 0; ind < vec.size(); ++ind) { cout << vec[ind] << " "; } } // 使用下標對 vector<int> 型別的元素進行遍歷 for (int ind = 0; ind < students_marks.size(); ++ind) { printvec(students_marks[ind]); } -
如果要使用以下方法對
students_marks進行遍歷:// 定義 Group 型別的 G Group G; // 使用范圍遍歷 for(auto v: G) { printvec(v); }則需要自己手動撰寫指向
vector<int>資料型別的迭代器,
回到頂部
2. 開始撰寫自定義迭代器之前需要思考的問題
- 迭代器進行遍歷的物件是什么?
- 迭代器遍歷的范圍是什么?
- 迭代器指向的資料是什么型別?
只要想明白這三個問題,就不難實作自定義型別的迭代器,
以上面的類 Group 為例,
我們想遍歷的是 students_marks ,將每個學生的分數輸出,
對應問題1,迭代器遍歷的物件是 vector<vector<int>> students_marks ,
對應問題2,假設總共有 k 個學生,則 students_marks.size() = k ,遍歷的范圍是從 students_marks[0] 到 students_marks[k-1] ,
對應問題3,迭代器指向的資料是 students_marks[x] ,型別是 vector<int> ,
回到頂部
3. 如何撰寫及實作自定義型別的迭代器?
在后面的步驟中,一些常用的名詞將會以以下識別符號代稱:
| 代替的識別符號 | 對應上面的例子是 | |
|---|---|---|
| 遍歷的物件 | OBJECT | students_marks |
| 遍歷物件的資料型別 | OBJECT_type | vector<vector<int>> |
| 遍歷物件所處類 | OBJECT_class | Group |
| 迭代器指向的資料 | VALUE | students_marks[x] |
| 迭代器指向的資料型別 | VALUE_type | vector<int> |
回到頂部
-
在
object所處的class中定義一個迭代器(iterator)的結構體(struct):class OBJECT_class { private: OBJECT_type OBJECT; public: struct Iterator { } ...... }
-
設定迭代器的屬性:
struct Iterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = VALUE_type; using reference = const VALUE_type&; using pointer = VALUE_type*; }iterator_category是迭代器的型別,如果是正常、基礎的情況下,選擇forward_iterator_tag就可以了difference_type選擇ptrdiff_t- 其余的
value_type、reference和pointer都是自定義的,根據實際情況填寫
-
定義迭代器的成員變數、建構式、基礎函式
struct Iterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = VALUE_type; using reference = const VALUE_type&; using pointer = VALUE_type*; // 建構式 Iterator(pointer p) :ptr(p) {} // 拷貝賦值函式 Iterator& operator=(const Iterator& it) { ptr = it.ptr; } // 等于運算子 bool operator==(const Iterator& it) const { return ptr == it.ptr; } // 不等于運算子 bool operator!=(const Iterator& it) const { return ptr != it.ptr; } // 前綴自加 Iterator& operator++() { ptr++; return *this; } // 后綴自加 Iterator operator ++(int) { Iterator tmp = *this; ++(*this); return tmp; } // 前綴自減 Iterator& operator--() { ptr--; return *this; } // 后綴自減 Iterator operator --(int) { Iterator tmp = *this; --(*this); return tmp; } // 取值運算 VALUE_type& operator*() { return *ptr; } private: // 定義一個指標 pointer ptr; }- 以上的函式不是必要也不是完整的,如果不需要用到的可以不寫,額外需要用到的函式可以自行撰寫,
- 但是在大多數情況下,上面這些函式基本上足矣,
-
設定遍歷的范圍:
class OBJECT_class { private: OBJECT_type OBJECT; public: struct Iterator { ...... ...... private: pointer ptr; } // 遍歷的第一個元素的位置 Iterator begin() { VALUE_type* head = &OBJECT[0]; return Iterator(head); } // 遍歷的最后一個元素的下一個位置 Iterator end() { VALUE_type* head = &OBJECT[0]; return Iterator(head + OBJECT.size()); } ...... }head是指向第一個 VALUE 的指標
回到頂部
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/472846.html
標籤:C++
上一篇:多執行緒04:互斥量和死鎖
