Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Programowanie obiektowe

Podobne prezentacje


Prezentacja na temat: "Programowanie obiektowe"— Zapis prezentacji:

1 Programowanie obiektowe
PO Programowanie obiektowe PO - LAB 1 Wojciech Pieprzyca

2 PO 1. Wstęp Programowanie obiektowe pozwala nam posługiwać się rzeczywistymi pojęciami, które znamy z codziennego życia. Nie musimy zatem odwoływać się do określonej specyfiki języka maszynowego, ani też nawet do jego bardziej abstrakcyjnych wersji (ale nadal odległych od rzeczywistości, która nas otacza). Obiektowość upraszcza nie tylko samo programowanie, ale także fazę projektowania oprogramowania. Pojęciem kluczowym dla tego sposobu programowania jest obiekt.

3 PO 2. Czym jest obiekt ? Obiekt jest tworem abstrakcyjnym jednak w dużym stopniu odzwierciedlającym rzeczywistą charakterystykę i działanie maszyn, ludzi, organizacji, itp. Z obiektem możemy utożsamiać 3 cechy: a) stan - dane opisujące obiekt tzw. składowe czyli informacje które obiekt ZNA, b) zachowanie - funkcje jakie może wykonywać obiekt tzw. metody, czyli zachowania które obiekt WYKONUJE, c) tożsamość - pozwala na jednoznaczne odróżnianie obiektów od siebie.

4 PO 3. Klasy Klasa jest pojęciem pierwotnym dla obiektu ponieważ każdy obiekt jest reprezentantem jakiejś klasy obiektów (czyli, że obiekty powstają na podstawie wcześniej zdefiniowanego opisu klasy). Klasa grupuje obiekty tego samego rodzaju, posiadające tę samą strukturę. Klasę możemy wyobrazić sobie jako matrycę służącą do tworzenia obiektów. W ten sposób informujemy kompilator jakie składowe i jakie metody zawiera dana klasa, a co za tym idzie poszczególne obiekty, które są związane z daną klasą. KLASA OBIEKTÓW o1 o2 o3 o4

5 PO 4. Przykład klasy Rozpatrzmy klasę samochód. Jak wiemy każdy obiekt typu samochód posiada dość podobną charakterystykę i funkcjonalność. Przykładem opisu klasy samochód może być kolor, masa, rodzaj silnika, elementy wyposażenia, itp. Jako funkcje (metody) możemy z kolei wyróżnić: zmianę prędkości, zmianę biegu, hamowanie, przyspieszanie, itp. Mamy więc klasę samochód na postawie której możemy stworzyć obiekty tej klasy, a więc konkretne wystąpienia klasy takie jak np. Ford, Mercedes, Honda, itp.

6 5. Komunikacja obiektów PO
W sposób uproszczony możemy przyjąć, że program obiektowy składa się z wielu obiektów komunikujących się między sobą, wymieniających informacje i wywołujących wzajemnie swoje metody. Musi zatem istnieć odpowiedni mechanizm komunikacji obiektów. Obiekty zwykle komunikują się poprzez wywołanie metod publicznych, tzn. takich które są dostępne spoza samego obiektu macierzystego. W przykładzie widzimy, ze obiekt kierowca wywołuje metodę publiczną zmianaBiegu obiektu samochód.

7 PO 6. Enkapsulacja (I) Enkapsulacja jest próbą ukrycia niektórych skladowych i metod obiektu przed dostępem z zewnątrz (czyli przez inne obiekty). Dobrym zwyczajem jest pisanie dla wszystkich skladowych (zmiennych) do których istnieje potrzeba dostania się z zewnątrz obiektu, odpowiednich metod dostępowych. Na przykład dla zmiennej int liczba, napisalibyśmy dwie metody dostępowe ustawLiczbe(int x) ustalającą wartość zmiennej na podaną wartość x i pobierzLiczbe() zwracającą aktualną wartość liczby. Taki sposób programowania chroni składową x przed bezpośrednim dostępem i ingerencją z zewnątrz. Dzięki temu w metodach dostępowych można kontrolować sposób zmiany tej wartości.

