Programowanie obiektowe w C++
dr inż. Tadeusz Wilusz
Akademia Ekonomiczna w Krakowie 31-510 Kraków, ul. Rakowicka 27 Budynek Biblioteki Głównej pokój 429 tel.: 2935-264
e-mail: wiluszt@ae.krakow.pl
Programowanie obiektowe
w C++
Wykład 02 Temat wiodący:
Koncepcja klasy. Obiekty.
Plan wykładu
n
Wprowadzenie
n
Rozszerzenia nieobiektowe
n
Paradygmat obiektowy, klasa
Paradygmat programowania
obiektowego, klasa, obiekt
Paradygmat
paradygmat (słownik PWN) — przyjęty sposób widzenia rzeczywistości w danej dziedzinie
n
Paradygmaty programowania
n programowanie strukturalne
n programowanie obiektowo zorientowane (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
n
Potoczne znaczenie słowa obiekt
n
Znaczenie pojęcia obiektu w programowaniu
n Reprezentuje na potrzeby programu obiekty ze świata rzeczywistego lub abstrakcyjne (w potocznym znaczeniu słowa obiekt)
n Uogólniona zmienna (struktura)
n Zdefiniowany i używany zgodnie ze składnią i semantyką języka
Obiekt - uogólniona zmienna (struktura)
n
Struktura
n zestaw danych, najczęściej różnych typów
n
Uogólniona
n obiekt = dane + metody operujące na tych danych
Obiekt - przykałady
Dużo obiektów
n
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
n
Potrzebujemy klasy dla podobnych obiektów
Klasa w programowaniu
n klasa w programowaniu — uogólniony typ zdefiniowany przez użytkownika języka
n służy do definiowania obiektów (uogólnionych zmiennych)
n Dostarcza wielu nowych możliwości (to be discussed later :-)
n Pojedyncza klasa powinna jasno reprezentować określone pojęcie, dla którego nie istnieje (jeszcze) odpowiedni typ
Dlaczego programowanie obiektowe?
n kolejny etap w rozwoju technik IP:
n strukturalne
n proceduralne
n modularne
n narzędzie do implementacji projektów obiektowych (istneje analiza obiektowa, projektowanie obiektowe)
n języki wspierające programowanie obiektowe C++, Java, …
n 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);
n bez kontroli dostępu do pól struktury
n 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ę
n dane i metody razem
n domyślnie bez dostępu do pól spoza metod klasy
Specyfikacja dostępu do składowych klasy
n private:
// składowe prywatne
// dostępne dla metod danej klasy // oraz metod i funkcji zaprzyjaźnionych // private – domyślne dla „class”
n public:
// składowe publiczne // dostępne spoza klasy // domyślne dla „struct”
n 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 public:
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).
n Domyślnie wszystkie składowe klasy są prywatne, czyli niedostępne z zewnątrz klasy.
n OOOP ;-) — ortodoksyjne programowanie obiektowe:
wszystkie dane są prywatne, operujemy na nich wyłącznie metodami klasy.
Obiekt – uogólniona struktura
n
Deklarujemy
class osoba ja, Ty;
osoba szef; // w deklaracji/definicji obiektu można // pomijać „class”, „struct” i „union”
n
Używamy
szef.wczytaj();szef.wypisz();
Operatory dostępu do składowych klasy
n kropka „ . ”
obiekt.pole; // jak w strukturach C obiekt.metoda(); // enkapsulacja
n operator zakresu „ :: „
klasa::pole; // sizeof, pola static
klasa::metoda(); // przy definicji, metody statyczne
n Najczęściej kwalifikacje ( obiekt. i klasa::) można pominąć
n metody klasy operujące na nieprzesłoniętych składowych klasy
n deklarowanie/definiowanie metod wewnątrz deklaracji klasy
Jak definiować metody klasy?
n Wewnątrz deklaracji klasy class osoba
{
…
void wczytaj() {
cin>>wiek>>imie>>nazwisko;
} // tu nie musi być średnika
… };
n Taka metoda jest domyślnie metodą inline
Jak definiować metody klasy?
n poza klasą trzeba użyć operatora zakresu w nagłówku
n 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);
}
n metoda ma być inline?
inline void osoba::wypisz() {
cout<<"wiek: "<<wiek<<" imie: "<<imie<<" nazwisko: "<<nazwisko<<"\n";
}
Jak definiować metody klasy?
n przy tworzeniu bibliotek w pliku nagłówkowym (*.h) umieszczamy deklaracje klasy i definicje metod inline, definicje nie-inline nie mogą znaleźć się w *.h.
n 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?
n 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?
n 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 {
int i;
public:
void test();
int fun();
};
void C::test() {
i++; // zwieksz C::i ::i++; // globalne i fun(); // C::fun() ::fun(); // globalna fun() }
Przykład
zadanie
n
zadeklarować klasę point, której obiekty będą punktami na płaszczyźnie 2D
n klasa powinna nie mieć zmiennych publicznych
n 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
n zdefiniować inline metody
n input()
n output()
n move()
n 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) );
}
n 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
n klasy doskonale nadają się do implementacji abstrakcyjnych typów danych
n klasy są abstrakcyjnymi typami danych
n 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.
n na przykład stos, kolejka, zbiór, punkt, odcinek
Przykład
zadanie
n
zadeklarować klasę segment, której obiekty będą odcinkami na płaszczyźnie 2D
n klasa powinna nie mieć zmiennych publicznych
n 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
n
deklaracja klasy może być zagnieżdżona w deklaracji innej klasy
n
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 {
int m;
};
};
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
n 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 };
n 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.