वर्चुअल, ओवरराइड, नया और सील ओवरराइड के बीच का अंतर


79

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

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

जवाबों:


107

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

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

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 को। वे प्रभावी रूप से दो पूरी तरह से अलग-अलग विधियां हैं जो आधार विधि को ओवरराइड करने की व्युत्पन्न विधि के बजाय एक ही नाम के होते हैं।

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

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


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

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

5
@ Xor: उस स्थिति में, आप किसी Derivedऑब्जेक्ट का एक उदाहरण बना रहे हैं और संदर्भ को एक Baseचर में संग्रहीत कर रहे हैं । यह मान्य है क्योंकि Derivedएक Baseवस्तु भी एक वस्तु है। यह कहने जैसा है कि हमें एक "व्यक्ति" की आवश्यकता है इसलिए हमें "जॉनी" मिलता है जो एक व्यक्ति होने के लिए होता है। यहाँ वही सौदा।
जेफ मर्काडो

मैं यहां सिर्फ एक बिंदु जोड़ना चाहता हूं। Base b = new Derived()यह बताता है कि एक Baseवर्ग Derived classसंदर्भ के माध्यम से सुलभ हो सकता है क्योंकि derived classइसके आधार वर्ग की विशेषज्ञता है। Derivedकक्षाएं सभी ऑपरेशन कर सकती हैं (जैसे बेस क्लास विधियों को लागू करना आदि ) जो base classकर सकती हैं। लेकिन Base classऑपरेशन नहीं Derived classकर सकता है कि यह कर सकता है। तो Derived d = new Base()सही नहीं है, लेकिन Base b = new Derived()सही है।
mmushtaq

क्या आप newसंशोधक के उपयोग के उद्देश्य को स्पष्ट कर सकते हैं hide a base class method? दूसरे उदाहरण में, कॉल b.SomeOtherMethod()बेस क्लास कार्यान्वयन को लागू करता है (कोई कह सकता है कि उसने व्युत्पन्न वर्ग की विधि छिपा दी है)। यदि यह उपयोग का एक विशिष्ट उदाहरण है, तो newइसका उपयोग तब किया जाता है जब कॉलर compile-time typeअपनी पद्धति का उपयोग करने के लिए एक चर का इरादा रखता है , न runtime typesकि किसी भी तरीके का तरीका जिसे इसे सौंपा जा सकता है।
मिन्ह

35

कोई भी तरीका अतिश्योक्तिपूर्ण (= 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";
    }
}

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

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");

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

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

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

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

जब आभासी विधि GetNameको Personउदाहरण के द्वारा पुकारा जाता है तो उसे 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तरीके बना सकते हैं - चाहे आप जिस तरीके को छिपा रहे हैं वह आभासी है या नहीं।

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


1
कहीं भी मैंने जो पाया, उससे आसान और पूर्ण उत्तर नहीं है। धन्यवाद लोकी
रीव्स

19

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

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

अंत में एक sealedसंशोधक virtualतरीकों की श्रृंखला को तोड़ता है और उन्हें फिर से उपयोग करने योग्य नहीं बनाता है। यह अक्सर उपयोग नहीं किया जाता है, लेकिन विकल्प है। यह पिछले एक से प्राप्त होने वाली 3 कक्षाओं की श्रृंखला के साथ अधिक समझ में आता है

A -> B -> C

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

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

आशा है कि ये आपकी मदद करेगा।


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

public class Derived : Base
{
   //Same method is written 3 times with different keywords to explain different behaviors. 


   //This one is Simple method
  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. virtualबेस क्लास और ओवरराइड का उपयोग करने से Derivedडी (पॉलीमॉर्फिज्म) मिलेगा।
  2. का उपयोग करते हुए overrideबिना virtualमें Baseत्रुटि दे देंगे।
  3. इसी तरह एक विधि (कोई ओवरराइड नहीं) virtualलिखने से चेतावनी के साथ 'बी' लिखा जाएगा (क्योंकि कोई बहुरूपता नहीं किया जाता है)।
  4. उपरोक्त बिंदु में इस तरह की चेतावनी को छिपाने के लिए newउस सरल विधि से पहले लिखें Derived
  5. new कीवर्ड एक और कहानी है, यह बस चेतावनी को छुपाता है जो बताता है कि आधार वर्ग में समान नाम वाली संपत्ति है।
  6. virtualया नए संशोधकnew को छोड़कर दोनों समान हैं

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

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

क्षमा करें, लेकिन कई संकलित त्रुटियों के कारण -1: विधि कई बार समान मापदंडों के साथ घोषित की जाती है, स्ट्रिंग्स B & D के आसपास कोई उद्धरण नहीं ...
DeveloperDan
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.