【C++】自主实现容器list

大家好,我是苏貝,本篇博客带大家了解如何自主实现list,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


下图是实现list的第一步

在这里插入图片描述

1. 构造函数

写出list的构造函数:创建哨兵位

在这里插入图片描述

因为要new Node,Node是自定义类型,因此要调用它的默认构造函数。我们来自己写一下Node的默认构造函数

在这里插入图片描述

2. push_back

在这里插入图片描述

3. 迭代器

写完了push_back后,我们想将list的内容打印出来,需要用到迭代器,所以我们要在list里面定义迭代器iterator

在这里插入图片描述

在前面实现string和vector中,迭代器都是指针,那list的迭代器也是指针吗?不是。String和vector的迭代器是指针的原因是:string/vector的是一块连续的空间,指针it++就是从当前元素跳到下一个元素
可是list不同,它是由许多不连续的空间通过指针链接在一起,指针it++不一定是从当前元素跳到下一个元素,所以list的迭代器是需要我们自己写的自定义类型

在这里插入图片描述

在命名空间zy中声明迭代器的类

在这里插入图片描述

我们还需要实现迭代器的!=、前置/后置++/–、*it的操作

在这里插入图片描述

问:需不需要重载>/<呢?不需要,因为比较的是地址,我们不能保证list中后面元素的地址一定大于前面元素的地址,因此重载>/<是无意义的

因为形参类型listIterator比较长,所以我们typedef一下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完成上面的3种操作后,再于类list 里写begin/end函数

在这里插入图片描述

Begin/end的返回值类型是迭代器,因此用_head->_next来新建一个迭代器x,return x。也可以返回匿名对象
在这里插入图片描述

还可以直接返回_head->_next,这是因为单参数的构造函数支持隐式类型转换,iterator的构造函数正是单参的,因此可以直接用_head->_next来创建一个类iterator的临时对象

在这里插入图片描述

这样就可以遍历list

在这里插入图片描述

4. Insert/erase/push_back/push_front/pop_back/pop_front

在这里插入图片描述

erase会导致迭代器失效,所以要返回pos对应的下一个元素的迭代器
在这里插入图片描述

接下来的4个函数会对insert/erase进行复用
在这里插入图片描述

注意:尾删的时候,pos不是end(),而是end()的前一个

在这里插入图片描述

5. size/empty

在这里插入图片描述

6. operator->

我们上面的测试都是用list来的,如果list<>中的类型是自定义类型,如下图的A,那我们的遍历也要修改,因为*it是A,A有2个成员变量

在这里插入图片描述
在这里插入图片描述

方法1:
既然*it是A,那么(*it)._a1就是_a1的值

在这里插入图片描述

方法2:
我们的迭代器是想让它类似于指针那样使用的,下图的指针ptr要访问_a1,就只需要ptr->_a1,我们的迭代器也想这样使用,那么就需要->运算符重载

在这里插入图片描述
在这里插入图片描述

返回的为什么是_data的地址?下面会说

在这里插入图片描述

It->_a1和it.operator->()->_a1是等价的。回答上面的问题,为什么->运算符重载的返回值是_data的地址?因为只有返回地址,才能通过地址->_a1来访问_a1。所以准确来讲,要想访问_a1,不应该是it->_a1,而应该是it->->_a1,但是编译器为了可读性,省略了一个->

7. const成员

我们在命名空间zy里再写一个函数来打印list的内容,因为我们对x只想读,因此用const修饰x

在这里插入图片描述

但是我们之前写的begin/end函数都是非const修饰的,因此const对象x不能调用非const的begin/end。为了解决这一问题,我们可以直接对begin/end用const修饰吗?
在这里插入图片描述

不能。直接用const修饰begin/end会导致PrintListInt函数的被const修饰的形参x的内容能被修改,为什么?

在这里插入图片描述
在这里插入图片描述

直接用const修饰begin/end,那就是const/非const对象都能调用begin/end,begin/end的返回值类型是iterator,类iterator对*运算符重载的返回值类型是引用,可读可写,因此这样的话,即使是const对象也能修改内容。

在这里插入图片描述

可是const对象本不应该能被修改,因此不能直接用const修饰begin/end。

解决方法:写begin/end的重载函数(用const修饰)

重载的Begin/end的参数用const修饰,那函数的返回值类型是什么?是const iterator吗?

问:const修饰的对象x,我们是不想让迭代器的指向修改,还是不想让迭代器指向的内容修改?迭代器指向的内容即x的内容。迭代器的指向是需要被修改的,如it++,让迭代器从当前元素指向下一个元素

如果是const iterator,那就是不想让迭代器的指向修改,而迭代器指向的内容可以修改。就像const int a=10;我们不能修改a,但是可以通过指针来修改a的值。
在这里插入图片描述

因此我们用const_iterator作为返回值类型,该类型之前没有被声明,因此我们需要声明该类型
在这里插入图片描述

声明const_iterator类型最简单的方法就是将iterator类(即listIterator类)拷贝一份,再对*/->的运算符重载修改
在这里插入图片描述

再于list类中typedef一下constlistIterator
在这里插入图片描述

这样就能保证const修饰的对象x,其内容不能被修改

在这里插入图片描述

但是listIterator和constlistIterator类很相似,只有类名和*/->的运算符重载的返回值类型不同,那我们可不可以写成一个模板类呢?将*/->的运算符重载的返回值类型作为模板参数

在这里插入图片描述

在这里插入图片描述

8. clear/析构函数

在这里插入图片描述

9. 拷贝构造/operator=

在这里插入图片描述

在这里插入图片描述


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值