2012-06-19 25 views
6

Tôi có một lớp như hình dưới đây:Cho phép truy cập vào các đối tượng chứa trong C++

class Foo { 
private: 
    std::map<std::string, Bar*> bars_by_name; 
    std::map<std::string, Baz*> bazs_by_name; 
}; 

Bây giờ tôi muốn cho phép người dùng truy cập cả hai bộ sưu tập nhưng ẩn chi tiết thực hiện mà tôi đang lưu trữ đối tượng vào std :: maps. Thay vào đó, tôi muốn có các hàm thành viên trả về, ví dụ: const iterators cho các bộ sưu tập và thậm chí có thể là một iterator tùy chỉnh trả về các đối tượng từ cả hai bộ sưu tập, vì Bar và Baz thuộc cùng một hệ thống phân cấp lớp. Xem xét phong cách, những gì sẽ là cách thích hợp để làm điều này trong C + +? Trong Java, tôi có thể đặt kiểu trả về của phương thức thành Iterable hoặc bọc bộ sưu tập thành một unCodifiableCollection.

+1

Nếu bạn sử dụng một cái gì đó như ['any_iterator'] (http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html), bạn có thể ẩn loại cơ bản mà không bị rò rỉ chi tiết. Bạn có thể sử dụng một cái gì đó như transform_iterator của Boost hoặc zip_iterator như một trung gian quá mà không sử dụng được bất kỳ khôn ngoan hơn. – Flexo

Trả lời

1

Bạn có thể chuyển các trình vòng lặp của bộ sưu tập thành của riêng bạn.

class Foo { 
    private: 
    typedef std::map<std::string, Bar*> BarContainer; 
    typedef std::map<std::string, Baz*> BazContainer; 
    public: 
    typedef BarContainer::const_iterator ConstBarIterator; 
    ConstBarIterator beginBars() { return bars_by_name.cbegin(); } 
    ConstBarIterator endBars() { return bars_by_name.cend(); } 
    typedef BazContainer::const_iterator ConstBazIterator; 
    ConstBazIterator beginBazs() { return bazs_by_name.cbegin(); } 
    ConstBazIterator endBazs() { return bazs_by_name.cend(); } 

    private: 
    BarContainer bars_by_name; 
    BazContainer bazs_by_name; 
}; 

Điều này giúp bạn linh hoạt thay đổi loại container của mình sau đó và chỉ yêu cầu người gọi phải biên dịch lại.

Nó không giải quyết được vấn đề lặp lại cả hai.

+0

Cảm ơn bạn. Tôi đã thử một cái gì đó với lặp của Boost nhưng không thể làm cho họ làm việc, vì vậy tôi quyết định làm điều gì đó khác đầu tiên. Tôi cũng tìm thấy thư viện này nhưng nó có vẻ đã được pre-alpha trong hơn mười năm: http://www.zib.de/weiser/vtl/ – tsnorri

1

Tạo một giao diện mà giấu đi các chi tiết:

class Foo { 
    public: 
     void AddBar(std::string name, Bar*); 
     void RemoveBar(std::string name); 

     Bar* GetBar(std::string name); 
     Bar* GetBar(std::string name) const; 

     void AddBaz(std::string name, Baz*); 
     void RemoveBaz(std::string name); 

     Baz* GetBaz(std::string name); 
     Baz* GetBaz(std::string name) const; 

    private: 
     std::map<std::string, Bar*> bars_by_name; 
     std::map<std::string, Baz*> bazs_by_name; 
}; 

Đối với tất cả người sử dụng biết được, bạn có thể lưu trữ chúng trong một std :: cặp bên trong một danh sách, bên trong một vector, hoặc thậm chí sử dụng các mảng song song. ..cái gì đó thật sự.

EDIT:

Thực tế là bạn đang lưu trữ nó trong một bản đồ nhưng muốn người dùng để lặp qua các mùi chứa cơ bản của một thiết kế xấu/không chính xác. Hoặc chỉ cho phép họ truy cập cá nhân như trên hoặc tạo các phương thức sẽ thực hiện việc này cho họ.

+0

OP đang tìm cách lặp qua các nội dung ... –

+0

Ngoài những gì Oli chỉ ra, các trình vòng lặp phơi sáng không phải tiết lộ loại cơ bản. Các trình vòng lặp có thể trừu tượng, ví dụ, giống như any_iterator được chỉ ra ở trên. – stinky472

Các vấn đề liên quan