নতুন এবং ওভাররাইডের মধ্যে পার্থক্য


198

নিম্নলিখিতগুলির মধ্যে পার্থক্যটি কী তা ভাবছেন:

কেস 1: বেস ক্লাস

public void DoIt();

কেস 1: উত্তরাধিকারী বর্গ

public new void DoIt();

কেস ২: বেস ক্লাস

public virtual void DoIt();

কেস ২: উত্তরাধিকারী শ্রেণি

public override void DoIt();

আমার চালানো পরীক্ষাগুলির উপর ভিত্তি করে কেস 1 এবং 2 উভয় ক্ষেত্রে একই প্রভাব রয়েছে বলে মনে হয়। পার্থক্য আছে, বা পছন্দসই উপায়?


2
অনেক প্রশ্নের নকল, স্ট্যাকওভারফ্লো
জোন স্কিটি

উত্তর:


267

ওভাররাইড মডিফায়ারটি ভার্চুয়াল পদ্ধতিতে ব্যবহৃত হতে পারে এবং বিমূর্ত পদ্ধতিতে অবশ্যই ব্যবহার করা যেতে পারে। এটি সংকলকটির জন্য কোনও পদ্ধতির সর্বশেষ সংজ্ঞায়িত প্রয়োগটি ব্যবহার করার নির্দেশ করে। এমনকি যদি পদ্ধতিটি বেস শ্রেণীর রেফারেন্সে ডাকা হয় তবে এটি প্রয়োগটিকে ওভাররাইড করে ব্যবহার করবে।

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, উদ্ভূত পর্যায়ে শুধুমাত্র প্রবেশযোগ্য।
এরিক Bongers

177

ভার্চুয়াল : ইঙ্গিত দেয় যে কোনও পদ্ধতি উত্তরাধিকারীর দ্বারা ওভাররেড করা যেতে পারে

ওভাররাইড : একটি বেস শ্রেণিতে ভার্চুয়াল পদ্ধতির কার্যকারিতা ওভাররাইড করে বিভিন্ন কার্যকারিতা সরবরাহ করে।

নতুন : বিভিন্ন কার্যকারিতা সরবরাহ করে মূল পদ্ধতিটি (যা ভার্চুয়াল হতে হবে না) আড়াল করে। এটি কেবল যেখানে এটি একেবারে প্রয়োজনীয় সেখানে ব্যবহার করা উচিত।

আপনি যখন কোনও পদ্ধতি আড়াল করেন, তবুও আপনি বেস ক্লাসে কাস্টিং দিয়ে মূল পদ্ধতিটি অ্যাক্সেস করতে পারেন। এটি কিছু পরিস্থিতিতে কার্যকর তবে বিপজ্জনক।


2
বেস পদ্ধতিটি আড়াল করে এমন একটি পদ্ধতি কেন ingালাই করা বিপজ্জনক? বা আপনি বোঝাচ্ছেন যে সাধারণভাবে আপ কাস্টিং বিপজ্জনক?
চিহ্নিত করুন

3
@ মার্ক - একজন কলকারী দুর্ঘটনাক্রমে অপব্যবহারের কারণ হিসাবে বাস্তবায়ন সম্পর্কে সচেতন না হতে পারে।
জন বি

আপনি কি প্যারেন্ট পদ্ধতিতে overrideএবং / অথবা newছাড়া ব্যবহার করতে পারেন virtual?
অ্যারন ফ্রাঙ্ক

16

প্রথম ক্ষেত্রে আপনি অভিভাবক শ্রেণিতে সংজ্ঞাটি গোপন করছেন। এর অর্থ হ'ল আপনি কেবল যখন শিশু শ্রেণি হিসাবে এই বিষয়টির সাথে লেনদেন করছেন কেবল তখনই সেটিকে ডাকা হবে। আপনি যদি ক্লাসটিকে তার পিতামাতার ধরণে ফেলে দেন তবে পিতামাতার পদ্ধতিটি শুরু করা হবে। দ্বিতীয় উদাহরণে, পদ্ধতিটি ওভাররাইড করা হয়েছে এবং অবজেক্টটি শিশু বা অভিভাবক শ্রেণি হিসাবে নিক্ষেপ করা হয়েছে তা বিবেচনা না করেই অনুরোধ করা হবে।


