三、模拟C#(Java)中的迭代器实现方式
C#和Java的迭代器实现方式较为类似,在这里以C#为例,我用C++来模拟它的实现。C#中,可迭代的类继承IEnumerable接口,它声明了一个方法GetEnumerator,返回一个迭代器。迭代器继承IEnumerator接口,接口定义了MoveNext()方法:将游标移动一个单位,并返回是否还可以移动;Reset()方法:游标归位; Current属性:返回当前游标所指向的值(在C#中,Current是一个属性,为了模拟它,在C++中将它定义为一个函数),并且用只包含抽象函数的类来模拟接口:
#define interface struct
template <TYPENAME T>
interface IEnumerator {
virtual T& Current() = 0;
virtual bool MoveNext() = 0;
virtual void Reset() = 0;
virtual ~IEnumerator<T>() { };
};
template <TYPENAME T>
interface IEnumerable {
virtual IEnumerator<T>& GetEnumerator() = 0;
virtual ~IEnumerable () { };
};
为了自定义一个foreach"关键字",可以用宏定义来进行迭代器的等效替代:
#define foreach(item, collection) \
auto &__item_enumerator = collection.GetEnumerator(); \
__item_enumerator.Reset(); \
while (item = __item_enumerator.Current(), __item_enumerator.MoveNext())
当我们使用foreach的时候,宏展开自动展开为调用集合类collection的GetEnumerator()函数来获得一个迭代器的引用,复位之,并将当前值赋予item,迭代器向前移动。需要注意的是,我们在代码中不能重复定义__item_enumerator变量,且类型一定要为auto&:auto变量不会保留引用符号,且如果不是引用(或指针),会触发拷贝构造函数,从而失去对象的多态性。 如同刚才一样,我们定义一个集合类:
class CSharpCollection : public IEnumerable<STD::STRING>{
public:
class Enumerator : public IEnumerator<STD::STRING> {
public:
CSharpCollection &outer; //外部类
int index = 0; //下标
Enumerator (CSharpCollection &o) : outer(o){
}
bool MoveNext() override {
index++;
if (index <= 10) return true;
delete this;
return false;
}
void Reset() override {
index = 0;
}
std::string &Current() override {
return outer.str[index];
}
~Enumerator (){
std::cout 《 "Enumerator 被析构" 《 std::endl;
}
};
public:
std::string str {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"};
IEnumerator<STD::STRING>& GetEnumerator() override{
return *new Enumerator(*this);
}
};