利用C++ 怎么实现一个迭代器功能
创始人
2024-12-15 19:21:37
0次

STL中的迭代器

迭代器模式是一种经典的设计模式,而STL的迭代器实现用到了模板的一些特性和技能,在这里稍微介绍一下

下面是STL中结构体iterator的定义,这么定义是给后面的算法多态和萃取时(具体见书中介绍)使用的。

其中的_Category 和_Ty 没有默认值,需要自己给参数的。

_Ty就是元素的类型

template
 struct iterator
 { // base type for iterator classes
 typedef _Category iterator_category;
 typedef _Ty value_type;
 typedef _Diff difference_type;
 typedef _Diff distance_type; // retained
 typedef _Pointer pointer;
 typedef _Reference reference;
 };

而_Category是迭代器的类型,主要有以下几种

// ITERATOR STUFF (from )
// ITERATOR TAGS (from )
struct input_iterator_tag //只读
 { // identifying tag for input iterators
 };
struct _Mutable_iterator_tag //只写
 { // identifying tag for mutable iterators
 };
struct output_iterator_tag //只写
 : _Mutable_iterator_tag
 { // identifying tag for output iterators
 };
struct forward_iterator_tag //前向移动
 : input_iterator_tag, _Mutable_iterator_tag
 { // identifying tag for forward iterators
 };
struct bidirectional_iterator_tag //可双向移动
 : forward_iterator_tag
 { // identifying tag for bidirectional iterators
 };
struct random_access_iterator_tag //随机读写
 : bidirectional_iterator_tag
 { // identifying tag for random-access iterators
 };
//...

自定义迭代器

我希望迭代器有以下操作:*,++。另外还想要通过迭代器调用count_if函数。那看一下count_if都用到哪些操作符吧

// TEMPLATE FUNCTION count_if
template inline
 typename iterator_traits<_InIt>::difference_type
 _Count_if(_InIt _First, _InIt _Last, _Pr _Pred)
 { // count elements satisfying _Pred
 typename iterator_traits<_InIt>::difference_type _Count = 0;
 for (; _First != _Last; ++_First)
 if (_Pred(*_First))
  ++_Count;
 return (_Count);
 }

可以看到用到了++,!=,*。所以我们的迭代器需要把这些都给实现了。代码很简单:

#include
template
class MyIterator : public iterator{
 public:
 MyIterator(T* p){
  _ptr = p;
 }
 //赋值
 MyIterator& operator = (const MyIterator &iter)
 {
 _ptr = iter._ptr;
 }
 //不等于
 bool operator != (const MyIterator &iter)
 {
 return _ptr!= iter._ptr;
 }
 //等于
 bool operator == (const MyIterator &iter)
 {
 return _ptr == iter._ptr;
 }
 //前缀自加
 MyIterator& operator ++ ()
 {
 _ptr++;
 return *this;
 }
 //后缀自加
 MyIterator operator ++ (int)
 {
 MyIterator tmp= *this;
 _ptr++;
 return tmp;
 }
 //取值
 T& operator * ()
 {
 return *_ptr;
 }
 private:
 T* _ptr;//实际的内容指针,通过该指针跟容器连接
};

自定义容器

下面给出个简单的数组容器,实现了数组的基本操作。并把刚刚定义的迭代器内置了

template
class myVector{
public:
 typedef MyIterator iterator;//所有类型迭代器用同一个名字,便于写出更通用的代码
 myVector(){
 _selfElems = new T[32];
 _count = 32;
 init();
 }
 myVector(int n){
 _selfElems = new T[n];
 _count = n;
 init();
 }
 void init(){
 memset(_selfElems, 0, sizeof(T)* _count);
 }
 //常用接口
 T& operator[](int i){
 return _selfElems[i];
 }
 iterator begin(){
 return iterator(_selfElems);
 }
 iterator end(){
 return iterator(_selfElems + _count);
 }
 int size() const {
 return _count;
 }
private:
 T* _selfElems;
 int _count;
};

##测试

定义一个vector和自定容器myVector,用迭代器去访问,并通过迭代器使用conunt_if函数,可以看到用法完全一样

