2009-04-21 7 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オブジェクト以外をスキップする独自のイテレータ(またはサブクラス)を作成することはできませんか? –

答えて

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

これは質問の「適切なサブタイプ」の部分の解決策ですが、最後のSubType要素に達した後、コンテナの終わりを超えてイテレータをインクリメントし続けるという欠点があります。 –

+0

dribeas、私はそれがどうして起こるか見ていない。彼はループの頭に正しい状態を持っています。 –

+1

オリジナルの質問はダイナミックキャストについても言及していないので、ポスターはダイナミックキャストを知らず、ソリューションの間違った方向を見ていたと思います(イテレータに関連するものを変更してください)。 おそらく必要以上に複雑な解決策(独自のイテレータを作成する)を提案する前に、最初に元の問題を解決する最も簡単な方法を提案することをお勧めしました。 それで、私の射影と字下げが意味するように、反復子はもちろん、if(item!= 0)ブロック内にあってはいけません。 – Jem

2

paintballbobがコメントで述べたように、おそらくvector<Type*>::iteratorから継承した独自のイテレータクラスを作成する必要があります。特に、operator++()operator++(int)を実装またはオーバーライドして、非サブタイプのオブジェクトをスキップする必要があります(dynamic_cast<SubType*>()を使用して各項目を確認できます)。このO'Reilly Net articleに独自のコンテナとイテレータを実装する素晴らしい概要があります。

+0

イテレータをコンテナの端を超えて増やさないように注意する必要があります。そのためには、終了条件を持つように 'end'イテレータのコピーを保持するラッパーが必要です。それは、Sanjayaが別の答えで示唆しているように、boost :: filter_iteratorを使用するだけです。 –

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を使用) –

+0

ああ、すでにこれが増強されていることを知っていたはずですか? – maxaposteriori

+0

素晴らしい!私は解決策を使用する準備ができているように感じましたありがとうございます。 –

4

ソリューション。しかし、あなたがブーストライブラリへのアクセス権を持っているなら、提案されているように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

ブーストイテレータを使用してそれを行う方法のもう1つの方法。これは、関数を呼び出します

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)); 

からSubTypeを指していた各ポインタのために:この時間、std::remove_copy_ifを使用して(someFunctionこの例では、しかし、それは何も高めることができます::バインドが構築でき、またメンバー関数。) 。

関連する問題