本文概要:
本文主要是模拟实现STL中迭代器和const迭代器的,主要阐述的一个问题就是,为什么我们在设计迭代器的时候需要使用三个模板参数呢
在设计迭代器的时候,我们有下面的代码
#include<iostream>
using namespace std;
template<class T>
struct _ListNode
{
_ListNode<T>* _next;
_ListNode<T>* _prev;
T _data;
_ListNode(T d = 0)
:_data(d)
, _next(NULL)
, _prev(NULL)
{}
};
//这个T标记的是维护的数据类型,Ref是引用,这个引用是对数据的引用,就是这里面data的引用
//Ptr是指针,这个指针也是指向数据data的指针这两个模板类型我们可以在
//List这个类里面使用,因为在编写List_Iterator的时候,会经常使用Ref和Ptr
template<class T, class Ref, class Ptr>
class List_Iterator
{
typedef _ListNode<T> Node;
typedef List_Iterator<T, Ref, Ptr> Self; //这个地方写的 有点失误了,就是把List_Iterator的单词写错了
public:
List_Iterator(Node* it)
:_it(it)
{}
//List_Iterator& operator++()
Self& operator++()
{
_it = _it->_next;
return *this;
}
Self operator++(int) //注意前置++返回的是引用,而后置++返回的是Self
{
Node* tmp = _it;
_it = _it->_next;
return tmp;
}
//T& operator*()
Ref operator*()
{
return _it->_data;
}
bool operator!=(const Self& it)
{
return _it != it._it; //一开始写这个!=运算符重载的时候也出现了错误,就是我一开始是拿this和&it比
//这显然是不对的,两个迭代器不可能是相等的,所以这个时候应该是拿
//这两个迭代器所指向的内容来比较,就是那他们的成员变量来 进行比较才正确
}
private:
Node* _it;
};
//这里我们需要做一个修改就是,我们需要把这个链表定义成一个双向的有头的循环链表
//这个工作就是要在构造函数的时候去做了
//所以这里_tail就不需要了
//有头结点,_head维护了一个头结点,但是这个节点不放置任何的数据,因为这样在后面的增删查改的时候使用的时候会非常的方便
template<class T>
class _List
{
typedef _ListNode<T> Node;
public:
typedef List_Iterator<T, T&, T*> Ierator;
//const迭代器
typedef List_Iterator<T, const T&, const T*> Const_Ierator;
_List()
:_head(new Node) //这里报了一个错误就是,没有合适的构造函数可以使用,原因是我上面写_ListNode的时候
//传参了,但是这里没有传参数,所以我上面的额时候把传递的参数默认为d = 0这个时候就算是我不传递参数
//也没有什么问题了
// , _tail(_head)
{
_head->_next = _head;
_head->_prev = _head;
}
Node* begin()
{
if (_head->_next == _head) //这里做了一个判断就是当我们的链表是空的时候,就不能直接返回next
{
return NULL;
}
return _head->_next;
}
Node* end()
{
if (_head->_next == _head)
{
return NULL;
}
return _head;
}
void Pushback(const T& data)
{
Node* cur = new Node(data);
cur->_prev = _head->_prev;
_head->_prev = cur;
cur->_next = _head;
cur->_prev->_next = cur;
}
void Print()
{
Const_Ierator it = begin(); //这个原因是,我们的begin不是 const的,但是我们的const_ietator是const的
while (it != end())
{
cout << *it << endl;
it++;
}
}
private:
Node* _head;
// Node* _tail;
};
void TestList()
{
_List<int> l;
l.Pushback(0); //一开始的时候,我这里设置的这个参数是引用,这个时候是辩不过的,因为我们的0是在常量区的
l.Pushback(1);
l.Pushback(2);
/*_List<int>::Ierator it = l.begin();
cout << *it << endl;
++it;
cout << *it << endl;
++it;
cout << *it << endl;*/
_List<int>::Ierator it = l.begin();
*it = 5;
l.Print();
}
这里想重点比较一下普通迭代器和const迭代器,这里我们想看我们的普通迭代器的定义,
template<class T, class Ref, class Ptr>
class List_Iterator
{
typedef _ListNode<T> Node;
typedef List_Iterator<T, Ref, Ptr> Self; //这个地方写的 有点失误了,就是把List_Iterator的单词写错了
public:
List_Iterator(Node* it)
:_it(it)
{}
//List_Iterator& operator++()
Self& operator++()
{
_it = _it->_next;
return *this;
}
Self operator++(int) //注意前置++返回的是引用,而后置++返回的是Self
{
Node* tmp = _it;
_it = _it->_next;
return tmp;
}
//T& operator*()
Ref operator*()
{
return _it->_data;
}
bool operator!=(const Self& it)
{
return _it != it._it; //一开始写这个!=运算符重载的时候也出现了错误,就是我一开始是拿this和&it比
//这显然是不对的,两个迭代器不可能是相等的,所以这个时候应该是拿
//这两个迭代器所指向的内容来比较,就是那他们的成员变量来 进行比较才正确
}
private:
Node* _it;
};
这里只是一个普通的迭代器的实现,一开始我一直疑惑的一个问题就是,为什么这里在设计的时候需要设计三个模板参数 呢,因为是为了实现迭代器的复用,这个时候还是需要看一下我们的list中对于迭代器的使用
class _List
{
typedef _ListNode<T> Node;
public:
typedef List_Iterator<T, T&, T*> Ierator;
//const迭代器
typedef List_Iterator<T, const T&, const T*> Const_Ierator;
_List()
:_head(new Node)
这里我只截图了迭代器的一部分,想看全部的可以从上面来看,这里需要定义一个普通的迭代器的时候,使用typedef List_Iterator
Ref operator*()
{
return _it->_data;
}
因为我们在list中使用的时候是按照下面的形式进行组织的
typedef List_Iterator<T, const T&, const T*> Const_Ierator;
所以在上面的那个Ref operator*()里面 返回值就变成了const的,这个时候const_iterator所指向的内容就不可变了