আমার উত্পন্ন ক্লাসে কোনও পদ্ধতি কল করে কেন বেস ক্লাস পদ্ধতি কল করে?


146

এই কোডটি বিবেচনা করুন:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Teacher();
        person.ShowInfo();
        Console.ReadLine();
    }
}

public class Person
{
    public void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}
public class Teacher : Person
{
    public new void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

আমি এই কোডটি চালানোর সময়, নিম্নলিখিতগুলি আউটপুট হয়:

আমি ব্যক্তি

তবে আপনি দেখতে পাচ্ছেন যে এটি একটি উদাহরণ Teacher, এর নয় Person। কোডটি কেন এটি করে?


3
একটি জাভা ব্যক্তির কাছ থেকে প্রশ্ন: কনসোল। রিডলাইন (); এই উদাহরণের জন্য প্রয়োজনীয়?
ধনী

2
@ শাহরুজ আমি আপনার প্রশ্নের উত্তর দিতে পারি না - আমি সি # জানি না। আমি খুব তুচ্ছ সি # প্রশ্ন জিজ্ঞাসা করছিলাম, যার অর্থ ব্যক্তি ও শিক্ষক শ্রেণিতে লিখনলাইন কল করতে সক্ষম হওয়ার জন্য মূল পদ্ধতিতে রিডলাইনকে কল করা প্রয়োজন কিনা।
ধনী

6
হ্যাঁ, .ইন মেইন () প্রস্থান করলে স্বয়ংক্রিয়ভাবে কনসোল উইন্ডোটি বন্ধ করে দেয়। এটি ঘুরে দেখার জন্য, আমরা অতিরিক্ত ইনপুটটির জন্য অপেক্ষা করার জন্য কনসোল.রেড () বা কনসোল.পঠন () ব্যবহার করি যাতে কনসোল খোলা থাকে।
ক্যাপ্টেন কেনপাচি

15
@ ধনী না, এটি প্রয়োজনীয় নয় তবে আপনি প্রায়শই এই কারণে এটি দেখতে পাবেন: ভিজ্যুয়াল স্টুডিও থেকে কনসোল প্রোগ্রাম চালানোর সময়, প্রোগ্রাম সমাপ্তির সময় কমান্ড উইন্ডোটি সরাসরি বন্ধ হয়ে যায়, তাই যদি আপনি প্রোগ্রামের আউটপুট দেখতে চান তবে আপনাকে এটি জানাতে হবে অপেক্ষা করা.
আকাশম

1
@ আকাশম ধন্যবাদ - আমি আমার সময়টি অ্যালিপসে কাটিয়েছি যেখানে কনসোলটি গ্রহগ্রহের উইন্ডোর অংশ, এবং তাই এটি বন্ধ হয় না। এটা নিখুঁত জ্ঞান করে তোলে।
ধনী

উত্তর:


368

newএবং virtual/ এর মধ্যে পার্থক্য রয়েছে override

আপনি কল্পনা করতে পারেন, একটি শ্রেণি, তাত্ক্ষণিকভাবে, এর পদ্ধতির প্রকৃত বাস্তবায়নের দিকে ইঙ্গিত করে পয়েন্টারগুলির একটি সারণী ছাড়া আর কিছুই নয়। নিম্নলিখিত চিত্রটি এটি সুন্দরভাবে কল্পনা করা উচিত:

পদ্ধতি বাস্তবায়নের উদাহরণ

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

1. বিমূর্ত ক্লাস

প্রথমটি হ'ল abstractabstractপদ্ধতিগুলি কেবল কোথাও নির্দেশ করে না:

বিমূর্ত শ্রেণির চিত্রণ

যদি আপনার শ্রেণিতে বিমূর্ত সদস্য থাকে, তবে এটি হিসাবে চিহ্নিত করা দরকার abstract, অন্যথায় সংকলকটি আপনার অ্যাপ্লিকেশনটি সংকলন করবে না। আপনি abstractক্লাসের উদাহরণ তৈরি করতে পারবেন না , তবে আপনি তাদের কাছ থেকে উত্তরাধিকারী হয়ে উঠতে পারেন এবং উত্তরাধিকার সূত্রে প্রাপ্ত শ্রেণীর উদাহরণ তৈরি করতে পারেন এবং বেস শ্রেণীর সংজ্ঞা ব্যবহার করে এগুলি অ্যাক্সেস করতে পারেন। আপনার উদাহরণে এটি দেখতে চাই:

public abstract class Person
{
    public abstract void ShowInfo();
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a teacher!");
    }
}

public class Student : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a student!");
    }
}

যদি ডাকা ShowInfoহয়, বাস্তবায়নের উপর ভিত্তি করে আচরণের পরিবর্তিত হয়:

Person person = new Teacher();
person.ShowInfo();    // Shows 'I am a teacher!'

person = new Student();
person.ShowInfo();    // Shows 'I am a student!'