8 PO Enkapsulacja (II) Ze względu na możliwy dostęp wyróżniamy 3 rodzaje składowych: 1) prywatne (private) – przeznaczone wyłącznie do użytku wewnątrz danej klasy 2) publiczne (public) – dostęp do nich jest nieograniczony, tzn. możliwy zarówno w ramach klasy jak i spoza niej, 3) chronione (protected) – dostępne wewnątrz danej klasy, ale również dla klas potomnych oraz klas i metod zaprzyjaźnionych (o tym powiemy później).

9 7. Definiowanie klasy w języku C++
PO 7. Definiowanie klasy w języku C++ Zdefiniowanie klasy opiera się zazwyczaj na określeniu jej nazwy, składowych oraz metod, które w niej występują. Dodatkowo składowe i metody należy umieścić w odpowiedniej sekcji określającej możliwości dostępu do danego elementu składowego (private, protected lub public). Szkielet klasy: class nazwaKlasy { private: //prywatne elementy składowe protected: //chronione elementy składowe public: //publiczne elementy składowe };

10 8. Przykład definicji klasy (I)
PO 8. Przykład definicji klasy (I) class osoba { private: char imie[20]; char nazwisko[20]; int wiek; public: void wpiszDane(char *_imie, char *_nazwisko, int _wiek) strcpy(imie, _imie); strcpy(nazwisko, _nazwisko); wiek = _wiek; }

11 Przykład definicji klasy (II)
PO Przykład definicji klasy (II) char * pobierzImie() { return imie; } char * pobierzNazwisko() return nazwisko; int pobierzWiek() return wiek; };

12 9. Program obiektowy (I) PO
Aby wykorzystać wcześniej zdefiniowaną klasę konieczne będzie utworzenie obiektu tej klasy. Możemy go utworzyć na przykład w obrębie funkcji main. int main() { osoba os1; //ten kod tworzy nowy obiekt char imie[20],nazwisko[20]; int wiek; cout << ”Podaj swoje imie: ”; cin >> imie; cout << ”Podaj swoje nazwisko: ”; cin >> nazwisko; cout << ”Podaj swoj wiek: ”; cin >> wiek;

13 9. Program obiektowy (II)
PO 9. Program obiektowy (II) os1.wpiszDane(imie,nazwisko,wiek); cout << ”Imie: ”<< os1.pobierzImie() << endl; cout << ”Nazwisko: ”<< os1.pobierzNazwisko() << endl; cout << ”Wiek: ”<< os1.pobierzWiek() << endl; } //koniec funkcji main W przykładzie tym utworzyliśmy jeden obiekt o nazwie os1. Mówimy, że obiekt os1 jest obiektem typu osoba. Dostęp do składowych i obiektów uzyskujemy pisząc nazwę obiektu, kropkę i nazwę danej składowej/metody. Wykorzystaliśmy metodę wpiszDane służącą do zapamiętania danych pobranych od użytkownika oraz 3 metody akcesorowe (dostępowe), dzięki którym mogliśmy się odwołać i pobrać wartości składowych klasy.

14 10. Inny sposób definicji klasy (I)
Inny sposób definicji klasy zakłada, że w obrębie samej definicji klasy znajdą się jedynie nagłówki funkcji (metod), natomiast samo ciało (treść) metod będzie zdefiniowana na zewnątrz klasy. class osoba { private: char imie[20]; char nazwisko[20]; int wiek; public: void wpiszDane(char *_imie, char *_nazwisko, int _wiek); char * pobierzImie(); char * pobierzNazwisko(); int pobierzWiek(); };

15 Inny sposób definicji klasy (II)
void osoba::wpiszDane(char *_imie, char *_nazwisko, int _wiek) { strcpy(imie, _imie); strcpy(nazwisko, _nazwisko); wiek = _wiek; } char * osoba::pobierzImie() //jedyna zmiana to { //dodanie frazy osoba:: return imie; //przed nazwami metod } //co wskazuje iż dana char * osoba::pobierzNazwisko() //metoda należy do klasy return nazwisko; int osoba::pobierzWiek() return wiek;

