it-swarm.com.de

Eigene Iteratoren erstellen

Ich versuche, C++ zu lernen, also verzeihen Sie mir, wenn diese Frage einen Mangel an Grundkenntnissen zeigt, sehen Sie, Tatsache ist, dass ich einen Mangel an Grundkenntnissen habe.

Ich möchte Hilfe beim Erstellen eines Iterators für eine von mir erstellte Klasse.

Ich habe eine Klasse 'Shape', die einen Container mit Punkten enthält. Ich habe eine Klasse 'Piece', die auf eine Form verweist und eine Position für die Form definiert. Das Teil hat keine Form, sondern verweist nur auf eine Form.

Ich möchte, dass es so aussieht, als ob Piece ein Container mit Punkten ist, die mit denen der Form identisch sind, auf die es verweist, jedoch mit dem Versatz der Position des Pieces.

Ich möchte die Piece's Points durchlaufen können, als wäre Piece selbst ein Container. Ich habe ein wenig herumgelesen und nichts gefunden, was mir geholfen hat. Für Hinweise wäre ich sehr dankbar.

139
Howard May

Sie sollten Boost.Iterators verwenden. Es enthält eine Reihe von Vorlagen und Konzepten zum Implementieren neuer Iteratoren und Adapter für vorhandene Iteratoren. Ich habe geschrieben ein Artikel zu diesem Thema ; Es ist im Dezember 2008 ACCU Magazin. Es wird eine (IMO) elegante Lösung für genau Ihr Problem beschrieben: Offenlegen von Mitgliedersammlungen aus einem Objekt mithilfe von Boost.Iterators.

Wenn Sie nur die STL verwenden möchten, enthält das Josuttis-Buch ein Kapitel zur Implementierung Ihrer eigenen STL-Iteratoren.

40
Roel

/ EDIT: Ich verstehe, ein eigener Iterator ist hier tatsächlich notwendig (ich habe die Frage zuerst falsch verstanden). Trotzdem lasse ich den folgenden Code stehen, da er unter ähnlichen Umständen nützlich sein kann.


Ist hier tatsächlich ein eigener Iterator notwendig? Möglicherweise reicht es aus, alle erforderlichen Definitionen an den Container mit den tatsächlichen Punkten weiterzuleiten:

// 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(); }
}

Dies setzt voraus, dass Sie vector intern verwenden, der Typ kann jedoch problemlos angepasst werden.

61
Konrad Rudolph

Hier Entwerfen einer STL wie eines benutzerdefinierten Containers ist ein hervorragender Artikel, der einige der grundlegenden Konzepte erläutert, wie eine STL-ähnliche Containerklasse zusammen mit der Iteratorklasse für sie entworfen werden kann. Reverse Iterator (etwas härter) bleibt aber als Übung :-)

HTH,

20
Abhay

Sie können dies lesen ddj Artikel

Erben Sie grundsätzlich von std :: iterator, um die meiste Arbeit für Sie zu erledigen.

15
gbjbaanb

Das Schreiben von benutzerdefinierten Iteratoren in C++ kann sehr ausführlich und komplex sein.

Da ich keinen minimalen Weg gefunden habe, einen benutzerdefinierten Iterator zu schreiben, habe ich geschrieben dieser Template-Header das könnte helfen. Um beispielsweise die Klasse Piece iterabel zu machen:

#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);
};

Dann können Sie es als normalen AWL-Container verwenden:

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;
}

Es erlaubt auch das Hinzufügen anderer Arten von Iteratoren wie const_iterator oder reverse_const_iterator.

Ich hoffe, es hilft.

2
VinGarcia

Die Lösung für Ihr Problem besteht nicht in der Erstellung eigener Iteratoren, sondern in der Verwendung vorhandener STL-Container und -Iteratoren. Speichern Sie die Punkte in jeder Form in einem Behälter wie Vektor.

class Shape {
    private:
    vector <Point> points;

Was Sie von da an tun, hängt von Ihrem Design ab. Am besten durchlaufen Sie Punkte in Methoden innerhalb von Shape.

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

Wenn Sie auf Punkte außerhalb von Shape zugreifen müssen (dies könnte ein Zeichen für ein fehlerhaftes Design sein), können Sie in Shape-Methoden erstellen, die die Iterator-Zugriffsfunktionen für Punkte zurückgeben (in diesem Fall erstellen Sie auch eine öffentliche Typdefinition für den Punktecontainer). Einzelheiten zu diesem Ansatz finden Sie in der Antwort von Konrad Rudolph.

1