2011-05-28 12 views
55

के बीच अंतर मैं बहुत OOP के कुछ अवधारणाओं के बीच संदेह में हूँ: virtual, override, new और sealed override। क्या कोई मतभेदों को समझा सकता है?आभासी, ओवरराइड, नए और सील ओवरराइड

मैं बहुत स्पष्ट है कि अगर व्युत्पन्न वर्ग पद्धति का उपयोग किया जा रहा है, एक override कीवर्ड का उपयोग कर सकते हैं ताकि आधार वर्ग विधि व्युत्पन्न वर्ग द्वारा ओवरराइड किया जा जाएगा। लेकिन मुझे new, और sealed override के बारे में निश्चित नहीं है।

उत्तर

74

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

यह सब polymorphism के साथ करने के लिए है। जब किसी वर्चुअल विधि को किसी संदर्भ पर बुलाया जाता है, तो उस संदर्भ का वास्तविक प्रकार जिसका संदर्भ संदर्भित करता है, यह तय करने के लिए उपयोग किया जाता है कि कौन सी विधि कार्यान्वयन का उपयोग करना है। जब किसी व्युत्पन्न वर्ग में बेस क्लास को ओवरराइड किया जाता है, तो व्युत्पन्न वर्ग में संस्करण का उपयोग किया जाता है, भले ही कॉलिंग कोड "पता" न हो कि ऑब्जेक्ट व्युत्पन्न वर्ग का उदाहरण था। उदाहरण के लिए:

public class Base 
{ 
    public virtual void SomeMethod() 
    { 
    } 
} 

public class Derived : Base 
{ 
    public override void SomeMethod() 
    { 
    } 
} 

... 

Base d = new Derived(); 
d.SomeMethod(); 

Derived.SomeMethod बुला खत्म हो जाएगा कि अगर Base.SomeMethod ओवरराइड करता है।

अब, अगर आप ओवरराइड के बजाय नई कीवर्ड का उपयोग व्युत्पन्न वर्ग में विधि आधार वर्ग में विधि पर हावी नहीं होता, यह केवल यह छुपाता है। उस मामले में, इस तरह कोड:

public class Base 
{ 
    public virtual void SomeOtherMethod() 
    { 
    } 
} 

public class Derived : Base 
{ 
    public new void SomeOtherMethod() 
    { 
    } 
} 

... 


Base b = new Derived(); 
Derived d = new Derived(); 
b.SomeOtherMethod(); 
d.SomeOtherMethod(); 

पहले Base.SomeOtherMethod, तो Derived.SomeOtherMethod कॉल करेंगे। वे आधार विधि को ओवरराइड करने वाली व्युत्पन्न विधि के बजाय प्रभावी रूप से दो पूरी तरह अलग विधियों के समान होते हैं।

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

एक ओवरराइडिंग संपत्ति घोषणा में सील संशोधक शामिल हो सकता है। इस संशोधक का उपयोग एक व्युत्पन्न वर्ग को संपत्ति को आगे बढ़ाने से रोकता है। एक सीलबंद संपत्ति के अभिगमियों को भी बंद कर दिया गया है।

+0

इनपुट के लिए धन्यवाद .. लेकिन एक बात मेरे दिमाग में नहीं आती है .. बेस बी = नया व्युत्पन्न() का उपयोग क्या है? क्या यह आधार वर्ग या व्युत्पन्न वर्ग का निर्माण वस्तु है ?? –

+2

व्युत्पन्न कक्षा। मुझे लगता है कि आपको बहुरूपता के बारे में और अधिक देखना है। आपके पढ़ने के लिए यहां एक अच्छा है। http://msdn.microsoft।com/en-us/library/ms173152 (v = vs.80) .aspx – CharithJ

+3

@Xor: उस स्थिति में, आप 'व्युत्पन्न' ऑब्जेक्ट का उदाहरण बना रहे हैं और संदर्भ को 'बेस' चर में संग्रहीत कर रहे हैं। यह मान्य है क्योंकि एक 'व्युत्पन्न' वस्तु-एक 'बेस' ऑब्जेक्ट भी है। ऐसा कहने की तरह है कि हमें "व्यक्ति" की ज़रूरत है ताकि हमें "जॉनी" मिल जाए जो एक व्यक्ति बनता है। यहाँ वही सौदा। –

15