16 PO 11. Zasady i dobry styl Poprzednie przykłady zostały przedstawione zgodnie z zasadami programowania obiektowego. Przede wszystkim mowa tu o tym, iż składowe (np. imie, nazwisko, wiek) zadeklarowane są jako prywatne oraz dostęp do nich następuje jedynie poprzez specjalnie utworzone metody dostępowe (wpiszDane, pobierzImie, pobierzNazwisko, pobierzWiek). Nie ma więc możliwości dotarcia do tych składowych bezpośrednio, z pominięciem metod. Możemy jednak napisać program, który nie będzie przestrzegał tych zasad. Możemy, ale czy powinniśmy ? Czasami zachodzi potrzeba użycia bezpośredniego dostępu do składowych w celu uproszczenia jakiegoś obiegu albo przetwarzania informacji. Generalnie jednak nie powinniśmy tego robić, gdyż jest to niezgodne z zasadą enkapsulacji, która stanowi jeden z fundamentów programowania obiektowego.

17 PO 12. Łamiemy zasady! (I) Tak, życie bez zasad jest prostsze ;-) (co nie znaczy, że lepsze) Definicja klasy upraszcza się w takim przypadku do zadeklarowania samych składowych. Metody dostępowe, które do tej pory używaliśmy stają się zbędne. Cała idea polega na tym iż deklarujemy składowe jako publiczne (public) a więc mamy do nich dostęp bezpośredni, bez pomocy metod. class osoba { private: //nie mamy skladowych prywatnych tylko publiczne public: char imie[20]; char nazwisko[20]; int wiek; };

18 PO Łamiemy zasady! (II) Wobec tego, że wszystkie składowe są publiczne, odwołamy się bezpośrednio do składowych a nie do metod. int main() { osoba os1; char imie[20],nazwisko[20]; int wiek; cout << ”Podaj swoje imie: ”; cin >> imie; cout << ”Podaj swoje nazwisko: ”; cin >> nazwisko; cout << ”Podaj swoj wiek: ”; cin >> wiek; strcpy(os1.imie, imie); strcpy(os1.nazwisko, nazwisko); os1.wiek = wiek; cout << ”Imie: ”<< os1.imie << endl; cout << ”Nazwisko: ”<< os1.nazwisko << endl; cout << ”Wiek: ”<< os1.wiek << endl; }

19 PO 13. Przykład drugi Tematem przykładu będzie program przechowujący informacje na temat liczb zespolonych i potrafiący obliczyć sumę dwóch takich liczb. Jak wszyscy wiedzą, liczbą zespoloną nazywamy parę uporządkowaną liczb rzeczywistych (a,b). Często taka parę zapisuje się w postaci sumy: z = a + bi, gdzie i2=-1 Oznaczenia: a – część rzeczywista, b – część urojona Sumę dwóch liczb zespolonych zdefiniujemy jako: z1 + z2 = (a+c) + (b+d)i

20 13. Przykład drugi (I) PO class zespolona { private: int a,b; public:
void wpisz(int a, int b); void pokaz(); int pobierzA(); int pobierzB(); }; void zespolona::wpisz(int _a, int _b) a = _a; b = _b; } void zespolona::pokaz() cout << a << ”+” << b << ”i”;

21 Przykład drugi (II) PO int zespolona::pobierzA() { return a; }
int zespolona::pobierzB() return b; Dodatkowo zdefiniujemy funkcje (poza klasą), która będzie obliczać sumę dwóch liczb zespolonych. Argumentami tej funkcji będą, rzecz jasna, dwie liczby zespolone. Wynikiem działania powinna być suma tych dwóch liczb, a więc również liczba zespolona.

22 Przykład drugi (III) PO Suma dwóch liczb zespolonych
zespolona suma(zespolona z1, zespolona z2) { int a,b; zespolona z; a = z1.pobierzA() + z2.pobierzA(); b = z1.pobierzB() + z2.pobierzB(); z.wpisz(a,b); return z; } Metoda ta tworzy nowy obiekt typu zespolona i wpisuje do niego parametry a,b, które zostały wcześniej obliczone zgodnie z definicją sumy dwóch liczb zespolonych.

23 Przykład drugi (IV) PO int main() { zespolona z1,z2; z1.wpisz(3,4);
cout << "Liczba 1 = "; z1.pokaz(); cout << endl << "Liczba 2 = "; z2.pokaz(); cout << endl << "Suma = "; suma(z1,z2).pokaz(); } Ostatnia linia kodu jest dość ciekawa. Odnosimy się w niej do obiektu, który choć istnieje to nigdzie wcześniej go nie deklarowaliśmy, ani nie posiada on nazwy. Wynika to stąd iż pracujemy bezpośrednio na obiekcie zwróconym przez funkcję suma.

