【C++之容器适配器】反向迭代器的实现

目录

    • 前言
    • 一、反向迭代器的实现
      • 1. 底层
      • 2. 成员函数
        • 1. 构造函数
      • 2. operator*()
        • 3. operator->()
        • 4. 前置++
        • 5. 后置++
        • 6. 前置--
        • 7. 后置--
        • 8. operator!=()
        • 9. operator==()
    • 二、vector反向迭代器的实现
      • 1. vector的正向迭代器
      • 2. vector反向迭代器的实现
      • 3. 测试vector的反向迭代器
    • 三、list反向迭代器的实现
      • 1. list的正向迭代器
      • 2. list反向迭代器的实现
      • 3. 测试list的反向迭代器

前言

前面我们学习的C++中适配器模式的一个例子:栈和队列的模拟实现,C++中的适配器模式本质上是一种代码复用的手段,其可以实现相同功能代码的复用,而不会写出一些重复的代码,从而造成代码的冗余。C++中另一个适配器模式的经典设计就是反向迭代器的封装,其通过适配正向迭代器的功能,从而实现了反向迭代器的功能,本篇文章将重点讲解C++中反向迭代器的适配模式,并以list和vector的反向迭代器为例。

一、反向迭代器的实现

1. 底层

反向迭代器的底层是适配了正向迭代器,所以反向迭代器的成员变量是正向迭代器。其形式如下:

template<class Iterator,class Ref,class Ptr>
	struct Reverse_iterator
	{
		Iterator _it;
	}

2. 成员函数

1. 构造函数

反向迭代器中只有一个成员变量:正向迭代器,所以我们需要实现一个带参的构造函数将正向迭代器作为参数来对反向迭代器的成员进行初始化。

// 构造函数
		Reverse_iterator(const Iterator& it)
			:_it(it)
		{}

2. operator*()

在正向迭代器中,对正向迭代器进行解引用访问的是这个迭代器指向的结点中的数据,但是反向迭代器和正向迭代器有所不同,反向迭代器调用operator*()之后访问的是当前反向迭代器指向的结点的前一个结点的数据。

// * 
		Ref operator*()
		{
			Iterator tmp(_it);
			return *(--tmp);
		}
3. operator->()

operator->()的作用是求当前迭代器指向的结点中的数据的地址,所以可以通过调用operator*()之后再取地址,也可以直接返回上一个结点的数据的地址。

// ->
		Ptr operator->()
		{
			return &(operator*());
		}
4. 前置++

正向迭代器中的++是朝正方向走,单向迭代器是朝着反方向走,所以可以通过正向迭代器中的–进行实现

// ++
		Self& operator++()
		{
			--_it;
			return *this;
		}
5. 后置++

当反向迭代器的前置++实现了之后,后置++可以通过调用前置++的功能完成

// ++
		Self& operator++()
		{
			--_it;
			return *this;
		}
6. 前置–

正向迭代器中的–是朝反方向走,单向迭代器是朝着正方向走,所以可以通过正向迭代器中的++进行实现

	// --
		Self& operator--()
		{
			++_it;
			return *this;
		}
7. 后置–

当反向迭代器的前置–实现了之后,后置–可以通过调用前置–的功能完成

Self operator--(int)
		{
			Self tmp(*this);
			--(*this);
			return tmp;
		}
8. operator!=()

反向迭代器的!=可以通过正向迭代器的!=进行判断

	// !=
		bool operator!=(const Self& it)
		{
			return _it != it._it;
		}
9. operator==()

反向迭代器的operator==() 可以通过正向迭代器的 operator==()进行判断

// ==
		bool operator==(const Self& it)
		{
			return _it == it._it;
		}

二、vector反向迭代器的实现

1. vector的正向迭代器

vector的底层是一块连续的数组,其迭代器本质上是原生指针

// 正向迭代器
		typedef T* iterator;
		typedef const T* const_iterator;

	// 正向迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

2. vector反向迭代器的实现

// 反向迭代器
		typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

 // 反向迭代器
		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}
		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

		reverse_iterator rbegin() 
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

通过上面的代码我们不难看出,vector的反向迭代器的实现本质上就是将正向迭代器传给我们实现好的反向迭代器的第一个模板参数作为适配器,然后根据传的类型是普通类型还是const类型从而将反向迭代器分为普通反向迭代器和const版本的反向迭代器。

在实现反向迭代器中的rbegin()和rend()的时候需要注意:因为operator*()访问的是当前反向迭代器的上一个结点的数据,所以这里的rbegin()是正向迭代器的end()去适配得到的反向迭代器,当该反向迭代器进行解引用的时候,得到的是上一个结点的数据,也就是链表中的最后一个结点。rend()是正向迭代器中的begin()适配得到的反向迭代器,当该反向迭代器进行解引用的时候,得到的是上一个结点的数据,也就是头结点。

3. 测试vector的反向迭代器

  • 代码:

void test_vector_iterator()
{
	hjt::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);

	hjt::vector<int>::iterator vit = v.begin();
	while (vit != v.end())
	{
		cout << *vit << " ";
		vit++;
	}
	cout << endl;

}
  • 运行结果:
    在这里插入图片描述

三、list反向迭代器的实现

1. list的正向迭代器

list是一个带头双向循环链表,其底层是一个个的结点链接起来的,比赛顺序存储的容器,所以原生指针的行为无法完成迭代器对应的功能,所以list的正向迭代器我们需要自己封装一个自定义类型加上运算符重载实现对迭代器的*和->操作。具体实现我们再list中已经详细讲解,这里只附上对应代码:

	// list正向迭代器的封装
	template <class T,class Ref,class Ptr>
	struct __list_iterator
	{
		typedef ListNode<T> Node;
		typedef __list_iterator<T, Ref, Ptr> Self;
	public:
		// 成员函数
		// 构造函数
		__list_iterator(Node* node)
			:_node(node)
		{}

		// *
		Ref operator*()
		{
			return _node->_data;
		}
		// ->
		Ptr operator->()
		{
			return &_node->_data;
		}

		// ++
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;
			return tmp;
		}

		// --
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		Self operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}

		// !=
		bool operator!=(const Self& it) const
		{
			return _node != it._node;
		}

		// ==
		bool operator==(const Self& it) const
		{
			return _node == it._node;
		}


		// 成员变量
		Node* _node;
	};
  • list中的代码
// 正向迭代器
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

// 正向迭代器
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}

		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}

		const_iterator end() const
		{
			return const_iterator(_head);
		}

2. list反向迭代器的实现

// 反向迭代器
		typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

// 反向迭代器
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}
		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

在实现反向迭代器中的rbegin()和rend()的时候需要注意:因为operator*()访问的是当前反向迭代器的上一个结点的数据,所以这里的rbegin()是正向迭代器的end()去适配得到的反向迭代器,当该反向迭代器进行解引用的时候,得到的是上一个结点的数据,也就是链表中的最后一个结点。rend()是正向迭代器中的begin()适配得到的反向迭代器,当该反向迭代器进行解引用的时候,得到的是上一个结点的数据,也就是头结点。

3. 测试list的反向迭代器

  • 代码:
void test_reverse_iterator()
{
	hjt::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(6);

	// 使用反向迭代器进行遍历
	hjt::list<int>::reverse_iterator rlit = lt.rbegin();
	while (rlit != lt.rend())
	{
		cout << *rlit << " ";
		rlit++;
	}
	cout << endl;

}
  • 运行结果:
    在这里插入图片描述

你可能感兴趣的:(STL,c++,适配器模式,反向迭代器)