উভয়, Students এবং Teacherগুলি হয় Personগুলি, কিন্তু তারা বিভিন্ন আচরণ যখন তারা নিজেদের সম্পর্কে প্রম্পট তথ্যে বলা হবে। তবে, তাদের তথ্য প্রম্পট করতে বলার উপায়টি হ'ল: Personশ্রেণি ইন্টারফেস ব্যবহার করে ।

সুতরাং পর্দার পিছনে কি ঘটবে, যখন আপনি উত্তরাধিকারী হবেন Person? বাস্তবায়ন করার সময় ShowInfo, পয়েন্টারটি আর কোথাও নির্দেশ করে না , এটি এখন প্রকৃত বাস্তবায়নের দিকে নির্দেশ করে ! একটি Studentউদাহরণ তৈরি করার সময় , এটি Studentএস ShowInfo:

উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতির উদাহরণ

ভার্চুয়াল পদ্ধতি

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

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am a person!");
    }
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a teacher!");
    }
}

কী পার্থক্য হচ্ছে বেস সদস্য হয় Person.ShowInfoনির্দেশিত নয় কোথাও আর। এটিও কারণ, আপনি কেন উদাহরণ তৈরি করতে পারেন Person(এবং এর ফলে এটি abstractআর চিহ্নিত করার দরকার নেই):

একটি বেস শ্রেণীর ভিতরে ভার্চুয়াল সদস্যের উদাহরণ Ill

আপনার লক্ষ্য করা উচিত, এটি এখনকার প্রথম চিত্রের চেয়ে আলাদা দেখাচ্ছে না। এর কারণ হল virtualপদ্ধতিটি একটি বাস্তবায়নের দিকে নির্দেশ করছে " মানক উপায় "। ব্যবহার virtual, আপনি বলতে পারেন Persons, যে তারা করতে পারেন (না উচিত নয় ) জন্য একটি ভিন্ন বাস্তবায়ন প্রদান ShowInfo। যদি আপনি উপরেরটির overrideমতো করে আলাদা আলাদা প্রয়োগকরণ (ব্যবহার করে ) সরবরাহ করেন Teacherতবে চিত্রটি যেমনটি দেখায় তেমনটি হবে abstract। কল্পনা করুন, আমরা Studentএর জন্য কাস্টম বাস্তবায়ন সরবরাহ করি নি :

public class Student : Person
{
}

কোডটি এভাবে কল করা হবে:

Person person = new Teacher();
person.ShowInfo();    // Shows 'I am a teacher!'

person = new Student();
person.ShowInfo();    // Shows 'I am a person!'

এবং চিত্রটি এর Studentমতো দেখায়:

ভার্চুয়াল-কীওয়ার্ড ব্যবহার করে কোনও পদ্ধতির ডিফল্ট প্রয়োগের চিত্রণ

৩. যাদু `নতুন` কীওয়ার্ড ওরফে" ছায়া "

newএই কাছাকাছি আরও একটি হ্যাক হয়। আপনি সাধারণীকৃত ক্লাসগুলিতে পদ্ধতি সরবরাহ করতে পারেন, যেগুলি বেস বর্গ / ইন্টারফেসের পদ্ধতির মতো একই নাম রয়েছে। উভয়ই নিজস্ব, কাস্টম প্রয়োগের দিকে নির্দেশ করে:

নতুন-কীওয়ার্ডটি ব্যবহার করে "প্রায় পথে" এর চিত্রণ

আপনি যে সরবরাহ করেছেন সেটি বাস্তবায়নের মতো দেখাচ্ছে। আপনি পদ্ধতিটিতে অ্যাক্সেস করার পদ্ধতির উপর ভিত্তি করে আচরণটি আলাদা হয়:

Teacher teacher = new Teacher();
Person person = (Person)teacher;

teacher.ShowInfo();    // Prints 'I am a teacher!'
person.ShowInfo();     // Prints 'I am a person!'

এই আচরণটি চাওয়া যেতে পারে তবে আপনার ক্ষেত্রে এটি বিভ্রান্তিকর।

আমি আশা করি এটি আপনার জন্য বিষয়গুলি আরও স্পষ্ট করে তুলবে!


9
আপনার দুর্দান্ত উত্তরের জন্য ধন্যবাদ

6
আপনি এই চিত্রগুলি উত্পন্ন করতে কী ব্যবহার করেছেন?
ব্লুরাজা - ড্যানি পিফ্লুঘুফুট

2
দুর্দান্ত এবং খুব গভীর উত্তর।
নিক বুগালিস

8
tl; dr আপনি ব্যবহার করেছেন newযা ফাংশনের উত্তরাধিকার ভেঙে ফেলে এবং নতুন ফাংশনটিকে সুপারক্লাসের ফাংশন থেকে আলাদা করে তোলে
ratchet freak

3
@ টেমন: আসলে না ... আমি কেবল পরিষ্কার করতে চেয়েছিলাম যে কলটি এখন বিপক্ষে রয়েছে Person, নয় Student;)
কার্স্টেন

