- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
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;
}
|
效果:
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我。如有错误或未考虑完全的地方欢迎留言讨论,望不吝赐教.
原文链接:https://blog.csdn.net/XiaoHeiBlack/article/details/77014626 。
最后此篇关于C++ 实现自定义类型的迭代器操作的文章就讲到这里了,如果你想了解更多关于C++ 实现自定义类型的迭代器操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在努力做到这一点 在我的操作中从数据库获取对象列表(确定) 在 JSP 上打印(确定) 此列表作为 JSP 中的可编辑表出现。我想修改然后将其提交回同一操作以将其保存在我的数据库中(失败。当我使用
我有以下形式的 Linq to Entities 查询: var x = from a in SomeData where ... some conditions ... select
我有以下查询。 var query = Repository.Query() .Where(p => !p.IsDeleted && p.Article.ArticleSections.Cou
我正在编写一个应用程序包,其中包含一个主类,其中主方法与GUI类分开,GUI类包含一个带有jtabbedpane的jframe,它有两个选项卡,第一个选项卡包含一个jtable,称为jtable1,第
以下代码产生错误 The nested query is not supported. Operation1='Case' Operation2='Collect' 问题是我做错了什么?我该如何解决?
我已经为 HA redis 集群(2 个副本、1 个主节点、3 个哨兵)设置了本地 docker 环境。只有哨兵暴露端口(10021、10022、10023)。 我使用的是 stackexchange
我正在 Desk.com 中构建一个“集成 URL”,它使用 Shopify Liquid 模板过滤器语法。对于开始日期为 7 天前而结束日期为现在的查询,此 URL 需要包含“开始日期”和“结束日期
你一定想过。然而情况却不理想,python中只能使用类似于 i++/i--等操作。 python中的自增操作 下面代码几乎是所有程序员在python中进行自增(减)操作的常用
我需要在每个使用 github 操作的手动构建中显示分支。例如:https://gyazo.com/2131bf83b0df1e2157480e5be842d4fb 我应该显示分支而不是一个。 最佳答
我有一个关于 Perl qr 运算符的问题: #!/usr/bin/perl -w &mysplit("a:b:c", /:/); sub mysplit { my($str, $patt
我已经使用 ArgoUML 创建了一个 ERD(实体关系图),我希望在一个类中创建两个操作,它们都具有 void 返回类型。但是,我只能创建一个返回 void 类型的操作。 例如: 我能够将 book
Github 操作仍处于测试阶段并且很新,但我希望有人可以提供帮助。我认为可以在主分支和拉取请求上运行 github 操作,如下所示: on: pull_request push: b
我正在尝试创建一个 Twilio 工作流来调用电话并记录用户所说的内容。为此,我正在使用 Record,但我不确定要在 action 参数中放置什么。 尽管我知道 Twilio 会发送有关调用该 UR
我不确定这是否可行,但值得一试。我正在使用模板缓冲区来减少使用此算法的延迟渲染器中光体积的过度绘制(当相机位于体积之外时): 使用廉价的着色器,将深度测试设置为 LEQUAL 绘制背面,将它们标记在模
有没有聪明的方法来复制 和 重命名 文件通过 GitHub 操作? 我想将一些自述文件复制到 /docs文件夹(:= 同一个 repo,不是远程的!),它们将根据它们的 frontmatter 重命名
我有一个 .csv 文件,其中第一列包含用户名。它们采用 FirstName LastName 的形式。我想获取 FirstName 并将 LastName 的第一个字符添加到它上面,然后删除空格。然
Sitecore 根据 Sitecore 树中定义的项目名称生成 URL, http://samplewebsite/Pages/Sample Page 但我们的客户有兴趣降低所有 URL(页面/示例
我正在尝试进行一些计算,但是一旦我输入金额,它就会完成。我只是希望通过单击按钮而不是自动发生这种情况。 到目前为止我做了什么: Angular JS - programming-fr
我的公司创建了一种在环境之间移动文件的复杂方法,现在我们希望将某些构建的 JS 文件(已转换和缩小)从一个 github 存储库移动到另一个。使用 github 操作可以实现这一点吗? 最佳答案 最简
在我的代码中,我创建了一个 JSONArray 对象。并向 JSONArray 对象添加了两个 JSONObject。我使用的是 json-simple-1.1.jar。我的代码是 package j
我是一名优秀的程序员,十分优秀!