24 Konstruktor i destruktor obiektu (I)
PO Konstruktor i destruktor obiektu (I) Konstruktor obiektu to metoda składowa klasy. Metoda ta uruchamiana jest automatycznie w czasie tworzenia każdego nowego obiektu danej klasy. Zazwyczaj używa się go do inicjalizowania danych (składowych) określonego obiektu. Dwie ważne informacje na temat konstruktora: 1) metoda definiująca konstruktor nosi nazwę taką samą jak nazwa klasy, 2) metoda ta nie może zwracać żadnych wartości (nawet typu void). Klasa może mieć więcej niż jeden konstruktor. Oznacza to, że może istnieć kilka możliwości inicjalizowania składowych klasy. Jeżeli istnieje kilka konstruktorów (a więc metod o tej samej nazwie) to mówimy, iż nastąpiło przeładowanie nazw metod. To który konstruktor będzie wywołany zależeć będzie od rodzaju argumentów, które mu podamy.

25 Konstruktor i destruktor obiektu (II)
PO Konstruktor i destruktor obiektu (II) Napiszemy klasę Osoba (podobną jak na zajęciach 1), tym razem jednak zamiast metody wpiszDane posłużymy się odpowiednim konstruktorem. Dodatkowo przechowywać będziemy informacje o wysokości płac danej osoby, przy czym liczba pensji o której przechowujemy informacje dla danej osoby może być różna (trzeba będzie więc zastosować odpowiednią strukturę dynamiczną). class Osoba { private: char imie[20], nazwisko[20]; int wiek,n; float *place; public: Osoba(); Osoba(char *_imie, char *_nazwisko, int _wiek, int _n); ~Osoba(); void info(); };

26 Konstruktor i destruktor obiektu (III)
PO Konstruktor i destruktor obiektu (III) Na razie zadeklarowaliśmy tylko składowe i metody klasy. W klasie Osoba występują dwa konstruktory. Jeden to konstruktor bezargumentowy Osoba(). Drugi konstruktor przyjmuje 4 argumenty Osoba(char *_imie, char *_nazwisko, int _wiek, int _n). O konstruktorze bezargumentowym mówimy, iż jest to konstruktor domniemany. Dlaczego tak ? Otóż jeżeli programista sam nie zdefiniuje żadnego konstruktora to kompilator automatycznie i samodzielnie stworzy domyślnie konstruktor bezargumentowy. Kompilator zatem domniema iż w przypadku, gdy sami nie zatroszczyliśmy się o zdefiniowanie konstruktora to praca ta spada na niego. Nie może bowiem zaistnieć klasa, która nie posiada konstruktora. W klasie wystąpiła jeszcze metoda o dziwnej nazwie ~Osoba(). To destruktor. Ale o nim za moment.

27 Konstruktor i destruktor obiektu (IV)
PO Konstruktor i destruktor obiektu (IV) //konstuktor domniemany Osoba::Osoba() { cout << ”Dziala konstuktor domniemany”<<endl; strcpy (imie, ”brak danych”); strcpy (nazwisko, ”brak danych”); wiek = 0; n = 0; place = null; } //konstruktor z określonymi argumentami Osoba::Osoba(char *_imie, char *_nazwisko, int _wiek, int _n) cout << ”Dziala konstuktor argumentowy”<<endl; strcpy (imie,_imie); strcpy (nazwisko, _nazwisko); wiek = _wiek; n = _n;

28 Konstruktor i destruktor obiektu (V)
PO Konstruktor i destruktor obiektu (V) place = new float[n]; for (int i=0; i<n; i++) { cout << "Podaj zarobki w miesiacu " << i+1 << " = "; cin >> place[i]; } } //koniec konstruktora z argumentami Uwagi: n – liczba pensji do zapamiętania Zmienna place to wskaźnik na obiekt typu float. W ten sposób możemy wskazać na początek tablicy, która będzie przechowywać informacje o płacach w kolejnych miesiącach. Za pomocą operatora new rezerwowany jest odpowiedni obszar pamięci potrzebny do przechowania n liczb typu float.

