C++迭代器在链表中的简单实现

什么是迭代器?

An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators (with at least the increment (++) and dereference (*) operators).

那么迭代器有什么用呢?,在之前的文章中,实现了单双链表的基本功能。使其可以以一个个的节点来分布存储元素,并有一系列的相关操作。但我们定义一个数据结构,就是定义一系列数据的存储类型并合理的使用它们。那么在定义完成之后,开始使用自定义的数据结构时,我们发现当我们需要遍历访问自定义的数据结构时我只能通过下标运算符来访问,而且对于不同的容器我都需要重载[]运算符,那么能不能定义一种类型可以遍历访问所有容器的类型呢?
——答案是有,那就是定义迭代器。

iterator类实现前的分析:

首先对iterator类的设计进行分析:

  1. 数据成员的类型与数据成员:
    根据迭代器的定义,至少实现的功能是*++这两个运算符,其中使用对迭代器对象使用*运算符可以获取容器当前的值。那么根据这样的情况来看迭代器的数据类型应该为Node*,需要定义此类型的数据成员。

  2. 构造函数:
    构造函数的目的是初始化类中的数据成员,所以要使用构造函数指明

  3. 成员函数与运算符重载:
    需要重载++*运算符,实现迭代器的基本核心功能。按照语义,重载运算符的函数返回类型必须是迭代器类型。

iterator类的实现:

  • 数据成员的定义:
template<typename T>
class iterator
{
private:
	 Node<T>* node;
 	//other codes
 }

因为迭代器也是一个指向Node类型的指针,所以把iterator类中声明一个Node的数据成员。

  • 构造函数:
iterator(Node<T>* x):node(x){}
iterator():node(NULL){}

很明显一个iterator类中的数据成员即它自己指向的节点的地址,所以说我们在构造函数中要把创建对象中的数据成员初始化为它要指向的地方。

  • 重载的运算符:
 iterator<T> operator++() {
	  node = node->next;
	  return this;
 }
 T& operator*()const {
 	 return node->value;
 }

这里要注意this的使用方法,在实际情况下例如

iterator iter;//创建一个iterator类型的对象iter
iter.Show();//假如有一个void Show();

那么iter.Show()其实就相当于Show(iter),将对象iter传入到函数Show()的this参数中去,隐式给函数赋值。所以上面的node = node->next;其实就相当于this.node = this.node->next;只不过this是隐式的故可以省略。

iterator类在别的类中的使用

好以上我们已经定义好了iterator类,但是我们怎么要在其它类中来使用它呢?要知道在使用的时候只会使用容器类型,而iterator类型是作为一个数据成员来使用的,那么也就是说,我们需要把citerator类变成容器类的一个类型成员,让容器类型可以通过::运算符来找到iterator类类型。

class forward_list {
public:
	 typedef iterator<T> iterator;
	 //other defines
}

如此声明之后我们就可以forward_list::iterator iter来声明一个iter变量了。如下图有图有真相:
C++迭代器在链表中的简单实现_第1张图片

定义类数据类型之后,就可以对他进行使用了。
但同时还有一个问题就是原来没有迭代器时的函数,要发生一些改变。如begin,end…
根据STL的使用经验,begin()应该返回一个迭代器类型,那么我直接改一下迭代器类型然后运行下发现ok。这是从STL的使用经验以及根据程序设计要求所得出的修改方法。接下来就来关注为什么修改一下返回类型而不需要修改其他的就可以正确运行:

iterator begin() {
  return HeadNode->next;
 }

itrator类只有一个数据成员,所以我返回这个数据成员会隐式生成一个iterator类对象并返回。写一个简单的小程序来判断:

#include
#include
class Iter_same {
public:
    int a;
	Iter_same(int x) :a(x) {}
	Iter_same() :a() {};
};
class Vector_same {
public:
    Iter_same Show1() { return 3; }
    Iter_same Show2(){return NULL;}
};
int main() {
Vector_same vec;
Iter_same it1,it2;
it1=vec.Show1();
it2=vec.Show2();
//第一个输出3,第二个输出0 当没有返回值时将会输出构造函数所给的值(在本例中)
std::cout << it1.a<<it2.a;
}

这说明函数在返回一个类类型的时候,可以隐式的返回一个类的所有数据成员,这样编译器在编译的时候会隐式创造一个对象用来返回。
如在本例中,Vector_same类中的Show1()函数返回一个Iter_same类,但是可以看到在Show()函数中只返回了一个数据3,但仍成功的返回了这个对象。具体过程为:
函数应该返回一个类,这个类有一个数据成员,那么编译时编译器创建临时对象,然后用这个返回的值初始化临时对象的数据成员,最后返回这个临时对象。
嗯以上就是这次练习的所有内容,源码如下:
完整的含有迭代器的单链表
返回临时对象的测试代码

你可能感兴趣的:(C/C++,pratice)