首先,這裏說的for循環,是指C++中新增的for(a : b)格式的for循環。
最近碰到了這樣的問題,就來記錄一下。如有錯漏,還望指摘。
C++新增的這種for循環,使用來遍歷容器中的每一個元素。但是有時候,我想自定義自己的容器,那能不能也使用這樣的for循環呢?
答案肯定是可以的。那麼需要什麼要求呢?
for循環的大致邏輯
要向弄明白有什麼需求,我們首先需要弄明白,這個for循環是怎麼實現的。
比如對於for(ele : list)
, 其實大致相當於如下代碼:
for(auto it = list.begin(); it != list.end(); ++it)
{
ele = *it;
// ......
}
自定義for循環要求
那麼我們就可以看出對於格式爲for(ele : list)
的for循環語句,有如下要求
- 變量list對應的類型中必須包含begin()函數
- 變量list對應的類型中必須包含end()函數
- begin()函數的返回值類型中,必須實現了++操作符
- begin()函數的返回值類型中,必須實現了*操作符
- begin()函數的返回值類型中,必須實現了參數類型爲end()函數返回值類型的!=操作符。
實現
所以如下代碼就可以實現自定義for循環:
class ArrayEnd
{
public:
int* ptr_;
ArrayEnd(int* ptr) : ptr_(ptr) {}
};
class ArrayBegin
{
private:
int* ptr_;
public:
ArrayBegin(int* ptr) : ptr_(ptr) {}
ArrayBegin& operator++()
{
ptr_++;
return *this;
}
int& operator *() { return *ptr_; }
bool operator != (const ArrayEnd& e) { return ptr_ != e.ptr_; }
};
class myArray
{
private:
int* ptr_;
int len_;
public:
myArray(int* ptr, int len) : ptr_(ptr), len_(len) {}
ArrayBegin begin() { return ArrayBegin(ptr_); }
ArrayEnd end() { return ArrayEnd(ptr_ + len_); }
};
不過當然,一般我們會將ArrayBegin和ArrayEnd合併在一起成爲ArrayIterator:
class ArrayIterator
{
private:
int* ptr_;
public:
ArrayIterator(int* ptr) : ptr_(ptr) {}
ArrayIterator& operator++()
{
ptr_++;
return *this;
}
int& operator *() { return *ptr_; }
bool operator != (const ArrayIterator& e) { return ptr_ != e.ptr_; }
};
class myArray
{
private:
int* ptr_;
int len_;
public:
myArray(int* ptr, int len) : ptr_(ptr), len_(len) {}
ArrayIterator begin() { return ArrayIterator(ptr_); }
ArrayIterator end() { return ArrayIterator(ptr_ + len_); }
};