2009-04-21 35 views
3

我想要一個C++中的迭代器,它只能迭代特定類型的元素。在下面的例子中,我只想迭代SubType實例的元素。如何通過與C++中派生類型相匹配的元素創建迭代器?

vector<Type*> the_vector; 
the_vector.push_back(new Type(1)); 
the_vector.push_back(new SubType(2)); //SubType derives from Type 
the_vector.push_back(new Type(3)); 
the_vector.push_back(new SubType(4)); 

vector<Type*>::iterator the_iterator; //***This line needs to change*** 

the_iterator = the_vector.begin(); 
while(the_iterator != the_vector.end()) { 
    SubType* item = (SubType*)*the_iterator; 
    //only SubType(2) and SubType(4) should be in this loop. 
    ++the_iterator; 
} 

我該如何在C++中創建這個迭代器?

+1

是不是可以讓你自己的迭代器(或子類),將跳過除SubType對象以外的任何東西? – 2009-04-21 19:49:50

回答

9

您必須使用動態轉換。

the_iterator = the_vector.begin(); 
while(the_iterator != the_vector.end()) { 
    SubType* item = dynamic_cast<SubType*>(*the_iterator); 
    if(item != 0) 
     ... 

    //only SubType(2) and SubType(4) should be in this loop. 
    ++the_iterator; 
} 
+1

這是'檢查正確的子類型'問題的一部分的解決方案,但它有一個缺陷,即在達到最後一個子類型元素後,它會繼續增加迭代器超過容器末尾。 – 2009-04-21 20:25:08

+0

dribeas,我不明白這是怎麼發生的。他在循環的頭部得到了正確的狀態。 – 2009-04-21 20:35:43

+1

原始問題甚至沒有提及動態演員,所以我認爲海報不知道動態演員,並且正在尋找解決方案的錯誤方向(改變與迭代器相關的東西)。 在提出一個解決方案(構建您自己的迭代器)之前,可能需要的不是很複雜,我首先建議最簡單的方法來解決原始問題。 然後,正如我的elipsis和indentation暗示的那樣,迭代器當然不能在if(item!= 0)塊中。 – Jem 2009-04-21 20:37:26

2

正如paintballbob在評論中所說,您應該創建自己的迭代器類,可能繼承自vector<Type*>::iterator。特別是,您需要實施或覆蓋operator++()operator++(int)以確保跳過非子類型對象(您可以使用dynamic_cast<SubType*>()來檢查每個項目)。在O'Reilly Net article中有一個很好的實現你自己的容器和迭代器的概述。

+0

您必須小心,不要將迭代器增加到容器末尾以外。爲此,你需要你的包裝器來保存'end'迭代器的副本,以便你有一個停止條件。這或者只是使用boost :: filter_iterator,因爲Sanjaya在另一個答案中提出了建議。 – 2009-04-21 20:21:45

12
+1

很好的答案,也想去吧:)用一個小例子會更好。我建議BOOST_FOREACH(類型* t,make_pair(make_filter_iterator(ll_dynamic_cast (_1),v.begin(),v.end()),make_filter_iterator(ll_dynamic_cast (_1),v.end(),v.end ))){...}(使用boost.iterators,boost.lambda和boost.foreach) – 2009-04-21 20:18:09

+0

啊,應該知道已經有這個提升了! – maxaposteriori 2009-04-21 20:27:34

+0

太棒了!我覺得應該準備好使用解決方案了謝謝,永遠不知道還有什麼提升。 – 2009-04-21 20:36:34

4

無需升壓解決方案。但是,如果您有權訪問boost庫 - 請按照提議使用Filter Iterator。

template <typename TCollection, typename T> 
class Iterator 
{ 
public: 
    typedef typename TCollection::iterator iterator; 
    typedef typename TCollection::value_type value_type; 

    Iterator(const TCollection& collection, 
      iterator it): 
     collection_(collection), 
     it_(it) 
    { 
     moveToNextAppropriatePosition(it_); 
    } 
    bool operator != (const Iterator& rhs) 
    { 
     return rhs.it_ != it_; 
    } 
    Iterator& operator++() 
    { 
     ++it_; 
     moveToNextAppropriatePosition(it_); 
     return *this; 
    } 
    Iterator& operator++(int); 
    Iterator& operator--(); 
    Iterator& operator--(int); 
    value_type& operator*() 
    { 
     return *it_; 
    } 
    value_type* operator->() 
    { 
     return &it_; 
    } 
private: 
    const TCollection& collection_; 
    iterator it_; 
    void moveToNextAppropriatePosition(iterator& it) 
    { 
     while (dynamic_cast<T*>(*it) == NULL && it != collection_.end()) 
      ++it; 
    } 
}; 

class A 
{ 
public: 
    A(){} 
    virtual ~A(){} 
    virtual void action() 
    { 
     std::cout << "A"; 
    } 
}; 
class B: public A 
{ 
public: 
    virtual void action() 
    { 
     std::cout << "B"; 
    } 
}; 
int main() 
{ 
    typedef std::vector< A* > Collection; 
    Collection c; 
    c.push_back(new A); 
    c.push_back(new B); 
    c.push_back(new A); 

    typedef Iterator<Collection, B> CollectionIterator; 
    CollectionIterator begin(c, c.begin()); 
    CollectionIterator end(c, c.end()); 

    std::for_each(begin, end, std::mem_fun(&A::action)); 
} 
2

只是另一種方法如何使用boost迭代器來做到這一點。這一次,使用std::remove_copy_if

std::remove_copy_if(v.begin(), v.end(), 
    boost::make_function_output_iterator(boost::bind(&someFunction, _1)), 
    !boost::lambda::ll_dynamic_cast<SubType*>(boost::lambda::_1)); 

它會調用一個函數(在這個例子中someFunction但它可以是任何的boost ::綁定可以構造 - 也是一個成員函數)。對於用於指向SubType每個指針。

相關問題