क्या गैर-आभासी पद्धति को ओवरराइड करना संभव है?


92

क्या गैर-आभासी पद्धति को ओवरराइड करने का कोई तरीका है? या ऐसा कुछ जो समान परिणाम देता है (वांछित पद्धति को कॉल करने के लिए एक नई विधि बनाने के अलावा)?

मैं Microsoft.Xna.Framework.Graphics.GraphicsDeviceइकाई परीक्षण को ध्यान में रखते हुए एक विधि को ओवरराइड करना चाहूंगा ।


8
क्या आपका मतलब है ओवरलोड या ओवरराइड ? अधिभार = एक ही नाम के साथ एक विधि जोड़ें, लेकिन विभिन्न मापदंडों (जैसे कंसोल के विभिन्न अधिभार। Witeite)। ओवरराइड = (मोटे तौर पर) विधि के डिफ़ॉल्ट व्यवहार को बदलते हैं (जैसे कि एक आकार। विधि, जिसमें सर्कल, आयत, आदि के लिए अलग व्यवहार है)। आप हमेशा एक विधि को एक व्युत्पन्न वर्ग में अधिभारित कर सकते हैं , लेकिन ओवरराइडिंग केवल आभासी तरीकों पर लागू होती है।
23

जवाबों:


112

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

लेकिन यहां तक ​​कि एक विधि को छिपाने से आपको निष्पादन कॉल का समय नहीं मिलेगा, एक वास्तविक वर्चुअल विधि कॉल की तरह विधि कॉल की पॉलीमॉर्फिक प्रेषण। इस उदाहरण पर विचार करें:

using System;

class Example
{
    static void Main()
    {
        Foo f = new Foo();
        f.M();

        Foo b = new Bar();
        b.M();
    }
}

class Foo
{
    public void M()
    {
        Console.WriteLine("Foo.M");
    }
}

class Bar : Foo
{
    public new void M()
    {
        Console.WriteLine("Bar.M");
    }
}

इस उदाहरण में दोनों Mविधि प्रिंट के लिए कहते हैं Foo.M। जैसा कि आप देख सकते हैं कि यह तरीका आपको किसी विधि के लिए एक नया कार्यान्वयन करने की अनुमति देता है, जब तक कि उस वस्तु का संदर्भ सही व्युत्पन्न प्रकार का नहीं है, लेकिन आधार विधि को छिपाने से बहुरूपता टूट जाता है।

मैं आपको सलाह दूंगा कि आप इस तरीके से आधार के तरीकों को न छुपाएं।

मैं उन लोगों के साथ पक्ष रखता हूं जो C # के डिफ़ॉल्ट व्यवहार का पक्ष लेते हैं जो कि डिफ़ॉल्ट रूप से गैर-आभासी हैं (जैसा कि जावा के विपरीत है)। मैं और भी आगे जाऊंगा और कहूंगा कि कक्षाएं भी डिफ़ॉल्ट रूप से सीलबंद होनी चाहिए। इनहेरिटेंस को ठीक से डिजाइन करना मुश्किल है और यह तथ्य कि एक ऐसी विधि है जिसे वर्चुअल नहीं चिह्नित किया गया है, यह दर्शाता है कि उस विधि के लेखक ने कभी भी इस विधि का उपयोग करने का इरादा नहीं किया है।

संपादित करें: "निष्पादन समय बहुरूपता प्रेषण" :

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

अगर मुझे b.Fooउस स्थिति में कॉल करना था, तो सीएलआर सही प्रकार से उस वस्तु का निर्धारण करेगा जो bसंदर्भ को इंगित करता है Barऔर Mउचित रूप से कॉल को भेज देगा ।


6
यद्यपि "निष्पादन समय बहुरूपता प्रेषण" तकनीकी रूप से इसे कहने का सही तरीका है, मुझे लगता है कि यह शायद लगभग सभी के सिर पर चला जाता है!
ओरियन एडवर्ड्स

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

2
@ या तो मुझे यह समझ में नहीं आया लेकिन एक त्वरित Google के बाद मैंने "सही" शब्दों के उपयोग को देखकर सराहना की।
zfedoran

10
मैं "लेखक के लिए यह इरादा नहीं है" तर्क बिल्कुल नहीं खरीदते हैं। यह कहने के समान है कि पहिये के आविष्कारक ने कारों पर लगाए गए पहियों का अनुमान नहीं लगाया था इसलिए हम कारों पर उनका उपयोग नहीं कर सकते हैं। मुझे पता है कि पहिया / विधि कैसे काम करती है और मैं इसके साथ कुछ अलग करना चाहता हूं। मुझे परवाह नहीं है कि निर्माता मुझे चाहते थे या नहीं। एक मरे हुए धागे को पुनर्जीवित करने की कोशिश के लिए क्षमा करें। मैं सिर्फ बाहर वास्तव में कुछ असुविधाजनक तरह से मैं आंकड़ा से पहले कुछ भाप का झटका करने की जरूरत है इस समस्या को मैं में :) हूँ चारों ओर पाने के लिए
जेफ

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

22

नहीं, तुम नहीं कर सकते।

आप केवल एक आभासी विधि को ओवरराइड कर सकते हैं - यहाँ MSDN देखें :

C # में, व्युत्पन्न वर्ग में आधार वर्ग विधियों के समान नाम वाले तरीके हो सकते हैं।

  • आधार वर्ग विधि को आभासी परिभाषित किया जाना चाहिए।

6

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


3

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

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

मौजूदा कक्षा में अधिभार को जोड़ने से आपको रोकने के लिए कुछ भी नहीं है, लेकिन केवल कोड जो आपकी कक्षा के बारे में जानता है, वह इसे एक्सेस करने में सक्षम होगा।


