2010-10-12 12 views
5

मेरे पास एक कक्षा है जिसमें बाल नियंत्रण सूचक का std :: वेक्टर है। स्पष्ट कारणों से, मैं नहीं चाहता कि कक्षा के उपयोगकर्ता को std :: vector तक सीधे पहुंच प्राप्त हो। मैं चाहता हूं कि कॉलर पॉइंटर्स को देने का एक तरीका है। ऐसा करने के लिए एक अच्छा ओओ तरीका क्या होगा? (इस समारोह अक्सर कहा जाएगा)ऑब्जेक्ट ओरिएंटेड तरीका std :: वेक्टर के माध्यम से पुन: प्रयास करने के लिए?

धन्यवाद

+6

आपको यह विचार भूलना चाहिए कि "ओओ" "अच्छा" के लिए एक और शब्द है। यह अक्सर नहीं है। विशेष रूप से, एसटीएल विशेष रूप से ऑब्जेक्ट उन्मुख नहीं है, लेकिन यह * अच्छी तरह डिज़ाइन किया गया है। जिस समस्या के बारे में आप पूछ रहे हैं, उसके पास ओओपी के साथ बहुत कुछ नहीं है, और जो जवाब आप प्राप्त कर रहे हैं वह वास्तव में "ऑब्जेक्ट उन्मुख" तरीकों के बारे में हल करने के तरीकों के बारे में नहीं है। Iterators बस करने के लिए * सही * तरीका हैं। जो कि "इसे करने का ओओपी तरीका है या नहीं। :) – jalf

+3

ठीक है," अच्छा "इसमें" ओओ "एम्बेडेड है :-) – Arun

+3

तो" poop "करता है। –

उत्तर

14

एक समारोह है कि वेक्टर के लिए एक const_iterator रिटर्न प्रदान करें। वेक्टर के अंत में इटरेटर को वापस करने के लिए एक को जोड़ने के लिए भी उपयोगी है।

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

तो इन्हें प्राप्त करने के बाद उपयोगकर्ता के लिए कर सकता है (यह; यह!= itend; ++ इसे) {} – jmasterx

+0

@ मिलो: हाँ, यह सही है। लेकिन वेक्टर को बदलने से रोका जाएगा; वे केवल इसे पढ़ सकते थे। – JoshD

+0

धन्यवाद! यह बहुत अच्छा काम करेगा! – jmasterx

3

इटरेटर ऐसा करने के लिए एक अच्छा, स्पष्ट तरीका है। एक आगंतुक पैटर्न एक और तरीका ग्राहक कोड वेक्टर में प्रत्येक तत्व पर काम करने की क्षमता देने के लिए है: कुछ मायनों में तो यह और भी क्लीनर है, उपयोगकर्ता के लिए कम उजागर, और कंटेनर अधिक नियंत्रण की अनुमति देता है, जैसे:

  • वहाँ ग्राहक होने iterators बाद में
  • अवैध एक म्युटेक्स ताला प्राप्त करने के लिए जब तक ग्राहक कोड सभी प्रविष्टियों पढ़ा था अन्य थ्रेड कंटेनर
  • पर संचालित करने के लिए करता है, तो आप फ़िल्टर या तत्वों के संश्लेषण के लिए अनुमति दी जाती से पहले हो सकता है कि के साथ कोई मुद्दा है, आपको जटिल इटरेटर प्रॉक्सी ऑब्जेक्ट्स बनाने की आवश्यकता नहीं है

लेकिन

  • ग्राहक और अधिक दृढ़ता से जो कुछ भी यात्रा उपलब्ध कराने में बंद कर दिया जाता है: उदाहरण के लिए आप आम तौर पर कई तत्वों पर संचालन को सुविधाजनक बनाने के लिए एक कंटेनर के माध्यम से कई स्वतंत्र इटरेटर्स को चला सकते हैं, लेकिन विज़िटर आमतौर पर लौटने से पहले एक बार चलाता है: कोई अतिरिक्त कार्यक्षमता - पुनरावृत्ति/पुनरावृत्ति पुन: पुन: प्रारंभ करने, तत्व को हटाने - विशेष रूप से कंटेनर के विज़िट कोड द्वारा समर्थित होना आवश्यक है (शायद आगंतुक समारोह से रिटर्न कोड द्वारा)। (यहां तक ​​कि स्पष्ट समर्थन के बिना, पुनरावृत्ति को समाप्त करना अपवाद द्वारा हासिल किया जा सकता है)। इसके विपरीत, इटरेटर के साथ एक इरिएटर पर एक मिटाने का फ़ंक्शन इस्तेमाल किया जा सकता है चाहे begin() से, बढ़ी हुई है या नहीं, साथ ही find() जैसे अन्य ऑपरेशंस: यह कार्यक्षमता का एक क्लीनर फैक्टरिंग है।

कि कुछ ऐसा दिखाई देगा:

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

मैं आमतौर पर वह ऐसा कुछ करना:

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

:

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

तो फिर तुम जैसे कुछ कर सकते हैं बाहरी दुनिया के लिए कोई इटरेटर की आवश्यकता नहीं है। यदि आपको कभी भी मानक सी एपीआई में ऐसा कुछ दिखाना है तो इसे बेनकाब करना बहुत आसान है।

+0

इस उत्तर को यहां सूचीबद्ध करने के लिए निश्चित रूप से अच्छा है, लेकिन कुछ समस्याएं भी हैं: एक इंटरफ़ेस जिसके लिए यादृच्छिक पहुंच की आवश्यकता होती है, क्लाइंट कोड अचानक प्रदर्शन प्रदर्शन हिट के बिना कार्यान्वयन में बदलाव करना कठिन बनाता है, इसलिए यह अभी भी इन कार्यों को प्रदान करना सर्वोत्तम है एक शुरुआत()/अंत() iterator और/या आगंतुक समर्थन के रूप में अच्छी तरह से। उन्हें आकार(), टी और ऑपरेटर [] (size_t)/कॉन्स टी और ऑपरेटर [] (size_t) कॉन्स कॉल करने के लिए अधिक सामान्य। –

संबंधित मुद्दे