The function of iterator: traverse a collection of the same elements.
The iterator pattern is a behavioral design pattern.
The idea of iterator: traverse the values of the elements in the collection in some way without changing the underlying elements.
Implementation of iterator:
1: premise: a collection element class, a collection class, and an iterator class are required
2: the iterator can obtain the object of the collection class and encapsulate the interface of the object.
3: how to extend iterator model: you can extend it with template model
reference resources https://www.cnblogs.com/bugxch/ To understand the iterator pattern:
1: The example of traversing the books in the bookshelf in the graphic design pattern is the UML diagram:
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-XahJ4p33-1627281881798)(... \ md document related pictures \ iterator mode instance UML diagram. png)]
To further illustrate the above figure,
- Aggregate represents the interface of the collection. The bookshelf implements this interface, so the bookshelf must have an iterator method;
- Iterator represents the interface of the iterator of the collection. The iterator of the bookshelf needs to use the specific object of the bookshelf to call the relevant methods to implement it;
It should be noted that the iterator here has only one forward iterator, and you can also define an iterator for backward traversal.
Understanding: Aggregate and Iterator are abstract classes and virtual interfaces;
Bookshelf is the implementation class of the actual collection class Initialize iterator class
BookShelfIterator is the specific iterator encapsulation implementation class corresponding to the bookshelf collection class. = = " The object to be passed into the collection class during initialization
2: According to the above understanding, a preliminary attempt is made to implement the demo code (C + +) of the iterator:
//1: A class that implements a single element in a collection //2: The class that implements the iterator. The class of the specific iterator can operate the corresponding collection class and use the relevant traversal methods in the collection class //How to implement the interface of the collection class object that can be used in the iterator needs to be passed //3: The class that implements the collection, including the interface to create the iterator. //Simply a collection class, and then create an iterator class to control the traversal of the collection and access the elements in the collection through the iterator class. #include <iostream> #include <vector> using namespace std; class TestIterator; class TestVector{ public: //Tectonics and Deconstruction TestVector():m_itr(nullptr), count(0) {} ~TestVector() { if(m_itr != nullptr) { delete m_itr; m_itr = nullptr; } } //Class itself inserts and gets elements void push(int d) { m_testvector.push_back(d); count++; } void pop() { m_testvector.pop_back(); count--; } int getCount() { return count; } int getData(int d) { if(d < count) { return m_testvector[d]; } return -1; } //The method of creating iterators is defined here, and the access of array elements is controlled through iterators TestIterator * CreateTestIterator() { if(m_itr == nullptr) { m_itr = new TestIterator(this); } return m_itr; } private: vector<int> m_testvector; TestIterator * m_itr; //Here in order to correspond to the release int count; }; //The corresponding method is called through the iterator class to access the collection elements. Here, the access is controlled by subscripts class TestIterator { public: //The class and collection subscript of the collection to operate on TestIterator(TestVector * ts):m_ts(ts), curr(0) {} ~TestIterator() {} //Determines whether there is a next element bool HasNext() { if(curr >= m_ts->getCount()) { return false; } return true; } //What is returned is actually the next element of the iterator in the collection class int Next() { int data = m_ts->getData(curr); curr++; return data; } //Reset node information void reset() { curr=0; } private: TestVector* m_ts; int curr; }; int main() { //Create a collection class and insert the relevant data TestVector * test = new TestVector(); test->push(5); test->push(8); test->push(6); test->push(7); test->push(3); test->push(2); cout<<"count:"<<test->getCount()<<endl; TestIterator *itr = test->CreateTestIterator(); int num = 0; //The element here is an int, so it can be printed directly. There can be other types while(itr->HasNext()) { cout<<" num "<<num <<"is "<<itr->Next()<<endl; num ++; } for(int i=0;i<test->getCount(); i++) { cout<<" i "<<i<<" is" <<test->getData(i)<<endl; } if(test != nullptr) { delete test; test= nullptr; } return 0; }
Note: it is found that the above code cannot be compiled because the two classes refer to each other.
3: Think about solving the problem of reference compilation
It can be treated with virtual basis functions.
You can use C + + template definition to avoid it and directly replace it with type.
//In the above demo, it is found that the compilation fails, which is the reason for the related references between classes, so an intermediate class is needed to implement it //The initialization of iterator test class needs to use collection class. Here, a base class of collection class is constructed to realize the initialization test of iterator //The collection class needs to use the iterator class for related initialization. It also needs to construct an iterator basic class for the collection class interface to call #include <iostream> #include <vector> using namespace std; class baseIterator{ public: virtual ~baseIterator() = default; virtual bool HasNext() = 0; virtual int Next() = 0; virtual void reset() = 0; }; //The method containing the necessary collection class, which is passed in to implement the call of the iterator class baseTestIterator{ public: virtual ~baseTestIterator() = default; virtual baseIterator * CreateTestIterator()= 0; virtual int getCount() = 0; virtual int getData(int d) = 0; }; class TestIterator: public baseIterator { public: //The class and collection subscript of the collection to operate on TestIterator(baseTestIterator * ts):m_ts(ts), curr(0) {} ~TestIterator() {} //Determines whether there is a next element bool HasNext() { if(curr >= m_ts->getCount()) { return false; } return true; } //What is returned is actually the next element of the iterator in the collection class int Next() { int data = m_ts->getData(curr); curr++; return data; } //Reset node information void reset() { curr=0; } private: baseTestIterator* m_ts; int curr; }; class TestVector: public baseTestIterator{ public: //Tectonics and Deconstruction TestVector():m_itr(nullptr), count(0) {} ~TestVector() { if(m_itr != nullptr) { delete m_itr; m_itr = nullptr; } } //Class itself inserts and gets elements void push(int d) { m_testvector.push_back(d); count++; } void pop() { m_testvector.pop_back(); count--; } int getCount() { return count; } int getData(int d) { if(d < count) { return m_testvector[d]; } return -1; } //The method of creating iterators is defined here, and the access of array elements is controlled through iterators baseIterator * CreateTestIterator() { if(m_itr == nullptr) { m_itr = new TestIterator(this); } return m_itr; } private: vector<int> m_testvector; baseIterator * m_itr; //Here in order to correspond to the release int count; }; int main() { //Create a collection class and insert the relevant data TestVector * test = new TestVector(); test->push(5); test->push(8); test->push(6); test->push(7); test->push(3); test->push(2); cout<<"count:"<<test->getCount()<<endl; baseIterator *itr = test->CreateTestIterator(); int num = 0; //The element here is an int, so it can be printed directly. There can be other types while(itr->HasNext()) { cout<<" num "<<num <<"is "<<itr->Next()<<endl; num ++; } for(int i=0;i<test->getCount(); i++) { cout<<" i "<<i<<" is " <<test->getData(i)<<endl; } if(test != nullptr) { delete test; test= nullptr; } return 0; } //The iterator implementation of related set class data structures in C + + is similar, except that the template definition is added, and the next processing uses the pointer address + 1 instead of the template mechanism instead of the virtual basis function to handle the reference problem