Cad*_*hon 11 c++ iterator const-iterator
我管理(对象的集合Collection的Real简单例子).然后我在我的集合上定义了迭代器.这意味着:iterator,const_iterator,reverse_iterator和const_reverse_iterator.在这个例子中,我只会注意iterator和const_iterator,其他两个非常相似.
之后,我想在我的集合中定义一个过滤器,它根据特定条件保留或不保留元素.例如,仅保留Real具有正值的实例.我也想在我保留的元素上迭代我的集合.
对于此示例,集合中的对象非常简单.目标只是拥有一个对象而不是一个本机类型:
struct Real
{
public:
double r;
};
Run Code Online (Sandbox Code Playgroud)
然后我定义我的集合而不必知道里面的真实容器:
class Collection
{
public:
typedef std::vector<Real>::iterator iterator;
typedef std::vector<Real>::const_iterator const_iterator;
private:
std::vector<Real> data;
public:
Collection() : data() {}
Collection(unsigned long int n) : data(n) {}
Collection(unsigned long int n, const Real& x) : data(n,x) {}
Collection::iterator begin() { return this->data.begin(); }
Collection::iterator end() { return this->data.end(); }
Collection::const_iterator begin() const { return this->data.begin(); }
Collection::const_iterator end() const { return this->data.end(); }
};
Run Code Online (Sandbox Code Playgroud)
在这个简单的例子中,这非常有效:
int main()
{
Collection c(5);
double k = 1.0;
for(Collection::iterator it = c.begin(); it != c.end(); ++it)
{
it->r = k;
k *= -2.0;
}
std::cout << "print c with Collection::iterator" << std::endl;
for(Collection::iterator it = c.begin(); it != c.end(); ++it)
std::cout << it->r << std::endl;
std::cout << "print c with Collection::const_iterator" << std::endl;
for(Collection::const_iterator it = c.begin(); it != c.end(); ++it)
std::cout << it->r << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此程序写入预期的输出:
print with Collection::iterator
1
-2
4
-8
16
print with Collection::const_iterator
1
-2
4
-8
16
Run Code Online (Sandbox Code Playgroud)
现在我想创建一个抽象过滤器,它具有一个引用或指向集合的指针,具有迭代器,并具有通过过滤器接受值的抽象函数.对于第一步,我只编写没有迭代器的类:
class CollectionFilter
{
private:
Collection& col;
public:
CollectionFilter(Collection& c) : col(c) {}
virtual ~CollectionFilter() {}
Collection& collection() { return this->col; }
iterator begin() { /* todo */ }
iterator end() { /* todo */ }
const_iterator begin() const { /* todo */ }
const_iterator end() const { /* todo */ }
virtual bool accept(const Real& x) const = 0;
};
Run Code Online (Sandbox Code Playgroud)
然后,创建一个实现特定条件的新过滤器非常容易:
class CollectionFilterPositive : public CollectionFilter
{
public:
CollectionFilterPositive(Collection& c) : CollectionFilter(c) {}
virtual ~CollectionFilterPositive() {}
virtual bool accept(const Real& x) const { return x.r >= 0.0; }
};
Run Code Online (Sandbox Code Playgroud)
在过滤器中实现迭代器之前,我有一些评论/问题.
Collection&的话,是在begin() const和end() const功能真正需要的?如果是,为什么?const Collection&,但这显然是我的目标所必需的.有什么好办法呢?我是否要将类复制CollectionFilter到CollectionFilterConst具有非常相似代码的类?此外,对于必须从两个类似类继承的用户来说,这种解决方案非常混乱.然后,让我们去实现迭代器.对于这个例子,我只写了iterator而不是const_iterator.我把它添加到我的班级:
class CollectionFilter
{
public:
class iterator
{
private:
CollectionFilter* filter;
Collection::iterator iter;
public:
iterator(CollectionFilter* f, Collection::iterator i) : filter(f), iter(i) {}
iterator(const iterator& i) : filter(i.filter), iter(i.iter) {}
iterator& operator = (const iterator& i) { this->filter = i.filter; this->iter = i.iter; return *this; }
iterator& operator ++ ()
{
if(this->iter != this->filter->collection().end())
{
do
{
++this->iter;
} while(this->iter != this->filter->collection().end() && !this->filter->accept(*this->iter));
}
}
iterator operator ++ (int) { /* similar */ }
Real& operator * () { return *this->iter; }
Collection::iterator operator -> () { return this->iter; }
bool operator == (const iterator& i) const { return this->iter == i.iter; }
bool operator != (const iterator& i) const { return this->iter != i.iter; }
};
public:
iterator begin()
{
Collection::iterator it = this->col.begin();
if(!this->accept(*it)) ++it;
return CollectionFilter::iterator(this,it);
}
iterator end()
{
Collection::iterator it = this->col.end();
return CollectionFilter::iterator(this,it);
}
};
Run Code Online (Sandbox Code Playgroud)
这也适用于这个简单的例子
int main()
{
Collection c(5);
double k = 1.0;
for(Collection::iterator it = c.begin(); it != c.end(); ++it)
{
it->r = k;
k *= -2.0;
}
std::cout << "print c with CollectionFilterPositive::iterator" << std::endl;
CollectionFilterPositive fc(c);
for(CollectionFilterPositive::iterator it = fc.begin(); it != fc.end(); ++it)
std::cout << it->r << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给出预期的输出:
print with CollectionFilterPositive::iterator
1
4
16
Run Code Online (Sandbox Code Playgroud)
一些问题:
CollectionFilter::iterator才能实现CollectionFilter::const_iterator,只需要很小的修改.有没有办法避免重复此代码(写入8次,如果我计算重复的类CollectionFilterConst和反向迭代器)?提前致谢 !
我建议放弃该类CollectionFilter,而是使用一个Collection::filter_iterator_tmpl模板类,其中有两个实例化Collection::filter_iterator和Collection::const_filter_iterator.
Collection::filter_iterator_tmpl可以这样实现:
class Collection {
template<typename Iterator, typename Predicate>
class filter_iterator_tmpl :
public std::iterator<std::input_iterator_tag, typename Iterator::value_type, typename Iterator::difference_type, typename Iterator::pointer, typename Iterator::reference> {
private:
Iterator underlying_iterator_;
Predicate predicate_;
public:
filter_iterator_tmpl& operator++() {
do {
++ underlying_iterator_;
} while(! predicate_(*underlying_iterator_));
return *this;
}
typename Iterator::reference operator*() const {
return *underlying_iterator_;
}
....
}
};
Run Code Online (Sandbox Code Playgroud)
可以通过让Predicate成为具有函数的多态函数来添加多态性virtual bool PolymorphicPredicate::operator(Real) const。
Collection然后定义实际的过滤器迭代器:
class Collection {
private:
template<typename Iterator, typename Predicate>
class filter_iterator_tmpl;
public:
template<typename Predicate>
using filter_iterator = filter_iterator_tmpl<Collection::iterator, Predicate>;
template<typename Predicate>
using const_filter_iterator = filter_iterator_tmpl<Collection::const_iterator, Predicate>;
template<typename Predicate>
filter_iterator<Predicate> begin_filter(const Predicate& pred);
template<typename Predicate>
const_filter_iterator<Predicate> begin_filter(const Predicate& pred) const;
}
Run Code Online (Sandbox Code Playgroud)
Boost 以类似的方式实现通用的“Filter Iterator”:http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/filter_iterator.html 作为独立类,而不是容器类的一部分。
关于 const 正确性:C++ 中的容器(std::vector、std::map、std::string等)拥有自己的内容对象:它们创建和删除它们,并且需要确保通过对容器的 const 访问,您也只能获得对内容对象的 const 访问。需要实现它们以强制执行此操作,因为它们访问分配的存储的底层指针没有这种所有权概念。这就是为什么他们需要有两个版本的迭代器(iterator和const_iterator)。迭代器本身并不拥有该对象:通过对 an 进行 const 访问iterator,您无法推进迭代器,但您仍然可以获得对该对象的非常量访问。
问题 1/2:
CollectionFilter是有问题的,因为它不拥有它提供访问权限的对象,但对过滤器的常量/非常量访问应该只提供对对象的常量/非常量访问。因为它包含对 , 的引用Collection,并且它应该适用于对Collection, 两个版本的const 和非常量访问CollectionFilter,ConstCollectionFilter然后需要使用该方法。
问题 4:
一旦将 const 正确的容器对象拆分为用于 const 和非常量访问的两个类,必然会出现一些代码重复。模板避免了手动实现这两个版本。还有一些额外的复杂性,例如比较 aniterator与 an const_iterator,以及const_iterator从 an构造 aiterator但反之则不然......
问题 3/5: 见上文。