2008-10-01 15 views
22

मैं थोड़ी देर के लिए सी # का उपयोग कर रहा हूं, और सी ++ पर वापस जाने का सिरदर्द है। मैं अपने कुछ अभ्यासों को सी # से सी ++ में लाने की कोशिश कर रहा हूं, लेकिन मुझे कुछ प्रतिरोध मिल रहा है और मुझे आपकी मदद स्वीकार करने में खुशी होगी।मैं कंटेनर का पर्दाफाश किए बिना इटरेटर का पर्दाफाश कैसे कर सकता हूं?

मैं इस तरह एक वर्ग के लिए एक इटरेटर बेनकाब करने के लिए करना चाहते हैं:

template <class T> 
class MyContainer 
{ 
public: 
    // Here is the problem: 
    // typedef for MyIterator without exposing std::vector publicly? 

    MyIterator Begin() { return mHiddenContainerImpl.begin(); } 
    MyIterator End() { return mHiddenContainerImpl.end(); } 

private: 
    std::vector<T> mHiddenContainerImpl; 
}; 

मैं कुछ है कि एक समस्या नहीं है पर कोशिश कर रहा हूँ? क्या मुझे सिर्फ typedef std :: vector < टी> :: इटरेटर चाहिए? मैं सिर्फ इटरेटर, नहीं लागू करने कंटेनर पर निर्भर करता है पर उम्मीद कर रहा हूँ ...

+0

