दिलचस्प पोस्ट
छोरों के साथ `दो 'और ब्लॉक स्कोपिंग का स्पष्टीकरण जेएसएफ एमवीसी ढांचे में एमवीसी क्या घटक हैं? मैं एक ही आईपी पते से कई युगपत कनेक्शन की अनुमति देने के लिए कैसे Apache2 को कॉन्फ़िगर कर सकता हूँ? गतिशील रूप से विद्यमान टैब फिर से बनाने के बिना चमकदार रूप से भूखंडों के साथ टैब बनाना मुझे OSV पर JAVA_HOME को क्या सेट करना चाहिए? स्विफ्ट में एक प्रेषण_ऑनसी सिंगलटन मॉडल का उपयोग करना कैसे जावास्क्रिप्ट में फ़ायरफ़ॉक्स से HTML को पार्स करने के लिए? डीपी के मामले में स्क्रीन चौड़ाई कैसे निर्धारित करें या एंड्रॉइड में रनटाइम पर डुबकी? php में json डीकोड मैं एक फ़ाइल में एक ड्रॉएबल संसाधन कैसे लिख सकता हूं? कैसे जावा में एक अवधि को प्रारूपित करें? (जैसे प्रारूप एच: एमएम: एसएस) मैट्रिक्स गुणन: मैट्रिक्स आकार में छोटा अंतर, समय में बड़ा अंतर उद्देश्य सी में यूटीएफ 8 वर्ण डिकोडिंग ARC4random_uniform XX 7.0 बीटा (7a176x) OSX 10.10.4 पर उपलब्ध नहीं है मैं TransactionScope का उपयोग सी # में कैसे करूं?

पॉलीमॉर्फिज़्म बिना संकेत / संदर्भ के काम क्यों करता है?

मैंने पहले से ही कुछ प्रश्नों को समान शीर्षक से प्राप्त किया है- लेकिन जब मैं जवाब पढ़ता हूं तो वे उस प्रश्न के विभिन्न हिस्सों पर ध्यान केंद्रित कर रहे थे जो वास्तव में विशिष्ट थे (उदाहरण के लिए एसटीएल / कंटेनर)

क्या कोई मुझे दिखा सकता है कि आपको बहुरूपता को लागू करने के लिए पॉइंटर्स / संदर्भ का उपयोग क्यों करना चाहिए? मैं समझ सकता हूँ कि संकेतक मदद कर सकते हैं- लेकिन निश्चित रूप से संदर्भ केवल पास-बाय-वैल्यू और पास-बाय-रेफरेंस के बीच अंतर करते हैं ??

निश्चित रूप से जब तक आप ढेर पर मेमोरी आवंटित करते हैं- ताकि आप गतिशील बाध्यकारी हो सकें, तो यह पर्याप्त होगा- स्पष्ट रूप से नहीं।

Solutions Collecting From Web of "पॉलीमॉर्फिज़्म बिना संकेत / संदर्भ के काम क्यों करता है?"

सी ++ में, एक ऑब्जेक्ट में हमेशा एक निश्चित प्रकार और आकार होता है जिसे संकलन-समय पर जाना जाता है और (यदि यह हो सकता है और इसका पता लेता है) हमेशा अपने जीवनकाल की अवधि के लिए एक निश्चित पते पर मौजूद होता है। ये सी से प्राप्त की जाने वाली विशेषताएं हैं जो कम-स्तरीय सिस्टम प्रोग्रामिंग के लिए दोनों भाषाओं को उपयुक्त बनाने में मदद करते हैं। (यह सब, जैसा कि नियम, के अधीन है, हालांकि: एक अनुरूप कम्पाइलर जो भी कोड के साथ चाहे चाहे जो करने के लिए स्वतंत्र होता है, यह साबित किया जा सकता है कि किसी अनुकूल प्रोग्राम के किसी भी व्यवहार पर कोई भी प्रभाव नहीं होता है जो कि गारंटी है मानक द्वारा।)

सी ++ में एक virtual फ़ंक्शन परिभाषित है (अधिक या कम, चरम भाषा कानून के लिए कोई ज़रूरत नहीं) किसी ऑब्जेक्ट के रन-टाइम प्रकार के आधार पर क्रियान्वित करने के लिए; जब किसी ऑब्जेक्ट पर सीधे कहा जाता है तो यह हमेशा ऑब्जेक्ट का संकलन-टाइम प्रकार होगा, इसलिए जब कोई virtual फ़ंक्शन इस तरह से कहा जाता है तो कोई बहुरूपता नहीं है।

ध्यान दें कि यह जरूरी नहीं कि मामला होना चाहिए: virtual फ़ंक्शंस के साथ ऑब्जेक्ट प्रकार आमतौर पर प्रत्येक वस्तु के लिए अद्वितीय virtual फ़ंक्शंस की मेज पर प्रति-ऑब्जेक्ट पॉइंटर के साथ सी ++ में कार्यान्वित किया जाता है। यदि ऐसा प्रतीत होता है, तो सी ++ के कुछ काल्पनिक संस्करणों के लिए एक कंपाइलर ऑब्जेक्ट पर ऑब्जेक्ट (जैसे Base b; b = Derived() ) को ऑब्जेक्ट की सामग्री और इसके साथ virtual टेबल पॉइंटर को कॉपी करने के रूप में काम करता है, जो आसानी से काम करेगा यदि दोनों Base और Derived एक ही आकार थे इस मामले में कि दोनों एक ही आकार नहीं थे, कंपाइलर उस कोड को भी सम्मिलित कर सकता है जो प्रोग्राम में मेमोरी को पुनर्व्यवस्थित करने के लिए कार्यक्रम को एक मनमाना राशि के लिए रोकता है और उस मेमोरी के सभी संभावित संदर्भों को एक तरह से अद्यतन करता है प्रोग्राम की शब्दार्थों पर कोई पता लगाने योग्य प्रभाव साबित नहीं हुआ है, यदि कोई ऐसा पुनर्व्यवस्था नहीं मिल पाई तो प्रोग्राम को समाप्त कर दिया जा सकता है: हालांकि यह बहुत ही अक्षम है, और कभी भी बंद करने की गारंटी नहीं दी जा सकती, स्पष्ट रूप से एक असाइनमेंट ऑपरेटर के लिए वांछनीय विशेषताओं की है।

इसलिए उपरोक्त के बजाय, सी ++ में बहुरूपता को संदर्भों और संकेतों को ऑब्जेक्ट के संदर्भ में संदर्भित करने और उनके घोषित संकलन-समय प्रकारों और उनके उप-प्रकार के ऑब्जेक्ट को इंगित करके पूरा किया जाता है। जब एक virtual फ़ंक्शन को संदर्भ या संकेतक के माध्यम से बुलाया जाता है, और कंपाइलर साबित नहीं कर सकता कि ऑब्जेक्ट को संदर्भित किया गया है या उस virtual फ़ंक्शन के विशिष्ट ज्ञात कार्यान्वयन के साथ रन-टाइम प्रकार की है, तो कंपाइलर सम्मिलित कोड जो सही दिखता है एक रन-टाइम कॉल करने के लिए virtual फ़ंक्शन यह इस तरह से होना ही नहीं था, या तो: संदर्भ और पॉइंटर्स को गैर-बहुरूपता के रूप में परिभाषित किया जा सकता था (इन्हें उनके घोषित प्रकार के उप-प्रकारों को संदर्भित करने या संदर्भ देने की अनुमति नहीं देनी चाहिए) और प्रोग्रामर को बहुरूपता को लागू करने के वैकल्पिक तरीकों के साथ आने के लिए मजबूर किया जा सकता है । उत्तरार्द्ध स्पष्ट रूप से संभव है क्योंकि यह सी में हर समय किया जाता है, परन्तु उस समय कोई नई भाषा नहीं होनी चाहिए।

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

"निश्चित रूप से जब तक आप ढेर पर मेमोरी आवंटित करते हैं" – जहां स्मृति को आवंटित किया गया है उसके साथ कुछ नहीं करना है। यह शब्दावली के बारे में है उदाहरण के लिए, लें:

 Derived d; Base* b = &d; 

d स्टैक (स्वचालित मेमोरी) पर है, लेकिन बहुरूपता अभी भी b पर कार्य करेगा।

यदि आपके पास कोई बेस क्लास पॉइंटर या व्युत्पन्न वर्ग के संदर्भ नहीं हैं, तो बहुरूपता काम नहीं करता क्योंकि आपके पास कोई व्युत्पन्न वर्ग नहीं है। लेना

 Base c = Derived(); 

c ऑब्जेक्ट एक Derived नहीं है, लेकिन Derived कारण Base । इसलिए, तकनीकी तौर पर, बहुरूपता अभी भी काम करता है, यह सिर्फ इतना है कि आप के बारे में बात करने के लिए अब कोई Derived वस्तु नहीं है

अब ले लो

 Base* c = new Derived(); 

c मेमोरी में कुछ जगह को इंगित करता है, और आप वास्तव में परवाह नहीं करते हैं कि यह वास्तव में एक Base या एक Derived , लेकिन एक virtual विधि को कॉल गतिशील रूप से हल किया जाएगा

मुझे यह समझने में मदद मिली कि एक प्रति निर्माता को इस तरह से निर्दिष्ट करते समय लागू किया जाता है:

 class Base { }; class Derived : public Base { }; Derived x; /* Derived type object created */ Base y = x; /* Copy is made (using Base's copy constructor), so y really is of type Base. Copy can cause "slicing" btw. */ 

चूंकि वाई मूल आधार की बजाय कक्षा आधार का एक वास्तविक वस्तु है, इसलिए इस पर बुलाए गए फ़ंक्शन हैं बेस के फ़ंक्शन।

छोटे अंत्येक आर्किटेक्चर पर विचार करें: मूल्यों को कम क्रम-बाइट्स पहले संग्रहीत किया जाता है। इसलिए, किसी भी हस्ताक्षरित पूर्णांक के लिए, मान 0-255 मूल्य के पहले बाइट में संग्रहीत किए जाते हैं। किसी भी मूल्य के कम 8-बिट तक पहुंचने के लिए बस इसके पते पर एक सूचक की आवश्यकता होती है

तो हम एक वर्ग के रूप में uint8 को लागू कर सकते हैं। हम जानते हैं कि uint8 का एक उदाहरण है … एक बाइट अगर हम इसे से प्राप्त करते हैं और uint16 , uint16 , इत्यादि का उत्पादन uint16 , तो अंतरफलक अमूर्त के उद्देश्यों के लिए एक ही रहता है, लेकिन एक सबसे महत्वपूर्ण परिवर्तन वस्तु के ठोस उदाहरणों का आकार है।

बेशक, अगर हम uint8 और char कार्यान्वित करते हैं, तो आकार समान हो सकते हैं, इसी तरह sint8

हालांकि, uint8 और uint16 uint8 operator= अलग-अलग आंकड़ों को स्थानांतरित करने जा रहे हैं।

पॉलीमॉर्फिक फ़ंक्शन बनाने के लिए हमें या तो निम्न में सक्षम होना चाहिए:

सही आकार और लेआउट के एक नए स्थान में डेटा की प्रतिलिपि करके मूल्य के आधार पर तर्क प्राप्त होता है, बी / एक सूचक को ऑब्जेक्ट के स्थान पर ले जाता है, सी / ऑब्जेक्ट इंस्टेंस के संदर्भ में,

हम प्राप्त करने के लिए टेम्प्लेट का उपयोग कर सकते हैं, इसलिए बहुरूपता बिना संकेत और संदर्भ के काम कर सकता है , लेकिन अगर हम टेम्पलेट की गिनती नहीं कर रहे हैं, तो हम क्या सोचते हैं कि क्या हम uint128 कार्यान्वित uint128 और uint128 लिए इसे पास करते हैं? उत्तर: 8 बिट्स को 128 की बजाय कॉपी किया जाता है

तो क्या हुआ अगर हमने अपना uint128 समारोह uint128 स्वीकार uint128 और हमने उसे uint8 पास कर दिया। यदि हमारे uint8 हम नकल की गई थी, दुर्भाग्य से स्थित था, तो हमारा कार्य 128 बाइट्स की प्रतिलिपि करने का प्रयास करेगा, जिनमें से 127 हमारे पहुंच योग्य मेमोरी के बाहर थे -> दुर्घटना

निम्नलिखित को धयान मे रखते हुए:

 class A { int x; }; A fn(A a) { return a; } class B : public A { uint64_t a, b, c; B(int x_, uint64_t a_, uint64_t b_, uint64_t c_) : A(x_), a(a_), b(b_), c(c_) {} }; B b1 { 10, 1, 2, 3 }; B b2 = fn(b1); // b2.x == 10, but a, b and c? 

उस समय fn संकलित किया गया था, B का कोई ज्ञान नहीं था। हालांकि, B A से प्राप्त किया जाता है इसलिए बहुरूपता हमें B साथ fn को बुला सकता है। हालांकि, वस्तु जिस पर रिटर्न करती है वह A होना चाहिए जिसमें एकल int होगा।

अगर हम इस समारोह में B का एक उदाहरण देते हैं, तो हम जो वापस प्राप्त करते हैं वह सिर्फ एक { int x; } { int x; } कोई नहीं, बी, सी के साथ

यह "टुकड़ा करने की क्रिया" है

यहां तक ​​कि पॉइंटर्स और संदर्भ के साथ भी हम इस से मुक्त नहीं होते हैं। विचार करें:

 std::vector<A*> vec; 

इस वेक्टर के तत्व A को संकेत दिए जा सकते हैं या A से प्राप्त हुई वस्तुएं भाषा आमतौर पर "vtable" के उपयोग के माध्यम से यह हल करती है, ऑब्जेक्ट के उदाहरण के लिए एक छोटे से अतिरिक्त जो कि प्रकार की पहचान करता है और वर्चुअल फ़ंक्शन के लिए फ़ंक्शन पॉइंटर्स प्रदान करता है। आप इसे की तरह कुछ के रूप में सोच सकते हैं:

 template<class T> struct PolymorphicObject { T::vtable* __vtptr; T __instance; }; 

प्रत्येक वस्तु के अलग-अलग vtable होने के बजाय, कक्षाएं उन्हें होती हैं, और ऑब्जेक्ट इन्सटेंस केवल संबंधित वीबले को इंगित करते हैं।

समस्या अब टुकड़ा करने की क्रिया नहीं है, लेकिन प्रकार की शुद्धता:

 struct A { virtual const char* fn() { return "A"; } }; struct B : public A { virtual const char* fn() { return "B"; } }; #include <iostream> #include <cstring> int main() { A* a = new A(); B* b = new B(); memcpy(a, b, sizeof(A)); std::cout << "sizeof A = " << sizeof(A) << " a->fn(): " << a->fn() << '\n'; } 

http://ideone.com/G62Cn0

 sizeof A = 4 a->fn(): B 

हमें क्या करना चाहिए था a->operator=(b)

http://ideone.com/Vym3Lp

लेकिन फिर से, यह ए को ए को प्रतिलिपि बना रहा है और इतना टुकड़ा करने की क्रिया होती है:

 struct A { int i; A(int i_) : i(i_) {} virtual const char* fn() { return "A"; } }; struct B : public A { int j; B(int i_) : A(i_), j(i_ + 10) {} virtual const char* fn() { return "B"; } }; #include <iostream> #include <cstring> int main() { A* a = new A(1); B* b = new B(2); *a = *b; // aka a->operator=(static_cast<A*>(*b)); std::cout << "sizeof A = " << sizeof(A) << ", a->i = " << a->i << ", a->fn(): " << a->fn() << '\n'; } 

http://ideone.com/DHGwun

( i नकल की गई है, लेकिन बी की j खो गई है)

इसका निष्कर्ष यह है कि संकेत / संदर्भों की आवश्यकता है क्योंकि मूल उदाहरण के साथ सदस्यता जानकारी रखती है कि प्रतिलिपि के साथ बातचीत हो सकती है।

लेकिन यह भी कि, बहुरूपता को पूरी तरह से सी ++ के भीतर हल नहीं किया गया है और एक को उन कार्यों को प्रदान करने / ब्लॉक करने के दायित्व की जानकारी होनी चाहिए, जो टुकड़ा करने की क्रिया का उत्पादन कर सकती हैं।

आपको पॉयेंटर या संदर्भ की आवश्यकता है क्योंकि आप (*) में रुचि रखने वाले बहुरूपता के लिए, आपको आवश्यक है कि गतिशील प्रकार स्थिर प्रकार से भिन्न हो सकता है, दूसरे शब्दों में, वस्तु का वास्तविक प्रकार घोषित प्रकार से अलग है। C ++ में केवल संकेत या संदर्भ के साथ होता है।


(*) जेनेरिकता, टेम्पलेट्स द्वारा प्रदत्त बहुरूपता का प्रकार, संकेतक की आवश्यकता नहीं है और न ही संदर्भ।

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

अब, सब कुछ ढेर पर नहीं जाता है, और वहाँ अन्य extenuating परिस्थितियों रहे हैं। आभासी विधियों के मामले में, ऑब्जेक्ट के पॉइंटर ऑब्जेक्ट के वीटेबल (एस) के लिए एक सूचक भी होता है, जिसमें यह संकेत मिलता है कि तरीके कहाँ हैं I इससे कंपाइलर को कार्य करने और कॉल करने की सुविधा मिलती है, इसके बावजूद यह किस वस्तु के साथ काम कर रहा है

एक अन्य कारण यह है कि अक्सर ऑब्जेक्ट को कॉलिंग पुस्तकालय के बाहर लागू किया जाता है, और पूरी तरह से अलग (और संभवतः असंगत) मेमोरी मैनेजर के साथ आवंटित किया गया है। इसमें ऐसे सदस्य भी हो सकते हैं जिन्हें कॉपी नहीं किया जा सकता, या यदि वे अलग प्रबंधक के साथ कॉपी किए गए हैं प्रतिलिपि करने और अन्य सभी जटिलताओं के सभी प्रकार के दुष्प्रभाव हो सकते हैं

नतीजा यह है कि पॉइंटर उस ऑब्जेक्ट पर जानकारी का एकमात्र बिट है जिसे आप वास्तव में अच्छी तरह से समझते हैं, और यह पता लगाने के लिए पर्याप्त जानकारी प्रदान करता है कि आपको अन्य बिट्स कहां चाहिए।