gpt4 book ai didi

C++ 实现自定义类型的迭代器操作

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 36 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章C++ 实现自定义类型的迭代器操作由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

##动机 。

我们知道STL实现了很多算法(#include<algorithm>),如果项目是基于STL构建那么能够最大化使用现有代码当然是最好的。在STL中容器和算法之间的桥梁是迭代器。所以在定义好自定义类型的容器后,接下来就是迭代器的实现.

STL中的迭代器 。

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

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

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

_Ty就是元素的类型 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template < class _Category,
  class _Ty,
  class _Diff = ptrdiff_t ,
  class _Pointer = _Ty *,
  class _Reference = _Ty&>
  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是迭代器的类型,主要有以下几种 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ITERATOR STUFF (from <iterator>)
// ITERATOR TAGS (from <iterator>)
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都用到哪些操作符吧 。

?
1
2
3
4
5
6
7
8
9
10
11
12
// TEMPLATE FUNCTION count_if
template < class _InIt,
  class _Pr> 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);
  }

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iterator>
template < class T>
class MyIterator : public iterator<input_iterator_tag, T>{
  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; //实际的内容指针,通过该指针跟容器连接
};

自定义容器 。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
template < class T>
class myVector{
public :
  typedef MyIterator<T> 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函数,可以看到用法完全一样 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
bool eq_10( int k){
  return k == 10;
}
int main(){
  //自定义类型
  myVector< int > mv(10);
  mv[3] = 10; mv[9] = 10;
  myVector< int >::iterator it = mv.begin();
  cout << "mv:" <<endl;
  while (it != mv.end()){
  cout << *(it++) << " " ;
  }
  cout << endl;
  cout << count_if(mv.begin(), mv.end(), eq_10) << endl;
  //STL 容器
  vector< int > v(10,0);
  v[3] = 10; v[9] = 10;
  vector< int >::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):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//T为某种迭代器
template < class T>
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< int > mv(10);
  mv[3] = 10; mv[9] = 10;
  //STL 容器
  vector< int > 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++ 自定义迭代器(实现++递增两格) 。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#pragma once
//MyIterator.h
#include <iterator>
#include <exception>
template < typename Container>
class MyIterator : public std::iterator<std::random_access_iterator_tag, typename Container::value_type>
{
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<T> vec 成员函数vec.begin()或全局函数begin(vec)
//我们做个假冒的全局函数 start(vec) over(vec)
template < typename Container>
MyIterator<Container> start(Container& c)
{
     MyIterator<Container> mi(c);
     mi.begin();
     return mi;
}
template < typename Container>
MyIterator<Container> over(Container & c)
{
     MyIterator<Container> mi(c);
     mi.end();
     return mi;
}

//main.cpp 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>
#include "MyIterator.h"
#include <list>
using namespace std;
//因继承了iterator<std::random_access_iterator_tag,Container::value_type>才拥有此特性
template < typename Iterator>
void printIterator( const Iterator &It)
{
   cout << typeid ( typename iterator_traits<Iterator>::iterator_category).name() << endl;
}
int main()
{
   vector< int > coll{ 1,2,3,4,5,6,7,8,9,10 };
   MyIterator<decltype(coll)> myit(coll);
   printIterator(myit);
   for (; myit != over(coll); ++myit)
   {
     cout << *myit << ends;
   }
   system ( "pause" );
   return 0;
}

效果:

C++ 实现自定义类型的迭代器操作

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我。如有错误或未考虑完全的地方欢迎留言讨论,望不吝赐教.

原文链接:https://blog.csdn.net/XiaoHeiBlack/article/details/77014626 。

最后此篇关于C++ 实现自定义类型的迭代器操作的文章就讲到这里了,如果你想了解更多关于C++ 实现自定义类型的迭代器操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com