2014-10-03 11 views
5

मैं एक जावा प्रोग्रामर हूं और हाल ही में सी ++ का अध्ययन करना शुरू कर दिया है। मैं कुछ से उलझन में हूँ।मैं सामान्य चर के साथ बहुरूपता क्यों नहीं कर सकता?

मैं समझता हूं कि सी ++ में, पॉलिमॉर्फिक व्यवहार प्राप्त करने के लिए आपको पॉइंटर्स या संदर्भों का उपयोग करना होगा। उदाहरण के लिए, एक लागू विधि getArea() के साथ कक्षा Shape पर विचार करें। इसमें कई उप-वर्ग हैं, प्रत्येक ओवरराइडिंग एरिया() अलग-अलग हैं।

void printArea(Shape* shape){ 
    cout << shape->getArea(); 
} 

समारोह सही getArea() कार्यान्वयन कहता है, के लिए ठोस Shape सूचक अंक के आधार पर: निम्नलिखित समारोह पर विचार की तुलना में।

यह वही काम करता है:

void printArea(Shape& shape){ 
    cout << shape.getArea(); 
} 

हालांकि, निम्न विधि polymorphicaly काम नहीं करता:

void printArea(Shape shape){ 
    cout << shape.getArea(); 
} 

, एक ही क्या Shape की ठोस तरह समारोह में पारित हो जाता है कोई फर्क नहीं पड़ता getArea() कार्यान्वयन कहा जाता है: Shape में डिफ़ॉल्ट एक।

मैं इसके पीछे तकनीकी तर्क समझना चाहता हूं। पॉलीमोर्फिज्म पॉइंटर्स और संदर्भों के साथ क्यों काम करता है, लेकिन सामान्य चर के साथ नहीं? (और मुझे लगता है कि यह न केवल फ़ंक्शन पैरामीटर के लिए सही है, बल्कि किसी भी चीज़ के लिए)।

कृपया समझने में मेरी सहायता के लिए, इस व्यवहार के तकनीकी कारणों की व्याख्या करें।

+0

यह सहायक हो सकता है। http://stackoverflow.com/questions/7516545/why-is-object-slice-needed-in-c-why-it-is-allowed-for-more-bugs –

+5

यह जानना भी उपयोगी हो सकता है कि जावा में सभी वस्तुओं वास्तव में असली वस्तुओं के लिए संकेतक हैं। इसलिए, यदि आपके पास कक्षा आकार है, तो "आकार ए = बी" केवल पॉइंटर को वास्तविक वस्तु पर आंतरिक रूप से प्रतिलिपि बनाता है, और आंतरिक संदर्भ गणना को बढ़ाता है। जब किसी ऑब्जेक्ट के सभी संदर्भ चले जाते हैं, तो यह जावा के कचरा संग्रह के अधीन हो जाता है। सी ++ में, आप वास्तविक वस्तुओं के साथ खेलना चाहते हैं। उन्हें चारों ओर कॉपी करें, इत्यादि यही कारण है कि बहुरूपता केवल पॉइंटर्स (या संदर्भ, जो पॉइंटर्स के लिए ज्यादातर वाक्य रचनात्मक चीनी हैं) के साथ काम करती है। –

+0

फ़ंक्शन को केवल 'आकार' प्राप्त होता है। यदि आप उप प्रकार (या किसी अन्य प्रकार) को पास करते हैं तो इसे 'आकार' में परिवर्तित किया जाता है। – Galik

उत्तर

4

उत्तर प्रतिलिपि है।

जब आप किसी ऑब्जेक्ट को C++ में मान से पास करते हैं, उदा। printArea(Shape shape) एक प्रति आपके द्वारा पारित वस्तु से बना है। और यदि आप इस फ़ंक्शन में व्युत्पन्न कक्षा पास करते हैं, तो कॉपी की गई सभी मूल श्रेणी Shape है। यदि आप इसके बारे में सोचते हैं, तो कंपाइलर कुछ और नहीं कर सकता है।

Shape shapeCopy = circle; 

shapeCopy एक Shape, नहीं एक Circle के रूप में घोषित किया गया था, इसलिए सभी संकलक कर सकते हैं वस्तु की Shape हिस्सा की एक प्रति का निर्माण है।

+0

