C ++ Iterator, क्यों कोई Iterator बेस क्लास नहीं है, जो सभी पुनरावृत्तियों से प्राप्त होता है


11

मैं एक परीक्षा के लिए सीख रहा हूं और मेरे पास एक सवाल है जिसे देने और जवाब देने के लिए मैं संघर्ष कर रहा हूं।

कोई भी इटरेटर बेस क्लास अन्य सभी पुनरावृत्तियों से क्यों नहीं मिलता है?

मेरा अनुमान है कि मेरे शिक्षक सीपीपी संदर्भ से पदानुक्रमित संरचना का उल्लेख कर रहे हैं " http://prntscr.com/mgj542 " रहे हैं और हमें उन्हें क्यों करना चाहिए इसके अलावा एक अन्य कारण प्रदान करना होगा?

मुझे पता है कि पुनरावृत्तियां किस तरह की होती हैं (और वे कंटेनर पर काम करने के लिए उपयोग की जाती हैं)। विभिन्न संभावित अंतर्निहित डेटास्ट्रक्चर के कारण जो मैं समझता हूं, उससे अलग कंटेनरों में अलग-अलग पुनरावृत्तियां होती हैं, क्योंकि आप बेतरतीब ढंग से एक सरणी तक पहुंच सकते हैं, उदाहरण के लिए, लेकिन एक लिंक की गई सूची और विभिन्न कंटेनरों को उनके माध्यम से जाने के विभिन्न तरीकों की आवश्यकता नहीं होती है।

वे शायद कंटेनर के आधार पर विशेष टेम्पलेट हैं, है ना?


2
अपने शोध को साझा करना हर किसी की मदद करता है । हमें बताएं कि आपने क्या प्रयास किया है और यह आपकी आवश्यकताओं को पूरा क्यों नहीं करता है। यह दर्शाता है कि आपने अपने आप को मदद करने का प्रयास करने के लिए समय लिया है, यह हमें स्पष्ट उत्तरों को दोहराने से बचाता है, और सबसे अधिक यह आपको अधिक विशिष्ट और प्रासंगिक उत्तर प्राप्त करने में मदद करता है। यह भी देखें कैसे पूछें करने के लिए
कुटकी

5
" क्यों कोई इटेरेटर बेस क्लास नहीं है जो अन्य सभी पुनरावृत्तियों से विरासत में मिला है? " उम ... एक क्यों होना चाहिए ?
निकोल बोलस

जवाबों:


14

आपने पहले ही जवाब दे दिया है कि यह इंगित करना आवश्यक नहीं है कि सभी पुनरावृत्तियों के लिए एक ही Iterator बेस वर्ग से विरासत में क्यों नहीं है। मैं हालांकि थोड़ा आगे मिल गया था। C ++ का एक लक्ष्य शून्य रन-टाइम लागत के साथ अमूर्त है।

यदि पुनरावृत्तियाँ उन सभी के द्वारा काम करती हैं जो एक सामान्य आधार वर्ग से विरासत में प्राप्त होते हैं, और इंटरफ़ेस को परिभाषित करने के लिए बेस क्लास में वर्चुअल फ़ंक्शंस का उपयोग करते हैं, और व्युत्पन्न वर्ग उन वर्चुअल फ़ंक्शंस के कार्यान्वयन प्रदान करते हैं, जो (और अक्सर) पर्याप्त रन-टाइम जोड़ देगा। शामिल कार्यों के लिए ओवरहेड।

उदाहरण के लिए, एक साधारण पुनरावृत्ति पदानुक्रम जो विरासत और आभासी कार्यों का उपयोग करता है, पर विचार करें:

template <class T>
class iterator_base { 
public:
    virtual T &operator*() = 0;
    virtual iterator_base &operator++() = 0;
    virtual bool operator==(iterator_base const &other) { return pos == other.pos; }
    virtual bool operator!=(iterator_base const &other) { return pos != other.pos; }
    iterator_base(T *pos) : pos(pos) {}
protected:
    T *pos;
};

