2009-06-29 8 views
9

Tôi đến từ thế giới Java và đang xây dựng một chương trình C++ nhỏ vào lúc này. Tôi có một đối tượng thực hiện một số công việc và sau đó trả về kết quả của công việc dưới dạng danh sách.Giao diện/Siêu lớp cho Bộ sưu tập/Thùng chứa trong c + +

Bây giờ một ngày sau đó, tôi đã thay đổi hành vi của đối tượng để lưu kết quả trong tập hợp để tránh trùng lặp trong vùng chứa. Nhưng tôi không thể trả lại đơn giản vì tôi đã sử dụng danh sách cho giao diện lần đầu tiên. Có giao diện vùng chứa chung nào mà tôi có thể sử dụng để chỉ định giao diện của đối tượng của mình và quên loại vùng chứa mà tôi sử dụng trong nội bộ không?

Hiện nay tôi là tạo ra một tập hợp thêm tất cả các giá trị và sau đó tạo ra một danh sách từ tập:

return std::list<foo>(this->mySet.begin(), this->mySet.end()) 

Có vẻ hơi lạ.

Trả lời

9

Khái niệm về vùng chứa được bao gồm bởi các trình vòng lặp.
Như bạn đã thấy khó mã hóa một loại cụ thể của container có lẽ không phải là những gì bạn muốn. Vì vậy, làm cho các trình vòng lặp của lớp của bạn trở lại. Sau đó, bạn có thể sử dụng lại trình lặp conatiners.

class MyClass 
{ 
    private: 
     typedef std::list<int>   Container; 
    public: 
     typedef Container::iterator  iterator; 
     typedef Container::const_iterator const_iterator; 


     iterator  begin()  {return myData.begin();} 
     const_iterator begin() const {return myData.begin();} 

     iterator  end()   {return myData.end();} 
     const_iterator end() const {return myData.end();} 

    private: 
     Container myData; 
}; 

Bây giờ khi bạn thay đổi loại vùng chứa từ std :: list thành std :: đặt không ai cần biết.
Cũng bằng cách sử dụng tên chuẩn mà các vùng chứa khác sử dụng lớp học của bạn bắt đầu trông giống như bất kỳ vùng chứa nào khác từ STL.

Lưu ý: Phương thức trả về bộ const_iterator phải là phương thức const.

9

Toàn bộ thư viện chuẩn C++ - bao gồm các thùng chứa của nó - không giống như Java - không giao diện (thừa kế, đa hình) - nhưng dựa trên mẫu (vì mục đích hiệu quả).

Bạn có thể tạo một trình bao bọc đa hình xung quanh bộ sưu tập của mình nhưng đây không phải là cách C++.

Giải pháp đơn giản nhất là chỉ để đơn giản hóa việc programm với một số bí danh loại:

#include <iostream> 
#include <list> 
#include <vector> 

using namespace std; 

class Test { 

private: 
    typedef vector<int> Collection; 

    Collection c; 

public: 

    typedef Collection::const_iterator It; 

    void insert(int Item) { 
     c.push_back(Item); 
    } 

    It begin() const { return c.begin(); } 
    It end() const { return c.end(); } 

}; 

int main() { 

    Test foo; 

    foo.insert(23); 
    foo.insert(40); 

    for (Test::It i = foo.begin(); i != foo.end(); ++i) 
     cout << *i << endl; 

    return 0; 
} 

Bây giờ bạn có thể thay đổi Collection -typedef mà không cần phải thay đổi bất cứ điều gì khác. (Lưu ý: Nếu bạn đặt Collection công khai, người dùng sẽ có thể tham chiếu loại bạn đã sử dụng một cách rõ ràng)

+0

Nếu bạn trả về const_iterators. Sau đó, tạo các phương thức const() và end() const. –

+0

Yep - Đã chỉnh sửa – Dario

2

Từ mô tả của bạn Tôi nghĩ câu trả lời ngắn gọn là không.

Nói chung khi tôi đang tạo ra một số hình thức của bộ sưu tập như thế này tôi thường sử dụng một typedef để xác định thùng chứa mà tôi đang sử dụng:

class Object { 
    typedef std::list<int> Cont; 
    typedef Cont::iterator iterator; 
    typedef Cont::const_iterator const_iterator; 

    // .... 
}; 

Tất cả các mã khách hàng đề cập đến "Object :: Tiếp "vv và miễn là khách hàng chỉ sử dụng các tính năng chung của container, họ sẽ không cần phải thay đổi nếu container thay đổi. Nếu bạn không thể thay đổi API của mình ngay bây giờ, thì tôi nghĩ giải pháp của bạn khá tốt, tuy nhiên, tùy thuộc vào dữ liệu bạn có, nếu bạn thực hiện nhiều lần chèn có xu hướng duy nhất, thì có thể hiệu quả hơn để tiếp tục sử dụng danh sách và chỉ xóa các bản sao ở cuối:

void foo (std::list<int> & list) { 

    // ... fill the list 

    list.sort(); 
    list.unique(); 
} 
2

Không có giao diện nào tồn tại. Thay vào đó, bạn thường sẽ sử dụng các mẫu và chỉ cần nói "Tôi không quan tâm loại đó là gì, miễn là nó hoạt động như một vùng chứa".

Giả sử hàm của bạn trông như thế này:

std::list<int> DoStuff() 

nó có thể được gọi là như thế này:

template <typename container_type> 
void caller() { 
    container_type result = DoStuff(); 
} 

Chỉ có chức năng đầu tiên cần phải được thay đổi nếu bạn quyết định trả lại một set để thay thế. Các chức năng gọi điện thoại không thực sự quan tâm (miễn là bạn không dựa vào các chi tiết cụ thể của một danh sách, tất nhiên).

Nếu bạn đăng thêm một mã mẫu, chúng tôi có thể đề xuất tốt hơn về cách thực hiện trong C++.