2

我正在对接口进行编程,并且我想以一种通用的方式对其内容进行交互。所以,一般来说,我的接口有这样的原型:

class Interface
{
public:
  class Iterator;
  virtual Interface::Iterator* begin() = 0;
  virtual Interface::Iterator* end() = 0;  

  class Iterator
  {
  public:
    virtual const Iterator* operator++() = 0;
    virtual bool operator!=(const Iterator& i) = 0;
  };
};

下面是一个简单专业化的示例:

class Derived : public Interface
{
public:
  Derived() : array {2, 0, 1, 5, 4, 3} {};
  Iterator* begin() { return new Derived::IterDerived(0);};
  Iterator* end() { return new Derived::IterDerived(6);};

  int array[6];

public:
  class IterDerived : public Interface::Iterator
  {
  public:
    IterDerived(int i) {pos = i;};
    IterDerived(IterDerived&& i) {pos = i.pos;};

    const Interface::Iterator* operator++() override { ++pos; return this;};
    bool operator!=(const Interface::Iterator& i) { return pos != dynamic_cast<const     Derived::IterDerived&>(i).pos;};
    int position() { return pos;};

  private:
    int pos;
  };
};

到目前为止,一切都很好。现在,我想编写一段代码,允许我使用新的 for 范围迭代其内容,如新标准 (c++11) 中所述。请注意,在实际接口中,我将提供 getter 方法,因此无需使用 dynamic_cast。IE:

int main()
{
  Interface *a = new Derived();

  for(auto i : a) 
    std::cout << dynamic_cast<Derived*>(a)->array[dynamic_cast<Derived::IterDerived*>(i.get())->position()] << " ";
  std::cout << std::endl;
}

但是这段代码无法编译。为了编译,我需要使用以下形式的宏:

#define FOR_ITERATOR(iter, object)                  \
  for(std::unique_ptr<Interface::Iterator> iter((object)->begin()), \
    iter##end((object)->end());                 \
      *iter != *(iter##end); ++(*iter))

在 for 范围的位置。有机会使用新的语句范围,还是我必须使用这种宏?

4

2 回答 2

6

当你说:

Interface *a = new Derived();
for(auto i : a) 

a是一个指针,迭代指针并没有任何意义。你可能想要:

for (auto i : *a)

也就是说,遍历a指向的对象。

这可能仍然行不通,因为您的Interface::beginandInterface::end方法返回 anInterface::Iterator *而不是 an Interface::Iterator,这是无稽之谈。

您似乎希望能够使用 的子类Interface::Iterator来迭代您的派生类,但这不起作用,因为auto需要能够找出i它构建的对象(和关联的迭代器)的静态类型。

如果你想做这样的事情,你需要让你的迭代器对象封装一个指向可以被 Derived 子类化的类的指针,同时保持迭代器类本身固定。就像是:

class Interface
{
public:
  class Iterator;
  virtual Interface::Iterator begin() = 0;
  virtual Interface::Iterator end() = 0;  

protected:
  class IteratorImpl {
  public:
    virtual IteratorImpl &operator++() = 0;
    virtual bool operator!=(const Iterator& i) = 0;
    virtual IteratorImpl *clone() = 0;
  };
};

public:
  class Iterator {
  protected:
    class IteratorImpl *impl;
  public:
    Iterator(IteratorImpl *a) : impl(a) {}
    Iterator(iterator &a) : impl(a.impl->clone()) {}
    Iterator &operator++() { ++*rep; return this; }
        :

然后,您可以从中得出

class Derived : Interface {
  class IteratorImpl : public Interface::IteratorImpl {
       :
  };
public:
  Iterator begin() { return Iterator(new IteratorImpl( ...

当然,您需要确保添加所有需要的析构函数、赋值运算符、解引用运算符等。

这可能还需要在应该包含在您实际迭代的任何类型中的类型上进行模板化。

于 2013-06-10T01:20:29.827 回答
3

::Iterator 是一个抽象对象,它必须是。所以,我不能返回一个具体的对象。

那么你现在在虚拟(运行时)多态性和通用(编译时)多态性之间发生冲突。基于范围的 for 以及几乎所有现有的算法都使用具体对象作为迭代器。它们将被算法随意复制。

要完成这项工作,您需要让迭代器将虚拟机隐藏在自己的内部。这可以像拥有一个Iterator存储指向“真实”迭代器类的指针的基本类一样简单,它将所有调用转发到该迭代器类。

你会做这样的事情:

class IteratorBase
{
public:
  virtual const IteratorBase* operator++() = 0;
  virtual bool operator!=(const IteratorBase& i) = 0;
};

class Iterator
{
public:
  explicit Iterator(IteratorBase *it) : m_it(it) {}
  const Iterator &operator++() {return Iterator(++(*m_it));}
  bool operator !=(const Iterator &i) {return *m_it != *i.m_it;}

private:
  IteratorBase *m_it;
};

您从IteratorBase.

通用编程风格的接口通常倾向于避免使用指针。如果不是实际对象,它们更多地使用引用。因此,如果您希望您的类在泛型编程中很好地工作,您将不得不遵循该约定。而且,一般来说,想要尝试做一些像运行时多态范围这样的事情是很奇怪的。

指针不是范围;只有对具体类型的引用可以是范围。所以你不能将指针传递给 range-based for,除非你要专门化std::beginand std::end

于 2013-06-10T01:41:37.217 回答