Programowanie obiektowe #3 – polimorfizm

Witajcie! W dzisiejszym wpisie dowiecie się czym jest polimorfizm, a także jak on działa. Zanim jednak przejdziemy do wpisu chcemy życzyć wszystkim maturzystom połamania długopisów i klawiatur na dzisiejszej maturze z informatyki – mamy nadzieję, że materiały z naszego bloga przyczynią się ku waszemu sukcesowi 🙂

Polimorfizm – definicja

Polimorfizm, jak pewnie pamiętacie z pierwszej lekcji, jest jednym z czterech filarów, na których opiera się programowanie obiektowe – dziedziczenie i hermetyzację omówiliśmy już w poprzednich wpisach. W krócie polega on na definiowaniu innych zachowań tej samej funkcji dla różnych, często dziedziczących po tym samym rodzicu, klas. Polimorfizm jest więc silnie powiązany z dziedziczeniem. Wynika to z faktu, że najczęściej w klasie bazowej definiowane są metody wirtualne, których nadpisanie jest wymagane w klasach pochodnych. Istnieją także metody czysto wirtualne, które w klasie bazowej nie mają implementacji, co czyni zawierające je klasy abstrakcyjnymi.

Czym jest klasa abstrakcyjna? Jest to klasa, której instancji nie da się stworzyć. Oznacza to, że nie da się jej wykorzystać jako typu obiektu. W języku C++ możliwe jest jednak zwracanie referencji na klasę abstrakcyjną, co wykorzystamy w późniejszym przykładzie. Jeżeli metoda czysto wirtualna nie zostanie nadpisana w klasach pochodnych, to one z automatu też stają się klasami abstrakcyjnymi.

polimorfizm - przykład

Każdy wielokąt możemy opisać tymi samymi właściwościami: ilością boków, obwodem, polem, kątami, przekątnymi, zachowaniem przekątnych etc. Każdy z katów ma jednak swoje własne właściwości i zachowania.

Polimorfizm – typy

Ze względu na sposób wdrożenia, polimorfizm możemy rozróżnić na dwa typy. Pierwszy z nich polega na przeciążaniu metod lub operatorów. Oznacza to, że tą samą metodę możemy zdefiniować wielokrotnie, jednak każda z tych definicji różni się ilością i/lub typami przyjmowanych argumentów. Często zdarza się też, że metody o mniej rozbudowanej konstrukcji korzystają z tych bardziej skomplikowanych, przekazując domyślne wartości w brakujących argumentach. Przykładowo klasa Boss może zawierać metodę paySalary(int amount, string message, Worker worker), która wypłaca amount pieniędzy pracownikowi worker, przekazując mu jednocześnie wiadomość o treści message. Szef tej firmy jest jednak bardzo gburowaty. Z tego powodu często przy wypłacie bez powodu krzyczy na pracownika, dlatego w jego klasie znajduje się również metoda paySalary(int amount, Worker worker), która wywołuje metodę o większej ilości argumentów, przekazując amount, wiadomość „Następnym razem Cię zwolnię!” i worker jako parametry.

Drugi typ polimorfizmu polega na definiowaniu tych samych metod w różny sposób w klasach pochodnych. Dzięki temu możemy określić specyficzne dla danego typu działanie funkcji, jednocześnie pozwalając na wywołanie jej bez dokładnej znajomości danego typu. Przykładowo chcemy wywołać metodę work() każdego z pracowników firmy. Wiemy, że każdy wykonuje pracę inaczej, nie znamy jednak konkretnych typów pracowników – wiemy jedynie, że wszystkie dziedziczą po klasie Worker. Okazuje się, że to już nam w zupełności wystarcza. Wystarczy bowiem do klasy Worker dodać metodę wirtualną, której implementacja jest wymagana w każdym z dziedziczących typów. Sama klasa bazowa nie może jednak implementować metody wirtualnej, dlatego przy wywołaniu metody work() każdego z pracowników wywoła się metoda specyficzna dla niego. Trochę zawikłane, prawda? Jednak, aby rozwiać wszelkie wątpliwości przejdźmy do przykładu.

grupa matura z informatyki

Polimorfizm – przykład

Dla przykładu stworzymy klasę komórki. W głównej metodzie programu stworzymy obszerny zbiór komórek, a następnie co określony czas będziemy wywoływać metody „tik” każdej z nich. Załóżmy, że komórka będzie przechowywała pewną ilość energii, którą będzie zużywała podczas każdego tiku życia. Określimy również ilość cykli, którą dana komórka będzie żyła. Warto również dodać metodę, która będzie sprawdzać czy dana komórka nadal żyje – przyjmijmy, że komórka jest żywa dopóki nie przekroczyła maksymalnej długości życia, a także posiada jeszcze jakąś energię.  Dodatkowo dodamy dwie metody wirtualne: jedna będzie odpowiadała za wytwarzanie energii, a druga za rozmnażanie komórki. Tak wygląda implementacja klasy komórki:

Cell.h

Cell.cpp

Następnie utwórzmy pochodną klasę komórki roślinnej. Jak już wiecie musi ona implementować z góry narzucone metody wirtualne klasy bazowej. Musimy więc określić w jakich warunkach i w jaki sposób komórka się reprodukuje, a także w jaki sposób pozyskuje energie. Stworzymy w tym celu uproszczoną metodę fotosyntezy, która będzie generowała losową ilość energii. Założymy też, że komórka zreprodukuje się tylko, gdy będzie miała odpowiednią ilość energii. Jeżeli tak, to podzieli ją na równo pomiędzy nowoutworzoną komórką a sobą. Poniżej kod klasy:

PlantCell.h

PlantCell.cpp

Następnie stworzymy klasę komórki zwierzęcej. Tutaj dodamy ilość przechowywanego pokarmu, a także stworzymy przeciążoną metodę pozyskiwania go. Następnie, tak jak w przypadku komórki roślinnej, musimy zaimplementować dziedziczone metody. Przyjmijmy, że klasa reprodukuje się, gdy ma wystarczająco pokarmu, a następnie dzieli się nim z nowo utworzoną komórką.

AnimalCell.h

AnimalCell.cpp

Następnie możemy przejść do wykorzystania utworzonych klas:

Main.cpp

Zwróćcie uwagę, że w pętli nie usuwamy/dodajemy komórek do głównego kontenera. Dlaczego? Modyfikacja zbioru iterowanych danych zmieniłaby zakres działania pętli, przez co program najprawdopodobniej by się posypał. Skorzystaliśmy więc z pomocniczych kontenerów, których zawartość sukcesywnie obsługiwaliśmy poza pętlą. Zauważcie, że w pętli for nie wiemy jakiego typu są przechowywane komórki, a jednak jesteśmy w stanie wywołać metodę reproduce i gainEnergy w sposób specyficzny dla każdego z tych typów. Zresztą widać to w działaniu samego programu:

Tym przykładem kończymy dzisiejszą lekcję. W następnym wpisie z serii omówimy czym jest ostatni z filarów: abstrakcja. Udanej środy i wysokich wyników z matur 🙂

You Might Also Like
Dodaj komentarz

icon