जब हम उन्हें चाइल्ड क्लास में लागू करते हैं, तो अमूर्त विधियों के सामने ओवरराइड करना क्यों आवश्यक है?


9

जब हम एक वर्ग बनाते हैं जो एक अमूर्त वर्ग से विरासत में मिलता है और जब हम विरासत में मिली अमूर्त कक्षा को लागू करते हैं तो हमें ओवरराइड कीवर्ड का उपयोग क्यों करना पड़ता है?

public abstract class Person
{
    public Person()
    {

    }

    protected virtual void Greet()
    {
        // code
    }

    protected abstract void SayHello();
}

public class Employee : Person
{
    protected override void SayHello() // Why is override keyword necessary here?
    {
        throw new NotImplementedException();
    }

    protected override void Greet()
    {
        base.Greet();
    }
}

चूँकि विधि को उसके मूल वर्ग में अमूर्त घोषित किया जाता है, इसलिए इसका मूल वर्ग में कोई कार्यान्वयन नहीं होता है, इसलिए यहाँ कीवर्ड ओवरराइड क्यों आवश्यक है?


2
एक सार विधि संक्षेप में एक आभासी विधि है, प्रति चश्मा
— पावेल एनिहौस्की


"विरासत में मिली विधि, संपत्ति, अनुक्रमणिका या घटना के सार या आभासी कार्यान्वयन को बढ़ाने या संशोधित करने के लिए ओवरराइड संशोधक की आवश्यकता होती है।" docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
— gunr2171

2
क्योंकि यदि आप इसे वहां नहीं रखते हैं, तो आप इसे ओवरराइड करने के बजाय विधि को "छुपा" रहे हैं। इसीलिए आपको चेतावनी मिलती है कि "अगर ऐसा आपका इरादा है, तो newकीवर्ड का उपयोग करें ... आपको" कोई विधि आधार वर्ग विधि को ओवरराइड नहीं करती है "त्रुटि।
— Ron Beyer

@RonBeyer एक आभासी विधि के साथ हाँ, लेकिन सार के साथ यह बस संकलन नहीं करेगा।
— जॉनाथन बार्कले

जवाबों:


14

जब हम एक वर्ग बनाते हैं जो एक अमूर्त वर्ग से विरासत में मिलता है और जब हम विरासत में मिली अमूर्त कक्षा को लागू करते हैं तो हमें ओवरराइड कीवर्ड का उपयोग क्यों करना पड़ता है?

"क्यों?" इस तरह के सवालों का जवाब देना मुश्किल हो सकता है क्योंकि वे अस्पष्ट हैं। मैं यह मानने जा रहा हूं कि आपका प्रश्न "भाषा डिज़ाइन के दौरान उस स्थिति के लिए तर्क देने के लिए क्या तर्क दिए जा सकते हैं जो overrideकीवर्ड की आवश्यकता है ?"

चलो एक कदम पीछे ले जाकर शुरू करते हैं। कुछ भाषाओं में, कहते हैं, जावा, विधियाँ डिफ़ॉल्ट रूप से आभासी हैं और स्वचालित रूप से ओवरराइड की जाती हैं। C # के डिज़ाइनर इसके बारे में जानते थे और इसे जावा में एक मामूली दोष मानते थे। C # को "बाहर निकाले गए बेवकूफ हिस्सों के साथ जावा" नहीं कहा गया है, जैसा कि कुछ ने कहा है, लेकिन C # के डिज़ाइनर C, C ++ और Java के समस्याग्रस्त डिज़ाइन बिंदुओं से सीखने के इच्छुक थे, और C # में उनकी प्रतिकृति नहीं बनाते थे।

C # डिजाइनरों ने ओवरराइडिंग को कीड़े का एक संभावित स्रोत माना; आखिरकार, यह मौजूदा, परीक्षण किए गए कोड के व्यवहार को बदलने का एक तरीका है , और यह खतरनाक है। ओवरराइडिंग ऐसी चीज नहीं है जिसे आकस्मिक रूप से या दुर्घटना से किया जाना चाहिए; इसे किसी व्यक्ति द्वारा इसके बारे में कठिन सोचकर बनाया जाना चाहिए । यही कारण है कि विधियां डिफ़ॉल्ट रूप से आभासी नहीं हैं, और आपको यह कहने की आवश्यकता क्यों है कि आप एक विधि को ओवरराइड कर रहे हैं।

