C++ 實(shí)現(xiàn)自定義類(lèi)型的迭代器操作
##動(dòng)機(jī)
我們知道STL實(shí)現(xiàn)了很多算法(#include<algorithm>),如果項(xiàng)目是基于STL構(gòu)建那么能夠最大化使用現(xiàn)有代碼當(dāng)然是最好的。在STL中容器和算法之間的橋梁是迭代器。所以在定義好自定義類(lèi)型的容器后,接下來(lái)就是迭代器的實(shí)現(xiàn)。
STL中的迭代器
迭代器模式是一種經(jīng)典的設(shè)計(jì)模式,而STL的迭代器實(shí)現(xiàn)用到了模板的一些特性和技能,在這里稍微介紹一下
下面是STL中結(jié)構(gòu)體iterator的定義,這么定義是給后面的算法多態(tài)和萃取時(shí)(具體見(jiàn)書(shū)中介紹)使用的。
其中的_Category 和_Ty 沒(méi)有默認(rèn)值,需要自己給參數(shù)的。
_Ty就是元素的類(lèi)型
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是迭代器的類(lèi)型,主要有以下幾種
// ITERATOR STUFF (from <iterator>) // ITERATOR TAGS (from <iterator>) struct input_iterator_tag //只讀 { // identifying tag for input iterators }; struct _Mutable_iterator_tag //只寫(xiě) { // identifying tag for mutable iterators }; struct output_iterator_tag //只寫(xiě) : _Mutable_iterator_tag { // identifying tag for output iterators }; struct forward_iterator_tag //前向移動(dòng) : input_iterator_tag, _Mutable_iterator_tag { // identifying tag for forward iterators }; struct bidirectional_iterator_tag //可雙向移動(dòng) : forward_iterator_tag { // identifying tag for bidirectional iterators }; struct random_access_iterator_tag //隨機(jī)讀寫(xiě) : bidirectional_iterator_tag { // identifying tag for random-access iterators }; //...
自定義迭代器
我希望迭代器有以下操作:*,++。另外還想要通過(guò)迭代器調(diào)用count_if函數(shù)。那看一下count_if都用到哪些操作符吧
// 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); }
可以看到用到了++,!=,*。所以我們的迭代器需要把這些都給實(shí)現(xiàn)了。代碼很簡(jiǎn)單:
#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;//實(shí)際的內(nèi)容指針,通過(guò)該指針跟容器連接 };
自定義容器
下面給出個(gè)簡(jiǎn)單的數(shù)組容器,實(shí)現(xiàn)了數(shù)組的基本操作。并把剛剛定義的迭代器內(nèi)置了
template<class T> class myVector{ public: typedef MyIterator<T> iterator;//所有類(lèi)型迭代器用同一個(gè)名字,便于寫(xiě)出更通用的代碼 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; };
##測(cè)試
定義一個(gè)vector和自定容器myVector,用迭代器去訪(fǎng)問(wèn),并通過(guò)迭代器使用conunt_if函數(shù),可以看到用法完全一樣
bool eq_10(int k){ return k == 10; } int main(){ //自定義類(lèi)型 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;
總結(jié)和思考
所以簡(jiǎn)單來(lái)說(shuō),如果想要定義自己容器的迭代器并想通過(guò)迭代器調(diào)用STL的算法函數(shù)的話(huà)。首先繼承iteroter,然后實(shí)現(xiàn)必要的操作符即可。不過(guò)具體的算法函數(shù)對(duì)迭代器類(lèi)型是有要求的,這個(gè)需要自己把握。
在這個(gè)簡(jiǎn)單的示例里面,直接用myVector的指針(mv._ptr)也是可以調(diào)用count_if的,因?yàn)镾TL通過(guò)模板偏特化技術(shù)使得迭代器也支持原生指針。不過(guò)既然把訪(fǎng)問(wèn)元素都放到迭代器中了,我們就可以對(duì)所有的容器用統(tǒng)一的方式訪(fǎng)問(wèn)了,而不用暴露每個(gè)容器的細(xì)節(jié)(myVector::_ptr):
//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(){ //自定義類(lèi)型 myVector<int> mv(10); mv[3] = 10; mv[9] = 10; //STL 容器 vector<int> v(10, 0); v[3] = 10; v[9] = 10; //vector 和 myVector底層實(shí)現(xiàn)有很大區(qū)別,但是可用同一個(gè)函數(shù)做遍歷等操作 display(mv.begin(), mv.end()); display(v.begin(), v.end()); getchar(); return 0; }
迭代器賦予了容器更多的功能和通用性
補(bǔ)充知識(shí):C++ 自定義迭代器(實(shí)現(xiàn)++遞增兩格)
//效果每次迭代器加移動(dòng)兩格
#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("對(duì)象錯(cuò)誤"); } } 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 構(gòu)造失敗"); } catch (exception &e) { cout << e.what(); exit(EXIT_FAILURE); } } }; //無(wú)法使用或添加vector<T> vec 成員函數(shù)vec.begin()或全局函數(shù)begin(vec) //我們做個(gè)假冒的全局函數(shù) 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
#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; }
效果:
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方歡迎留言討論,望不吝賜教。
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)空戰(zhàn)游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)空戰(zhàn)游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05C++中volatile和mutable關(guān)鍵字用法詳解
這篇文章主要介紹了C++中volatile和mutable關(guān)鍵字用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02C++實(shí)現(xiàn)LeetCode(134.加油站問(wèn)題)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(134.加油站問(wèn)題),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C++實(shí)現(xiàn)N個(gè)骰子的點(diǎn)數(shù)算法
這篇文章主要介紹了C++實(shí)現(xiàn)N個(gè)骰子的點(diǎn)數(shù)算法,用兩種方法實(shí)現(xiàn)了該功能,是非常實(shí)用的技巧,需要的朋友可以參考下2014-09-09