bool eq_10(int k){
 return k == 10;
}
int main(){
 //自定义类型
 myVector mv(10);
 mv[3] = 10; mv[9] = 10;
 myVector::iterator it = mv.begin();
 cout <<"mv:"< v(10,0);
 v[3] = 10; v[9] = 10;
 vector::iterator it1 = v.begin();
 cout << "v:" << endl;
 while (it1 != v.end()){
 cout << *(it1++) << " ";
 }
 cout << endl;
 cout << count_if(mv.begin(), mv.end(), eq_10) << endl;
 getchar();
 return 0;

总结和思考

所以简单来说,如果想要定义自己容器的迭代器并想通过迭代器调用STL的算法函数的话。首先继承iteroter,然后实现必要的操作符即可。不过具体的算法函数对迭代器类型是有要求的,这个需要自己把握。

在这个简单的示例里面,直接用myVector的指针(mv._ptr)也是可以调用count_if的,因为STL通过模板偏特化技术使得迭代器也支持原生指针。不过既然把访问元素都放到迭代器中了,我们就可以对所有的容器用统一的方式访问了,而不用暴露每个容器的细节(myVector::_ptr):

//T为某种迭代器
template
void display(T it, T end){
 T it1 = it;
 while (it1 != end){
 cout << *(it1++) << " ";
 }
 cout << endl;
 cout << count_if(it,end, eq_10) << endl;
}
int main(){
 //自定义类型
 myVector mv(10);
 mv[3] = 10; mv[9] = 10;
 //STL 容器
 vector v(10, 0);
 v[3] = 10; v[9] = 10;
 //vector 和 myVector底层实现有很大区别,但是可用同一个函数做遍历等操作
 display(mv.begin(), mv.end());
 display(v.begin(), v.end());
 getchar();
 return 0;
}

迭代器赋予了容器更多的功能和通用性

补充知识:C++ 自定义迭代器(实现++递增两格)

//效果每次迭代器加移动两格

#pragma once
//MyIterator.h
#include 
#include 
template
class MyIterator :public std::iterator
{
protected:
  Container& container;
  typename Container::iterator pos;
public:
  explicit MyIterator(Container& c) :container(c), pos(c.begin()){}
  MyIterator(const MyIterator& rhs) :container(rhs.container),pos(rhs.pos) {}
  MyIterator& operator =(const MyIterator& rhs)
  {
    throw_ex(rhs.container);
    pos = rhs.pos;
    return *this;
  }
  //--等就省略了...
  MyIterator& operator ++()
  {
    auto tmp = container.end() - 1;
    if (pos == tmp)
      ++pos;
    else
      pos += 2;
    return *this;
  }
  bool operator ==(const MyIterator& rhs)const
  {
    try
    {
      if (&rhs.container == &container)
        return pos == rhs.pos;
      else
      {
        throw exception("对象错误");
      }
    }
      catch (exception &e)
      {
        cout << e.what();
        exit(EXIT_FAILURE);
      }
    }
bool operator !=(const MyIterator& rhs)const
{
  return !(*this == rhs);
}
typename Container::value_type & operator *()
{
      return *pos;
}
void begin()
{
  pos = container.begin();
}
void end()
{
  pos = container.end();
}
private:
  void throw_ex(const Container& c)
  {
    try
    {
      if (&c == &container)
        return;
      else
        throw exception("Copy 构造失败");
    }
    catch (exception &e)
    {
      cout << e.what();
      exit(EXIT_FAILURE);
    }
  }
};
//无法使用或添加vector vec 成员函数vec.begin()或全局函数begin(vec)
//我们做个假冒的全局函数 start(vec) over(vec)
template
MyIterator start(Container& c)
{
    MyIterator mi(c);
    mi.begin();
    return mi;
}
template
MyIterator over(Container & c)
{
    MyIterator mi(c);
    mi.end();
    return mi;
}

//main.cpp

#include 
#include 
#include "MyIterator.h"
#include 
using namespace std;
//因继承了iterator才拥有此特性
template
void printIterator(const Iterator &It)
{
  cout << typeid(typename iterator_traits::iterator_category).name() << endl;
}
int main()
{
  vector coll{ 1,2,3,4,5,6,7,8,9,10 };
  MyIterator myit(coll);
  printIterator(myit);
  for (; myit != over(coll); ++myit)
  {
    cout << *myit << ends;
  }
  system("pause");
  return 0;
}

效果:

利用C++ 怎么实现一个迭代器功能

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...