नए और ओवरराइड के बीच अंतर


200

निम्नलिखित के बीच क्या अंतर है, यह सोचकर:

केस 1: बेस क्लास

public void DoIt();

केस 1: विरासत में मिला वर्ग

public new void DoIt();

केस 2: बेस क्लास

public virtual void DoIt();

केस 2: विरासत में मिला वर्ग

public override void DoIt();

मेरे द्वारा चलाए गए परीक्षणों के आधार पर केस 1 और 2 दोनों समान प्रभाव डालते हैं। क्या कोई अंतर है, या पसंदीदा तरीका है?


2
कई सवाल का डुप्लीकेट, सहित stackoverflow.com/questions/159978/...
जॉन स्कीट

जवाबों:


269

ओवरराइड संशोधक का उपयोग आभासी तरीकों पर किया जा सकता है और इसे अमूर्त तरीकों पर इस्तेमाल किया जाना चाहिए। यह संकलक के लिए एक विधि के अंतिम परिभाषित कार्यान्वयन का उपयोग करने के लिए इंगित करता है। यहां तक ​​कि अगर विधि को आधार वर्ग के संदर्भ में कहा जाता है तो यह इसे लागू करने वाले कार्यान्वयन का उपयोग करेगा।

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

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

Base b = new Derived();
b.DoIt();                      // Calls Derived.DoIt

Derived.DoItअगर वह ओवरराइड करता है तो कॉल करेगा Base.DoIt

नया संशोधक कंपाइलर को निर्देश देता है कि वह मूल श्रेणी के कार्यान्वयन के बजाय आपके चाइल्ड क्लास कार्यान्वयन का उपयोग करें। कोई भी कोड जो आपकी कक्षा को संदर्भित नहीं कर रहा है, लेकिन मूल वर्ग अभिभावक वर्ग के कार्यान्वयन का उपयोग करेगा।

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

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

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

b.DoIt();                      // Calls Base.DoIt
d.DoIt();                      // Calls Derived.DoIt

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

स्रोत: माइक्रोसॉफ्ट ब्लॉग


5
This indicates for the compiler to use the last defined implementation of a method। कैसे एक विधि के अंतिम परिभाषित कार्यान्वयन पा सकते हैं ??
अमीनम

5
एक ठोस वर्ग से शुरू करें, जांचें कि क्या यह ब्याज की पद्धति का कार्यान्वयन है। यदि ऐसा होता है, तो आप कर रहे हैं। यदि ऐसा नहीं होता है, तो वंशानुक्रम पदानुक्रम में एक कदम ऊपर जाएं, अर्थात, जांचें कि क्या सुपर क्लास में ब्याज की विधि है। तब तक जारी रखें जब तक आपको ब्याज की विधि नहीं मिल जाती।
csoltenborn

2
यह भी ध्यान दें कि आप केवल overrideएक विधि कर सकते हैं जब बेस क्लास विधि को परिभाषित करता है virtual। यह शब्द virtualआधार वर्ग कह रहा है "अरे, जब मैं इस पद्धति को कॉल करता हूं, तो इसे वस्तुतः एक व्युत्पन्न कार्यान्वयन द्वारा प्रतिस्थापित किया जा सकता है, इसलिए मुझे वास्तव में पहले से पता नहीं है कि मैं वास्तव में रनटाइम में किस पद्धति का कार्यान्वयन कर रहा हूं। इसलिए virtualयह संकेत है ।" किसी विधि के लिए प्लेसहोल्डर। इसका तात्पर्य यह है कि जिन विधियों को चिह्नित virtualनहीं किया गया है, उन्हें ओवरराइड नहीं किया जा सकता है। लेकिन आप किसी गैर-आभासी विधि को किसी व्युत्पन्न वर्ग में संशोधक के साथ बदल सकते हैं new, जो केवल व्युत्पन्न स्तर पर सुलभ हो।
एरिक बॉन्गर्स 20-18

177

