144

我正在努力学习 C++,所以如果这个问题表明缺乏基础知识,请原谅我,你看,事实是,我缺乏基础知识。

我需要一些帮助来解决如何为我创建的类创建迭代器。

我有一个“形状”类,它有一个点容器。我有一个类'Piece',它引用了一个形状并定义了一个形状的位置。Piece 没有 Shape,它只是引用一个 Shape。

我希望它看起来像 Piece 是一个 Points 容器,它与它引用的 Shape 相同,但添加了 Piece 位置的偏移量。

我希望能够遍历 Piece 的点,就像 Piece 本身就是一个容器一样。我做了一些阅读,并没有找到任何对我有帮助的东西。我将非常感谢任何指示。

4

6 回答 6

63

/编辑:我明白了,这里实际上需要一个自己的迭代器(我首先误读了这个问题)。尽管如此,我仍然保留下面的代码,因为它在类似情况下很有用。


这里真的需要一个自己的迭代器吗?也许将所有必需的定义转发到包含实际点的容器就足够了:

// Your class `Piece`
class Piece {
private:
    Shape m_shape;

public:

    typedef std::vector<Point>::iterator iterator;
    typedef std::vector<Point>::const_iterator const_iterator;

    iterator begin() { return m_shape.container.begin(); }

    const_iterator begin() const { return m_shape.container.begin(); }

    iterator end() { return m_shape.container.end(); }

    const_iterator end() const { return m_shape.const_container.end(); }
}

这是假设您在vector内部使用 a ,但可以轻松调整类型。

于 2008-09-29T13:05:40.330 回答
42

你应该使用 Boost.Iterators。它包含许多模板和概念,用于为现有的迭代器实现新的迭代器和适配器。我写了一篇关于这个主题的文章;它在 2008 年 12 月的 ACCU 杂志上。它为您的问题讨论了一个(IMO)优雅的解决方案:使用 Boost.Iterators 从对象公开成员集合。

如果您只想使用 stl,Josuttis 书中有一章介绍如何实现您自己的 STL 迭代器。

于 2008-09-29T15:34:12.457 回答
20

在这里Designing a STL like Custom Container是一篇很棒的文章,它解释了如何设计类似 STL 的容器类及其迭代器类的一些基本概念。反向迭代器(有点难)虽然留作练习:-)

高温下,

于 2009-05-08T14:37:05.757 回答
15

你可以阅读这篇ddj 文章

基本上,从 std::iterator 继承来为您完成大部分工作。

于 2008-09-29T13:09:48.277 回答
3

用 C++ 编写自定义迭代器可能非常冗长且难以理解。

由于我找不到编写自定义迭代器的最小方法,所以我编写了这个可能有帮助的模板头。例如,要使Piece类可迭代:

#include <iostream>
#include <vector>

#include "iterator_tpl.h"

struct Point {
  int x;
  int y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}
  Point operator+(Point other) const {
    other.x += x;
    other.y += y;
    return other;
  }
};

struct Shape {
  std::vector<Point> vec;
};

struct Piece {
  Shape& shape;
  Point offset;
  Piece(Shape& shape, int x, int y) : shape(shape), offset(x,y) {}

  struct it_state {
    int pos;
    inline void next(const Piece* ref) { ++pos; }
    inline void begin(const Piece* ref) { pos = 0; }
    inline void end(const Piece* ref) { pos = ref->shape.vec.size(); }
    inline Point get(Piece* ref) { return ref->offset + ref->shape.vec[pos]; }
    inline bool cmp(const it_state& s) const { return pos != s.pos; }
  };
  SETUP_ITERATORS(Piece, Point, it_state);
};

然后您就可以将其用作普通的 STL 容器:

int main() {
  Shape shape;
  shape.vec.emplace_back(1,2);
  shape.vec.emplace_back(2,3);
  shape.vec.emplace_back(3,4);

  Piece piece(shape, 1, 1);

  for (Point p : piece) {
    std::cout << p.x << " " << p.y << std::endl;
    // Output:
    // 2 3
    // 3 4
    // 4 5
  }

  return 0;
}

它还允许添加其他类型的迭代器,例如const_iteratoror reverse_const_iterator

我希望它有所帮助。

于 2017-06-01T15:36:56.737 回答
1

您的问题的解决方案不是创建您自己的迭代器,而是使用现有的 STL 容器和迭代器。将每个形状中的点存储在类似矢量的容器中。

class Shape {
    private:
    vector <Point> points;

从那时起你做什么取决于你的设计。最好的方法是遍历 Shape 内部方法中的点。

for (vector <Point>::iterator i = points.begin(); i != points.end(); ++i)
    /* ... */

如果您需要访问 Shape 之外的点(这可能是设计缺陷的标志),您可以在 Shape 中创建将返回点的迭代器访问函数的方法(在这种情况下,还要为点容器创建一个公共 typedef)。有关此方法的详细信息,请查看 Konrad Rudolph 的答案。

于 2008-09-29T13:06:05.777 回答