如何做电影网站推广,齐河县建设局网站,网站备案起名要求,一站式建站价格自定义类能够被for each#xff0c;应该算是个老生常谈的话题了#xff0c;相关的资料都很多#xff0c;不过这里整理总结主流语言的不同实现方式#xff0c;并比较部分细节上的差异。 第一种语言#xff0c;也是实现起来最简单的Java语言。在Java里#xff0c;要被for e… 自定义类能够被for each应该算是个老生常谈的话题了相关的资料都很多不过这里整理总结主流语言的不同实现方式并比较部分细节上的差异。 第一种语言也是实现起来最简单的Java语言。在Java里要被for each就须实现IterableT接口。IterableT接口定义有一个方法注Java8以后多了两个default方法不用管他 1 IteratorT iterator(); IteratorT接口下有三个方法 1 boolean hasNext();
2 T next(); 细节迭代的第一次会先调用hasNext();方法这一点跟后面有些语言不相同。 多说几句可能有些同学对IterableT接口与IteratorT接口不一样的地方是IterableT是容器类所实现的IteratorT是迭代器。容器类是存放数据的迭代器是存放迭代过程中的游标当前访问的位置和控制游标和访问器的移动的。 实现例子 1 public class Person {2 private String name;3 public Person() {//构造函数4 }5 public String getName() {6 return name;7 }8 }9 public class PersonSet implements IterablePerson{
10 private Person[] persons;//容器类存放数据数组本身就可以被for each只是这里演示如何使用IterablePerson接口。
11 public PersonSet(){
12 //构造函数
13 }
14 Override
15 public IteratorPerson iterator() {
16 // TODO Auto-generated method stub
17 return new IteratorPerson() {
18 private int index0;//迭代器存放游标
19 Override
20 public boolean hasNext() {
21 // TODO Auto-generated method stub
22 return index persons.Length;
23 }
24
25 Override
26 public Person next() {
27 // TODO Auto-generated method stub
28 return persons[index];//别忘了访问完数据还得移动游标
29 }
30 };
31 }
32 } 遍历方法 1 PersonSet persons//具体初始化过程不写
2 for (Person person : persons)
3 {
4 System.out.println(person.getName());
5 } 第二种语言C#跟JAVA相当类似只是在迭代器的具体实现有些细节上的差异。Java是IterableTC#对应的接口叫IEnumerableT。IEnumerableT从非泛型的版本继承有两个方法 1 IEnumeratorT GetEnumerator();
2 IEnumerator GetEnumerator(); 与IEnumerableT相似IEnumeratorT接口也是从IEnumerator继承同时还继承了IDisposable接口。其有3个方法和2个属性 1 T Current { get; }
2 object Current { get; }
3 void Dispose();
4 bool MoveNext();
5 void Reset(); 方法和属性较多逻辑容易乱。不用愁我来捋一下顺序 第一次访问Reset()初始化后游标被设置为空位置不指向任何元素-MoveNext()-Current 第二次及以后访问MoveNext()-Current 访问退出MoveNext()-Dispose() 具体实现 1 class Person2 {3 public string Name { get; }4 }5 class PersonSet:IEnumerablePerson6 {7 private Person[] persons;8 public PersonSet()9 {//构造函数
10 }
11 public IEnumeratorPerson GetEnumerator() new Enumerator(this);
12
13 IEnumerator IEnumerable.GetEnumerator() GetEnumerator();//显式接口实现直接返回泛型版本就可
14 private class Enumerator : IEnumeratorPerson
15 {
16 private int index;
17 private PersonSet parent;
18 public Enumerator(PersonSet parent)
19 {
20 this.parent parent;
21 }
22 public Person Current parent.persons[index];
23
24 object IEnumerator.Current parent.persons[index];
25
26 void IDisposable.Dispose() { }
27
28 public bool MoveNext() (index) parent.persons.Length;
29
30 public void Reset() index -1;//游标一定要设为空
31
32 }
33 } 调用方法 PersonSet persons//具体初始化过程不写。
foreach(var person in persons)
{Console.WriteLine(person.Name);
} 第三种方法是C/cli其实C/cli与C#都是基于.net的C/cli也一样从IEnumerableT继承只是C/cli不支持显式接口实现写法有些差异。并且C/cli语法啰嗦臃肿顺便给大家开眼界。一般不主张使用C/cli但是在混合使用C#和本地C代码时会很有用。另外C/cli的成员可以是非托管类的指针但不能是对象本身可能是因为托管对象会在内存移动使得非托管类无法对自身成员进行取地址C/cli的泛型参数不能使非托管的指针也不行。 头文件 1 #pragma once2 ref class Person3 {4 public:5 property System::String^ Name { System::String^ get();}6 };7 ref class PersonSet : System::Collections::Generic::IEnumerablePerson^8 {9 ref class Enumerator : System::Collections::Generic::IEnumeratorPerson^
10 {
11 private:
12 PersonSet^ parent;
13 public:
14 Enumerator();
15 ~Enumerator();
16 property Person^ Current{ virtual Person^ get(); };
17 property Object^ NonGenericCurrent
18 {
19 virtual Object^ get() final System::Collections::IEnumerator::Current::get;
20 //通过重命名地方法来实现C#的“显式接口调用”的效果。
21 }
22 virtual bool MoveNext();
23 virtual void Reset();
24 };
25 arrayPerson^^ persons;
26 public:
27 PersonSet();
28 virtual System::Collections::Generic::IEnumeratorPerson^^ GetEnumerator() final;
29 virtual System::Collections::IEnumerator^ GetNonGenericEnumerator() final
30 System::Collections::IEnumerable::GetEnumerator;
31 //通过重命名地方法来实现C#的“显式接口调用”的效果。
32 }; CPP文件部分 1 Person^ PersonSet::Enumerator::Current::get()2 {3 return parent-persons[index];4 }5 Object^ PersonSet::Enumerator::NonGenericCurrent::get()6 {7 return parent-persons[index];8 }9
10 bool PersonSet::Enumerator::MoveNext()
11 {
12 return index parent-persons-Length;
13 }
14
15 void PersonSet::Enumerator::Reset()
16 {
17 index -1;
18 }
19
20 System::Collections::Generic::IEnumeratorPerson^^ PersonSet::GetEnumerator()
21 {
22 return gcnew Enumerator(this);
23 }
24
25 System::Collections::IEnumerator ^ PersonSet::GetNonGenericEnumerator()
26 {
27 return GetEnumerator();
28 } 调用方法 1 PersonSet^ persons gcnew PersonSet();
2 for each (auto person in persons)
3 {
4 Console::WriteLine(person-Name);
5 } 最后是非托管C方式非托管C没有接口这个概念所以不存在要实现哪个接口的问题。事实上C11之前并没有foreach(C11里叫for range)C11要实现for range需要实现以下五个函数 1 iterator begin();//前两个函数是容器类的成员iterator是自行实现的迭代器类名任意。
2 iterator end();
3 iterator operator();//后三个是迭代器的成员操作符重载。
4 bool operator!(iterator other);
5 T operator*();//T是想要访问的元素 调用顺序 第一次访问元素 begin() end() operator!(iterator other) operator*() 第二次即以后访问元素operator() operator!(iterator other) operator*() 访问退出operator() operator!(iterator other) 注意的是for range的迭代器游标初始化一定是指向首元素实现方式 头文件 1 struct NativePerson2 {3 const char* name;4 };5 class PersonSet16 {7 NativePerson* const persons;8 const int length;9 public:
10 class iterator
11 {
12 PersonSet1* parent;
13 int current;
14 public:
15 iterator(PersonSet1* parent,int current);
16 iterator operator();
17 bool operator!(iterator other);
18 NativePerson operator*();
19 };
20 PersonSet1(NativePerson* const persons, int length);
21 iterator begin();
22 iterator end();
23 }; CPP文件部分 1 PersonSet1::iterator PersonSet1::iterator::operator()2 {3 current;4 return *this;5 }6 7 bool PersonSet1::iterator::operator!(iterator other)8 {9 return current other.current;
10 }
11
12 NativePerson PersonSet1::iterator::operator*()
13 {
14 return parent-persons[current];
15 }
16
17 PersonSet1::iterator PersonSet1::begin()
18 {
19 return iterator(this,0);
20 }
21
22 PersonSet1::iterator PersonSet1::end()
23 {
24 return iterator(this, length);
25 } C98的遍历方式 1 PersonSet1 ps(new NativePerson[10],10);
2 for (PersonSet1::iterator pp ps.begin();pp ! ps.end();pp)
3 {
4 cout (*p).name endl;
5 } C11的遍历方式 1 PersonSet1 ps(new NativePerson[10],10);
2 for (auto p : ps)
3 {
4 coutp.nameendl;
5 } 这里有个问题按照要求迭代器似乎必须知道最后一个元素那对于只能遍历得等到遍历到最后一个元素才能知道他的存在没有后继是否就没法实现了呢也不是可以这么变通begin()和end()不是各返回一个迭代器么前者的游标会动后者不动。给迭代器设置一个成员curPosbegin()返回的迭代器curPos为0end()返回的迭代器curPos为1然后当begin()的迭代器迭代到没有没有后继时把curPos设为1然后不就能使得循环退出么 实现方法假设有一个读取NativePerson的读取器他长这样的 1 class PersonReader
2 {
3 public:
4 bool next();
5 NativePerson get();
6 }; 然后就可以这样实现 头文件 1 class PersonSet22 {3 PersonReader reader;4 public:5 class iterator6 {7 PersonSet2 parent;8 CurPos curPos;9 public:
10 iterator(PersonSet2 parent);//begin
11 iterator();//end
12 iterator operator();
13 bool operator!(iterator other);
14 NativePerson operator*();
15 };
16 PersonSet2(PersonReader reader);
17 iterator begin();
18 iterator end();
19 }; CPP文件部分 1 PersonSet2::iterator::iterator(PersonSet2 parent) : parent(parent)2 {3 curPos BEGIN;4 operator();//必须调用一次operator()保证指针处在第一个元素。5 }6 PersonSet2::iterator::iterator() : parent(*(PersonSet2*)nullptr)7 {8 curPos END;9 }
10
11 PersonSet2::iterator PersonSet2::iterator::operator()
12 {
13 if (parent.reader.next())
14 {
15 //把读取器的游标往后移动后要做的事
16 }
17 else
18 {
19 curPos END;//这样就把迭代器标记为末元素
20 }
21 return *this;
22 }
23
24 bool PersonSet2::iterator::operator!(iterator other)
25 {
26 return curPos ! other.curPos;//如果没读到最后一个元素迭代器游标位置为BEGIN否则就被设为END
27 }
28
29 NativePerson PersonSet2::iterator::operator*()
30 {
31 return parent.reader.get();
32 }
33
34 PersonSet2::iterator PersonSet2::begin()
35 {
36 return iterator(*this);
37 }
38
39 PersonSet2::iterator PersonSet2::end()
40 {
41 return iterator();
42 } 然后就没有然后了。还有什么问题么 转载于:https://www.cnblogs.com/CCQLegend/p/5110755.html