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

本文记录我对迭代器的一点理解。先列出参考的文章[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,那么问题来了。

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

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

  3. 为什么迭代器遍历的方式好?
    有了上文的分析,就很容易看出,及时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;
}
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值