वर्चुअल : इंगित करता है कि एक विधि एक इनहेरिटेरियन द्वारा ओवरराइड की जा सकती है

ओवरराइड : एक बेस क्लास में एक वर्चुअल मेथड की कार्यक्षमता को ओवरराइड करता है, विभिन्न कार्यक्षमता प्रदान करता है।

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

जब आप किसी विधि को छिपाते हैं, तब भी आप मूल विधि तक पहुँच बना सकते हैं बेस क्लास तक। यह कुछ परिदृश्यों में उपयोगी है, लेकिन खतरनाक है।


2
आधार विधि खतरनाक क्यों है? या आप का मतलब है कि सामान्य रूप में कास्टिंग खतरनाक है?
मार्क

3
@ मर्क - एक कॉलर को कार्यान्वयन के बारे में जानकारी नहीं हो सकती है, जिससे आकस्मिक दुरुपयोग हो सकता है।
जॉन बी

क्या आप मूल विधि पर override/ और newबिना उपयोग कर सकते हैं virtual?
एरॉन फ्रेंके

16

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


7

निम्नलिखित प्रयास करें: (case1)

((BaseClass)(new InheritedClass())).DoIt()

संपादित करें: वर्चुअल + ओवरराइड को रनटाइम पर हल किया जाता है (इसलिए ओवरराइड वास्तव में वर्चुअल तरीकों को ओवरराइड करता है), जबकि नया सिर्फ एक ही नाम के साथ नई विधि बनाता है, और पुराने को छुपाता है, यह संकलन समय पर हल किया जाता है -> आपका कंपाइलर विधि को कॉल करेगा ' देखता है '


3

मामले 1 में यदि आपने वंशानुक्रम वर्ग के DoIt () विधि का उपयोग किया है, जबकि प्रकार को आधार वर्ग के रूप में घोषित किया जाता है, तो आप आधार वर्ग की कार्रवाई भी देखेंगे।

/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
    public void DoIt() { Console.WriteLine("Base1"); }
}
public  class Class1 : Base1 
{
    public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
    public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
    public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
    var c1 = new Class1();
    c1.DoIt();
    ((Base1)c1).DoIt();

    var c2 = new Class2();
    c2.DoIt();
    ((Base2)c2).DoIt();
    Console.Read();
}

क्या आप प्राप्त होने वाली चेतावनी या त्रुटि को पोस्ट कर सकते हैं। जब मैंने मूल रूप से इसे पोस्ट किया तो इस कोड ने ठीक काम किया।
मैथ्यू व्हाइट

यह सब आपके प्रवेश बिंदु वर्ग (प्रोग्राम) के भीतर चिपकाया जाना चाहिए। इस साइट पर बेहतर स्वरूपण की अनुमति देने के लिए इसे हटा दिया गया था।
मैथ्यू Whited

3

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

BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method

SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method

यह वास्तव में भ्रामक हो सकता है और गैर-अपेक्षित व्यवहार में परिणाम हो सकता है और यदि संभव हो तो बचा जाना चाहिए। तो पसंदीदा तरीका केस 2 होगा।


3
  • newका अर्थ है अपने संदर्भ प्रकार (बाएं हाथ की ओर =) का सम्मान करें , जिससे संदर्भ प्रकार की विधि चल रही है। यदि पुनर्निर्धारित विधि में newकीवर्ड नहीं है , तो यह व्यवहार किया जाता है जैसे कि यह है। इसके अलावा, इसे गैर-बहुरूपी विरासत के रूप में भी जाना जाता है । यही है, "मैं व्युत्पन्न वर्ग में एकदम नया तरीका बना रहा हूं, जिसका आधार वर्ग में समान नाम से किसी भी तरीके से कोई लेना-देना नहीं है।" - कहा व्हिटकर ने
  • override, जिसका उपयोग virtualइसके आधार वर्ग में कीवर्ड के साथ किया जाना चाहिए , का अर्थ है अपने OBJECT प्रकार (दाएं-हाथ की ओर =) का सम्मान करें , जिससे संदर्भ प्रकार की परवाह किए बिना पद्धति ओवरराइड हो। इसके अलावा, यह बहुरूपी विरासत के रूप में भी जाना जाता है