template <class T>
class array_iterator : public iterator_base<T> {
public: 
    virtual T &operator*() override { return *pos; }
    virtual array_iterator &operator++() override { ++pos; return *this; }
    array_iterator(T *pos) : iterator_base(pos) {}
};

तो फिर चलो यह एक त्वरित परीक्षण दे:

int main() { 
    char input[] = "asdfasdfasdfasdfasdfasdfasdfadsfasdqwerqwerqwerqrwertytyuiyuoiiuoThis is a stringy to search for something";
    using namespace std::chrono;

    auto start1 = high_resolution_clock::now();
    auto pos = std::find(std::begin(input), std::end(input), 'g');
    auto stop1 = high_resolution_clock::now();

    std::cout << *++pos << "\n";

    auto start2 = high_resolution_clock::now();
    auto pos2 = std::find(array_iterator(input), array_iterator(input+sizeof(input)), 'g');
    auto stop2 = high_resolution_clock::now();

    std::cout << *++pos2 << "\n";

    std::cout << "time1: " << duration_cast<nanoseconds>(stop1 - start1).count() << "ns\n";
    std::cout << "time2: " << duration_cast<nanoseconds>(stop2 - start2).count() << "ns\n";
}

[ध्यान दें: आपके कंपाइलर के आधार पर, आपको कुछ और करने की आवश्यकता हो सकती है, जैसे कि iterator_category, अंतर_type, reference, और इतने पर, कंपाइलर को इट्रेटर स्वीकार करने के लिए परिभाषित करना।]

और आउटपुट है:

y
y
time1: 1833ns
time2: 2933ns

[बेशक, यदि आप कोड चलाते हैं, तो आपके परिणाम इनसे बिल्कुल मेल नहीं खाएंगे।]

तो, इस साधारण मामले के लिए भी (और केवल लगभग 80 वेतन वृद्धि और तुलनाएँ करते हुए) हमने एक साधारण रेखीय खोज में लगभग 60% ओवरहेड जोड़ दिया है। विशेष रूप से जब पुनरावृत्तियों को मूल रूप से C ++ में जोड़ा गया था, तो कुछ लोगों ने बस उस ओवरहेड के साथ एक डिजाइन स्वीकार नहीं किया होगा। वे शायद मानकीकृत नहीं थे, और अगर उनके पास होता, तो भी कोई भी उनका उपयोग नहीं करता।


7

अंतर यह है कि कुछ क्या है, और कैसे है कुछ व्यवहार करता है।

बहुत सारी भाषाएं दोनों को एक साथ जोड़ने का प्रयास करती हैं, लेकिन वे काफी अलग चीजें हैं।

यदि कैसे है, और कैसे है ...

यदि सब कुछ विरासत में मिलता है objectतो कुछ लाभ होते हैं जैसे: वस्तु का कोई भी चर किसी भी मूल्य को कभी भी धारण कर सकता है। लेकिन यह भी रगड़ना है, सब कुछ ( एक ) की तरह व्यवहार करना चाहिए ( और क्या )objectobject

परंतु:

  • क्या होगा यदि आपकी वस्तु में समानता की सार्थक परिभाषा नहीं है?
  • अगर इसके पास कोई सार्थक हैश न हो तो क्या होगा?
  • क्या होगा यदि आपकी वस्तु को क्लोन नहीं किया जा सकता है, लेकिन ऑब्जेक्ट हो सकते हैं?

या तो objectप्रकार अनिवार्य रूप से बेकार हो जाता है - वस्तु के कारण सभी संभावित उदाहरणों में कोई समानता नहीं प्रदान करता है। या ऐसी वस्तुएं मौजूद होंगी जिनके पास कुछ प्रकल्पित सार्वभौमिक संपत्ति की टूटी हुई / जूता-सींग वाली / बेतुकी परिभाषा है, objectजिस पर लगभग साबित होता है को छोड़कर सार्वभौमिक व्यवहार होता है।

