c++学习-为什么要用迭代器

xiaoxiao2021-02-28  59

本文记录我对迭代器的一点理解。先列出参考的文章[LevelDB源码分析–使用Iterator简化代码设计]。我对参考文章的内容自己做了实现,我讲的不清楚的地方可以直接参考原文。

为什么要设计迭代器这个东西

用迭代器可以很大程度上隔离容器底层实现,使用时只需依赖迭代器相对统一的方法/接口。

这是为什么要设计迭代器这个东西,我在看ACC的时候,容器-迭代器-算法这三者有着密不可分的关系,算法通过迭代器作用于容器,迭代器相当于起到了媒介的作用,这是它的功能。但是,上面说的才是为什么要设计这样的一个东西。

代码

#include <iostream> #include <string> #include <vector> class Book { public: Book(){} Book( const char* name ){ book_name_ = name; } friend std::ostream& operator<<( std::ostream& os, const Book& book ); private: std::string book_name_; }; std::ostream& operator<<( std::ostream& os, const Book& book ){ if(os){ os << book.book_name_; } return os; } class Shelf { public: Shelf() {} public: typedef std::vector<Book>::iterator iter; iter begin() { return shelf_.begin(); } iter end() { return shelf_.end(); } std::vector<Book> get_shelf() const { return shelf_; } void push_back( Book& book ){ shelf_.push_back( book ); } private: std::vector<Book> shelf_; }; typedef void (*callback)( Book& ); void traverse( std::vector<Book>& shelf, callback visit ){// 不使用迭代器遍历 int sz = shelf.size(); for( int i = 0; i < sz; ++i ){ visit( shelf[i] ); } } void traverse1( Shelf::iter b, Shelf::iter e, callback visit ){// 使用迭代器遍历 while( b != e ){ visit(*b); ++b; } } void visit(Book& book){ std::cout << book << std::endl; } int main(){ Book book1 = "C++"; Book book2 = "Java."; Book book3 = "Python"; Shelf shelf; shelf.push_back( book1 ); shelf.push_back( book2 ); shelf.push_back( book3 ); std::vector<Book> books = shelf.get_shelf(); traverse( books, visit ); traverse1( shelf.begin(), shelf.end(), visit ); return 0; }

说说上面的代码,我的目的是为了遍历shelf里面的book,那么问题来了。

为什么不把遍历方法写在Shelf里面? 作为类的设计者,无法了解过多的应用场景,只能是提供最基本的接口。比如对于Shelf的遍历可能有很多种,输出所有元素,输出所有元素+逗号,输出所有元素+\ ……所有,遍历的场景可能有很多,这个不应该由类的设计者来提供。所以,不能写在类的里面。

既然不使用迭代器可以遍历,那么为什么还要使用迭代器遍历 先说一个从文章开始处的链接中学到的东西,对于非迭代器遍历的方法,traverse需要知道shelf_的类型,那么如果现在不用vector< Book >去实现,而是换成了list< Book >,那么类的使用者需要该这里的参数类型,相当于向类的使用者暴露了过多的内部信息。其实,我觉得这个还倒是其次,这么做没有屏蔽实现的细节,通常情况下,类的使用者是不需要关注类的实现细节的,所以这么做不好。

为什么迭代器遍历的方式好? 有了上文的分析,就很容易看出,及时Shelf的设计换成了list< Book >,遍历的接口也任然不需要修改,因为迭代器类型屏蔽了底层实现的机制,用户只需专注怎么更好的使用即可。

用迭代器可以很大程度上隔离容器底层实现,使用时只需依赖迭代器相对统一的方法/接口。


后记

看了leveldb迭代器设计之后,再看原文链接的感触。

代码1

不采用迭代器的设计,客户端暴露了内部的实现。

#include <iostream> #include <string> #include <vector> namespace TJU{ class Shelf { public: Shelf() {} void push_back(const std::string& book) { books_.push_back(book); } std::vector<std::string> get_books() const { return books_; } private: std::vector<std::string> books_; };// shelf class BookStore { public: BookStore() {} void push_back( const Shelf& shelf ) { shelfs_.push_back(shelf); } std::vector<Shelf> get_shelfs() const { return shelfs_; } private: std::vector<Shelf> shelfs_; };// BookStore }// namespace TJU int main(){ TJU::BookStore store; TJU::Shelf math; math.push_back( "linear algebra" ); math.push_back( "calculus" ); math.push_back( "statics" ); TJU::Shelf cs; cs.push_back("java"); cs.push_back( "c++" ); cs.push_back( "AI" ); store.push_back(math); store.push_back(cs); /* iterate the books */ std::vector<TJU::Shelf> shelfs = store.get_shelfs(); int sz = shelfs.size(); for( int i = 0; i < sz; ++i ){ std::vector<std::string> books = shelfs[i].get_books(); int sz1 = books.size(); for( int j = 0; j < sz1; ++j ){ std::cout << books[j] << " "; } std::cout << std::endl; } return 0; }

代码2

模仿我之前对于vector的实现,内部提供迭代器类型,供外部访问。现在遍历屏蔽了底层的实现。

#include <iostream> #include <string> #include <vector> namespace TJU{ class Shelf { public: Shelf() {} void push_back(const std::string& book) { books_.push_back(book); } public: typedef std::vector<std::string>::iterator Iterator; Iterator begin() { return books_.begin(); } Iterator end() { return books_.end(); } private: std::vector<std::string> books_; };// shelf class BookStore { public: BookStore() {} void push_back( const Shelf& shelf ) { shelfs_.push_back(shelf); } public: typedef std::vector<Shelf>::iterator Iterator; Iterator begin() { return shelfs_.begin(); } Iterator end() { return shelfs_.end(); } private: std::vector<Shelf> shelfs_; };// BookStore }// namespace TJU int main(){ TJU::BookStore store; TJU::Shelf math; math.push_back( "linear algebra" ); math.push_back( "calculus" ); math.push_back( "statics" ); TJU::Shelf cs; cs.push_back("java"); cs.push_back( "c++" ); cs.push_back( "AI" ); store.push_back(math); store.push_back(cs); /* iterate the books */ TJU::BookStore::Iterator b = store.begin(); TJU::BookStore::Iterator e = store.end(); while( b != e ){ TJU::Shelf::Iterator bb = b->begin(); TJU::Shelf::Iterator ee = b->end(); while( bb != ee ){ std::cout << *bb << " "; ++bb; } std::cout << std::endl; ++b; } return 0; }
转载请注明原文地址: https://www.6miu.com/read-82540.html

最新回复(0)