[Q] Интерфейси, имплементация и наследяване.


0

Здравейте, колеги! Имам въпрос относно наследяването и имплементацията на интерфейс. Ето и примерния код, който предизвика въпроса ми:

interface ITeacher
    {
        void Teach();
    }
 
class AnotherTeacher : ITeacher
    {
        public void Teach()
        {
            Console.WriteLine("Hell I am a Teacher!");
        }
    } 
 
class AnotherSchoolTeacher : AnotherTeacher
    {
   public void Teach()
        {
            Console.WriteLine("Hello I am a SCHOOL Teacher!");
        }
    }
 
ITeacher teacher = new AnotherTeacher();
ITeacher schoolTeacher = new AnotherSchoolTeacher();
 
teacher.Teach();
schoolTeacher.Teach();
 
 
когато си направя 2 инстанции и извикам Teach() за всяка от тях, резултатът е, че в крайна сметка се вика имплементацията само на базовия клас. Защо се получава така? Когато в имплементацията на метода в базовия клас "кажа", че методът е виртуален и го пренапиша в наследника, проблеми нямам и всичко е какато трябва. Не трябва ли, когато имплементирам интерфейс да имам имплементацията му ПОНЕ в базовия клас и ако такава липсва в наследниците му, те да ползват тази на базовия си клас, а ако освен тази в базовия клас имам имплементация и в наследните, те да си ползват своята?
 
Благодаря :)

в C# OOP от rodi1i (237 точки)


Отговори



4

Имплементацията на ITeacher е само и единствено методът AnotherTeacher.Teach. Нито методът е отбелязан като виртуален за да може AnotherSchoolTeacher.Teach да го замести, нито върху AnotherSchoolTeacher е маркирано че изпълнява сам ITeacher за да го прави "по своему", за да може ITeacher.Teach да сочи към неговия метод. 

От гледна точка на компилатора, AnotherSchoolTeacher.Teach е просто някакъв случаен метод, който няма нищо общо с интерфейса. Това е доста праволинейно и логично поведение, защото избягва хаоса, който иначе би се получил ако някой наследяващ клас въведе нов метод със същото име, който прави нещо различно. Не че един разбиращ програмист би направил нещо подобно, но това е вид защита за ползващите базовите класове.

ПС: ето нагледно трите сценария които споменах:

AnotherTeacher.Teach е виртуален и заместен от AnotherSchoolTeacher.Teach

ITeacher.Teach -> AnotherTeacher.Teach -> AnotherSchoolTeacher.Teach

AnotherSchoolTeacher изпълнява отделно ITeacher (в декларацията на класа имаме AnotherSchoolTeacher : ITeacher)

ITeacher.Teach -> AnotherSchoolTeacher.Teach

кодът който си постнал

ITeacher.Teach -> AnotherTeacher.Teach (AnotherSchoolTeacher.Teach е съвсем отделен метод който въобще не играе роля в случая)


от staafl (5770 точки)


0
Т.е. да разбирам ли, че в този случай AnotherSchoolTeacher НЕ имплементира ITeacher?

от rodi1i (237 точки)

0
може така да се каже - AnotherTeacher го имплементира, а AnotherSchoolTeacher използва неговата имплементация; виж обяснението което добавих накрая на поста ми

от staafl (5770 точки)


1
Мисля, че реално наистина имаш метод Teach във всеки един от child класовете, но просто затормозяваш компилатора. Реално имаш 2 метода с еднакив имена. Явно така са настроени нещата, че да извиква най-старшия(т.е. този който е родителския). Имплементацията на интерфейса си я имаш в базовия клас и оттам в child класовете.
Виждам, че сам си стигнал до отговора, че методът ти трябва да е virtual и да се override-не в child класовете, за да изкарва каквото искаш. Другият вариант е да го зададeш абстрактен в класа родител и отново да го override-неш надолу public abstract void Teach(). Така няма да ти трябва тяло на на метода.
Иначе като обобщение нещата не работят както ти си мислиш. Да, наистина наследниците наследяват метода, но когато искаш да го модифицираш трябва да е virtual или abstract (зависи от конкретния случай). Не може просто да напишеш метод със същото име в child класа.

от Vazzzz (1380 точки)


1
Като допълнение на колегата, ако искаш да ти се изпълни точно това направи
AnotherSchoolTeacher schoolTeacher = new AnotherSchoolTeacher();
за да ти изпише "Hello I am a SCHOOL Teacher!"
Другият вариант ти е ако го декларираш така:
ITeacher schoolTeacher = new AnotherSchoolTeacher();
да го извикаш така:
(schoolTeacher as AnotherSchoolTeacher).Teach();

от nikivat (246 точки)