Polimorfizm w C
1. Wprowadzenie
- Polimorfizm (z greckiego „wiele form") to zdolność obiektów różnych klas do reagowania na te same komunikaty (metody) w różny sposób.
- Jest to jeden z trzech głównych filarów programowania obiektowego (obok enkapsulacji i dziedziczenia).
- W C# występują dwa typy polimorfizmu:
- Polimorfizm w czasie kompilacji (compile-time) – przeciążanie metod i operatorów,
- Polimorfizm w czasie wykonania (runtime) – przesłanianie metod (override).
2. Polimorfizm w czasie kompilacji (statyczny)
2.1. Przeciążanie metod (Method Overloading)
- Przeciążanie metod to definiowanie kilku metod o tej samej nazwie, ale z różnymi parametrami.
- Kompilator wybiera właściwą metodę na podstawie liczby i typów argumentów.
2.2. Przeciążanie operatorów (Operator Overloading)
- C# pozwala na przeciążanie operatorów dla własnych typów.
3. Polimorfizm w czasie wykonania (dynamiczny)
- Polimorfizm dynamiczny polega na przesłanianiu metod z klasy bazowej w klasach pochodnych.
- Wymaga użycia słów kluczowych
virtualioverride. - Dzięki temu można traktować obiekty klas pochodnych jako obiekty klasy bazowej i wywoływać odpowiednie metody.
3.1. Podstawowy przykład
Wynik:
Hau hau!
Miau!
Zwierzę wydaje dźwięk
- Mimo że wszystkie obiekty są typu
Zwierze, każdy wywołuje swoją własną implementację metodyDajGlos().
3.2. Zalety polimorfizmu dynamicznego
- Elastyczność – ten sam kod działa dla różnych typów obiektów.
- Rozszerzalność – łatwo dodać nowe klasy bez zmiany istniejącego kodu.
- Czytelność – uproszczenie kodu przez unikanie wielokrotnych instrukcji warunkowych.
4. Różnica między virtual/override a new
4.1. virtual i override – polimorfizm
4.2. new – ukrywanie metody (brak polimorfizmu)
newnie tworzy polimorfizmu – wywoływana jest metoda z klasy bazowej.
5. Polimorfizm z klasami abstrakcyjnymi
- Klasy abstrakcyjne idealnie nadają się do tworzenia polimorficznych hierarchii.
- Wymuszają implementację metod abstrakcyjnych w klasach pochodnych.
Wynik:
Pole: 78.54
Pole: 24.00
6. Polimorfizm z interfejsami
- Interfejsy również umożliwiają polimorfizm.
- Klasy implementujące ten sam interfejs mogą być traktowane jako obiekty tego interfejsu.
7. Rzutowanie i sprawdzanie typów
7.1. Operator is
- Sprawdza, czy obiekt jest danego typu.
7.2. Operator as
- Próbuje rzutować obiekt na dany typ. Jeśli się nie uda, zwraca
null.
7.3. Pattern matching (C# 7+)
8. Przykładowy program
Wynik:
Jan Kowalski - Pensja: 5 000,00 zł
Anna Nowak - Pensja: 8 000,00 zł
9. Najlepsze praktyki
- Używaj
virtual/overridezamiastnewdla polimorfizmu. - Stosuj klasy abstrakcyjne lub interfejsy do tworzenia wspólnych kontraktów.
- Unikaj nadużywania polimorfizmu – zbyt złożone hierarchie mogą być trudne do zrozumienia.
- Używaj pattern matching dla czytelniejszego kodu przy sprawdzaniu typów.
- Zawsze rozważ kompozycję jako alternatywę dla dziedziczenia.
10. Podsumowanie
- Polimorfizm statyczny – przeciążanie metod i operatorów (compile-time).
- Polimorfizm dynamiczny – przesłanianie metod
virtual/override(runtime). - Polimorfizm umożliwia pisanie elastycznego, rozszerzalnego kodu.
- Klasy abstrakcyjne i interfejsy wspierają polimorfizm.