दोनों खोजशब्दों को ध्यान में रखने का मेरा तरीका है कि वे एक दूसरे के विपरीत हैं।

override: virtualविधि को ओवरराइड करने के लिए कीवर्ड को परिभाषित किया जाना चाहिए। उपयोग करने की विधिoverrideकीवर्ड जो संदर्भ प्रकार (बेस क्लास या व्युत्पन्न वर्ग का संदर्भ) की परवाह किए बिना अगर इसे बेस क्लास के साथ तत्काल किया जाता है, बेस क्लास का तरीका चलता है। अन्यथा, व्युत्पन्न वर्ग की विधि चलती है।

new: यदि कीवर्ड का उपयोग किसी विधि द्वारा किया जाता है override, तो कीवर्ड के विपरीत , संदर्भ प्रकार महत्वपूर्ण है। यदि इसे व्युत्पन्न वर्ग के साथ त्वरित किया जाता है और संदर्भ प्रकार बेस क्लास है, बेस क्लास की विधि चलती है। यदि यह व्युत्पन्न वर्ग के साथ तात्कालिक है और संदर्भ प्रकार व्युत्पन्न वर्ग है, तो व्युत्पन्न वर्ग की विधि चलती है। अर्थात्, यह overrideखोजशब्द के विपरीत है । यदि आप नए कीवर्ड को विधि में जोड़ना भूल जाते हैं या छोड़ना चाहते हैं तो एन पासेंट, कंपाइलर डिफ़ॉल्ट रूप से व्यवहार करता है जैसे कि newकीवर्ड का उपयोग किया जाता है।

class A 
{
    public string Foo() 
    {
        return "A";
    }

    public virtual string Test()
    {
        return "base test";
    }
}

class B: A
{
    public new string Foo() 
    {
        return "B";
    }
}

class C: B 
{
    public string Foo() 
    {
        return "C";
    }

    public override string Test() {
        return "derived test";
    }
}

मुख्य में कॉल करें:

A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());

Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());

आउटपुट:

A
B
B
base test
derived test

नया कोड उदाहरण,

एक-एक करके टिप्पणी करके कोड के साथ खेलें।

class X
{
    protected internal /*virtual*/ void Method()
    {
        WriteLine("X");
    }
}
class Y : X
{
    protected internal /*override*/ void Method()
    {
        base.Method();
        WriteLine("Y");
    }
}
class Z : Y
{
    protected internal /*override*/ void Method()
    {
        base.Method();
        WriteLine("Z");
    }
}