45

সি # তে সাব টাইপ পলিমারফিজম সি ++ এর মতো তবে জাভা থেকে পৃথক প্রকৃতির স্বতন্ত্রতা ব্যবহার করে। এর অর্থ হ'ল আপনার স্পষ্টতই পদ্ধতিগুলিকে অতিমাত্রায়যোগ্য (যেমন virtual) হিসাবে চিহ্নিত করতে হবে । সি # তে আপনাকে স্পষ্টরূপে overrideটাইপগুলি প্রতিরোধ করার জন্য ওভাররাইড পদ্ধতিতে ওভাররাইডিং (যেমন ) হিসাবে চিহ্নিত করতে হবে।

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

আপনার প্রশ্নের কোডটিতে , আপনি ব্যবহার newকরেন যা ওভাররাইডের পরিবর্তে ছায়া ফেলে । ছায়া গোছানো কেবল রানটাইম শব্দার্থবিজ্ঞানের চেয়ে কমপাইল-টাইম শব্দার্থকে প্রভাবিত করে, তাই অনিচ্ছাকৃত আউটপুট।


4
কে বলতে হবে ওপি সেগুলির অর্থ কী তা জানে।
কোল জনসন

@ কোল জনসন আমি একটি স্পেসিফিকেশন যুক্ত করব।

25

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

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}
public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

ভার্চুয়াল পদ্ধতি

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

ছায়ার জন্য নতুন ব্যবহার

আপনি ওভাররাইডের পরিবর্তে নতুন কী শব্দটি ব্যবহার করছেন, এটিই নতুন করে

  • যদি উত্পন্ন শ্রেণিতে পদ্ধতিটি নতুন বা ওভাররাইড কীওয়ার্ডগুলির আগে না হয় তবে সংকলক একটি সতর্কতা জারি করবে এবং পদ্ধতিটি নতুন কীওয়ার্ডের উপস্থিতি হিসাবে আচরণ করবে।

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

প্রারম্ভিক বাইন্ডিং ভিএস লেট বাঁধাই

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

একটি সাধারণ ফাংশনের জন্য, সংকলক স্মৃতিতে এর সংখ্যাসূচক অবস্থানটি নিয়ে কাজ করতে পারে। তারপরে যখন ফাংশন বলা হয় তখন এটি এই ঠিকানায় ফাংশনটি কল করার জন্য একটি নির্দেশ জেনারেট করতে পারে।

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


7

আমি আচার্টের উত্তরটি বন্ধ করে দিতে চাই । সম্পূর্ণতার জন্য, পার্থক্যটি হ'ল ওপি newব্যাস শ্রেণীর পদ্ধতিটি ওভাররাইড করার জন্য উত্পন্ন শ্রেণীর পদ্ধতিতে মূলশব্দটি আশা করে । এটি আসলে যা করে তা হ'ল বেস ক্লাস পদ্ধতিটি লুকানো

সি # তে, উল্লিখিত অন্য উত্তর হিসাবে, traditionalতিহ্যগত পদ্ধতি ওভাররাইডিং অবশ্যই স্পষ্ট হওয়া উচিত; বেস ক্লাস পদ্ধতিটি অবশ্যই চিহ্নিত করতে হবে virtualএবং উত্পন্ন শ্রেণিকে অবশ্যই overrideবেস শ্রেণির পদ্ধতিটি আবশ্যক। যদি এটি করা হয়ে থাকে, তবে বস্তুটি বেস বর্গ বা উদ্ভূত শ্রেণীর উদাহরণ হিসাবে বিবেচিত হবে তা বিবেচ্য নয়; উদ্ভূত পদ্ধতিটি পাওয়া যায় এবং বলা হয়। এটি সি ++ এর মতো একই ফ্যাশনে করা হয়; "ভার্চুয়াল" বা "ওভাররাইড" চিহ্নিত একটি পদ্ধতি, যখন সংকলন করা হয়, তখন "দেরী" (রানটাইম সময়ে) রেফারেন্সযুক্ত বস্তুর প্রকৃত প্রকার নির্ধারণ করে এবং বস্তুর স্তরক্রমটিকে গাছের পাশের নিচে দিকে ভেরিয়েবল টাইপ থেকে আসল অবজেক্ট টাইপের দিকে অনুসরণ করে সমাধান করা হয়, ভেরিয়েবল টাইপ দ্বারা সংজ্ঞায়িত পদ্ধতিটির সর্বাধিক উদ্ভূত বাস্তবায়ন সন্ধান করতে।

এটি জাভা থেকে পৃথক, যা "অন্তর্নিহিত ওভাররাইড" করতে দেয়; উদাহরণস্বরূপ পদ্ধতিগুলির জন্য (অ স্থিতিশীল), কেবল একই স্বাক্ষরের একটি পদ্ধতি (নাম এবং সংখ্যা / পরামিতিগুলির ধরণ) সংজ্ঞায়িত করার ফলে সাবক্লাস সুপারক্লাসকে ওভাররাইড করে।