7

নিম্নলিখিত চেষ্টা করুন: (কেস 1)

((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();
}

আপনি যে সতর্কতা বা ত্রুটিটি পেয়েছেন তা পোস্ট করতে পার। আমি এই কোডটি মূলত পোস্ট করার সময় এই কোডটি ঠিকঠাকভাবে কাজ করেছিল।
ম্যাথু সাদা

এটি আপনার প্রবেশ পয়েন্ট শ্রেণিতে (প্রোগ্রাম) মধ্যে আটকানো উচিত। এই সাইটে আরও ভাল ফর্ম্যাটিংয়ের অনুমতি দেওয়ার জন্য এটি সরানো হয়েছে।
ম্যাথু সাদা

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তার বেস শ্রেণিতে কীওয়ার্ডের সাথে ব্যবহার করা উচিত , এর অর্থ আপনার ওবিজেইসিটি ধরণের (ডান দিকের দিকের =) সম্মান করুন , যার ফলে রেফারেন্স প্রকার নির্বিশেষে চলমান পদ্ধতিটি ওভার্রাইডেন। তদুপরি, এটি বহুবর্ষগত উত্তরাধিকার হিসাবেও পরিচিত ।

উভয় কীওয়ার্ড মনে রাখার আমার উপায় যে তারা একে অপরের বিপরীতে।

override: virtualপদ্ধতিটি ওভাররাইড করতে কীওয়ার্ডটি অবশ্যই সংজ্ঞায়িত করা উচিত। overrideকীওয়ার্ড ব্যবহারের পদ্ধতি যা রেফারেন্স টাইপ নির্বিশেষে (বেস শ্রেণি বা উত্পন্ন শ্রেণীর রেফারেন্স) যদি এটি বেস শ্রেণীর সাথে তাত্ক্ষণিকভাবে চালিত হয় তবে বেস শ্রেণীর পদ্ধতিটি চলে runs অন্যথায়, উদ্ভূত শ্রেণীর পদ্ধতিটি চলে।

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যদি ডেরিভ ক্লাসে ব্যবহৃত হয় তবে এর প্যারেন্ট পদ্ধতিটি ওভাররাইড করে।

যদি কীওয়ার্ডটি newডেরিভ ক্লাসে ব্যবহার করা হয় তবে প্যারেন্ট পদ্ধতিতে লুকিয়ে থাকা পদ্ধতি অর্জন করুন।


1

আমার একই প্রশ্ন ছিল এবং এটি সত্যিই বিভ্রান্তিকর, আপনার বিবেচনা করা উচিত যে ওভাররাইড এবং নতুন কীওয়ার্ডগুলি কেবলমাত্র টাইপ বেজ ক্লাসের অবজেক্ট এবং উদ্ভূত শ্রেণীর মান নিয়ে কাজ করে। এক্ষেত্রে আপনি কেবল ওভাররাইড এবং নতুনের প্রভাব দেখতে পাবেন: সুতরাং যদি আপনার যদি থাকে class Aএবং B, Bউত্তরাধিকার সূত্রে প্রাপ্ত হয় 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
আপনি আপত্তি যদি আপনার মন্তব্য যোগ করুন। হিট এন্ড রান এত কাপুরুষোচিত।
দরকারী

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

প্রথম ক্ষেত্রে এটি উদ্ভূত শ্রেণি ডোআইটি () পদ্ধতি কল করবে কারণ নতুন কীওয়ার্ড বেস ক্লাসটি ডিআইটি () পদ্ধতি লুকায়।

দ্বিতীয় ক্ষেত্রে এটি ডাবটি ওভাররাইডেনকে কল করবে ()

  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()

উপরে উপরে সবকিছু প্রত্যাশিত। দৃষ্টান্তবিতে উদাহরণস্বরূপ बी এবং ইনস্ট্যান্সসি সেট করা যাক এবং ডওআইটি () পদ্ধতিতে কল করুন এবং ফলাফলটি দেখুন।

    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 (); আপনাকে সি :: ডু ইট () দেবে, বি :: ডোইট () নয়
বিওয়াইএস 2

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.