class Programxyz
{
    private static void Main(string[] args)
    {
        X v = new Z();
        //Y v = new Z();
        //Z v = new Z();
        v.Method();
}

1

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

यदि Keyword newका उपयोग derive class में किया जाता है तो मूल विधि द्वारा hered विधि प्राप्त की जाती है।


1

मेरे पास एक ही सवाल था और यह वास्तव में भ्रामक है, आपको विचार करना चाहिए कि ओवरराइड और नए कीवर्ड केवल टाइप बेस क्लास की वस्तुओं और व्युत्पन्न वर्ग के मूल्य के साथ काम कर रहे हैं। इस मामले में केवल आप ओवरराइड और नए का असर दिखाई देगा: तो अगर आपके पास class Aऔर B, Binherits से Aहै, तो आप इस तरह एक वस्तु का दृष्टांत:

A a = new B();

अब कॉलिंग के तरीकों पर विचार किया जाएगा। ओवरराइड : इसका मतलब है कि यह विधि के कार्य का विस्तार करता है, फिर वह व्युत्पन्न वर्ग में विधि का उपयोग करता है, जबकि नए संकलक को विधि को व्युत्पन्न वर्ग में छिपाने और इसके बजाय आधार वर्ग में विधि का उपयोग करने के लिए कहते हैं। यहाँ उस विषय पर बहुत अच्छी दृष्टि है:

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2%29.aspx?f=255&MSPPError=-2147217396


1

नीचे दिया गया लेख vb.net में है, लेकिन मुझे लगता है कि नए बनाम ओवरराइड्स के बारे में स्पष्टीकरण समझाना बहुत आसान है।

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

लेख के कुछ बिंदु पर, यह वाक्य है:

सामान्य तौर पर, शैडोज़ मानता है कि प्रकार से जुड़े फ़ंक्शन को लागू किया जाता है, जबकि ओवरराइड्स मान लेता है कि ऑब्जेक्ट कार्यान्वयन निष्पादित किया गया है।

इस प्रश्न का स्वीकृत उत्तर एकदम सही है, लेकिन मुझे लगता है कि यह लेख इन दो खोजशब्दों के बीच अंतर के बारे में बेहतर अर्थ जोड़ने के लिए अच्छे उदाहरण प्रदान करता है।


1

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

नीचे दिए गए उदाहरण में, परिणाम "व्युत्पन्न परिणाम" लौटाएगा, जब तक कि प्रकार को स्पष्ट रूप से बेसक्लास परीक्षण के रूप में परिभाषित नहीं किया जाता है, तभी "आधार परिणाम" वापस आ जाएगा।

class Program
{
    static void Main(string[] args)
    {
        var test = new DerivedClass();
        var result = test.DoSomething();
    }
}

class BaseClass
{
    public virtual string DoSomething()
    {
        return "Base result";
    }
}

class DerivedClass : BaseClass
{
    public new string DoSomething()
    {
        return "Derived result";
    }
}

3
आपत्ति होने पर अपनी टिप्पणी जोड़ें। हिट एंड रन तो कायरता है।
उपयोगी 16

0

इन परीक्षणों में कार्यात्मक अंतर नहीं दिखाया जाएगा:

BaseClass bc = new BaseClass();

bc.DoIt();

DerivedClass dc = new DerivedClass();

dc.ShowIt();

इस छूट में, जो बुलाया जाता है वह वह है जिसे आप कहे जाने की अपेक्षा करते हैं।

अंतर को देखने के लिए आपको ऐसा करना होगा:

BaseClass obj = new DerivedClass();

obj.DoIt();

आपको किसी भी परीक्षण उस मामले 1 (के रूप में आप इसे परिभाषित) में, चलाते हैं देखेंगे DoIt()में BaseClassमामला 2 में, कहा जाता है (यदि आप इसे परिभाषित है), DoIt()में DerivedClassकहा जाता है।


-1

पहले मामले में इसे व्युत्पन्न वर्ग DoIt () विधि कहा जाएगा क्योंकि नया कीवर्ड आधार वर्ग DoIt () विधि को छुपाता है।

दूसरे मामले में यह दोरहित DoIt () कॉल करेगा

  public class A
{
    public virtual void DoIt()
    {
        Console.WriteLine("A::DoIt()");
    }
}

public class B : A
{
    new public void DoIt()
    {
        Console.WriteLine("B::DoIt()");
    }
}

public class C : A
{
    public override void DoIt()
    {
        Console.WriteLine("C::DoIt()");
    }
}

इन वर्गों का उदाहरण दें

   A instanceA = new A();

    B instanceB = new B();
    C instanceC = new C();

    instanceA.DoIt(); //A::DoIt()
    instanceB.DoIt(); //B::DoIt()
    instanceC.DoIt(); //B::DoIt()

ऊपर से सब कुछ अपेक्षित है। इंस्टा और इंस्टा को इंस्टा पर सेट करें और DoIt () विधि और परिणाम की जांच करें।

    instanceA = instanceB;
    instanceA.DoIt(); //A::DoIt() calls DoIt method in class A

    instanceA = instanceC;
    instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C

instanceC.DoIt (); आपको C :: DoIt () देगा, B नहीं :: DoIt ()
BYS2

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.