যেহেতু আপনি নিয়ন্ত্রণ করেন না এমন একটি ভার্চুয়াল পদ্ধতিটির কার্যকারিতা প্রসারিত করতে বা ওভাররাইড করার জন্য এটি প্রায়শই কার্যকর, সি # এর সাথে newপ্রাসঙ্গিক কীওয়ার্ডও অন্তর্ভুক্ত থাকে । newKEYWORD "চামড়া" পিতা বা মাতা এর পরিবর্তে এটি অগ্রাহ্য পদ্ধতি। কোনও উত্তরাধিকার সূত্রে ভার্চুয়াল কিনা তা আড়াল হতে পারে; এটি আপনাকে, বিকাশকারীকে, পিতামাতার কাছ থেকে আপনি যে সদস্যদের উত্তরাধিকারী হিসাবে পেতে চান সেগুলি নিয়ে কাজ না করেই আপনার কোডের গ্রাহকদের কাছে একই "ইন্টারফেস" উপস্থাপন করার অনুমতি দেয়।

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

newতদ্ব্যতীত, কীওয়ার্ডটি কেবল এটি স্পষ্টভাবেই করবে না , সি # অন্তর্নিহিত পদ্ধতি লুকানোর অনুমতি দেয়; কেবল ছাড়াই একটি পিতা বা মাতা বর্গ পদ্ধতি হিসাবে একই স্বাক্ষর সহ একটি পদ্ধতি সংজ্ঞায়িত overrideবা new, গোপন করবে না (যদিও এটি একটি কম্পাইলার সতর্কবার্তা বা ReSharper বা CodeRush মত নির্দিষ্ট refactoring সহায়ক থেকে একটি অভিযোগ উত্পাদন করা হবে)। এটিই সমঝোতা সি # এর ডিজাইনারগণ জাভা এর অন্তর্নিহিত বনাম বনাম সি ++ এর সুস্পষ্ট ওভাররাইডগুলির মধ্যে এসেছিলেন, এবং এটি মার্জিত হওয়ার পরেও, আপনি যদি পুরানো কোনও ভাষার কোনও পটভূমি থেকে আগমন করেন তবে আপনি যে আচরণটি আশা করেন তা সর্বদা তৈরি করে না।

এখানে নতুন জিনিস: আপনি দীর্ঘ উত্তরাধিকার শৃঙ্খলে দুটি কীওয়ার্ড একত্রিত করলে এটি জটিল হয়ে ওঠে। নিম্নোক্ত বিবেচনা কর:

class Foo { public virtual void DoFoo() { Console.WriteLine("Foo"); } }
class Bar:Foo { public override sealed void DoFoo() { Console.WriteLine("Bar"); } }
class Baz:Bar { public virtual void DoFoo() { Console.WriteLine("Baz"); } }
class Bai:Baz { public override void DoFoo() { Console.WriteLine("Bai"); } }
class Bat:Bai { public new void DoFoo() { Console.WriteLine("Bat"); } }
class Bak:Bat { }

Foo foo = new Foo();
Bar bar = new Bar();
Baz baz = new Baz();
Bai bai = new Bai();
Bat bat = new Bat();

foo.DoFoo();
bar.DoFoo();
baz.DoFoo();
bai.DoFoo();
bat.DoFoo();

Console.WriteLine("---");

Foo foo2 = bar;
Bar bar2 = baz;
Baz baz2 = bai;
Bai bai2 = bat;
Bat bat2 = new Bak();

foo2.DoFoo();
bar2.DoFoo();
baz2.DoFoo();
bai2.DoFoo();    

Console.WriteLine("---");

Foo foo3 = bak;
Bar bar3 = bak;
Baz baz3 = bak;
Bai bai3 = bak;
Bat bat3 = bak;

foo3.DoFoo();
bar3.DoFoo();
baz3.DoFoo();
bai3.DoFoo();    
bat3.DoFoo();

আউটপুট:

Foo
Bar
Baz
Bai
Bat
---
Bar
Bar
Bai
Bai
Bat
---
Bar
Bar
Bai
Bai
Bat

পাঁচটির প্রথম সেটটি সব আশা করা যায়; যেহেতু প্রতিটি স্তরের একটি বাস্তবায়ন রয়েছে এবং তাত্ক্ষণিকভাবে একই ধরণের একটি অবজেক্ট হিসাবে রেফারেন্স করা হয়, রানটাইমটি প্রতিটি কলটি ভেরিয়েবল টাইপের দ্বারা রেফারেন্স করে উত্তরাধিকার স্তরে সলভ করে।