यही मूल तर्क है। अब हम कुछ और उन्नत तर्क में जा सकते हैं।

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

हालाँकि यह बिंदु वाजिब है, कई प्रतिवाद हैं, जैसे:

  • एक व्युत्पन्न वर्ग के लेखक के पास बेस क्लास के बारे में सब कुछ जानने की जिम्मेदारी है ! वे उस कोड का फिर से उपयोग कर रहे हैं, और उन्हें उस कोड को दोबारा उपयोग करने से पहले उस कोड को अच्छी तरह से समझने के लिए उचित परिश्रम करना चाहिए।
  • आपके विशेष परिदृश्य में वर्चुअल विधि अमूर्त है; यह इसे ओवरराइड नहीं करने के लिए एक त्रुटि होगी , और इसलिए यह संभावना नहीं है कि लेखक दुर्घटना से एक कार्यान्वयन बना रहा होगा।

चलिए फिर इस बिंदु पर एक और अधिक उन्नत तर्क बनाते हैं। आधार वर्ग क्या करता है यह जानने के लिए किसी व्युत्पन्न वर्ग के लेखक को किन परिस्थितियों में बहाना हो सकता है? इस परिदृश्य पर विचार करें:

  • बेस क्लास लेखक एक सार बेस क्लास बी बनाता है।
  • एक अलग टीम पर व्युत्पन्न वर्ग लेखक, विधि एम के साथ एक व्युत्पन्न वर्ग डी बनाता है।
  • बेस क्लास लेखक को पता चलता है कि बेस क्लास बी का विस्तार करने वाली टीमों को हमेशा एक विधि एम की आपूर्ति करने की आवश्यकता होगी, इसलिए बेस क्लास लेखक ने अमूर्त एम।
  • जब क्लास डी को दोबारा शुरू किया जाता है, तो क्या होता है?

हम जो चाहते हैं, वह है डी के लेखक को सूचित किया जाता है कि कुछ प्रासंगिक बदल गया है । जो प्रासंगिक बात बदल गई है, वह यह है कि एम अब एक आवश्यकता है और उनका कार्यान्वयन अतिभारित होना चाहिए। डीएम को अपने व्यवहार को बदलने की आवश्यकता हो सकती है क्योंकि हम जानते हैं कि इसे आधार वर्ग से बुलाया जा सकता है। सही बात यह है कि चुपचाप नहीं कहना है "ओह, डीएम मौजूद है और बीएम का विस्तार करता है"। संकलक के लिए सही काम विफल है , और कहते हैं , "हे, डी के लेखक, तुम्हारी इस धारणा को देखें जो अब मान्य नहीं है और यदि आवश्यक हो तो अपने कोड को ठीक करें"।

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

लेकिन अगर override है की आवश्यकता तो हम अलग तीन परिदृश्य बता सकते हैं। अगर वहाँ कोड में संभावित गलती है तो overrideहै याद आ रही । यह जानबूझकर अधिभावी रहा है तो overrideहै वर्तमान । और अगर यह जानबूझकर किया गया है नहीं अधिभावी तो newहै वर्तमान । C # का डिज़ाइन हमें इन सूक्ष्म भेदों को बनाने में सक्षम बनाता है।

याद रखें कंपाइलर त्रुटि रिपोर्टिंग को डेवलपर के दिमाग को पढ़ने की आवश्यकता होती है ; कंपाइलर को गलत कोड से हटना होगा जो लेखक के सही कोड को ध्यान में रखता है , और एक त्रुटि देता है जो उन्हें सही दिशा में इंगित करता है। अधिक सुराग हम डेवलपर को उस कोड के बारे में बता सकते हैं जो वे सोच रहे थे, संकलक रिपोर्ट त्रुटियों में बेहतर काम कर सकता है और इसलिए जितनी तेज़ी से आप अपने कीड़े पा सकते हैं और ठीक कर सकते हैं।