मैं देखता हूं। और यह सरल असाइनमेंट पर भी लागू होता है, न केवल पैरामीटर पास करने के लिए, सही? उदाहरण के लिए निम्नलिखित कोड में: 'आकार एस; अगर (कुछ) एस = आयताकार (5, 5); अन्य एस = मंडल (5); cout << s.getArea(); 'जो भी हो, उसे जो भी सौंपा गया है उसे' आकार 'में घटा दिया गया है (इससे कोई फर्क नहीं पड़ता कि यह' आयत 'या' सर्कल 'है, क्योंकि मूल्य की प्रतिलिपि बनाई गई है? –

+0

सही, मूल्य से गुज़रने से एक प्रतिलिपि बनती है, लेकिन यह एक प्रतिलिपि बनाने के बारे में है, विशेष रूप से पैरामीटर को पार करने के बारे में नहीं। –

+0

फिर भी, यह सुनिश्चित नहीं है कि संकलक 'आकार' चर को 'सर्कल' आवृत्ति को क्यों निर्दिष्ट नहीं कर सकता है - यानी इसे चर को निर्दिष्ट करने से पहले इसे 'टुकड़ा' क्यों करना है। एक धारणा यह है कि यह स्मृति की वजह से है: संकलक ने वैरिएबल को 'आकार' के लिए उचित मात्रा में स्मृति आवंटित किया है, जो आवश्यक नहीं है 'सर्कल' ऑब्जेक्ट। इसलिए यह 'आकार' की परिभाषा को 'सर्किल' को कम करता है। क्या वो सही है? –

1

जब void printArea(Shape shape) कहा जाता है, तो आपकी ऑब्जेक्ट को स्टैक पर एक नए नए Shape में कॉपी किया गया है। उप-वर्ग भागों की प्रतिलिपि नहीं बनाई गई है। इसे object slicing के रूप में जाना जाता है। यदि बेस-क्लास ऑब्जेक्ट वैध नहीं है (उदा। इसमें शुद्ध वर्चुअल फ़ंक्शंस हैं), तो आप इस फ़ंक्शन को घोषित या कॉल भी नहीं कर सकते हैं। यह "मूल्य से गुजरना" अर्थशास्त्र है; पास-इन ऑब्जेक्ट की एक प्रति आपूर्ति की जाती है।

जब void printArea(Shape& shape) कहा जाता है, तो आपके Circle या Rectangle ऑब्जेक्ट का संदर्भ पारित किया जाता है। (विशेष रूप से, उस ऑब्जेक्ट के Shape भाग का संदर्भ। आप Circle - या Square-कास्टिंग किए बिना विशिष्ट सदस्यों तक नहीं पहुंच सकते हैं। लेकिन वर्चुअल फ़ंक्शन सही तरीके से काम करते हैं।) यह "संदर्भ द्वारा पास" अर्थशास्त्र है; मूल वस्तु का संदर्भ पारित किया गया है।

+0

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

+0

स्पष्ट करने के लिए शरीर में एक पैरेंटिकल जोड़ा गया। धन्यवाद! – StilesCrisis

+0

उत्तर देने के लिए धन्यवाद। फिर भी, मुझे यकीन नहीं है कि संकलक एक सारणी चर पर सर्कल ऑब्जेक्ट को असाइन नहीं कर सकता है - यानी इसे चर को निर्दिष्ट करने से पहले इसे 'टुकड़ा' क्यों करना है। मेरे पास एक धारणा है कि यह स्मृति की वजह से है: संकलक ने वैरिएबल को 'आकार' के लिए उचित मात्रा में स्मृति आवंटित किया है, जो आवश्यक रूप से मंडल ऑब्जेक्ट के अनुरूप नहीं है। इसलिए यह 'आकार' की परिभाषा के लिए मंडल को 'कम करता है'। क्या वो सही है? –

1

आप रन-टाइम पॉलीमोर्फिज्म के बारे में बात कर रहे हैं।

यह विचार है कि कोई ऑब्जेक्ट * सांख्यिकीय रूप से ज्ञात वर्ग से प्राप्त कक्षा का हो सकता है, ताकि स्थैतिक रूप से ज्ञात वर्ग में वर्चुअल सदस्य फ़ंक्शंस को कॉल किया जा सके, व्युत्पन्न क्लास कार्यान्वयन में समाप्त हो।

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


*) स्थिरता में जाना जाता वर्ग किसी भी विश्लेषण, घोषित वर्ग के बिना संकलक के लिए जाना जाता का मतलब है।

+0

मुझे नहीं पता कि इस स्तर पर हर कोई समझता है कि "सांख्यिकीय रूप से ज्ञात वर्ग" के साथ आपका क्या मतलब है। इसके अतिरिक्त, ओपी जावा पृष्ठभूमि बताता है, इसलिए सी ++ मान/कॉपी सेमेन्टिक्स अज्ञात हो सकता है। थोड़ा अलग दृष्टिकोण से, कोई उस वस्तु के प्रकार के बारे में बात कर सकता है जो वास्तव में स्मृति में मौजूद है, और फ़ंक्शन पैरामीटर को देखते समय कंपाइलर को देखता है। – dyp

+0

ओकाई, एक शब्दावली फुटनोट जोड़ा गया। धन्यवाद! –

0

मूल रूप से, जब आप मूल्य द्वारा एक वस्तु पारित यह गंतव्य प्रकार का ऑब्जेक्ट को कॉपी किया है - उस बिंदु पर यह है गंतव्य प्रकार का ऑब्जेक्ट, तो Polymorph की कोई बात नहीं है (है कि यहां तक ​​कि एक शब्द?) ।

printArea() समारोह अंदर पैरामीटर shape है एक Shape वस्तु क्या वस्तु कॉल स्थल पर उपयोग किया गया हो अपने उदाहरण, void printArea(Shape shape); का उपयोग करने के लिए,।

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