পাঁচটির দ্বিতীয় সেটটি হ'ল তাত্ক্ষণিক প্যারেন্ট টাইপের একটি ভেরিয়েবলকে প্রতিটি উদাহরণ বরাদ্দ করার ফলাফল। এখন, আচরণের কিছু পার্থক্য ঝাঁকুনি দেয়; foo2, যা আসলে একটি হয় Barহিসেবে ঢালাই Foo, এখনও প্রকৃত অবজেক্ট প্রকারটি বার আরো উদ্ভূত পদ্ধতি পাবেন। bar2এটি একটি Baz, তবে এর বিপরীতে foo2, কারণ বাজ স্পষ্টভাবে বারের বাস্তবায়নটিকে ওভাররাইড করে না (এটি পারে না; sealedএটি বার করতে পারে না ), এটি "টপ-ডাউন" দেখার সময় রানটাইম দ্বারা দেখা যায় না, তার পরিবর্তে বারের প্রয়োগটি বলা হয়। লক্ষ করুন যে বাজকে newকীওয়ার্ডটি ব্যবহার করতে হবে না ; আপনি কীওয়ার্ডটি বাদ দিলে আপনি একটি সংকলক সতর্কতা পাবেন, তবে সি # তে অন্তর্নিহিত আচরণটি প্যারেন্ট পদ্ধতিটি আড়াল করা। baz2একটি হল Bai, যা ওভাররাইড Bazএরnewবাস্তবায়ন, সুতরাং এর আচরণ foo2'এর অনুরূপ ; বাইতে আসল অবজেক্ট টাইপের বাস্তবায়ন বলা হয়। bai2এটি একটি Bat, যা আবার তার পিতামাতার Baiপদ্ধতি প্রয়োগকরণকে আড়াল করে , এবং এটি একই রকম আচরণ করে bar2যদিও বাইয়ের প্রয়োগটি সিল না করা হয়েছে, সুতরাং তাত্ত্বিকভাবে ব্যাটটি পদ্ধতিটি গোপন করার পরিবর্তে ওভাররাইড করতে পারত। পরিশেষে, bat2এটি একটি Bak, যার কোনওরূপে কোনও ওভাররাইডিং বাস্তবায়ন নেই এবং কেবল তার পিতামাতার ব্যবহার করে।

পাঁচটির তৃতীয় সেটটি সম্পূর্ণ টপ-ডাউন রেজোলিউশন আচরণের চিত্র তুলে ধরে। সবকিছু আসলে চেইনের মধ্যে সবচেয়ে উত্সযুক্ত শ্রেণীর উদাহরণ উল্লেখ করছে Bak, তবে ভেরিয়েবল ধরণের প্রতিটি স্তরের রেজোলিউশন উত্তরাধিকার শৃঙ্খলার সেই স্তরে শুরু করে এবং পদ্ধতির সর্বাধিক উত্স প্রাপ্ত স্পষ্টতাকে ছাড়িয়ে দিয়ে ড্রিলিং করে সম্পাদিত হয় , যা যাদের Bar, Baiএবং Bat। এইভাবে লুকানোর পদ্ধতিটি ওভাররাইডিং উত্তরাধিকার শৃঙ্খলে "ব্রেক" করে; আড়াল করার পদ্ধতিটি ব্যবহার করার জন্য পদ্ধতিটি আড়াল করে এমন উত্তরাধিকারের স্তরে বা তার নীচে আপনাকে অবজেক্টের সাথে কাজ করতে হবে। অন্যথায়, লুকানো পদ্ধতিটি "অনাবৃত" এবং পরিবর্তে ব্যবহৃত হয়।


4

দয়া করে C # তে পলিমারফিজম সম্পর্কে পড়ুন: পলিমॉर्फিজম (সি # প্রোগ্রামিং গাইড)

এটি সেখান থেকে একটি উদাহরণ:

যখন নতুন কীওয়ার্ড ব্যবহার করা হয়, তখন বেস ক্লাসের সদস্যদের পরিবর্তে নতুন শ্রেণীর সদস্যদের ডাকা হয়। এই বেস ক্লাসের সদস্যদের লুকানো সদস্য বলা হয়। উত্পন্ন শ্রেণীর কোনও উদাহরণ যদি বেস শ্রেণীর উদাহরণে ফেলে দেওয়া হয় তবে লুকানো শ্রেণির সদস্যদের এখনও ডাকা যেতে পারে। উদাহরণ স্বরূপ:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Calls the old method.

3

আপনাকে এটি তৈরি করতে হবে virtualএবং তারপরে সেই ফাংশনটি ওভাররাইড করতে হবে Teacher। যেহেতু আপনি উত্তরাধিকার সূত্রে পেয়েছেন এবং উত্পন্ন শ্রেণীর উল্লেখ করতে বেস পয়েন্টার ব্যবহার করছেন, আপনাকে এটি ব্যবহার করে ওভাররাইড করা দরকার virtual। ক্লাসের পদ্ধতিটি কোনও উত্সগত শ্রেণীর রেফারেন্সে নয়, শ্রেণি রেফারেন্সে newলুকিয়ে রাখার জন্য ।basebase


3

আমি এই চারপাশের তথ্যের উপর প্রসারিত করতে আরও কয়েকটি উদাহরণ যুক্ত করতে চাই। আশা করি এটিও সহায়তা করে:

এখানে একটি কোডের নমুনা রয়েছে যা কোনও ডাইরিভেড টাইপ বেস টাইপকে অর্পণ করা হলে যা ঘটে তার চারদিকে বাতাসকে পরিষ্কার করে দেয়। কোন পদ্ধতি উপলভ্য এবং এই প্রসঙ্গে ওভাররাইড এবং লুকানো পদ্ধতির মধ্যে পার্থক্য।

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            a.foo();        // A.foo()
            a.foo2();       // A.foo2()

            a = new B();    
            a.foo();        // B.foo()
            a.foo2();       // A.foo2()
            //a.novel() is not available here

            a = new C();
            a.foo();        // C.foo()
            a.foo2();       // A.foo2()

            B b1 = (B)a;    
            b1.foo();       // C.foo()
            b1.foo2();      // B.foo2()
            b1.novel();     // B.novel()

            Console.ReadLine();
        }
    }


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

        public void foo2()
        {
            Console.WriteLine("A.foo2()");
        }
    }

    class B : A
    {
        public override void foo()
        {
            // This is an override
            Console.WriteLine("B.foo()");
        }

        public new void foo2()      // Using the 'new' keyword doesn't make a difference
        {
            Console.WriteLine("B.foo2()");
        }

        public void novel()
        {
            Console.WriteLine("B.novel()");
        }
    }

    class C : B
    {
        public override void foo()
        {
            Console.WriteLine("C.foo()");
        }

        public new void foo2()
        {
            Console.WriteLine("C.foo2()");
        }
    }
}

নিম্নলিখিত সামান্য কোডের জন্য আরেকটি সামান্য বিড়ম্বনাটি হ'ল:

A a = new B();    
a.foo(); 

ভিএস সংকলক (ইন্টেলিসেন্স) এ a.foo () কে এ.ফু () হিসাবে দেখায়।

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

এই কোড নমুনা এই সাবধানে বর্ণিত সাহায্য করা উচিত!


2

অভিভাবক / শিশু শ্রেণীর ওভাররাইড আচরণে জা # জাভা থেকে আলাদা # সি C জাভাতে ডিফল্টরূপে সমস্ত পদ্ধতি ভার্চুয়াল, তাই আপনি যে আচরণটি চান তা বাক্সের বাইরে সমর্থিত।

সি # তে আপনাকে কোনও পদ্ধতিটি বেস শ্রেণিতে ভার্চুয়াল হিসাবে চিহ্নিত করতে হবে, তারপরে আপনি যা চান তা পাবেন।


2

নতুন শব্দ বলুন যে বর্তমান ক্লাসে পদ্ধতি হবে কেবল কাজই যদি আপনি টাইপ গুরু পরিবর্তনশীল সঞ্চিত শ্রেণী শিক্ষক এর একটি দৃষ্টান্ত আছে। বা আপনি এটিকে কাস্টিংগুলি ব্যবহার করে ট্রিগার করতে পারেন: ((শিক্ষক) ব্যক্তি)। শোও ইনফো ()


1

এখানে ভেরিয়েবলের 'টিচার' typeof(Person)ধরণের রয়েছে এবং এই প্রকারটি শিক্ষক শ্রেণীর সম্পর্কে কিছুই জানে না এবং উত্পন্ন প্রকারের কোনও পদ্ধতি সন্ধান করার চেষ্টা করে না। শিক্ষক ক্লাসের পদ্ধতি কলের আপনার পরিবর্তনশীল নিক্ষেপ করা উচিত: (person as Teacher).ShowInfo()

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

public class Program
{
    private static void Main(string[] args)
    {
        Person teacher = new Teacher();
        teacher.ShowInfo();

        Person incognito = new IncognitoPerson ();
        incognito.ShowInfo();

        Console.ReadLine();
    }
}

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

public class IncognitoPerson : Person
{

}

1

খুব দেরি হতে পারে ... তবে প্রশ্নটি সহজ এবং উত্তরের একই স্তরের জটিলতা থাকা উচিত।

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

উত্তরাধিকারের জন্য দরকারী পন্থা রয়েছে - আপনার কোড শ্রেণিবদ্ধের সাথে আপনি কী বলতে চান তা কল্পনা করার চেষ্টা করুন। এক বা অন্য সরঞ্জাম নিজের সম্পর্কে কী বলে তা কল্পনা করার চেষ্টা করুন। যেমন আপনি যদি কোনও বেস শ্রেণিতে ভার্চুয়াল ফাংশন যুক্ত করেন তবে আপনি ধরুন: 1. এটির ডিফল্ট বাস্তবায়ন থাকতে পারে; ২. এটি উদ্ভূত শ্রেণিতে পুনরায় প্রয়োগ করা যেতে পারে। আপনি যদি বিমূর্ত ফাংশন যুক্ত করেন তবে এর অর্থ কেবল একটি জিনিস - সাবক্লাসকে অবশ্যই একটি বাস্তবায়ন তৈরি করতে হবে। তবে আপনার যদি সরল কার্যকারিতা থাকে - আপনি কারওর প্রয়োগটি পরিবর্তন করবেন বলে আশা করবেন না।