लेकिन आम तौर पर, C # एक ऐसी दुनिया के लिए डिज़ाइन किया गया था जिसमें कोड बदलता है । C # की एक बहुत सी विशेषताएं जो "अजीब" दिखाई देती हैं, वास्तव में वहां होती हैं क्योंकि वे डेवलपर को सूचित करती हैं जब एक धारणा जो वैध हुआ करती थी वह अमान्य हो गई क्योंकि एक आधार वर्ग बदल गया। बगों के इस वर्ग को "भंगुर आधार वर्ग की विफलताएं" कहा जाता है, और इस विफलता वर्ग के लिए C # में कई दिलचस्प मिथिगेशन हैं।


4
विस्तृत करने के लिए धन्यवाद। मैं हमेशा आपके उत्तरों की सराहना करता हूं, क्योंकि दोनों को "अंदर से" किसी से आधिकारिक आवाज़ मिलना अच्छा है और क्योंकि आप चीजों को केवल और पूरी तरह से समझाने का एक बड़ा काम करते हैं।
— स्ट्रिपलिंगवर्यर

गहराई से स्पष्टीकरण के लिए धन्यवाद! मैं इसकी प्रशंसा करता हूँ।
— भजन ०१

शानदार अंक! क्या आप कुछ अन्य उपशमनों को सूचीबद्ध कर सकते हैं जिनका आप उल्लेख करते हैं?
— aksh1618

3

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

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


भाषा डिजाइन टीम के तर्क को समझने पर यह एक अच्छी शुरुआत है; मैंने एक उत्तर जोड़ा है जो दिखाता है कि टीम आपके द्वारा व्यक्त किए गए विचार से कैसे शुरू होती है लेकिन इसे एक कदम आगे ले जाती है।
— एरिक लिपर्ट

1

क्योंकि abstractविधि एक आभासी विधि है जिसमें कोई कार्यान्वयन नहीं है, C # भाषा विनिर्देश के अनुसार , इसका मतलब है कि अमूर्त विधि एक आभासी विधि है। और overrideअमूर्त या आभासी कार्यान्वयन को बढ़ाने या संशोधित करने के लिए उपयोग किया जाता है, जैसा कि आप यहां देख सकते हैं

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


1
मुझे लगता है कि सवाल यह नहीं है कि यह क्या करता है, लेकिन इसे स्पष्ट क्यों किया जाना चाहिए।
— जॉनाथन बार्कले

0

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

public abstract class MyBase
{
    public virtual void MyVirtualMethod() { }

    public virtual void MyOtherVirtualMethod() { }

    public abstract void MyAbtractMethod();
}

public class MyDerived : MyBase
{
    // When overriding a virtual method in MyBase, we use the override keyword.
    public override void MyVirtualMethod() { }

    // If we want to hide the virtual method in MyBase, we use the new keyword.
    public new void MyOtherVirtualMethod() { }

    // Because MyAbtractMethod is abstract in MyBase, we have to override it: 
    // we can't hide it with new.
    // For consistency with overriding a virtual method, we also use the override keyword.
    public override void MyAbtractMethod() { }
}

तो C # डिज़ाइन किया जा सकता था ताकि आपको अमूर्त विधियों को ओवरराइड करने के लिए ओवरराइड कीवर्ड की आवश्यकता न हो, लेकिन मुझे लगता है कि डिजाइनरों ने निर्णय लिया कि यह भ्रमित करने वाला होगा क्योंकि यह वर्चुअल विधि को ओवरराइड करने के अनुरूप नहीं होगा।


पुन: "डिजाइनरों ने तय किया कि यह भ्रामक होगा क्योंकि यह एक आभासी पद्धति को ओवरराइड करने के अनुरूप नहीं होगा" - हाँ, लेकिन अधिक। मान लीजिए कि आपके पास वर्चुअल विधि के साथ बेस क्लास B है और ओवरराइड के साथ एक व्युत्पन्न वर्ग D है। अब मान लीजिए कि बी का लेखक एम अमूर्त बनाने का फैसला करता है। यह एक ब्रेकिंग चेंज है, लेकिन शायद वे ऐसा करते हैं। प्रश्न: क्या डी को हटाने के लिए लेखक का होना चाहिए override? मुझे लगता है कि ज्यादातर लोग इस बात से सहमत होंगे कि डी के लेखक को एक अनावश्यक कोड परिवर्तन करने के लिए मजबूर करना बेतुका है; उनकी कक्षा ठीक है!
— एरिक लिपर्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.