डिफ़ॉल्ट रूप से एक विधि को व्युत्पन्न वर्ग में ओवरराइड नहीं किया जा सकता है जब तक कि इसे virtual, या abstract घोषित नहीं किया जाता है। virtual का अर्थ है और abstract पर कॉल करने से पहले नए कार्यान्वयन की जांच करें, लेकिन यह सभी व्युत्पन्न कक्षाओं में ओवरराइड होने की गारंटी है। इसके अलावा, बेस क्लास में कोई कार्यान्वयन की आवश्यकता नहीं है क्योंकि इसे कहीं और फिर से परिभाषित किया जा रहा है।

उपरोक्त का अपवाद new संशोधक है। एक विधि घोषित नहीं की गई virtual या abstract को व्युत्पन्न कक्षा में new संशोधक के साथ फिर से परिभाषित किया जा सकता है। जब बेस क्लास में विधि को मूल विधि में निष्पादित किया जाता है, और जब व्युत्पन्न कक्षा में बुलाया जाता है, तो नई विधि निष्पादित की जाती है।सभी new कीवर्ड आपको कक्षा के पदानुक्रम में एक ही नाम के साथ दो विधियों करने की अनुमति देता है।

अंत में एक sealed संशोधक virtual तरीकों की श्रृंखला टूट जाता है और उन्हें फिर से overridable नहीं बनाता है। इसका उपयोग अक्सर नहीं किया जाता है, लेकिन विकल्प वहां होता है। यह 3 वर्गों की एक श्रृंखला प्रत्येक पिछले एक

A -> B -> C 

अगर A एक virtual या abstract विधि है से पाने के साथ और अधिक समझ में आता है, कि B में overridden है, तो यह भी C इसमें बदलाव करने से फिर से की घोषणा के द्वारा रोका जा सकता है B में।

sealed का उपयोग classes में भी किया जाता है, और यही वह जगह है जहां आप आमतौर पर इस कीवर्ड का सामना करेंगे।

मुझे आशा है कि इस मदद करता है।

29

कोई भी विधि अधिभार योग्य हो सकती है (= virtual) या नहीं।

class Person 
{ 
    // this one is not overridable (not virtual) 
    public String GetPersonType() 
    { 
     return "person"; 
    } 

    // this one is overridable (virtual) 
    public virtual String GetName() 
    { 
     return "generic name"; 
    } 
} 

अब आप उन तरीकों कि overridable हैं ओवरराइड कर सकते हैं: निर्णय एक है जो विधि को परिभाषित करता है द्वारा किया जाता है

class Friend : Person 
{ 
    public Friend() : this("generic name") { } 

    public Friend(String name) 
    { 
     this._name = name; 
    } 

    // override Person.GetName: 
    public override String GetName() 
    { 
     return _name; 
    } 
} 

लेकिन क्योंकि यह आभासी नहीं है आप GetPersonType विधि ओवरराइड नहीं कर सकते।

के उन वर्गों के दो उदाहरणों बनाएँ:

Person person = new Person(); 
Friend friend = new Friend("Onotole"); 

गैर आभासी विधि GetPersonTypeFiend उदाहरण से बुलाया यह वास्तव में Person.GetPersonType कि कहा जाता है जाता है:

Console.WriteLine(friend.GetPersonType()); // "person" 

जब आभासी विधि GetName कहा जाता है Friend उदाहरण के अनुसार यह Friend.GetName है जिसे कहा जाता है:

Console.WriteLine(friend.GetName()); // "Onotole" 

आभासी विधि GetNamePerson उदाहरण यह Person.GetName है कि कहा जाता है के द्वारा कहा जाता है जब:

Console.WriteLine(person.GetName()); // "generic name" 

जब गैर आभासी विधि कहा जाता है विधि शरीर को देखा नहीं है - संकलक पहले से ही वास्तविक विधि की जरूरत है जानता है कहा जा सकता है। जबकि वर्चुअल विधियों के संकलक के साथ यह सुनिश्चित नहीं किया जा सकता कि कौन सी कॉल करनी है, और क्लास पदानुक्रम में इसे रनटाइम पर देखा जाता है, जिस प्रकार से विधि को कॉल किया जाता है: friend.GetName के लिए यह Friend से शुरू होता है कक्षा और इसे तुरंत पाता है, person.GetName कक्षा के लिए यह Person पर शुरू होता है और इसे वहां पाता है।

