สร้าง Iterators ของฉันเอง


141

ฉันพยายามเรียนรู้ C ++ ดังนั้นให้อภัยฉันถ้าคำถามนี้แสดงให้เห็นถึงการขาดความรู้พื้นฐานคุณเห็นไหมความจริงก็คือฉันไม่มีความรู้พื้นฐาน

ฉันต้องการความช่วยเหลือในการหาวิธีสร้างตัววนซ้ำสำหรับชั้นเรียนที่ฉันสร้างขึ้น

ฉันมีคลาส 'รูปร่าง' ซึ่งมีที่เก็บคะแนน ฉันมีคลาส 'ชิ้นส่วน' ซึ่งอ้างอิงรูปร่างและกำหนดตำแหน่งสำหรับรูปร่าง ชิ้นส่วนไม่มีรูปร่างมันเพียงแค่อ้างอิงรูปร่าง

ฉันต้องการให้ดูเหมือนว่า Piece เป็นคอนเทนเนอร์ของคะแนนซึ่งเหมือนกับของ Shape ที่อ้างอิง แต่ด้วยออฟเซ็ตของตำแหน่งของ Piece ที่เพิ่มเข้ามา

ฉันต้องการที่จะสามารถย้ำผ่านคะแนนของชิ้นเหมือนว่าชิ้นเป็นภาชนะเอง ฉันอ่านหนังสือไปรอบ ๆ แล้วไม่พบอะไรที่ช่วยฉันได้ ฉันจะขอบคุณมากสำหรับพอยน์เตอร์ใด ๆ


6
การโพสต์โค้ดตัวอย่างจะช่วยอธิบายสิ่งที่คุณทำได้ดีกว่าข้อความภาษาอังกฤษธรรมดา
Greg Rogers

3
การสร้างตัววนซ้ำแบบกำหนดเองอาจไม่ใช่อันดับต้น ๆ
ldog

คำตอบ:


41

คุณควรใช้ Boost.Iterators มันมีเทมเพลตและแนวคิดจำนวนมากเพื่อใช้ตัววนซ้ำและอะแดปเตอร์ใหม่สำหรับตัววนซ้ำที่มีอยู่ ฉันได้เขียนบทความเกี่ยวกับหัวข้อนี้มาก ; มันอยู่ในนิตยสาร ACCU เดือนธันวาคม 2008 มันกล่าวถึงวิธีการแก้ปัญหาที่สง่างาม (IMO) สำหรับปัญหาของคุณ: การเปิดเผยคอลเลกชันของสมาชิกจากวัตถุโดยใช้ Boost.Iterators

หากคุณต้องการใช้ stl เท่านั้นหนังสือ Josuttisมีบทหนึ่งเกี่ยวกับการใช้ตัววนซ้ำ STL ของคุณเอง


3
เพียงแค่คำพูดเล็ก ๆ น้อย ๆ : หนังสือเล่มนี้พูดเกี่ยวกับห้องสมุด c ++ มาตรฐานไม่ STL - เหล่านี้เป็นที่แตกต่างกัน แต่ได้รับสับสนมาก (ผม / เป็นความผิดด้วย)
CppChris

62

/ แก้ไข: ฉันเห็นจริง iterator ของตัวเองเป็นสิ่งจำเป็นที่นี่ ยังฉันให้รหัสด้านล่างยืนเพราะจะมีประโยชน์ในสถานการณ์ที่คล้ายกัน


จำเป็นต้องมีตัววนซ้ำของจริงหรือไม่ อาจเพียงพอที่จะส่งต่อคำจำกัดความที่จำเป็นทั้งหมดไปยังคอนเทนเนอร์ที่เก็บคะแนนจริง:

// 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ภายใน แต่สามารถปรับประเภทได้อย่างง่ายดาย


บางทีเขาอาจจะต้องการที่จะใช้อัลกอริทึม STL หรือคุณสมบัติการทำงานกับชั้นเรียนของเขา ...
gbjbaanb

2
คำถามเดิมไม่ได้บอกว่าตัววนซ้ำของคอนเทนเนอร์ชิ้นควรแก้ไขค่าเมื่อส่งคืน ที่จะต้องมีตัววนซ้ำที่แยกจากกันถึงแม้ว่ามันควรจะได้รับมรดกหรือได้มาเป็นอย่างอื่นส่วนใหญ่มาจากต้นฉบับ
workmad3 3

@gbjbaanb: สิ่งที่ดีเกี่ยวกับรหัสของฉันคือมันสามารถใช้โดยอัลกอริทึม STL
Konrad Rudolph

1
หลายปีต่อมาและสิ่งนี้ยังคงเป็นหนึ่งในผลลัพธ์อันดับต้น ๆ ของ google ... ตอนนี้เป็นไปได้ที่จะสรุปสิ่งนี้โดยทำสิ่งนี้:auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
2962533

20

ที่นี่การออกแบบ STL like Custom Containerเป็นบทความที่ยอดเยี่ยมซึ่งจะอธิบายแนวคิดพื้นฐานบางอย่างเกี่ยวกับวิธีที่ STL like class container สามารถออกแบบพร้อมกับคลาส iterator ได้ ย้อนกลับตัววนซ้ำ (แกร่งเล็กน้อย) แม้ว่าจะถูกปล่อยให้เป็นแบบฝึกหัด :-)

HTH,



2

การเขียนตัววนซ้ำแบบกำหนดเองใน C ++ นั้นค่อนข้างซับซ้อนและซับซ้อน

เนื่องจากฉันไม่สามารถหาวิธีการเขียนตัววนซ้ำแบบกำหนดเองได้ฉันจึงเขียนส่วนหัวเทมเพลตนี้ที่อาจช่วยได้ ตัวอย่างเช่นการทำให้Pieceคลาส iterable:

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

นอกจากนี้ยังช่วยในการเพิ่มประเภทอื่น ๆ เช่น iterators หรือconst_iteratorreverse_const_iterator

ฉันหวังว่ามันจะช่วย


1

การแก้ปัญหาของคุณไม่ใช่การสร้างตัววนซ้ำของคุณเอง แต่เป็นการใช้คอนเทนเนอร์ STL และตัววนซ้ำที่มีอยู่เดิม เก็บคะแนนในแต่ละรูปร่างไว้ในคอนเทนเนอร์เหมือนเวกเตอร์

class Shape {
    private:
    vector <Point> points;

สิ่งที่คุณทำนับจากนั้นขึ้นอยู่กับการออกแบบของคุณ วิธีที่ดีที่สุดคือวนซ้ำตามจุดต่าง ๆ ในรูปร่าง

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

หากคุณต้องการจุดเชื่อมต่อภายนอกรูปร่าง (อาจเป็นเครื่องหมายของการออกแบบที่ไม่เพียงพอ) คุณสามารถสร้างในวิธีการรูปร่างที่จะส่งกลับฟังก์ชันการเข้าถึงตัววนซ้ำสำหรับจุด ดูคำตอบของ Konrad Rudolph สำหรับรายละเอียดของวิธีการนี้


3
เขาจะยังคงต้องสร้างตัววนซ้ำของตัวเองซึ่งส่งต่อคำขอไปยัง Piece to the Shape ที่อยู่ใน Piece นั้น ตัววนซ้ำแบบกำหนดเองเป็นเครื่องมือที่ยอดเยี่ยมที่นี่และใช้งานได้อย่างหรูหรา
Roel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.