2

आप C # (बिना हैकिंग CLR) के किसी भी वर्ग के गैर-आभासी तरीके को ओवरराइड नहीं कर सकते हैं, लेकिन आप क्लास क्लास के इंटरफ़ेस के किसी भी तरीके को ओवरराइड कर सकते हैं। गौर करें कि हम गैर-सील हैं

class GraphicsDevice: IGraphicsDevice {
    public void DoWork() {
        Console.WriteLine("GraphicsDevice.DoWork()");
    }
}

// with its interface
interface IGraphicsDevice {
    void DoWork();
}

// You can't just override DoWork in a child class,
// but if you replace usage of GraphicsDevice to IGraphicsDevice,
// then you can override this method (and, actually, the whole interface).

class MyDevice: GraphicsDevice, IGraphicsDevice {
    public new void DoWork() {
        Console.WriteLine("MyDevice.DoWork()");
        base.DoWork();
    }
}

और यहाँ डेमो है

class Program {
    static void Main(string[] args) {

        IGraphicsDevice real = new GraphicsDevice();
        var myObj = new MyDevice();

        // demo that interface override works
        GraphicsDevice myCastedToBase = myObj;
        IGraphicsDevice my = myCastedToBase;

        // obvious
        Console.WriteLine("Using real GraphicsDevice:");
        real.DoWork();

        // override
        Console.WriteLine("Using overriden GraphicsDevice:");
        my.DoWork();

    }
}

: @Dan यहां लाइव डेमो है dotnetfiddle.net/VgRwKK
व्याचेस्लाव Napadovsky

0

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


0

क्या गैर-आभासी पद्धति को ओवरराइड करने का कोई तरीका है? या ऐसा कुछ जो समान परिणाम देता है (वांछित पद्धति को कॉल करने के लिए एक नई विधि बनाने के अलावा)?

आप एक गैर-आभासी विधि को ओवरराइड नहीं कर सकते। हालांकि आप समान परिणाम प्राप्त करने के लिए संशोधक कीवर्ड का उपयोग कर सकते हैं new:

class Class0
{
    public int Test()
    {
        return 0;
    }
}

class Class1 : Class0
{
    public new int Test()
    {
        return 1;
    }
}
. . .
// result of 1
Console.WriteLine(new Class1().Test());

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

यदि पहुँच संशोधक समान नहीं है:

class Class0
{
    protected int Test()
    {
        return 0;
    }
}

class Class1 : Class0
{
    // different access modifier
    new int Test()
    {
        return 1;
    }
}

class Class2 : Class1
{
    public int Result()
    {
        return Test();
    }
}
. . .
// result of 0
Console.WriteLine(new Class2().Result());

... बनाम यदि पहुँच संशोधक है ही:

class Class0
{
    protected int Test()
    {
        return 0;
    }
}

class Class1 : Class0
{
    // same access modifier
    protected new int Test()
    {
        return 1;
    }
}

class Class2 : Class1
{
    public int Result()
    {
        return Test();
    }
}
. . .
// result of 1
Console.WriteLine(new Class2().Result());

जैसा कि पिछले उत्तर में बताया गया है, यह एक अच्छा डिज़ाइन सिद्धांत नहीं है।


-5

अमूर्त वर्ग और अमूर्त पद्धति का उपयोग करके इसे प्राप्त करने का एक तरीका है।

विचार करें

Class Base
{
     void MethodToBeTested()
     {
        ...
     }

     void Method1()
     {
     }

     void Method2()
     {
     }

     ...
}

अब, यदि आप विधि के विभिन्न संस्करणों को चाहते हैं MethodToBeTested (), तो क्लास बेस को अमूर्त वर्ग में बदल दें और MethodToBeTested () को अमूर्त विधि के रूप में

abstract Class Base
{

     abstract void MethodToBeTested();

     void Method1()
     {
     }

     void Method2()
     {
     }

     ...
}

अमूर्त शून्य के साथ MethodToBeTested () एक मुद्दा आता है; कार्यान्वयन हो गया है।

इसलिए class DefaultBaseImplementation : Baseडिफ़ॉल्ट कार्यान्वयन के लिए एक बनाएं ।

और class UnitTestImplementation : Baseइकाई परीक्षण कार्यान्वयन के लिए दूसरा बनाएं ।

इन 2 नई कक्षाओं के साथ, बेस क्लास कार्यक्षमता को ओवरराइड किया जा सकता है।

Class DefaultBaseImplementation : Base    
{
    override void MethodToBeTested()    
    {    
        //Base (default) implementation goes here    
    }

}

Class UnitTestImplementation : Base
{

    override void MethodToBeTested()    
    {    
        //Unit test implementation goes here    
    }

}

अब आपके पास 2 कक्षाएं लागू हैं (ओवरराइडिंग) MethodToBeTested()

आप (व्युत्पन्न) वर्ग को आवश्यकता के अनुसार (यानी या तो आधार क्रियान्वयन के साथ या इकाई परीक्षण कार्यान्वयन के साथ) त्वरित कर सकते हैं।


@ शालू: हाय स्लावू। कोड अपडेट के लिए धन्यवाद। लेकिन क्या आप कृपया मुझे इसको नीचा दिखाने का कारण बता सकते हैं?
शिवानंदके

6
क्योंकि यह सवाल का जवाब नहीं है। वह पूछ रहा है कि क्या आप सदस्यों को वर्चुअल चिह्नित नहीं कर सकते हैं। आपने प्रदर्शित किया है कि आपको अमूर्त चिह्नित सदस्यों को लागू करना है।
ली लौविएरे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.