अगर व्हाट्स अप के साथ बाउंड नहीं है

वैकल्पिक रूप से आप क्या और कैसे अलग रख सकते हैं । तब कई अलग अलग प्रकार (कम से आम में कुछ भी नहीं के साथ सभी क्या ) कर सकते हैं उसी तरह से सब व्यवहार सहयोगी से देखा कैसे । इस अर्थ में एक Iteratorका विचार एक विशिष्ट नहीं है , लेकिन कैसे है । विशेष रूप से आप किसी चीज़ के साथ कैसे बातचीत करते हैं जब आप अभी तक नहीं जानते हैं कि आप किसके साथ बातचीत कर रहे हैं।

जावा (और इसी तरह) इंटरफेस का उपयोग करके इस तक पहुंचने की अनुमति देता है। इस संबंध में एक इंटरफ़ेस संचार के साधनों का वर्णन करता है, और इसके बाद संचार और कार्रवाई का एक प्रोटोकॉल होता है। किसी भी क्या है जो अपने आप वाणी एक दिया की हो कैसे , कहा गया है कि यह प्रासंगिक संचार और कार्रवाई प्रोटोकॉल द्वारा उल्लिखित का समर्थन करता है। यह किसी भी सहयोगी पर भरोसा करने की अनुमति देता है कैसे और नहीं वास्तव में कौन-निर्दिष्ट द्वारा झमेले में क्या इस्तेमाल किया जा सकता है।

C ++ (और समान) बतख टाइपिंग द्वारा इस के लिए दृष्टिकोण की अनुमति देते हैं। एक टेम्पलेट परवाह नहीं करता है अगर सहयोगी प्रकार घोषित करता है कि यह एक व्यवहार का अनुसरण करता है, बस एक दिए गए संकलन संदर्भ में, कि वस्तु के साथ एक विशेष तरीके से बातचीत की जा सकती है। यह C ++ पॉइंटर्स, और ऑब्जेक्ट्स को एक ही कोड द्वारा उपयोग किए जाने वाले विशिष्ट ऑपरेटरों की सवारी करने की अनुमति देता है। क्योंकि वे चेक-लिस्ट को समतुल्य मानने के लिए मिलते हैं।

  • * a, a->, ++ a, और a ++ -> इनपुट / फॉरवर्ड इटरेटर का समर्थन करता है
  • * a, a->, ++ a, a +, --a, और a-- -> द्विदिश पुनरावृत्ति का समर्थन करता है

अंतर्निहित प्रकार भी बार-बार दोहराना एक कंटेनर हो सकता है, यह किसी भी हो सकता है नहीं है क्या । इसके अतिरिक्त यह कुछ सहयोगियों को और भी सामान्य होने की अनुमति देता है, केवल एक फ़ंक्शन की आवश्यकता की कल्पना करें a++, एक पुनरावृत्तिकर्ता उसे संतुष्ट कर सकता है, इसलिए एक संकेतक, तो एक पूर्णांक, तो किसी भी वस्तु को लागू कर सकता है operator++

अंडर और ओवर स्पेसिफिकेशन

दोनों दृष्टिकोणों के साथ समस्या अंडर और ओवर स्पेसिफिकेशन है।

एक इंटरफ़ेस का उपयोग करने के लिए ऑब्जेक्ट को घोषित करने की आवश्यकता होती है यह एक दिए गए व्यवहार का समर्थन करता है, जिसका अर्थ यह भी है कि निर्माता को शुरुआत से ही इसे लागू करना होगा। इस कारण कुछ क्या 'कटौती नहीं करने के लिए है, के रूप में वे यह घोषणा नहीं की थी। इसका अर्थ यह भी है कि कभी-कभी एक सामान्य पूर्वज क्या होता है, इंटरफ़ेस हाउ का प्रतिनिधित्व करता है । यह प्रारंभिक समस्या का हल करता है object। यह सहयोगियों को उनकी आवश्यकताओं को अधिक निर्दिष्ट करने का कारण बनता है, साथ ही साथ कुछ वस्तुओं को घोषणा की कमी के कारण या तो अनुपयोगी होना पड़ता है, या एक अपेक्षित व्यवहार के रूप में छिपे हुए गोचरों को खराब परिभाषित किया जाता है।