कभी कभी तुम एक उपवर्ग बनाने के लिए, एक आभासी विधि ओवरराइड और आप किसी भी अधिक ओवरराइड नीचे नहीं करना चाहती पदानुक्रम में - आपको लगता है कि के लिए sealed override का उपयोग करें (कह आप पिछले एक है जो विधि को ओवरराइड करता हैं):

class Mike : Friend 
{ 
    public sealed override String GetName() 
    { 
     return "Mike"; 
    } 
} 

लेकिन कभी कभी अपने दोस्त माइक ऐलिस के लिए अपने लिंग और इस तरह उसका नाम परिवर्तित करने का निर्णय :) आप या तो मूल कोड बदलने के लिए या बजाय उपवर्ग सकता माइक:

class Alice : Mike 
{ 
    public new String GetName() 
    { 
     return "Alice"; 
    } 
} 

यहाँ आप एक ही नाम के साथ एक पूरी तरह से अलग विधि बनाने (अब तुम दो है)। कौन सी विधि और कब कहा जाता है? यह कैसे आप इसे कहते पर निर्भर करता है:

Alice alice = new Alice(); 
Console.WriteLine(alice.GetName());    // the new method is called, printing "Alice" 
Console.WriteLine(((Mike)alice).GetName());  // the method hidden by new is called, printing "Mike" 

जब आप इसे Alice से फोन के परिप्रेक्ष्य आप Alice.GetName कहते हैं, जब Mike से की - आप Mike.GetName कहते हैं। कोई रनटाइम लुकअप यहां नहीं बनाया गया है - क्योंकि दोनों विधियां गैर-वर्चुअल हैं।

आप हमेशा new विधियों को बना सकते हैं - चाहे आप छिपा रहे तरीके आभासी हैं या नहीं।

यह गुणों और घटनाओं पर भी लागू होता है - उन्हें नीचे विधियों के रूप में दर्शाया जाता है।

+0

मुझे कहीं भी मिला यह एक सरल और पूरा उत्तर नहीं है। धन्यवाद लोकी – Reevs

5
public class Base 
{ 
    public virtual void SomeMethod() 
    { 
    Console.WriteLine("B"); 
    } 
    } 

    //This one is Simple method 
public class Derived : Base 
{ 
    public void SomeMethod() 
    { 
    Console.WriteLine("D"); 
    } 

    //This method has 'new' keyword 
    public new void SomeMethod() 
    { 
    Console.WriteLine("D"); 
    } 

    //This method has 'override' keyword 
    public override void SomeMethod() 
    { 
    Console.WriteLine("D"); 
    } 
} 

अब पहली बात सबसे पहले

Base b=new Base(); 
Derived d=new Derived(); 
b.SomeMethod(); will always write B 
d.SomeMethod(); will always write D 

अब कीवर्ड आधार वर्ग में सभी के बारे में बहुरूपता

       Base b = new Derived(); 
  1. का उपयोग कर रहे हैं और virtualDerived में ओवरराइड डी दे देंगे (बहुरूपता)।
  2. overridevirtualBase में त्रुटि देगी।
  3. इसी तरह virtual के साथ एक विधि (कोई ओवरराइड) लिखना चेतावनी के साथ 'बी' लिखेंगे (क्योंकि कोई बहुलक नहीं किया जाता है)।
  4. Derived में उस सरल विधि से पहले new पर इस तरह की चेतावनी को छिपाने के लिए।
  5. new कीवर्ड एक और कहानी है, यह केवल चेतावनी को छुपाती है जो बताती है कि समान नाम वाली संपत्ति बेस क्लास में है।
  6. virtual या new दोनों को छोड़कर new modifier

  7. new और override ही कर रहे हैं एक ही विधि या संपत्ति से पहले नहीं किया जा सकता।

  8. sealed किसी वर्ग या विधि से पहले इसे व्युत्पन्न कक्षा में उपयोग करने के लिए लॉक करें और यह संकलन समय त्रुटि देता है।
+0

क्षमा करें, लेकिन -1 एकाधिक संकलन त्रुटियों के कारण: विधि समान पैरामीटर के साथ कई बार घोषित किया गया है, स्ट्रिंग्स बी एंड डी के आसपास कोई उद्धरण नहीं है ... – DeveloperDan

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