INF.04 · C# · lekcja 14

Polimorfizm i metody wirtualne

Ten sam kontrakt, inne wykonanie

  • Zrozum
  • Sprawdź
  • Napisz sam

Po tej lekcji: ten sam kontrakt, inne wykonanie

Dzisiaj zrobisz konkretną rzecz

Polimorfizm to trzecia z czterech głównych zasad OOP (po hermetyzacji i dziedziczeniu) i jeden z tematów, w których uczniowie najczęściej czują się niepewnie na egzaminie — a jednocześnie jedna z najbardziej praktycznych technik, eliminująca długie łańcuchy warunków sprawdzających typ obiektu.

Naciśnięcie "drukuj" działa tak samo niezależnie od tego, jaka konkretnie drukarka jest podłączona (laserowa, atramentowa, etykiet) — każda "wie", jak zinterpretować to samo polecenie na swój własny sposób. To właśnie polimorfizm.

Sprawdź w działaniu

Ten sam kontrakt, inne wykonanie

Najpierw przewidź wynik. Zmień dane w modelu i porównaj efekt. Spróbuj także przypadku granicznego, a nie tylko pierwszego poprawnego przykładu.

Ta interakcja wymaga włączonego JavaScriptu.

Model pokazuje wybraną zasadę. Nie uruchamia ani nie ocenia wklejonego kodu C#.

1. Przygotuj i uruchom własny projekt

2. Najpierw mały przykład

Wykonaj tę próbę przed dłuższym rozwiązaniem. virtual pozwala nadpisać metodę, override robi to w klasie pochodnej. Zmienna ma typ Pracownik, lecz rzeczywisty obiekt jest Programista — to jego implementacja zostanie wykonana.

Program.cscsharp
Pracownik osoba = new Programista();
Console.WriteLine(osoba.Opis());

class Pracownik { public virtual string Opis() => "Pracownik"; }
class Programista : Pracownik
{
    public override string Opis() => "Programista";
}
Wynik
Programista
  1. Co sprawdzić? Zmień jedną wartość i przed uruchomieniem zapisz przewidywany rezultat. Porównaj go z opisem wyniku; przy błędzie wróć do konkretnej instrukcji.

Jak to działa — 1

Polimorfizm (z greckiego "wiele form") pozwala, żeby TO SAMO wywołanie metody zachowywało się RÓŻNIE, w zależności od tego, na jakim konkretnie obiekcie zostało wywołane — nawet jeśli w kodzie operujesz na nich przez wspólny typ bazowy.

Aby to działało, klasa bazowa musi oznaczyć metodę jako virtual ("może zostać nadpisana"), a klasa pochodna nadpisuje ją słowem override: class Pracownik { public virtual double ObliczPremie() { return Pensja * 0.05; } } class Kierownik : Pracownik { public override double ObliczPremie() { return Pensja * 0.20; } }

Dzięki temu możesz mieć tablicę czy listę typu bazowego (Pracownik[]), przechowującą obiekty RÓŻNYCH klas pochodnych, i wywołać na każdym tę samą metodę — C# sam "wie", którą wersję uruchomić, sprawdzając RZECZYWISTY typ obiektu, nie typ zmiennej.

Bez polimorfizmu musiałbyś sprawdzać typ każdego obiektu ręcznie (if (p is Kierownik) { ... } else if (p is Programista) { ... }) — z polimorfizmem ten cały łańcuch warunków znika, bo każdy obiekt "sam wie", jak się zachować.

Jak to działa — 2

To jedna z najważniejszych korzyści programowania obiektowego: możesz dodać NOWĄ klasę pochodną (np. Stazysta) w przyszłości, bez zmiany ani jednej linii kodu, który już korzysta z polimorficznego wywołania ObliczPremie().

3. Pełny przykład — czytaj od Main

Teraz zastąp Program.cs tym programem. Zanim uruchomisz, znajdź dane wejściowe, operację i miejsce prezentacji wyniku. W tym wariancie zachowujemy jawny Main. Nie wklejaj kilku pełnych programów do jednego pliku.