टेम्पलेट का उपयोग करने के लिए यह आवश्यक है कि सहयोगी पूरी तरह से अज्ञात व्हाट्स के साथ काम करता है , और अपनी बातचीत के माध्यम से यह एक हाउ को परिभाषित करता है । कुछ हद तक यह बनाता है, कठिन सहयोगियों लेखन के रूप में यह विश्लेषण करना चाहिए क्या अपने संचार पुरातन के लिए बाहर (कार्यों / क्षेत्रों / आदि), जबकि संकलन त्रुटियों से परहेज, या कम से कम बात कैसे एक दिया क्या के लिए अपनी आवश्यकताओं को मेल नहीं खाता कैसे । यह सहयोगी किसी भी से निरपेक्ष न्यूनतम आवश्यकता होती है की अनुमति देता है क्या , का व्यापक रेंज की अनुमति देता है क्या 'प्रयोग की जाने वाली है। दुर्भाग्यवश इसमें वस्तुओं के निरर्थक उपयोग की अनुमति देने का नकारात्मक पहलू है जो तकनीकी किसी दिए गए संचार प्राइमेटिव प्रदान करते हैंकैसे , लेकिन निहित प्रोटोकॉल का पालन न करें ताकि सभी प्रकार की बुरी चीजें घटित हो सकें।

iterators

इस मामले में एक Iteratorहै एक यह कैसे बातचीत के विवरण के लिए आशुलिपि है। जो कुछ भी उस विवरण से मेल खाता है वह परिभाषा ए है Iterator। यह जानते हुए कि कैसे हमें सामान्य एल्गोरिदम लिखने और की 'एक छोटी सूची के लिए अनुमति देता है कैसे ' एक विशिष्ट दिया रहा है क्या 'की जरूरत आदेश एल्गोरिथ्म काम करने के लिए में प्रदान किया जाना है। उस सूची में समारोह / गुण / आदि, उनके क्रियान्वयन पर ध्यान देता है विशिष्ट हैं क्या कि एल्गोरिथ्म द्वारा के साथ निपटा जा रहा है।


6

क्योंकि सी ++ नहीं है जरूरत है बहुरूपता करने के लिए (सार) आधार वर्ग के लिए। इसमें संरचनात्मक उपप्रकार के साथ-साथ नाममात्र उपप्रकार भी है

Iterators के विशेष मामले में भ्रमित, पिछले मानकों std::iteratorको (लगभग) के रूप में परिभाषित किया गया है

template <class Category, class T, class Distance = std::ptrdiff_t, class Pointer = T*, class Reference = T&>
struct iterator {
    using iterator_category = Category;
    using value_type = T;
    using difference_type = Distance;
    using pointer = Pointer;
    using reference = Reference;
}

यानी केवल आवश्यक सदस्य प्रकारों के प्रदाता के रूप में। यह किसी भी क्रम व्यवहार नहीं था, और C ++ 17 में पदावनत किया गया था

ध्यान दें कि यहां तक ​​कि यह एक सामान्य आधार नहीं हो सकता है, क्योंकि एक वर्ग टेम्पलेट एक वर्ग नहीं है, प्रत्येक तात्कालिकता दूसरों से अकेला खड़ा है।



5

एक कारण यह है कि पुनरावृत्तियों को एक वर्ग का उदाहरण नहीं होना चाहिए। उदाहरण के लिए, कई मामलों में संकेत पूरी तरह से अच्छे चलने वाले होते हैं, और चूंकि वे आदिम हैं इसलिए वे किसी भी चीज़ से विरासत में नहीं मिल सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.