Как создать итератор для элементов, соответствующих производному типу в C++?
Я хотел бы итератор в 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 ответов
Вы должны использовать динамическое приведение.
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;
}
Решение без повышения. Но если у вас есть доступ к библиотеке надстройки - используйте 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) );
}
Просто еще один способ сделать это с помощью буст-итераторов. На этот раз, используя 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
,
Как сказал в комментарии пейнтбольный боб, вы должны создать свой собственный класс итераторов, возможно, наследуя от vector<Type*>::iterator
, В частности, вам нужно будет реализовать или переопределить operator++()
а также operator++(int)
чтобы гарантировать, что вы пропускаете не-SubType объекты (вы можете использовать dynamic_cast<SubType*>()
проверить каждый элемент). В этой статье O'Reilly Net есть хороший обзор реализации вашего собственного контейнера и итератора.