2011-12-19 14 views
27
object a = new Dog(); 

बनामअंतर() बनाम कुत्ता एक = नया कुत्ता()

Dog a = new Dog(); 

दोनों ही मामलों में a.GetType()Dog देता है। दोनों एक ही कन्स्ट्रक्टर (उसी पदानुक्रम के साथ) का आह्वान करते हैं।

तो क्या आप कृपया मुझे इन दो बयानों के बीच अंतर बता सकते हैं?

+0

मुझे मिली इस की सुंदरता यह है कि कभी-कभी, एक विधि को 'कुत्ते' से अधिक के साथ काम करने की आवश्यकता हो सकती है। 'ऑब्जेक्ट ए = नया कुत्ता()' कथन के साथ, आप इसे एक विधि में उपयोग कर सकते हैं। इसी तरह, आप 'ऑब्जेक्ट बी = नई बिल्ली()' कर सकते हैं, और आप उसी तरह इसका उपयोग कर सकते हैं। –

+1

@ केन फिर इंटरफ़ेस का उपयोग क्यों नहीं करते? हाउसपेट की तरह एक = नया कुत्ता(); हाउसपेट इंटरफ़ेस या एक एनिम इंटरफ़ेस में साझा विधियां डालना। – Andy

+9

यह एक डुप्लिकेट होना है ... – slugster

उत्तर

36

दोनों एक कुत्ते वस्तु बनाते हैं। केवल दूसरा आपको सीधे कुत्ते के तरीकों का आह्वान करने की अनुमति देता है या अन्यथा इसे कुत्ते की तरह व्यवहार करने की अनुमति देता है, जैसे कि आपको Dog (या कुत्ते पदानुक्रम में कुछ जो कि बस से अधिक विशिष्ट है) के पैरामीटर के रूप में ऑब्जेक्ट को पास करने की आवश्यकता है। object)।

object obj = new Dog(); 
// can only see members declared on object 
var type = obj.GetType(); // can do this 
Console.WriteLine(obj.ToString()); // also this 
obj.Bark(); // Error! Bark is not a member of System.Object 

Dog dog = new Dog(); 
// can do all of the methods declared for Object 
dog.Bark(); // can finally use the method defined for Dog 
+0

धन्यवाद। मैं आपसे सहमत हूं। लेकिन जब मैं निम्नलिखित कोड ऑब्जेक्ट लिखता हूं तो एक = नया कुत्ता(); Console.WriteLine (a.GetType()); मैं कुत्ते के रूप में बाहर निकलता हूं और वस्तु नहीं। ऐसा क्यों है? – om471987

+3

@ ओमकरपानकर, यह आवृत्ति के नहीं, उदाहरण का प्रकार प्राप्त कर रहा है। यह एक रनटाइम तंत्र है जो इंस्टेंस से जुड़े मेटाडेटा को प्राप्त करता है, और रनटाइम जानता है कि उदाहरण एक कुत्ता है। जो आपने खो दिया है संकलन-समय लाभ हैं। –

+0

अगली बार जब मुझे कुछ इसी तरह से पूछा गया था, तो मैं एक गैर अंग्रेजी मूल निवासी के रूप में, "यह एक xxx की तरह व्यवहार करें" का उपयोग करूंगा, जो मेरे लिए सबसे उपयुक्त शब्द है। –

5

में आप सबसे पहले प्रकार object के चर पैदा करता है।

कंपाइलर आपको Dog के रूप में इसका इलाज नहीं करने देगा।

+0

जब तक आप इसे कास्ट नहीं करते, उदा। '(कुत्ता) एक ' –

+1

@ पीटर ओलसन किस मामले में यह अब एक सादा' वस्तु 'नहीं है ... – poke

6

new Dog() एक अभिव्यक्ति है जो एक नया Dog उदाहरण बनाता है। यह Dog कक्षा के पैरामीटर रहित कन्स्ट्रक्टर को आमंत्रित करता है।

a एक चर है: स्मृति में एक स्टोरेज सेल जो Dog असाइनमेंट के बाद उदाहरण का संदर्भ रखता है।