29 Konstruktor i destruktor obiektu (VI)
PO Konstruktor i destruktor obiektu (VI) //informacje o osobie void Osoba::info() { cout << ”Imie: ” << imie << endl; cout << ”Nazwisko: ” << nazwisko << endl; cout << ”Wiek: ” << wiek << endl; if (n>0) cout << ”Zarobki” << endl; else cout << ”Brak zarobkow”<<endl; for (int i=0; i<n; i++) cout << ”Miesiac ”<< i+1 << ” = ” << place[i]; } //destruktor Osoba::~Osoba() cout << ”Dziala destuktor” << endl; delete []place;

30 Konstruktor i destruktor obiektu (VII)
PO Konstruktor i destruktor obiektu (VII) Jak już wspomnieliśmy metoda o nazwie ~Osoba to destruktor. Pojawia się pytanie: po co nam destruktor ? Naturalnie kojarzy nam się on z czymś odwrotnym niż konstruktor. I słusznie. Destruktor wywoływany jest przy usuwaniu obiektu z pamięci. Jednak samo usunięcie obiektu nie zawsze wystarcza. Bowiem metody obiektu mogły wcześniej np. utworzyć jakieś struktury dynamiczne, które nie przestaną istnieć nawet po usunięciu samego obiektu. Co więcej usunięcie obiektu, spowoduje, że przestaniemy mieć do nich dostęp i nie będziemy mogli ich w żaden sposób wykorzystać ani usunąć. Programując w języku C++ należy zatem pamiętać o tym iż konieczne jest zwalnianie pamięci, którą wcześniej w jakiś sposób zarezerwowaliśmy. I między innymi w tym celu możemy wykorzystać destruktor. W naszym przykładzie w destruktorze zwalniamy pamięć wcześniej zarezerwowaną dynamicznie na tablice z płacami.

31 Konstruktor i destruktor obiektu (VIII)
PO Konstruktor i destruktor obiektu (VIII) int main() { Osoba os1; //lub Osoba os1(); – utworzenie obiektu przy //użyciu konstruktora domniemanego char imie[20],nazwisko[20]; int wiek,n; os1.info(); getch(); cout << ”Podaj imie: ”; cin >> imie; cout << ”Podaj nazwisko: ”; cin >> nazwisko; cout << ”Podaj wiek: ”; cin >> wiek; cout << ”Podaj ilosc pensji: ”; cin >> n;

32 Konstruktor i destruktor obiektu (IX)
PO Konstruktor i destruktor obiektu (IX) Osoba os2(imie,nazwisko,wiek,n); //utworzenie obiektu z pomocą //konstruktora argumentowego os2.info(); getch(); //nowy blok kodu { Osoba os3("Marek","Janik",20,1); os3.info(); }//koniec bloku kodu – tutaj wywoła się destruktor }

33 Konstruktor i destruktor obiektu (X)
PO Konstruktor i destruktor obiektu (X) W funkcji main utworzyliśmy 3 obiekty. Dla jednego obiektu wykorzystany został konstruktor domniemany, bezargumentowy, dla pozostałych konstruktor argumentowy. Uwaga! Jeżeli zdefiniujemy konstruktor argumentowy, a chcemy używać do tworzenia obiektów również konstruktora bezargumentowego, to musimy go jawnie zdefiniować. Wynika to z tego, iż w przypadku, gdy programista sam zdefiniuje jakikolwiek konstruktor, kompilator nie będzie już tworzył automatycznie bezargumentowego konstruktora domniemanego. Innymi słowy kompilator stworzy konstruktor za nas tylko i wyłącznie wówczas jeżeli sami nie zdefiniujemy żadnego swojego konstruktora. Trzeci obiekt istnieje w ramach wydzielonego bloku kodu. Zakończenie tego bloku jest jednoznaczne z zakończeniem cyklu życia obiektu o nazwie os3. Przed usunięciem obiektu wywoływany jest destruktor, który zwalnia pamięć zarezerwowaną wcześniej na tablicę płac dla osoby reprezentowanej przez ten obiekt.


Pobierz ppt "Programowanie obiektowe"

Podobne prezentacje


Reklamy Google