Paradygmat programowania obiektowego, klasa, obiekt
Paradygmat paradygmat (słownik PWN) — przyjęty sposób widzenia rzeczywistości w danej dziedzinie Paradygmaty programowania programowanie strukturalne programowanie obiektowe
Paradygmat programowania obiektowego programowanie obiektowe — to paradygmat rozwiązywania problemów programistycznych z wykorzystaniem obiektów, sposób interpretacji problemu jako zbioru obiektów i relacji pomiędzy nimi.
Obiekt Potoczne znaczenie słowa obiekt Znaczenie pojęcia obiektu w programowaniu Reprezentuje na potrzeby programu obiekty ze świata rzeczywistego lub abstrakcyjne (w potocznym znaczeniu słowa obiekt) Uogólniona zmienna (struktura) Zdefiniowany i używany zgodnie ze składnią i semantyką języka
Obiekt - uogólniona zmienna (struktura) zestaw danych, najczęściej różnych typów Uogólniona obiekt = dane + metody operujące na tych danych
Obiekt - przykałady
Dużo obiektów zazwyczaj wiele obiektów ma taki sam zbiór cech, potrzebujemy aby te cechy definiować raz, ale wykorzystywać wielokrotnie klasa (słownik PWN) — kategoria przedmiotów lub zjawisk wyróżnionych na podstawie wspólnych cech Potrzebujemy klasy dla podobnych obiektów
Klasa w programowaniu klasa w programowaniu — uogólniony typ zdefiniowany przez użytkownika języka służy do definiowania obiektów (uogólnionych zmiennych) Dostarcza wielu nowych możliwości (to be discussed later :-) Pojedyncza klasa powinna jasno reprezentować określone pojęcie, dla którego nie istnieje (jeszcze) odpowiedni typ
Dlaczego programowanie obiektowe? kolejny etap w rozwoju technik IP: strukturalne proceduralne modularne narzędzie do implementacji projektów obiektowych (istneje analiza obiektowa, projektowanie obiektowe) języki wspierające programowanie obiektowe C++, Java, … kęzyki umożliwiające programowanie obiektowe wszystkie
Przykład – osoba strukturalnie struct osoba { int wiek; char imię[20], nazwisko[30]; }; void wczytaj_osobe(osoba *o); void ustaw_osobę(osoba *o, int wiek, char *imię, char *nazwisko); void wypisz_osobe(osoba *o); bez kontroli dostępu do pól struktury programista musi pamiętać, których funkcji używać na rzecz których struktur
Przykład – osoba obiektowo class osoba { int wiek; // składowe klasy – zmienne klasowe char imię[20], nazwisko[30]; public: void wczytaj(); // składowe klasy – metody klasy void ustaw(int wiek, char *p_imię, char *p_nazwisko); void wypisz(); }; // ten średnik musi tu być by zakończyć deklarację dane i metody razem domyślnie bez dostępu do pól spoza metod klasy
Specyfikacja dostępu do składowych klasy private: // składowe prywatne // dostępne dla metod danej klasy // oraz metod i funkcji zaprzyjaźnionych // private – domyślne dla „class” public: // składowe publiczne // dostępne spoza klasy // domyślne dla „struct” protected: // składowe chronione // tak jak private, ale // mogą być dodatkowo dostępne dla klas potomnych
Specyfikacja dostępu do składowych klasy class osoba { int wiek; // private char imię[20]; // private public: void wczytaj(); // public private: char nazwisko[30]; // private void ustaw(int wiek, char *p_imię, char *p_nazwisko); // public void wypisz(); // public };
Hermetyzacja i enkapsulacja Zamknięcie danych i metod w klasie (enkapsulacja) pozwala programiście na świadome ograniczenie możliwości dostępu do danych przez kod spoza klasy (hermetyzacja). Domyślnie wszystkie składowe klasy są prywatne, czyli niedostępne z zewnątrz klasy. OOOP ;-) — ortodoksyjne programowanie obiektowe: wszystkie dane są prywatne, operujemy na nich wyłącznie metodami klasy.
Obiekt – uogólniona struktura Deklarujemy class osoba ja, Ty; osoba szef; // w deklaracji/definicji obiektu można // pomijać „class”, „struct” i „union” Używamy szef.wczytaj(); szef.wypisz();
Operatory dostępu do składowych klasy kropka „ . ” obiekt.pole; // jak w strukturach C obiekt.metoda(); // enkapsulacja operator zakresu „ :: „ klasa::pole; // sizeof, pola static klasa::metoda(); // przy definicji, metody statyczne Najczęściej kwalifikacje ( obiekt. i klasa::) można pominąć metody klasy operujące na nieprzesłoniętych składowych klasy deklarowanie/definiowanie metod wewnątrz deklaracji klasy
Jak definiować metody klasy? Wewnątrz deklaracji klasy class osoba { … void wczytaj() cin>>wiek>>imie>>nazwisko; } // tu nie musi być średnika }; Taka metoda jest domyślnie metodą inline
Jak definiować metody klasy? poza klasą trzeba użyć operatora zakresu w nagłówku domyślnie metoda nie będzie inline void osoba::ustaw(int wiek, char *p_imię, char *p_nazwisko) { osoba::wiek=wiek; // tu też operator zakresu bo wiek przysłonięty strcpy(imię, p_imię); strcpy(nazwisko, p_nazwisko); } metoda ma być inline? inline void osoba::wypisz() cout<<"wiek: "<<wiek<<" imie: "<<imie<<" nazwisko: "<<nazwisko<<"\n";
Jak definiować metody klasy? przy tworzeniu bibliotek w pliku nagłówkowym (*.h) umieszczamy deklaracje klasy i definicje metod inline, definicje nie-inline nie mogą znaleźć się w *.h. metody podobnie jak funkcje mogą mieć argumenty domyślne i być przeciążane void ustaw(int w, char *pi="Jan", char *pn="Kowalski"); void ustaw(const osoba & przyklad); szef.ustaw(Ty); szef.ustaw(50, „Osama”, „bin Laden”); szef.ustaw(50, „Osama”); szef.ustaw(50); // szef.ustaw(); ERROR!
Jak definiować metody klasy? metody i zmienne zadeklarowane wewnątrz klasy są widoczne od początku definicji klasy oraz wewnątrz ciał metod zadeklarowanych wewnątrz klasy class A { public: void wczytaj() cin>>i; // deklaracja „i” jest w klasie wypisz(); // jak wyżej } void wypisz(); int i; };
Jak definiować metody klasy? Przypomnienie: z poza metod klasy jej składowe trzeba kwalifikować nazwą klasy bądź obiektu int test() { A a; int j=sizeof(A::i); void (A::*p)()=&A::wczytaj; a.i=3; // i jest publiczne w A }
Operator zakresu jako rozszerzenie nieobiektowe int fun(); int i; class C { public: void test(); }; void C::test() { i++; // zwieksz C::i ::i++; // globalne i fun(); // C::fun() ::fun(); // globalna fun() }
Przykład zadanie zadeklarować klasę point, której obiekty będą punktami na płaszczyźnie 2D klasa powinna nie mieć zmiennych publicznych publiczne metody klasy: input, output, move (przesuń o wektor zadany parą współrzędnych), distance (odległość od drugiego punktu przekazanego przez referencję) oraz metody coordX i coordY zwracające rzędną i odciętą punktu
Przykład class point { double x, y; public: void input(); void output(); void move(double dx, double dy); double distance(const punkt &p); double coordX(); // tzw akcesory – udostępniają prywatne pola klasy double coordY(); };
Przykład zadanie zdefiniować inline metody input() output() move() distance()
Przykład class point { double x, y; public: void input() {cin>>x>>y; }; void output() {cout<<x<<y; }; … }; inline void point::move(double dx, double dy) x+=dx; y+=dy; }
Przykład inline double point::distance(point &p) { return sqrt( (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y) ); } uwaga: mamy dostęp do prywatnych pól obiektu na rzecz którego aktywowana jest dana metoda i do prywatnych pól innych obiektów klasy tej co obiektu na którego rzecz aktywowana jest metoda (p). Prywatne znaczy prywatne dla klasy (a nie dla obiektu klasy).
Klasy a Abstrakcyjne Typy Danych klasy doskonale nadają się do implementacji abstrakcyjnych typów danych klasy są abstrakcyjnymi typami danych Znamy interfejs – gdy posługujemy się operacjami dozwolonymi dla typu, nie przejmujemy się tym, jak są one realizowane. Hermetyzacja pozwala oddzielić nieistotne z punktu widzenia użytkownika typu szczegóły implementacyjne od istotnego interfejsu. na przykład stos, kolejka, zbiór, punkt, odcinek
Przykład zadanie zadeklarować klasę segment, której obiekty będą odcinkami na płaszczyźnie 2D klasa powinna nie mieć zmiennych publicznych publiczne metody klasy: input, output, move (przesuń o wektor zadany parą współrzędnych), length (długość odcinka).
Przykład class segment { point p1, p2; public: void input() p1.input(); p2.input(); } void output() p1.output(); p2.output(); void move(double dx, double dy) { p1. move(dx, dy); p2. move(dx, dy); } double length() return p1.distance(p2); };
Ciekawostka: deklaracje zagnieżdżone deklaracja klasy może być zagnieżdżona w deklaracji innej klasy klasa zagnieżdżona nie jest widoczna globalnie, można kwalifikować klasą zewnętrzną jeżeli jest publiczna.
Ciekawostka: deklaracje zagnieżdżone class X { class M1 int m; }; public: class M2 void f() { M1 m1; // blad //nie w zasięgu globalnym X::M1 xm1; // blad //M1 w sekcji prywatnej X X::M2 xm2; // ok. }
Ciekawostka: deklaracje zagnieżdżone X to klasa która nie ma żadnych zmiennych ani metod, tylko określone typy (można oczywiście tworzyć obiekty klasy X). klasa, która zawiera zmienne klasowe: class X_d { public: class M2 int m; }; M2 m2; // tutaj generalnie należy unikać i unika się zagnieżdżania klas (za wyjątkiem bardzo małych klas) — mało czytelne i mało przydatne.