首页 > 设计1.0 -- iterator 和const_iterator底层的模拟实现

设计1.0 -- iterator 和const_iterator底层的模拟实现

本文概要:

本文主要是模拟实现STL中迭代器和const迭代器的,主要阐述的一个问题就是,为什么我们在设计迭代器的时候需要使用三个模板参数呢

在设计迭代器的时候,我们有下面的代码

#include
using namespace std;template<class T>
struct _ListNode
{_ListNode* _next;_ListNode* _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 Node;typedef List_Iterator 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 Node;public:typedef List_Iterator Ierator;//const迭代器typedef List_Iteratorconst 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::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 Node;typedef List_Iterator 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 Node;public:typedef List_Iterator Ierator;//const迭代器typedef List_Iteratorconst T&, const T*> Const_Ierator;_List():_head(new Node)   

这里我只截图了迭代器的一部分,想看全部的可以从上面来看,这里需要定义一个普通的迭代器的时候,使用typedef List_Iterator

Ref operator*(){return _it->_data;}

因为我们在list中使用的时候是按照下面的形式进行组织的

typedef List_Iteratorconst T&, const T*> Const_Ierator;

所以在上面的那个Ref operator*()里面 返回值就变成了const的,这个时候const_iterator所指向的内容就不可变了

更多相关:

  • 随着国内内控的兴起,经常有人会问,内控跟IT安全有什么关系?为什么内控话题总是被搞信息安全的人经常提及?我想,一方面,是因为内控与信息安全存在内在的联系,另一方面,则是信息安全从业人员为了找到体现自身价值的附着点吧。 内控与IT的关系企业内部控制(简称“内控”)是一个涉及广泛的概念,根据ISACA组织的定义,内部控制指“为减少风险所...

  • list_for_each_safeBidirect-list list_for_each_safe().https://biscuitos.github.io/blog/LIST_list_for_each_safe/...

  • /*hanzhiguang coded at 2009.07.30 1:20*/ // nesting_map.cpp : Defines the entry point for the console application. // /*-----------------------------------------------...

  • 已知k个已排序链表头节点指针,将这k个链表合并,合并后仍为有序的 ,返回合并后的头节点 如下三个链表: 合并后的结果如下: 方法一(STL sort算法进行排序): 先将输入的排序链表插入一个迭代器中,vector数组中国呢直接对数组中的链表节点进行按值排序即可 实现算法如下,最终实现源码见文末: bool cmp(Dat...

  • 本题要求实现一个函数,找到并返回链式表的第K个元素。 函数接口定义: ElementType FindKth( List L, int K ); 其中List结构定义如下: typedef struct LNode *PtrToLNode; struct LNode {ElementType Data;PtrToLNode Ne...

  • 一、前述 企业中linux搭建ftp服务器还是很实用的,所以本文针对centoos7和centoos6搭建服务器教程做个总结。 二、具体 1、显示如下图则表示已安装 vsftp软件。如果未显示则需要安装vsftpd软件。 如果没有则通过yarm源进行安装 yum install -y vsftpd 2、安装完成之后 进入到ftp的根...

  • mutable的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。   在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。   我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成cons...

  • 前言:很多人都把const int * 、int * const、int const* 的区别和联系搞混,我自己在学习C++的过程中,也经常性          弄不 清楚,今天特意总结一下,作为学习笔记记录下来。 一,const修饰符用于指针         将const用于指针有些很微妙的地方,有两种不同的方式将const关键...

  •   注意,前情提示: 本代码基于《Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)》 传送门Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)_你挚爱的强哥❤给你发来1条消息❤-CSDN博客   在/api/demo/文件夹下面创建exportAndDownl...

  • 项目结构 main.js(入口文件,开启9999端口监听,实现RESTful风格接口访问) const express = require("express"); const app = express(); const port = 9999;//设置端口号,如果端口号被占用需要自己修改,否则无法跑起来(建议不要用80和80...

  • ES6 你可能不知道的事 – 基础篇 转载 作者:淘宝前端团队(FED)- 化辰 链接:taobaofed.org/blog/2016/07/22/es6-basics/   序   ES6,或许应该叫 ES2015(2015 年 6 月正式发布),对于大多数前端同学都不陌生。   首先这篇文章不是工具书,不会去过多谈概念,而是...