首先,迭代器是STL里的一大重点,它实现了对各种封装容器的遍历,保证了容器封闭的同时能够将其应用到STL中的算法里面。 其本质还是对容器数据成员的指针进行操作,并重载了一些操作符以实现简便操作。
纸上得来终觉浅,上代码。
- 首先构造一个双向链表的结点Listnode
#include<iostream>
#include<vector>
using namespace std;
template <typename T1>
struct Listnode {
Listnode* next_node;
Listnode* pre_node;
T1 val;
Listnode() :next_node(nullptr) {};
Listnode(Listnode& node) :next_node(node.next_node), pre_node(node.pre_node), val(node.val) {};
Listnode(T1 _val, Listnode* nextnode=nullptr, Listnode* prenode = nullptr) :val(_val), next_node(nextnode), pre_node(prenode) {};
};
- 其次构造一个链表的类list,其中包含了内部类list_iterator
template<typename T>
class list {
private:
Listnode<T>* head, * tail;
size_t size=0;
private:
class list_iterator {
private:
Listnode<T>* ptr;
public:
list_iterator(Listnode<T>* _ptr = nullptr) :ptr(_ptr) {};
};
public:
typedef list_iterator iterator;
list() {
head = nullptr;
tail = nullptr;
}
void push_back(const T t) {
if (head == nullptr) {
head = new Listnode<T>(t);
tail = head;
}
else {
tail->next_node = new Listnode<T>(t,nullptr,tail);
tail = tail->next_node;
}
size++;
}
void pop_back() {
if (head == nullptr) {
cerr << "pop_back error, list is empty!" << endl;
}
else {
Listnode<T>* temp =tail;
tail = tail->pre_node;
tail->next_node = nullptr;
delete temp;
}
size--;
}
iterator begin const() {
return iterator(head);
}
iterator end const() {
return iterator();
}
};
类list当中,所有的成员变量都是private,包含的迭代器也是private,仅能通过几个成员函数进行访问,成员函数与STL容器基本保持一致的功能。
其中,迭代器类list_iterator,声明了一个私有变量指向单个结点,并定义一个构造函数以方便list获取首尾迭代器。
以上都比较明了,接下来重点说迭代器的内部成员函数实现。
class list_iterator {
private:
Listnode<T>* ptr;
public:
list_iterator(Listnode<T>* _ptr = nullptr) :ptr(_ptr) {};
T& operator *() const {
return ptr->val;
}
//前置++操作符
list_iterator& operator++() {
ptr = ptr->next_node;
return *this;
}
//后置++操作符
list_iterator operator++(int) {
Listnode<T>* temp = ptr;
ptr = ptr->next_node;
return list_iterator(temp);
}
list_iterator& operator--() {
ptr = ptr->pre_node;
return *this;
}
list_iterator operator--(int) {
Listnode<T>* temp = ptr;
ptr = ptr->pre_node;
return list_iterator(temp);
}
Listnode<T>* operator->() const {
return ptr;
}
bool operator != (list_iterator t) const {
return t.ptr != this->ptr;
}
};
其中,都是对各种操作符进行重载:
- 操作符*,返回当前迭代器指向的结点的数据
- 前置操作符++,使迭代器向后位移一个结点,直接返回位移后结点迭代器的引用
- 后置操作符++,使迭代器向后位移一个结点,但返回位移前的结点迭代器。为了区分前置与后置的操作符,语法规定后置操作符需要写入int加以区分。而为什么返回不是引用?因为返回的是一个局部变量
- 前置操作符--,后置操作符--同理
- 操作符->,为了能够直接由迭代器访问容器的内部数据成员,因此返回迭代器对应结点的指针
- 关系操作符!=或==,对比两个迭代器是否指向同一个结点,返回bool类型
以上的操作,便能够完成使用迭代器对list内部成员的访问,无需了解list的内部构造。