इसके अलावा इस [सवाल] को देखने के (http://stackoverflow.com/questions/127009/returning-an-any-kind-of-input-iterator-instead-of-a-vectoriterator-or-a -listit) –

उत्तर

2

यह आप क्या चाहते हैं करना चाहिए:

typedef typename std::vector<T>::iterator MyIterator; 

Accelerated C++ से:

जब भी आप एक प्रकार है, जैसे कि vector<T>, जो एक टेम्पलेट पैरामीटर पर निर्भर करता है, और आप size_type जैसे उस सदस्य के सदस्य का उपयोग करना चाहते हैं, जो कि स्वयं ही एक प्रकार है, आपको पूरे नाम को typename द्वारा पूर्ववत करना होगा ताकि कार्यान्वयन को नाम के इलाज के बारे में पता चल सके। एक प्रकार।

1

मैं आप "को उजागर नहीं std :: वेक्टर सार्वजनिक रूप से" क्या मतलब के बारे में अनिश्चित हूँ, लेकिन वास्तव में, आप बस ऐसे ही अपने typedef परिभाषित कर सकते हैं:

typedef typename std::vector<T>::iterator iterator; 
typedef typename std::vector<T>::const_iterator const_iterator; // To work with constant references 

आप इन typedefs को बदलने में सक्षम हो जाएगा बाद में उपयोगकर्ता देख कुछ भी ...

वैसे बिना, यह अच्छा अभ्यास माना जाता है भी कुछ अन्य प्रकार का पर्दाफाश करने के लिए यदि आप अपने वर्ग एक कंटेनर के रूप में व्यवहार करना चाहते हैं:

typedef typename std::vector<T>::size_type size_type; 
typedef typename std::vector<T>::difference_type difference_type; 
typedef typename std::vector<T>::pointer pointer; 
typedef typename std::vector<T>::reference reference; 

और यदि आपके वर्ग द्वारा की जरूरत: STL documentation on vectors

संपादित करें::

आप इन सभी यहाँ है typedef के अर्थ मिल जाएगा के रूप में टिप्पणी में सुझाव दिया typename जोड़ा

+0

हो सकता है कि मैं इसे थोड़ा अधिक कर रहा हूं, लेकिन मैं टाइपिफ़ को सिर्फ यह खुलासा करना चाहता हूं कि मैं एसएलएल इटरेटर्स का उपयोग कर रहा हूं, वास्तविक कंटेनर नहीं। अगर मैं typedef std :: vector :: iterator iterator करता हूं, तो लोग केवल std :: vector <ínt> :: iterator iter = example.Begin(); (जारी) – Statement

+0

हालांकि यह पहली बार एक समस्या के रूप में प्रतीत नहीं होता है, कल्पना करें कि मैंने अपनी कक्षा के आंतरिक कार्यान्वयन को बदले में सूची का उपयोग करने के लिए बदल दिया है या नहीं।ग्राहक कोड तोड़ देगा। एक सामान्य इटरेटर का उपयोग करना जो कई अलग-अलग कंटेनरों के साथ काम करता है, इस समस्या को हल करेगा। समस्या यह है कि मुझे ऐसा करने का एक तरीका मिला। – Statement

+0

आपकी पोस्ट में थोड़ा सुधार: चूंकि टी एक टेम्पलेट पैरामीटर है, इसलिए आपको अपने टाइपपीफ में टाइपनाम कीवर्ड का उपयोग करना होगा, यानी टाइपपीफ टाइपनाम नाम std :: वेक्टर :: इटरेटर इटरेटर; –

2

मैंने पहले से पहले निम्नलिखित किया है टोपी मुझे एक इटरेटर मिला जो कंटेनर से स्वतंत्र था। यह अधिक हो सकता है क्योंकि मैं एक एपीआई भी इस्तेमाल कर सकता था जहां कॉलर vector<T*>& में गुजरता है जिसे सभी तत्वों के साथ पॉप्युलेट किया जाना चाहिए और फिर कॉलर सीधे वेक्टर से फिर से चालू हो सकता है।

template <class T> 
class IterImpl 
{ 
public: 
    virtual T* next() = 0; 
}; 

template <class T> 
class Iter 
{ 
public: 
    Iter(IterImpl<T>* pImpl):mpImpl(pImpl) {}; 
    Iter(Iter<T>& rIter):mpImpl(pImpl) 
    { 
     rIter.mpImpl = 0; // take ownership 
    } 
    ~Iter() { 
     delete mpImpl; // does nothing if it is 0 
    } 
    T* next() { 
    return mpImpl->next(); 
    } 
private: 
    IterImpl<T>* mpImpl; 
}; 

template <class C, class T> 
class IterImplStl : public IterImpl<T> 
{ 
public: 
    IterImplStl(C& rC) 
    :mrC(rC), 
    curr(rC.begin()) 
    {} 
    virtual T* next() 
    { 
    if (curr == mrC.end()) return 0; 
    typename T* pResult = &*curr; 
    ++curr; 
    return pResult; 
    } 
private: 
    C& mrC; 
    typename C::iterator curr; 
}; 


class Widget; 

// in the base clase we do not need to include widget 
class TestBase 
{ 
public: 
    virtual Iter<Widget> getIter() = 0; 
}; 


#include <vector> 

class Widget 
{ 
public: 
    int px; 
    int py; 
}; 

class Test : public TestBase 
{ 
public: 
    typedef std::vector<Widget> WidgetVec; 

    virtual Iter<Widget> getIter() { 
     return Iter<Widget>(new IterImplStl<WidgetVec, Widget>(mVec)); 
     } 

    void add(int px, int py) 
    { 
     mVec.push_back(Widget()); 
     mVec.back().px = px; 
     mVec.back().py = py; 
    } 
private: 
    WidgetVec mVec; 
}; 


void testFn() 
{ 
    Test t; 
    t.add(3, 4); 
    t.add(2, 5); 

    TestBase* tB = &t; 
    Iter<Widget> iter = tB->getIter(); 
    Widget* pW; 
    while (pW = iter.next()) 
    { 
     std::cout << "px: " << pW->px << " py: " << pW->py << std::endl; 
    } 
} 
+0

ठीक है लेकिन मानक इटरेटर नहीं है। मैं पहिया को फिर से नहीं बदलूंगा। दूसरों को पहले से ही मानक इटरेटर्स में इस्तेमाल होने की उम्मीद है, वहां कोई सीखने की वक्र नहीं है। –