अंतर यह है कि एक Dog चर केवल एक Dog उदाहरण (या किसी भी वर्ग कि Dog से निकला का एक उदाहरण) के लिए एक संदर्भ पकड़ सकता है, जबकि एक object चर (एक object उदाहरण के लिए एक संदर्भ या का एक उदाहरण हो सकते हैं object से प्राप्त कोई भी वर्ग - जो Dog कक्षा करता है)।

जब आपके पास Dog वैरिएबल है, तो आप संदर्भित उदाहरण पर Dog कक्षा (और इसके आधार वर्ग) द्वारा परिभाषित किसी भी विधि का आह्वान कर सकते हैं। जब आपके पास object वैरिएबल है, तो आप उदाहरण पर केवल object कक्षा के तरीकों का आह्वान कर सकते हैं।

+0

धन्यवाद। मैं आपसे सहमत हूं। लेकिन जब मैं निम्नलिखित कोड ऑब्जेक्ट लिखता हूं = नया कुत्ता(); कंसोल। राइटलाइन (ए। गेट टाइप()); मैं कुत्ते के रूप में बाहर निकलता हूं और वस्तु नहीं। ऐसा क्यों है? – om471987

+1

क्योंकि आप 'a' द्वारा संदर्भित 'कुत्ते' उदाहरण पर GetType विधि का आह्वान करते हैं। GetType आवृत्ति के नहीं, उदाहरण के प्रकार देता है। – dtb

5

दोनों बयानों में एक घोषणा और एक कन्स्ट्रक्टर आमंत्रण शामिल है। कन्स्ट्रक्टर के आविष्कार समान हैं, इसलिए आपको दोनों मामलों में Dog मिलता है। घोषणाएं अलग-अलग हैं: पहले मामले में, आप object प्रकार का एक चर घोषित करते हैं, Dog का सुपरक्लास; दूसरे मामले में, आप Dog प्रकार का एक चर घोषित करते हैं। अंतर यह है कि बाद के कोड में आप Dog के तरीकों को केवल एक कलाकार के बिना आमंत्रित कर सकते हैं जब आप चर को Dog के रूप में घोषित करते हैं; यदि आप इसे object के रूप में घोषित करते हैं, तो आपको एक कलाकार की आवश्यकता होगी।

4

दोनों वक्तव्यों में आप उल्लेख करते हैं कि Dog के डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करना शामिल है; इसलिए, यह स्पष्ट है कि दोनों मामलों में Dog उदाहरण बनाया गया है। इसका मतलब है कि दोनों कथन को एक समान उदाहरण के साथ एक चर प्रारंभ करने के लिए समाप्त होते हैं (यह बराबर के बाद बयान का हिस्सा है)।

हालांकि, बयान में एक और हिस्सा भी है: एक चर की घोषणा (यह बराबर से पहले बयान का हिस्सा है)।

object a = new Dog(); // static type: object/runtime type: Dog 
Dog b = new Dog(); // static type: Dog/runtime type: Dog 

संकलक है कि यह साबित नहीं कर सकते आप एक चर को कोई मान निर्दिष्ट करने की अनुमति नहीं: इस तरह के सी # के रूप में स्थिर टाइप किया भाषाओं में, हर चर - - अधिक आम तौर पर, किसी भी अभिव्यक्ति एक स्थिर प्रकार है परिवर्तनीय के स्थिर प्रकार का है, उदाहरण के लिए यह

Cat c = new Dog(); // unless Dog derives from Cat, which we know isn't true 

के बाद से सभी reference types परोक्ष System.Object से निकाले जाते हैं की अनुमति नहीं होगी, स्थिर प्रकार का एक चर object ठीक है के लिए एक Dog बताए। आप "स्थैतिक प्रकार" के बारे में सोच सकते हैं क्योंकि वस्तु "घोषित" है। आप स्रोत कोड पढ़कर बस के स्थिर प्रकार का निर्धारण कर सकते हैं; इस तरह संकलक यह करता है।

फिर ऊपर वर्णित प्रत्येक चर (अभिव्यक्ति) के रनटाइम प्रकार भी है। यह दोनों मामलों में समान है, क्योंकि दोनों मामलों में हमने Dog बनाया है। आप "रनटाइम प्रकार" के बारे में सोच सकते हैं क्योंकि वास्तव में ऑब्जेक्ट है। कुछ रनटाइम प्रकार केवल स्रोत को पढ़कर निर्धारित नहीं किया जा सकता है; जब आप प्रोग्राम चल रहे हों, तो आप केवल यह निर्धारित करेंगे, इसलिए नाम। सी # में, यह GetType पर कॉल करके किया जाता है।

