2010-10-12 26 views
5

Tôi có một lớp có std :: vector của con trỏ điều khiển con. Vì lý do hiển nhiên, tôi không muốn người dùng của lớp có quyền truy cập trực tiếp vào std :: vector. Tất cả những gì tôi muốn là một cách để cung cấp cho người gọi các con trỏ. Điều gì sẽ là một cách tốt OO để làm điều này? (Chức năng này sẽ được gọi là thường xuyên)Cách định hướng đối tượng để lặp qua một std :: vector?

Cảm ơn

+6

Bạn nên quên ý tưởng rằng "OO" là một từ khác cho "tốt". Nó thường không phải là. Cụ thể, STL không đặc biệt hướng đối tượng, nhưng nó * được thiết kế tốt. Vấn đề bạn đang yêu cầu có rất ít để làm với OOP, và câu trả lời bạn đang nhận được không thực sự về cách "hướng đối tượng" để giải quyết nó. Iterator chỉ là * đúng cách * để làm điều đó. Điều đó quan trọng hơn nhiều so với việc chúng có phải là "cách làm OOP" hay không. :) – jalf

+3

Vâng, "tốt" có "oo" được nhúng vào trong nó :-) – Arun

+3

Vì vậy, "poop". –

Trả lời

14

Cung cấp một hàm trả về một const_iterator vào vector. Nó cũng hữu ích để thêm một để trả về trình lặp cho đến cuối của vec-tơ.

class MyClass { 
public: 
    typedef vector<T>::const_iterator c_iter; 

    c_iter getBegin() const {return v.begin();} 
    c_iter getEnd() const {return v.end();} 

    // and perhaps if it's useful and not too invasive. 
    const T& getAt(int i) const {return v.at(i);} 

    //stuff 
    vector<T> v; 
}; 
+0

vì vậy sau khi nhận được những người dùng có thể làm cho (nó; nó!= itend; ++ it) {} – jmasterx

+0

@Milo: vâng, đúng vậy. Nhưng chúng sẽ bị ngăn cản thay đổi vectơ; họ chỉ có thể đọc nó. – JoshD

+0

Cảm ơn! điều này sẽ làm việc tuyệt vời! – jmasterx

3

Iterator là cách tốt, rõ ràng để thực hiện việc này. Mẫu khách truy cập là một cách khác để cung cấp cho khách hàng mã khả năng hoạt động trên từng phần tử trong vectơ: theo một số cách, nó thậm chí còn sạch hơn, tiết lộ ít hơn cho người dùng và cho phép kiểm soát container nhiều hơn, ví dụ:

  • không có vấn đề gì với khách hàng có trình vòng lặp có thể bị vô hiệu sau
  • để lấy khóa mutex cho đến khi mã khách hàng đọc tất cả các mục trước khi các chủ đề khác được phép hoạt động trên vùng chứa
  • nếu bạn lọc hoặc tổng hợp các phần tử, bạn không cần phải tạo các đối tượng proxy lặp phức tạp

BUT

  • khách hàng bị khóa mạnh hơn vào bất kỳ lần lặp nào bạn cung cấp: ví dụ: bạn thường có thể thực hiện nhiều bước lặp độc lập thông qua một thùng chứa, tạo điều kiện cho nhiều hoạt động, nhưng khách truy cập thường chạy qua một lần trước khi quay trở lại: bất kỳ chức năng bổ sung nào - tạm ngưng/tiếp tục lặp lại, xóa phần tử - cần được mã truy cập của vùng chứa hỗ trợ cụ thể (có lẽ bằng mã trả về từ hàm khách truy cập). (Ngay cả khi không có hỗ trợ rõ ràng, việc kết thúc lặp lại có thể đạt được bằng một ngoại lệ). Ngược lại, với các trình vòng lặp, một hàm xóa đơn có thể được sử dụng trên một trình lặp cho dù từ begin(), tăng hay không, cũng như các hoạt động khác như find(): đây là một tính năng bao quát hơn.

Điều đó sẽ giống như thế:

class Container 
{ 
    public: 
    template <typename Visitor> 
    void visit(Visitor& visitor) 
    { 
     for (Vector::const_iterator i = v_.begin(); i != v_.end(); ++i) 
      visitor(*i); 
    } 

    private: 
    typedef std::vector<X> Vector; 
    Vector v_; 
}; 

// client code... 

struct Visitor 
{ 
    void operator()(const X&) { ... } 
    // any data you want to update as you iterate... 
}; 

Visitor v(...any construction arguments...); 
container.visit(v); 
1

Tôi thường làm điều đó giống như sau:

class MyClass { 
public: 
    const unsigned int GetNumberOfItems() { return v.size(); } 

    T* GetItemNumber(const unsigned int n) 
    { 
    // 3 options here, thrown your own exception type, or use the std one, or 
    // or just return NULL meaning nothing there or out of range. 
    try{ 
     return v.at(n); 
    } catch (std::out_of_range &e){ 
    } 

    return NULL;  
    } 

    vector<T> v; 
}; 

Sau đó, bạn chỉ có thể làm điều gì đó như:

MyClass cl; 
int count = cl.GetNumberOfItems(); 
for (int i = 0; i < cl.GetNumberOfItems(); i++){ 
    T* item = cl.GetItemNumber(i); 
} 

Không có vòng lặp cho thế giới bên ngoài yêu cầu. Nếu bạn đã từng để lộ một cái gì đó như thế này để một API C tiêu chuẩn sau đó nó rất dễ dàng để lộ.

+0

Chắc chắn là tốt để có câu trả lời được liệt kê ở đây, nhưng cũng có một số vấn đề: giao diện yêu cầu quyền truy cập ngẫu nhiên sẽ khiến việc thay đổi triển khai trở nên khó khăn hơn. cũng như một trình lặp()/end() lặp lại và/hoặc hỗ trợ khách truy cập. Thông thường hơn để gọi chúng là size(), T & operator [] (size_t)/const T & toán tử [] (size_t) const. –

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