Programowanie II Lista 3 Modyfikatory dostępu plik TKLientBanku.h
plik z funkcją main
Przyjaźń
Dziedziczenie Dziedziczenie to nic innego jak definiowanie nowych klas w oparciu o już istniejące. Jest to najważniejsza cecha świadcząca o sile programowania obiektowo zorientowanego.
Dzięki tej technice możliwe jest najbardziej naturalne odzwierciedlenie związków jakie zachodzą pomiędzy obiektami modelowanej w programie rzeczywistości. Przykład najprostszy: class Tpunkt int x,y; void odbij_wzgledem_poczatku() //... void obroc(int kat) //... Zawartość metod składowych została już dawno wymyślona podobnie jak i sama definicja punktu. Okazuje się jednak, już w przypadku ekranu komputerowego taka definicja już nie wystarcza. Klasę Tpunkt należało by bowiem rozszerzyć o wartości RGB, tak aby mógł on zostać poprawnie wyświetlony. class TPunkt_monitor int x,y; int R,G,B; Oczywiście w przypadku programowania strukturalnego musielibyśmy ponownie sprecyzować metody odbij_wzgledem_poczatku() i obroc(int kat), czyli musielibyśmy wykonać tę samą pracę ponownie. Dzięki jednak technice dziedziczenia możemy zaproponować nową klasę, wykorzystując możliwości starej: class Tpunkt_monitor:public Tpunkt int R,G,B; A następnie w programie głównym użyć konstrukcji: Tpunkt_monitor punkt; punkt.x=10; Punkt.obroc(90); Fakty bardzo istotne: - dziedziczenie nie polega na przekopiowaniu zawartości jednej klasy do drugiej. Składniki dziedziczone nadal mają zakres klasy podstawowej, na który to zostaje nałożony zakres klasy pochodnej - w przypadku ponownego definiowania składników w klasie pochodnej o takich samych nazwach jak w klasie podstawowej tracimy bezpośredni dostęp do tych ostatnich - aby odwołać się do pierwotnego znaczenia przesłoniętego składnika należy użyć kwalifikatora zakresu, np.:
Tpunkt_monitor obiekt; obiekt.wypisz(); //metoda składowa klasy Tpunkt_monitor Obiekt.Tpunkt::wypisz(); //metoda składowa klasy Tpunkt - należy pamiętać, iż dziedziczenie dotyczy klas (czyli typów danych), a nie obiektów będących ich reprezentantami. Dziedziczenie kilkupokoleniowe : class A //--- ciało klasy A class B: public A //--- ciało klasy B class C: public B //--- ciało klasy C Wywoływanie konstruktorów : class Tpunkt int x,y; Tpunkt() cout<<"konstruktor punktu"<<"\n"; class Tpunkt_monitor:public Tpunkt int R,G,B; Tpunkt_monitor() cout<<"konstruktor punktu ekranowego"<<"\n"; class TPunkt_3D:public Tpunkt_monitor TPunkt_3D() cout<<"konstruktor punktu 3D"<<"\n"; Dziedziczenie, a dostęp do składników Mechanizm dziedziczenia pozwala określać w jaki sposób mają być dziedziczone składniki klasy podstawowej.
Prywatne składniki klasy podstawowej są dziedziczone, ale nie ma do nich dostępu. Nie prywatne składniki klasy podstawowej są dostępne w zakresie klasy pochodnej bezpośrednio. Dziedziczenie, a składniki chronione Składniki chronione (PROTECTED) traktowaliśmy do tej pory jak prywatne. W praktyce klauzula PROTECTED oznacza, że składnik jest zastrzeżony tylko dla klas pochodnych. W praktyce oznacza to, że składnik typu PROTECTED: dla całego świata powinien być traktowany jak prywatny czyli niedostępny dla wszystkich klas pochodnych od danej klasy powinien być dostępny, tak jakby był składnikiem publicznym. Można zatem powiedzieć, iż to klasa podstawowa poprzez odpowiednią specyfikację dostępu decyduje, które składniki zamierza udostępnić otoczeniu, a które tylko klasom pochodnym. Sposoby dziedziczenia Również klasa pochodna ma możliwość określania sposobu w jaki chce dziedziczyć składniki klasy podstawowej. Wybór taki dokonywany jest w momencie definicji klasy pochodnej: class Tpunkt_monitor:public Tpunkt Słowo public może zostać zastąpione protected lub private. Dzięki temu mamy możliwość określenia sposobu dziedziczenia składników nie prywatnych (!!!). Zasada definiowania sposobu dziedziczenia jest prosta: PUBLIC powoduje, że wszystkie składniki publiczne dziedziczone są w sposób publiczny, chronione jako chronione, a prywatne jako prywatne PROTECTED powoduje, że wszystkie składniki publiczne i chronione dziedziczone są jako chronione PRIVATE powoduje, że wszystkie składniki dziedziczone są jako prywatne. Składniki statyczne
Funkcje wirtualne Funkcje wirtualne sprawiają, że program jest obiektowo zorientowany inaczej mówiąc orientuje się względem obiektów. Przykład najprostszy: class instrument char nazwa[30]; void virtual graj() cout<<"intrument wydaje dzwiek... \n"; class trabka:public instrument void virtual graj() cout<<"teraz gra trabka... \n"; class fortepian:public instrument void virtual graj()
cout<<"teraz gra fortepian...\n"; int main(int argc, char* argv[]) instrument jakis_instrument; trabka jakas_trabka; fortepian jakis_fortepian; jakis_instrument.graj(); jakas_trabka.graj(); jakis_fortepian.graj(); Return 0; } A teraz dla odmiany inna wersja funkcji głównej: instrument *wsk_na_instrument; instrument jakis_instrument; trabka jakas_trabka; fortepian jakis_fortepian; wsk_na_instrument = &jakis_instrument; wsk_na_instrument->graj(); wsk_na_instrument = &jakas_trabka; wsk_na_instrument->graj(); wsk_na_instrument = &jakis_fortepian; wsk_na_instrument->graj(); W praktyce wirtualny oznacza tyle co możliwy, czy też mogący zaistnieć, gdyż funkcja oznaczona jako wirtualna może, ale nie musi być zrealizowana w klasach pochodnych jeszcze raz. Virtual mówi, że od tej pory po wszystkie dalsze pokolenia kompilator ma użyć swojej inteligencji, gdy chodzi o wywołania tejże funkcji przez wskaźnik. Polimorfizm W zależności od wywołania funkcji wirtualnej, wywoływany jest w praktyce inny kod. Zatem np. fragment kodu: referencja.graj(); wywoływany jest praktycznie w postaci: referencja.instrument::graj(); referencja.trąbka::graj(); referencja.fortepian::graj(); lub lub Mówimy tutaj o wielości formy programu, czyli polimorfizmie. Fragment kodu zmienia się tak, że raz odpowiada wywołaniu w wersji pierwszej raz w innej.
Statyczne funkcje składowe Klasa biblioteczna STRING
Zadanie 1 (10 pkt) Zaimplementuj małą klasę, która będzie wyposażona w statyczne metody pozwalające wyznaczać następujące miary dla zbioru liczb całkowitych (reprezentowanego w postaci wektora liczb): minimum maksimum średnia mediana dominanta Zadanie 2 (10 pkt) Wykorzystując metody z klasy string oraz wektory, zaproponuj klasę która będzie posiadać metody realizujące funkcjonalności z zadania 5 z listy 1 (obróbka podanego ciągu znaków). Dodatkowo wyposaż klasę w metodę szyfrującą oraz deszyfrującą podany napis, przy użyciu uproszczonego szyfru Cezara. Zadanie 3 (10 pkt) Zmodyfikuj strukturę klas gry monopoly tak aby uwzględnić konieczność zabezpieczenia niektórych pól przed nieautoryzowanym dostępem (zastanów się, które pola tego wymagają, ze względu na przebieg rozgrywki). Zadanie 4 (25 pkt)
Zaproponuj rozwiązanie, które umożliwiło by przechowywanie obiektów różnych klas (w grze monopoly) w jednej liście dwukierunkowej (trzeba wykorzystać dziedziczenie). Oczywiście poza listą należałoby zaimplementować możliwość wypełnienia istotnymi danymi wszystkich pól w grze, możliwość ustalenia właściciela danego pola, postawienia na polu domku czy też hotelu, pobrania opłaty (na różnych typach pól) w praktyce przeprowadzenia rozgrywki.