यह स्पष्ट होना चाहिए कि रनटाइम प्रकार ऐसा कुछ है जिसे आप बिना नहीं कर सकते; सब कुछ सब के बाद कुछ "होना" है। लेकिन स्थिर प्रकार की धारणा का आविष्कार करने के साथ परेशान क्यों?

आप static types के बारे में सोच सकते हैं जो आपके (प्रोग्रामर) और कंपाइलर के बीच अनुबंध के रूप में है। b के स्थिर प्रकार को Dog होने की घोषणा करके, आप संकलक को बताते हैं कि आप Dog के अलावा किसी अन्य चीज़ को संग्रहीत करने के लिए उस चर का उपयोग करने का इरादा नहीं रखते हैं। बदले में, संकलक, आपको अपने निर्दिष्ट उद्देश्य का उल्लंघन करने नहीं देता है और यदि आप ऐसा करने का प्रयास करते हैं तो एक त्रुटि उत्पन्न करता है। यह आपको d का उपयोग करने से भी रोकता है, प्रत्येकDog का समर्थन करना चाहिए।

पर विचार करें:

class Dog { 
    public void Woof(); 
} 

Dog d = new Dog(); 
d.Woof(); // OK 

object o = new Dog(); 
o.Woof(); // COMPILER ERROR 

अंतिम पंक्ति एक संकलक त्रुटि क्योंकि यह स्थिर टाइपिंग अनुबंध का उल्लंघन करती कारण बनता है: आप संकलक कि oSystem.Object से पाने के लिए कुछ भी किया जा सकता है कहा था, लेकिन ऐसा नहीं है कि चीजों से पाने के सभी एक विधि Woof है। तो संकलक यह कहकर आपकी रक्षा करने की कोशिश कर रहा है कि "आप वहां क्या कर रहे हैं? मैं साबित नहीं कर सकता कि o में जो कुछ भी है, वह हो सकता है! अगर यह Cat था?"।

नोट्स:

यह ¹ मतलब यह नहीं है कि हर वस्तु है कि जादुई जानता है कि यह क्या सभी भाषाओं में "है।" कुछ मामलों में (उदा।सी ++ में) किसी ऑब्जेक्ट को बनाते समय यह जानकारी उपयोग की जा सकती है, लेकिन फिर संकलक को कोड को अनुकूलित करने की अधिक स्वतंत्रता को अनुमति देने के लिए "भूल गया" है। यदि ऐसा होता है तो ऑब्जेक्ट अभी भी कुछ है, लेकिन आप इसे पोक नहीं कर सकते हैं और पूछ सकते हैं "आप क्या हैं?"।

² असल में, इस छोटे उदाहरण में यह साबित कर सकता है। लेकिन यह इस ज्ञान का उपयोग नहीं करना चुनेगा क्योंकि स्थिर प्रकार के अनुबंध का सम्मान पूरे बिंदु है।

+0

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

+0

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

+0

@DanielPryden: रनटाइम प्रकार के बारे में, मैंने मार्ग को दोहराया ताकि यह स्पष्ट हो कि ऑब्जेक्ट अभी भी * कुछ है (उदाहरण के लिए इसमें एक vtable हो सकता है जो वास्तव में तय करता है), लेकिन आप यह जानकारी वापस पाने के लिए नहीं कह सकते हैं।Polymorphism के बारे में आपका बिंदु पूरी तरह से सही है; यह मेरे हिस्से पर बस एक आखिरी मिनट सोचा था, जिसे मैं पिछले कुछ घंटों के लिए निकालना चाहता हूं, मैं एएफके रहा हूं। – Jon

2

यह उपयोगी है जब आप बहुरूपता का उपयोग करना चाहते हैं और आप कुत्ते में कार्यान्वयन करने वाली अमूर्त विधि का उपयोग कर सकते हैं। इसलिए, इस तरह वस्तु वस्तु कुत्ता है, यहां तक ​​कि ऑब्जेक्ट भी है। तो जब आप बहुरूपता का उपयोग करना चाहते हैं तो आप इस तरीके का उपयोग कर सकते हैं।

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