Как создать итератор для элементов, соответствующих производному типу в C ++? - PullRequest
3 голосов
/ 21 апреля 2009

Мне нужен итератор в C ++, который может перебирать только элементы определенного типа. В следующем примере я хочу выполнить итерацию только для элементов, которые являются экземплярами SubType.

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 ++?

Ответы [ 5 ]

12 голосов
/ 22 апреля 2009
9 голосов
/ 21 апреля 2009

Вы должны использовать динамическое приведение.

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;
}
4 голосов
/ 22 апреля 2009

Решение без наддува. Но если у вас есть доступ к библиотеке надстройки - используйте 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 голосов
/ 22 апреля 2009

Просто еще один способ сделать это с помощью буст-итераторов. На этот раз, используя 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 :: bind - также функция-член) для каждого указателя, указывающего на SubType.

2 голосов
/ 21 апреля 2009

Как сказал в комментарии пейнтбольный боб, вы должны создать свой собственный класс итераторов, возможно, унаследованный от vector<Type*>::iterator. В частности, вам нужно будет реализовать или переопределить operator++() и operator++(int), чтобы гарантировать, что вы пропускаете объекты не-SubType (вы можете использовать dynamic_cast<SubType*>() для проверки каждого элемента). В этой статье O'Reilly Net .

есть хороший обзор реализации вашего собственного контейнера и итератора.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...