Tạo các vòng lặp của riêng tôi


141

Tôi đang cố gắng học C ++ vì vậy hãy tha thứ cho tôi nếu câu hỏi này thể hiện sự thiếu kiến ​​thức cơ bản, bạn thấy đấy, thực tế là, tôi thiếu kiến ​​thức cơ bản.

Tôi muốn một số trợ giúp tìm ra cách tạo iterator cho một lớp tôi đã tạo.

Tôi có một lớp 'Hình dạng' có một thùng Điểm. Tôi có một lớp 'Mảnh' tham chiếu Hình dạng và xác định vị trí cho Hình dạng. Piece không có Shape mà nó chỉ tham chiếu một Shape.

Tôi muốn nó có vẻ như Piece là một thùng chứa các Điểm giống như các Hình dạng mà nó tham chiếu nhưng với phần bù của vị trí của Mảnh được thêm vào.

Tôi muốn có thể lặp đi lặp lại qua Điểm của mảnh giống như thể chính mảnh đó là một vật chứa. Tôi đã đọc một chút xung quanh và không tìm thấy bất cứ điều gì đã giúp tôi. Tôi sẽ rất biết ơn cho bất kỳ con trỏ.


6
Đăng mã mẫu sẽ giúp mô tả những gì bạn đang làm tốt hơn là chỉ văn bản tiếng Anh đơn giản.
Greg Rogers

3
Tạo các vòng lặp tùy chỉnh có lẽ không phải là một cơ bản hàng đầu, trung gian ít nhất.
ldog

Câu trả lời:


41

Bạn nên sử dụng Boost.Iterators. Nó chứa một số mẫu và khái niệm để triển khai các trình vòng lặp và bộ điều hợp mới cho các trình vòng lặp hiện có. Tôi đã viết một bài báo về chính chủ đề này ; đó là trên tạp chí ACCU tháng 12 năm 2008. Nó thảo luận về một giải pháp tao nhã (IMO) cho chính xác vấn đề của bạn: phơi bày các bộ sưu tập thành viên từ một đối tượng, sử dụng Boost.Iterators.

Nếu bạn chỉ muốn sử dụng stl, cuốn sách Josuttis có một chương về việc thực hiện các trình lặp STL của riêng bạn.


3
Chỉ là một nhận xét nhỏ: Cuốn sách nói về Thư viện chuẩn C ++, không phải STL - những thứ này khác nhau, nhưng bị lẫn lộn rất nhiều (tôi cũng có tội)
CppChris 16/1/2015

62

/ EDIT: Tôi thấy, một trình vòng lặp riêng thực sự cần thiết ở đây (tôi đã đọc sai câu hỏi trước). Tuy nhiên, tôi để mã bên dưới đứng vì nó có thể hữu ích trong các trường hợp tương tự.


Là một iterator riêng thực sự cần thiết ở đây? Có lẽ nó đủ để chuyển tiếp tất cả các định nghĩa cần thiết đến vùng chứa Điểm thực tế:

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

Điều này giả sử bạn đang sử dụng vectornội bộ nhưng loại có thể dễ dàng được điều chỉnh.


có lẽ anh ta muốn sử dụng thuật toán STL hoặc các tính năng chức năng chống lại lớp của mình ...
gbjbaanb

2
Câu hỏi ban đầu thực sự nói rằng bộ lặp của thùng chứa mảnh nên sửa đổi các giá trị khi trả về chúng. Điều đó sẽ yêu cầu một trình vòng lặp riêng biệt, mặc dù nó có thể được kế thừa hoặc nếu không thì hầu hết được lấy từ bản gốc.
workmad3

@gbjbaanb: Điểm hay của mã của tôi là nó có thể được sử dụng bởi các thuật toán STL.
Konrad Rudolph

1
Vài năm sau và đây vẫn là một trong những kết quả hàng đầu trên google ... Bây giờ có thể khái quát hóa điều này bằng cách làm một cái gì đó như thế này:auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
user2962533

20

Ở đây Thiết kế STL như Custom Container là một bài viết xuất sắc giải thích một số khái niệm cơ bản về cách một lớp container giống như STL có thể được thiết kế cùng với lớp iterator cho nó. Đảo ngược (ít khó khăn hơn) mặc dù được để lại như một bài tập :-)

HTH



2

Viết các trình lặp tùy chỉnh trong C ++ có thể khá dài dòng và phức tạp để hiểu.

Vì tôi không thể tìm thấy một cách tối thiểu để viết một trình vòng lặp tùy chỉnh, tôi đã viết tiêu đề mẫu này có thể giúp ích. Ví dụ, để làm cho Piecelớp lặp lại:

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

Sau đó, bạn sẽ có thể sử dụng nó như một STL Container bình thường:

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

Nó cũng cho phép thêm các loại trình vòng lặp khác như const_iteratorhoặc reverse_const_iterator.

Tôi hy vọng nó sẽ giúp.


1

Giải pháp cho vấn đề của bạn không phải là tạo ra các trình vòng lặp của riêng bạn, mà là việc sử dụng các trình chứa và trình lặp STL hiện có. Lưu trữ các điểm trong mỗi hình dạng trong một container như vector.

class Shape {
    private:
    vector <Point> points;

Những gì bạn làm từ đó phụ thuộc vào thiết kế của bạn. Cách tiếp cận tốt nhất là lặp qua các điểm trong các phương thức bên trong Shape.

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

Nếu bạn cần truy cập các điểm bên ngoài Shape (đây có thể là dấu hiệu của thiết kế thiếu), bạn có thể tạo trong các phương thức Shape sẽ trả về các hàm truy cập iterator cho các điểm (trong trường hợp đó cũng tạo ra một typedef công khai cho vùng chứa điểm). Nhìn vào câu trả lời của Konrad Rudolph để biết chi tiết về phương pháp này.


3
Anh ta sẽ vẫn cần phải tạo ra trình vòng lặp của riêng mình để chuyển các yêu cầu tới Mảnh thành các Hình dạng trong Mảnh đó. Lặp đi lặp lại tùy chỉnh là một công cụ tuyệt vời ở đây, và rất thanh lịch để sử dụng.
Roel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.