Dziedziczenie, polimorfizm, Interfejsy Akademia C# - Lab 4 Dziedziczenie, polimorfizm, Interfejsy
Dziedziczenie
Dziedziczenie Dziedziczenie to kluczowy mechanizm obiektowości. Dziedziczenie pozwala na powielanie funkcjonalności wobec różnych klas w ten sposób nie musimy pisać ciągle samego kodu. . W dziedziczeniu używamy następujących terminów: -klasa bazowa (klasa z której dziedziczymy) -klasa pochodna (klasa która dziedziczy) Klasa pochodna może dziedziczyć tylko z jednej klasy bazowej. Dziedziczenie jest przechodnie, tzn jak klasa A dziedziczy po klasie B, która dziedziczy po klasie C to klasa A również dziedziczy po klasie C
Dziedziczenie class Figury { public string kolorWypelnienia; public string kolorObramowania; public int wielkoscObramowania; } class Prostokąt :Figury { } Klasa pochodna dziedziczy po klasie bazowej . W wyniku tej operacji wszystkie pola, metody, właściwości nieoznaczone modyfikatorem private są dostępne dla klasy pochodnej. W C# dziedziczenie zawsze jest publiczne.
Wywoływanie konstruktorów klas bazowych Wywołanie konstruktora klasy bazowej w klasie pochodnej odbywa się za pomocą słowa kluczowego “base” , a w nim trzeba podać odpowiednie argumenty. class Figury { public Figury(string kolowyp, string kolobr) { kolorWypelnienia = kolowyp; kolorObramowania = kolobr; } public string kolorWypelnienia; public string kolorObramowania; } class Prostokąt :Figury { public Prostokąt(string kolowyp, string kolobr) : base(kolowyp,kolobr) { } } W tym przykładzie konstruktor klasy bazowej (Figury) wykona się najpierw potem wykona się konstruktor klasy pochodnej (Prostokąt) Ta sztuczka działa pod warunkiem , że konstruktor w klasie bazowej nie jest prywatny.
Wywołanie konstruktora klasy bazowej w klasie pochodnej class KlasaPochodna : KlasaBazowa { public KlasaPochodna(int x) : base(x){} } class KlasaBazowa { public KlasaBazowa(int x) {} public KlasaBazowa() {} } W tym przypadku najpierw wykona się konstruktor klasy bazowej ,a potem klasy pochodnej.
Polimorfizm class Ssak { public void Spij() { } } class Kot : Ssak { new public void Spij() { } public void Miauczenie() { } } Kiedy dodamy do metody w klasie pochodnej słowo kluczowe new to informujemy kompliator, że wiemy co robimy i jest to celowo przesłonięta metoda klasy bazowej
Przesłanianie a nadpisywanie metod Pamiętaj, że nadpisanie metody, a jej przysłonięcie to dwie różne rzeczy. Metoda, która celowo ma być nadpisana jest metodą wirtualną. Nadpisywanie metody jest to mechanizm, który oferuje różne implementacje dla tej samej metody. Cel metody jest zawsze taki sam tylko dostosowany do danego obiektu.
Metody virtual i override public override void SenRem() { base.SenRem(); } Użyj słowa kluczowego base. //Użyj słowa ‘virtual’ do deklaracji tej metody. class Ssak { public virtual void Sen() { //ciało } } //Użyj słowa ‘override’ aby napisać metodę z klasy bazowej. class Kot : Ssak { public override void Sen() { //inne ciało } }
Metody wirtualne i metody nadpisane (przysłanianie i nadpisywanie metod) Zasady użycia metod wirtualnych i metod nadpisanych Istnieje pewna grupa zasad, które muszą być przestrzegane , aby mechanizm metod wirtualnych działał poprawnie. Metody wirtualne i metody nadpisujące nie mogą być być prywatne. Nazwy metody wirtualnej i nadpisującej muszą być takie same. Wielkość znaków się liczy. Metoda wirtualna i metoda nadpisująca muszą mieć ten sam poziom dostępności. Czyli muszą mieć taki sam modyfikator dostępu. Możesz nadpisać tylko metodę wirtualną. Jeśli metoda nadpisująca nie ma słowa kluczowego override kompilator uznaje ,że chcesz przysłonić metodę, czyli stworzyć kompletnie inną implementacje. Jeśli chodzi o mechanizm dziedziczenia każda klasa dziedzicząca po klasie, która nadpisała metodę X może nadpisać ją jeszcze raz na swój sposób.
Klasa z modyfikatorem sealed Klasa z modyfikatorem sealed jest klasą „zamkniętą”, to znaczy że nie może być ona użyta jako klasa bazowa. sealed class Klasa { //ciało klasy }
Interfejsy Interfejs nie zawiera żadnego kodu użycia natomiast zawiera tylko specyfikacje metod i jej właściwości. Interfejsy można traktować jak kontrakt, który gwarantuje ,że dana klasa lub struktura, która po nim dziedziczy obsługuje dane zachowania. Kiedy klasa obsługuje dany interfejs musi udostępniać wszystkie elementy tego interfejsu. namespace System { public interface IComparable int CompareTo(object obj); }
Implementowanie interfejsów class Test :IComparable { public int CompareTo(object obj) throw new NotImplementedException(); } Klasa bądź struktura, która dziedziczy po interfejsie musi implementować wszystkie jej metody w przeciwnym wypadku zobaczymy błąd.
Ważne! Klasa może mieć tylko jedną klasę bazową ,ale klasa może mieć wiele interfejsów
Zadanie Stwórz klasy: • Osoba z polami: imie, nazwisko, wiek, konstruktorem inicjującym wszystkie pola oraz metodą Wypisz. • Książka z polami: tytul, autor (typu Osoba), data wydania oraz metodą Wypisz Utwórz różne obiekty stworzonych klas. Wykonaj metody Wypisz.
Zadanie Stwórz klasę Czytelnik, dziedziczącą z klasy Osoba. Dodatkowo klasa Czytelnik powinna posiadać pole – listę / tablicę obiektów typu Książka - listę książek przeczytanych przez danego czytelnika oraz metodę WypiszKsiążki - wypisujące tytuły książek, które czytelnik przeczytał. Stwórz 3-5 książek, 2-4 czytelników, przypisz książki do tablic / list przeczytanych książek czytelników, wykonaj metody WypiszKsiążki.
Zadanie Zdefiniuj interfejs IOsoba. Powinien on nakazywać implementację właściwości Nazwa oraz metody Opisz. Następnie stwórz klasę Student dziedziczącą po tym interfejsie i implementującą go. Utwórz Studenta i przetestuj działanie metody
Zadanie