Program.cs — osobne uruchomieniecsharp
using System;

class Pracownik
{
    public string Imie;
    public double Pensja;

    public Pracownik(string imie, double pensja)
    {
        Imie = imie;
        Pensja = pensja;
    }

    public virtual double ObliczPremie() // "virtual" = może być nadpisana
    {
        return Pensja * 0.05;
    }
}

class Kierownik : Pracownik
{
    public Kierownik(string imie, double pensja) : base(imie, pensja) { }

    public override double ObliczPremie() // "override" = własna wersja
    {
        return Pensja * 0.20;
    }
}

class Stazysta : Pracownik
{
    public Stazysta(string imie, double pensja) : base(imie, pensja) { }

    public override double ObliczPremie()
    {
        return 0; // stażyści na razie bez premii
    }
}

class Program
{
    static void Main()
    {
        Pracownik[] zespol = {
            new Pracownik("Ala", 5000),
            new Kierownik("Bartek", 9000),
            new Stazysta("Celina", 3000)
        };

        foreach (Pracownik p in zespol)
        {
            // to samo wywołanie - RÓŻNY wynik dla każdego typu!
            Console.WriteLine(p.Imie + ": premia = " + p.ObliczPremie() + " zł");
        }
    }
}
  1. Prześledź kod Tablica Pracownik[] zespol przechowuje TRZY RÓŻNE typy obiektów (Pracownik, Kierownik, Stazysta) — to możliwe właśnie dzięki dziedziczeniu (Lekcja 13), bo każdy z nich JEST RODZAJEM Pracownik. Pętla foreach wywołuje p.ObliczPremie() identycznie dla każdego elementu, ale C# w czasie DZIAŁANIA programu sprawdza rzeczywisty typ obiektu i uruchamia WŁAŚCIWĄ, nadpisaną wersję metody — to się nazywa wiązanie dynamiczne.

Sprawdź, zanim przepiszesz cały program

Najczęstszy błąd to zapomnienie słowa virtual w metodzie klasy bazowej — bez niego override w klasie pochodnej zgłosi błąd kompilacji, bo metoda nie jest oznaczona jako "nadpisywalna". Drugi błąd: użycie new zamiast override przy nadpisywaniu metody — to UKRYWA metodę bazową zamiast ją nadpisać, co psuje polimorfizm (przy wywołaniu przez typ bazowy uruchomi się stara wersja). Trzeci: ręczne sprawdzanie typu obiektu (if (p is Kierownik)) tam, gdzie polimorfizm załatwiłby sprawę prościej i bezpieczniej.

Ćwiczenie z pomocą · samodzielna praca

4. Teraz Twoja zmiana

Dodaj do przykładu z lekcji nową klasę pochodną Dyrektor : Pracownik z premią 30%, bez zmiany kodu w Main() poza dodaniem nowego obiektu do tablicy.

Oczekiwany rezultat
Spełnij warunki polecenia. Zapisz wejście, otrzymany wynik i wyjaśnij, która część kodu za niego odpowiada.
Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź

Wróć do podstawowej formy oraz objaśnienia: virtual pozwala nadpisać metodę, override robi to w klasie pochodnej. Zmienna ma typ Pracownik, lecz rzeczywisty obiekt jest Programista — to jego implementacja zostanie wykonana.

Krok 2 — pokaż podpowiedź

Zmień tylko część potrzebną do polecenia. Zachowaj działającą wersję przed zmianą i uruchamiaj po każdym małym etapie.

Krok 3 — pokaż podpowiedź

Sprawdź przypadek zwykły i graniczny; porównaj z regułą: Programista

Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.

5. Sprawdź rozumienie, nie tylko uruchomienie

Dalej na swoim koncie

Rozgrzewki, quiz i zadania są w biurku ucznia.

Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.

Zaloguj się →
Źródła i dalsza nauka