0

সংকলক এটি করে কারণ এটি জানে না যে এটি একটি Teacher। এটি কেবলমাত্র এটি জানে যে এটি একটি Personবা এটি থেকে উত্পন্ন কিছু। সুতরাং এটি করতে পারে সমস্ত হল Person.ShowInfo()পদ্ধতি কল ।


0

শুধু একটি সংক্ষিপ্ত উত্তর দিতে চেয়েছিলেন -

আপনার ব্যবহার করা উচিত virtualএবং overrideযে ক্লাসগুলিতে ওভাররাইড করা যেতে পারে in ব্যবহারের virtualপদ্ধতি সন্তান ক্লাস এবং ব্যবহার দ্বারা ওভাররাইড করা যেতে পারে জন্য overrideপদ্ধতি যে এই ধরনের ওভাররাইড উচিত virtualপদ্ধতি।


0

আপনি জাভাতে উপরে উল্লিখিত একই কোডটি কিছু পরিবর্তন বাদে লিখেছেন এবং এটি ব্যতীত সূক্ষ্মভাবে কাজ করেছে। বেস ক্লাসের পদ্ধতিটি ওভাররাইড করা হয় এবং তাই আউটপুট প্রদর্শিত হয় "আমি শিক্ষক"।

কারণ: যেহেতু আমরা বেস শ্রেণীর একটি রেফারেন্স তৈরি করছি (যা উত্পন্ন শ্রেণীর রেফারেন্সিং উদাহরণ থাকতে সক্ষম) যা আসলে উত্পন্ন শ্রেণীর রেফারেন্স ধারণ করে। এবং যেমনটি আমরা জানি যে উদাহরণটি সর্বদা প্রথমে তার পদ্ধতির দিকে নজর রাখে যদি এটি এটির সন্ধান করে এটি এটি কার্যকর করে এবং যদি সেখানে সংজ্ঞাটি খুঁজে না পায় তবে এটি স্তরক্রমতে উঠে যায়।

public class inheritance{

    public static void main(String[] args){

        Person person = new Teacher();
        person.ShowInfo();
    }
}

class Person{

    public void ShowInfo(){
        System.out.println("I am Person");
    }
}

class Teacher extends Person{

    public void ShowInfo(){
        System.out.println("I am Teacher");
    }
}

0

কীথ এস এর দুর্দান্ত বিক্ষোভ এবং অন্য প্রত্যেকের মানের উত্তরের উপর ভিত্তি করে এবং পুরোপুরি দক্ষতার জন্য যে কীভাবে কাজ করে তা প্রদর্শন করতে সুস্পষ্ট ইন্টারফেস বাস্তবায়ন টস করতে দেয়। নীচে বিবেচনা করুন:

নেমস্পেস লিনক কনসোল অ্যাপ {

class Program
{

    static void Main(string[] args)
    {


        Person person = new Teacher();
        Console.Write(GetMemberName(() => person) + ": ");
        person.ShowInfo();

        Teacher teacher = new Teacher();
        Console.Write(GetMemberName(() => teacher) + ": ");
        teacher.ShowInfo();

        IPerson person1 = new Teacher();
        Console.Write(GetMemberName(() => person1) + ": ");
        person1.ShowInfo();

        IPerson person2 = (IPerson)teacher;
        Console.Write(GetMemberName(() => person2) + ": ");
        person2.ShowInfo();

        Teacher teacher1 = (Teacher)person1;
        Console.Write(GetMemberName(() => teacher1) + ": ");
        teacher1.ShowInfo();

        Person person4 = new Person();
        Console.Write(GetMemberName(() => person4) + ": ");
        person4.ShowInfo();

        IPerson person3 = new Person();
        Console.Write(GetMemberName(() => person3) + ": ");
        person3.ShowInfo();

        Console.WriteLine();

        Console.ReadLine();

    }

    private static string GetMemberName<T>(Expression<Func<T>> memberExpression)
    {
        MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
        return expressionBody.Member.Name;
    }

}
interface IPerson
{
    void ShowInfo();
}
public class Person : IPerson
{
    public void ShowInfo()
    {
        Console.WriteLine("I am Person == " + this.GetType());
    }
    void IPerson.ShowInfo()
    {
        Console.WriteLine("I am interface Person == " + this.GetType());
    }
}
public class Teacher : Person, IPerson
{
    public void ShowInfo()
    {
        Console.WriteLine("I am Teacher == " + this.GetType());
    }
}

}

এখানে ফলাফল:

ব্যক্তি: আমি ব্যক্তি == লিনককনসোল অ্যাপ.টিকার

শিক্ষক: আমি শিক্ষক == লিনক কনসোল অ্যাপ.টিচার

