为基类设计基迭代器

Design a base iterator for a base class

本文关键字:迭代器 基类      更新时间:2023-10-16

我目前正在设计一个接口(Base在下面的例子中),它提供了几个虚拟方法,包括begin()end()。这两个方法简单地返回对应的迭代器,就像在任何其他集合(如类)中一样。派生类应该实现这些方法并返回其特定的迭代器实现。

下面的(简化的)示例显示了一个派生类,它使用boost::transform_iterator来转换私有的内部整数列表。这个实现只是一个例子,实际上迭代的"东西"可以是其他东西,迭代器也是如此。

的例子工作,但我有一个问题。main()中的对象类型并不隐藏所使用的迭代器是TransformIterator类型的事实。基类将在某种插件架构中使用,其中每个插件都是共享库。插件不应该知道使用的是哪种类型的迭代器,而应该完全依赖于抽象接口。有办法做到这一点吗?

#include <boost/iterator/transform_iterator.hpp>
#include <iostream>
#include <string>
#include <vector>
template<class Iterator>
class Base
{
public:
    virtual Iterator begin() = 0;
    virtual Iterator end() = 0;
};
struct toString
{
    std::string operator()(int number) const
    {
        return std::to_string(number);
    }
};
typedef boost::transform_iterator<toString, std::vector<int>::iterator> TransformIterator;
class Derived : public Base<TransformIterator>
{
public:
    Derived() : ints{132, 3, 6451, 12, 5} {}
    TransformIterator begin()
    {
        return boost::make_transform_iterator(ints.begin(), toString());
    }
    TransformIterator end()
    {
        return boost::make_transform_iterator(ints.end(), toString());
    }
private:
    std::vector<int> ints;
};
int main()
{
    Base<TransformIterator>* obj = new Derived();
    for(const auto& value : *obj)
    {
        std::cout << value.size() << std::endl;
    }
    return 0;
}

更多的背景知识:这个特定的例子是基于一个读取配置文件的接口。目前,我只计划给出YAML文件的实现,但其他格式,如XML或老式INI也是可能的。

我最近在我的一个工作项目中做了非常类似的事情。我的方法是引入一个抽象迭代器接口和一个类,用于访问该接口的迭代器。下面是一个简化的版本:

template <class ValueType>
struct AbstractIterator
{
  virtual ValueType& dereference() const = 0;
  virtual void increment() = 0;
  // and so on...
};

template <class ValueType>
struct ClientIterator : public std::iterator<whatever>
{
  std::unique_ptr<AbstractIterator<ValueType>> it;
  ClientIterator(std::unique_ptr<AbstractIterator<ValueType>> it) : it(std::move(it)) {}
  ValueType& operator* const () { return it->dereference(); }
  ClientIterator& operator++ () { it>increment(); return *this; }
  // and so on...
};
struct Base
{
  typedef ClientIterator<std::string> Iterator;
  virtual Iterator begin() = 0;
  virtual Iterator end() = 0;
}

struct Derived : Base
{
  struct ServerIterator : AbstractIterator<std::string>
  {
    boost::transform_iterator<toString, std::vector<int>::iterator> it;
    virtual std::string& dereference() const override { return *it; }
    virtual void increment() override { ++it; }
  }
  virtual Iterator begin() override { return Iterator({new ServerIterator(something)}); }
  virtual Iterator end() override { return Iterator({new ServerIterator(anotherThing)}); }
};

不能用经典的c++迭代器。它们不打算用于多态使用。

你所能做的是为你的迭代器定义一个抽象基类,然后通过一个(模板化的)包装器来实现每个具体的迭代器类型。抽象基类简单地将所有必需的操作符定义为纯虚的。缺点是迭代器上的每个操作都需要一个虚函数调用…根据您的使用情况,这可能会或可能不会成为一个问题(通常不会,除非您使用它们频繁地迭代非常大的集合)。

的例子:

template <typename T>
class InputIterator<T>
{
  public:
    virtual T operator*() const = 0;
    // Other operators go here
};
template <typename TIterator>
class ConcreteInputIterator final
:  public InputIterator<typename std::iterator_traits<TIterator>::value_type>
{
  public:
    ConcreteInputIterator(TIterator iterator) : m_iterator(iterator) {}
  public:
    virtual T operator*() const override
    {
      return *m_iterator;
    };
  private:
    TIterator m_iterator;
};