ব্যক্তি 1: আমি শিক্ষক == লিঙ্ককনসোল অ্যাপ। টিচার

ব্যক্তি 2: আমি শিক্ষক == লিঙ্ককনসোল অ্যাপ। টিচার

শিক্ষক 1: আমি শিক্ষক == লিঙ্ককনসোল অ্যাপ। টিচার her

person4: আমি ব্যক্তি == লিঙ্ককনসোল অ্যাপ.পার্সন

person3: আমি ইন্টারফেস ব্যক্তি == লিঙ্ককনসোল অ্যাপ.পার্সন

দুটি বিষয় লক্ষণীয়:
শিক্ষক.শো আইএনফো () পদ্ধতিটি নতুন কীওয়ার্ডটি বাদ দেয়। নতুন বাদ দেওয়া হলে পদ্ধতির আচরণটি একই রকম হয় যেন নতুন কীওয়ার্ডটি স্পষ্টভাবে সংজ্ঞায়িত করা হয়েছিল।

আপনি কেবল ভার্চুয়াল কী শব্দের সাথে মিল রেখে ওভাররাইড কীওয়ার্ডটি ব্যবহার করতে পারেন। বেস ক্লাস পদ্ধতিটি ভার্চুয়াল হতে হবে। বা বিমূর্ত যা ক্ষেত্রে ক্লাসটি অবশ্যই বিমূর্ত হতে হবে।

ব্যক্তি শো-ইনফো-র বেস বাস্তবায়ন পায় কারণ শিক্ষক শ্রেণি বেস প্রয়োগটি (কোনও ভার্চুয়াল ঘোষণা নয়) ওভাররাইড করতে পারে না এবং ব্যক্তি হয় et গেটটাইপ (শিক্ষক) তাই এটি শিক্ষক শ্রেণীর প্রয়োগটি আড়াল করে।

শিক্ষক শো-ইনফো এর উত্সাহিত শিক্ষক প্রয়োগ পেয়েছেন কারণ শিক্ষক কারণ এটি টাইপফ (শিক্ষক) এবং এটি ব্যক্তি উত্তরাধিকারের স্তরে নেই।

ব্যক্তি 1 উদ্ভূত শিক্ষক বাস্তবায়ন পায় কারণ এটি .GetType (শিক্ষক) এবং প্রকৃত নতুন কীওয়ার্ডটি বেস প্রয়োগটি আড়াল করে।

ব্যক্তি 2 এছাড়াও আইফারসন বাস্তবায়ন করে এবং এটি আইফারসনে একটি সুস্পষ্ট কাস্ট পেয়ে যায় তবুও উদ্ভূত শিক্ষক বাস্তবায়ন পান। এটি আবার কারণ শিক্ষক শ্রেণি স্পষ্টভাবে আইপারসন.শোইনফো () পদ্ধতি প্রয়োগ করে না।

শিক্ষক 1 এছাড়াও উদ্ভূত শিক্ষক বাস্তবায়ন পায় কারণ এটি .GetType (শিক্ষক)।

কেবল ব্যক্তি 3 শোআইএনফো-এর আইফারসন বাস্তবায়ন পায় কারণ কেবল ব্যক্তি শ্রেণি স্পষ্টভাবে পদ্ধতিটি প্রয়োগ করে এবং ব্যক্তি 3 আইফারসন টাইপের একটি উদাহরণ।

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

নোট করুন এমনকি ব্যক্তি 4 আইফারসনকে পাবেন না h এটি কারণ ব্যক্তি 4 যদিও .গেটটাইপ (ব্যক্তি) এবং ব্যক্তি আইপসন প্রয়োগ করে, ব্যক্তি 4 আইফারসনের উদাহরণ নয়।


আমি দেখছি ফর্ম্যাটিং কোডটি সঠিকভাবে একটি চ্যালেঞ্জ উপস্থাপন করছে। এখনই এটি সুন্দর করার কোনও সময় নেই ...
অবিচলিত

0

অন্ধভাবে লঞ্চ করতে কোডের নকলকরণ হ্রাস করতে লিনকুইপ্যাড নমুনা যা আমি মনে করি আপনি যা করার চেষ্টা করছেন তা।

void Main()
{
    IEngineAction Test1 = new Test1Action();
    IEngineAction Test2 = new Test2Action();
    Test1.Execute("Test1");
    Test2.Execute("Test2");
}

public interface IEngineAction
{
    void Execute(string Parameter);
}

public abstract class EngineAction : IEngineAction
{
    protected abstract void PerformAction();
    protected string ForChildren;
    public void Execute(string Parameter)
    {  // Pretend this method encapsulates a 
       // lot of code you don't want to duplicate 
      ForChildren = Parameter;
      PerformAction();
    }
}

public class Test1Action : EngineAction
{
    protected override void PerformAction()
    {
        ("Performed: " + ForChildren).Dump();
    }
}

public class Test2Action : EngineAction
{
    protected override void PerformAction()
    {
        ("Actioned: " + ForChildren).Dump();
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.