int
Transkrypt
int
www.imio.polsl.pl JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM Wykład 13 1 KLASY A ZASŁANIANIE NAZW www.imio.polsl.pl Nazwy danych składowych i funkcji składowych mają zakres klasy, więc w obrębie klasy zasłaniają takie same nazwy spoza klasy. Przykład (wersja 1): #include <iostream> using namespace std; //----------------------------------------------------------------------------- int dana=5; // dana (zmienna) globalna //----------------------------------------------------------------------------- class Obliczenia {public: int dana; // dana lokalna klasy (nazwa jak dana globalna) int oddaj_1() {return dana;} // odniesienie się do danej lokalnej int oddaj_2() {return ::dana;} // odniesienie się do danej globalnej // ... // ciąg dalszy ciała klasy }; //----------------------------------------------------------------------------- int main() { Obliczenia obiekt; obiekt.dana=777; cout<<obiekt.oddaj_1()<<endl; cout<<obiekt.oddaj_2()<<endl; return 0; } // tworzymy obiekt // wpisujemy do danej obiektu // wywołania funkcji 2 KLASY A ZASŁANIANIE NAZW www.imio.polsl.pl Przykład z poprzedniego slajdu jest poprawny, lecz... o Klasy należy konstruować tak, by były „samowystarczalne”. o Jeśli klasa ma korzystać ze zmiennej globalnej – należy przesłać ją do klasy jako argument stosownej funkcji składowej: void Klasa::odbior(int te) { zmienna=te; } Podsumowując: nie należy z wnętrza klasy odwoływać się do zmiennych globalnych w programie (szczególnie jeśli będziemy chcieli klasę wykorzystać w innym projekcje lub np. komuś udostępnić). 3 KLASY A ZASŁANIANIE NAZW www.imio.polsl.pl Przykład (wersja 2): #include <iostream> using namespace std; //----------------------------------------------------------------------------int dana=5; // obiekt globalny //----------------------------------------------------------------------------class Obliczenia // samowystarczalna klasa... {public: int dana, dana_odebrana; void odbierz(int a) {dana_odebrana=a;} // nowa funkcja „do odbierania” int oddaj_1() {return dana;} // odniesienie się do danej lokalnej int oddaj_2() {return dana_odebrana;} // odniesienie się do odebranej danej }; //----------------------------------------------------------------------------int main() Obliczenia obiekt; // tworzymy obiekt { obiekt.dana=777; // wpisujemy do danej obiektu obiekt.odbierz(dana); // dana globalna jako argument cout<<obiekt.oddaj_1()<<endl; cout<<obiekt.oddaj_2()<<endl; return 0; } // wywołania funkcji 4 DZIEDZICZENIE www.imio.polsl.pl Dziedziczenie – technika obiektowa, pozwalająca tworzyć nowe klasy na podstawie już istniejących klas. „Dziedziczenie jest jedną z najwspanialszych cech obiektowo orientowanych języków programowania” – J. Grębosz, Symfonia C++ standard. Po co? 1. Oszczędność czasu. o Załóżmy, że istnieje jakaś klasa, która nie spełnia wszystkich oczekiwań. o Można ją poprzez dziedziczenie dopasować do naszych potrzeb tworząc na jej bazie tzw. klasę pochodną. o Np.: mając klasę Telewizor_LCD można na jej podstawie stworzyć klasę Telewizor_LCD_3D. o Ważne – nie musimy znać kodu źródłowego klasy podstawowej (a tylko jej definicję w pliku .h) – możemy korzystać z klas napisanych przez kogoś innego... 5 www.imio.polsl.pl DZIEDZICZENIE 2. Tworzenie hierarchii klas. o Często klasy są w pewnej logicznej zależności i tworzą „naturalną” hierarchię. o Np.: Srodek_transportu Pojazd Samochod Rower Statek Samolot ... o Zamiast osobnych klas mamy sytuację: jakaś klasa jest szczególnym rodzajem innej klasy, o np. Samochod i Rower są rodzajami czegoś, co nazwaliśmy Pojazd. 6 DZIEDZICZENIE o Inne przykłady: - zarówno Prostokat , Trapez jak i Romb to specyficzny Czworokat, - Lew i Mysz są to zwierzęta należące do gromady (tu: klasy) Ssak, itd. o Proces dziedziczenia pozwala w takim przypadku na wprowadzenie relacji między poszczególnymi klasami. www.imio.polsl.pl Dziedziczenie pozwala na wykorzystanie tego, co istniejąca klasa posiada i dostosowanie jej do innych potrzeb: o dodanie nowych danych składowych i funkcji składowych; o stworzenie nowych wariantów funkcji składowych lub ew. danych składowych. Jeżeli w klasie podstawowej i w klasie pochodnej są składniki (dane lub funkcje) o tych samych nazwach, to w zakresie klasy pochodnej składnik z tej klasy zasłania składnik odziedziczony. 7 DZIEDZICZENIE www.imio.polsl.pl Np.: mając klasę Pralka z poprzedniego wykładu: class Pralka // definicja klasy { int nr_programu; int temperatura_prania; public: void pranie(int program, int temperatura); void plukanie(); }; moglibyśmy chcieć stworzyć (postęp techniczny!) klasę Lepsza_Pralka, która posiada nową daną składową (dla uproszczenia np. tylko godzina): int o_ktorej_zaczac; oraz zmodyfikowaną funkcję: void pranie(int program, int temperatura, bool niski_poziom=false); 8 DZIEDZICZENIE www.imio.polsl.pl Realizacja: class Lepsza_Pralka : public Pralka // lista pochodzenia { int o_ktorej_zaczac; public: void pranie(int program, int temperatura, bool niski_poziom); }; o Klasa Pralka jest w tym przypadku klasą podstawową dla klasy Lepsza_Pralka. o Klasa Lepsza_Pralka jest w tym przypadku klasą pochodną klasy Pralka. o Nowa wersja funkcji składowej pranie „zastępuje” (zasłania) wersję funkcji pranie z klasy podstawowej. o Wyrażenie po dwukropku to lista pochodzenia. o Specyfikator public przy liście pochodzenia – o tym nieco później... 9 DZIEDZICZENIE o www.imio.polsl.pl Stwórzmy obiekt moja_nowa_pralka klasy Lepsza_Pralka: Lepsza_pralka moja_nowa_pralka; o Wywołanie funkcji pranie dla obiektu klasy Lepsza_Pralka uruchamia funkcję klasy pochodnej: moja_nowa_pralka.pranie(7,40,1); moja_nowa_pralka.pranie(7,40); //ostatni argument domyślny o Gdybyśmy chcieli wywołać funkcję pranie z klasy podstawowej, to należy skorzystać z kwalifikatora zakresu :: moja_nowa_pralka.Pralka::pranie(7,40); o Należy pamiętać definiując obiekt klasy pochodnej, że wewnątrz znajduje się fragment odziedziczony po klasie podstawowej... 10 www.imio.polsl.pl DZIEDZICZENIE Przykład (publiczne dane składowe): #include <iostream> using namespace std; class Punkt2D { public: float x, y; void wypisz1() { cout<<x<<" "<<y;} }; // klasa podstawowa // dane publiczne // funkcja publiczna //------------------------------------------------------------------ class Punkt3D: public Punkt2D // { public: float z; void wypisz2() { cout<<x<<" "<<y<<" "<<z;} }; klasa pochodna //------------------------------------------------------------------ int main() { Punkt2D p2D; p2D.x=1.1; p2D.y=2.2; p2D.wypisz1(); cout<<endl; // tworzymy obiekt klasy Punkt2D // mamy dostęp do danych... Punkt3D p3D; p3D.x=5.5; p3D.y=6.6; p3D.z=7.7; p3D.wypisz2(); cout<<endl; // tworzymy obiekt klasy Punkt3D p3D.Punkt2D::wypisz1(); cout<<endl; //wywołanie f. klasy podstawowej return 0;} 11 www.imio.polsl.pl DZIEDZICZENIE Przykład (prywatne dane składowe): #include <iostream> using namespace std; class Punkt2D { float x, y; public: Punkt2D(float a, float b) {x=a; y=b;} void wypisz1() {cout<<x<<" "<<y;} }; // klasa podstawowa // prywatne dane // konstruktor // publiczna funkcja //------------------------------------------------------------------ class Punkt3D: public Punkt2D // klasa pochodna { float z; // prywatna dana public: Punkt3D(float a, float b, float c): Punkt2D(a,b)// konstruktor (o tym później) {z=c;} void wypisz2() {Punkt2D::wypisz1(); //korzystamy z funkcji z klasy podstawowej cout<<" "<<z;} }; //------------------------------------------------------------------ int main() { Punkt2D p2D (1.1, 2.2); p2D.wypisz1(); cout<<endl; Punkt3D p3D(5.5,6.6,7.7); p3D.wypisz2(); cout<<endl; return 0;} // tworzymy obiekt klasy Punkt2D // tworzymy obiekt klasy Punkt3D 12 DZIEDZICZENIE www.imio.polsl.pl Dane składowe często nie są publiczne. Co wtedy z ewentualnymi klasami pochodnymi? Mogą istnieć funkcje dostępowe (jak w poprzednim przykładzie). Można jednak inaczej... Jak to jest z etykietą protected, czyli: rozwiązanie zagadki, po co ona jest... o Etykieta ta została wprowadzona w właśnie na potrzeby dziedziczenia. o Składniki za taką etykietą: - są dostępne dla klas pochodnych (jak gdyby były public); dla „całego świata” są niedostępne, (jak gdyby były private). 13 www.imio.polsl.pl DZIEDZICZENIE Np.: class Radio { string obudowa; int zakres; protected: float dlugosc_fali; void aut_strojenie(); public: void glosnosc(int vol); }; o // definicja klasy // składniki prywatne // składniki dostępne dla klas pochodnych // składniki dostępne dla każdego Klasa podstawowa określa odpowiednimi etykietami, które ze składników: - są dostępne tylko dla niej (private); - chce udostępniać tylko klasom pochodnym (protected); - chce, by były ogólnodostępne (public). 14 www.imio.polsl.pl DZIEDZICZENIE Przykład (dane składowe protected): #include <iostream> using namespace std; class Punkt2D // klasa podstawowa {protectec: float x, y; // dane protected public: Punkt2D(float a, float b) {x=a; y=b;} // konstruktor void wypisz1() {cout<<x<<" "<<y;} // publiczna funkcja }; //------------------------------------------------------------------ class Punkt3D: public Punkt2D // klasa pochodna {protectec: float z; // dana protected public: Punkt3D(float a, float b, float c): Punkt2D(a,b) // konstruktor {z=c;} void wypisz2() { cout<<x<<" "<<y <<" "<<z;} // mamy dostęp do danych protected }; //------------------------------------------------------------------ int main() { Punkt2D p2D (1.1, 2.2); p2D.wypisz1(); cout<<endl; Punkt3D p3D(5.5,6.6,7.7); p3D.wypisz2(); cout<<endl; return 0;} // tworzymy obiekt klasy Punkt2D // tworzymy obiekt klasy Punkt3D 15 DZIEDZICZENIE www.imio.polsl.pl o O dostępie do odziedziczonych składników decyduje też (oczywiście w zakresie ograniczonym do składników public i protected!) klasa pochodna. o Np.: w klasie Lepsza_Pralka jest to słowo public przed nazwą klasy podstawowej: class Lepsza_Pralka : public Pralka { // ciało klasy pochodnej }; o oznacza to, że: - składniki public z klasy podstawowej będą nadal public; - składniki protected z klasy podstawowej będą nadal protected . o gdyby zamiast public było tam słowo protected lub private to: tabelka na następnym slajdzie... 16 www.imio.polsl.pl DZIEDZICZENIE słowo na liście dziedziczenia: składowe w klasie podstawowej były: w klasie pochodnej są: protected protected public public public protected protected protected public protected private private public o Klasa pochodna może co najwyżej ograniczyć uprawnienia do odziedziczonych składników! o W ramach naszych rozważań ograniczymy się do wariantu public... 17 DZIEDZICZENIE www.imio.polsl.pl Czego się nie dziedziczy: o konstruktorów – konstruktor klasy podstawowej nie staje się konstruktorem klasy pochodnej. dlaczego? Klasa pochodna = klasa podstawowa + X gdzie X: składniki zdefiniowane w klasie pochodnej (których klasa podstawowa nie zna) zatem – konstruktory klasy pochodnej należy zdefiniować! o destruktorów - z tych samych powodów co powyżej. o dla zainteresowanych – operatora przypisania = (jeśli został zdefiniowany w klasie podstawowej). 18 DZIEDZICZENIE www.imio.polsl.pl Kolejność uruchamiania konstruktorów: o najpierw uruchamiany jest konstruktor klasy podstawowej; o w następnej kolejności wykonywane są konstruktory obiektów składowych klasy pochodnej (jeśli występują składowe obiekty innych klas); o dopiero na końcu uruchamiany jest konstruktor klasy pochodnej. „Klasa uszanuje najpierw starszych, potem swoich gości, a dopiero na samym końcu zajmie się sobą”. J. Grębosz: „Symfonia C++ standard”, str. 808 wydania z 2008 roku 19 DZIEDZICZENIE www.imio.polsl.pl Konstruktor klasy pochodnej jest zwykłym konstruktorem, przy czym: o Na jego liście inicjalizacyjnej można (a często trzeba) umieścić wywołanie konstruktora klasy podstawowej. Wywołanie takie można pominąć, gdy: o klasa podstawowa nie ma żadnego konstruktora (więc nie ma czego wywołać...); o klasa podstawowa ma konstruktory a wśród nich jest konstruktor domyślny. 20 www.imio.polsl.pl DZIEDZICZENIE Przykład: #include <iostream> using namespace std; class Prostokat // { protected: float bok_a, bok_b; // public: Prostokat(float a, float b){bok_a=a; bok_b=b;} // void pole() // { cout<<"\nPole prostokata o bokach a=" <<bok_a<<" b="<<bok_b<< " wynosi "<<bok_a*bok_b;} }; klasa podstawowa dane protected konstruktor funkcja składowa //------------------------------------------------------------------ class Kwadrat: public Prostokat // klasa pochodna { protected: float bok; // dana protected public: Kwadrat(float dl):Prostokat(dl, dl) // konstruktor - wywołanie { bok=dl;} // konstruktora klasy podstawowej void pole() // funkcja składowa – nowa wersja! { cout<<"\nPole kwadratu o boku a="<<bok<<" wynosi "<<bok*bok;} }; //------------------------------------------------------------------ int main() { Kwadrat k1(2.3); k1.pole(); k1.Prostokat::pole(); return 0;} // tworzymy obiekt klasy Kwadrat // pole kwadratu // pole prostokąta ("schowanego" w klasie Kwadrat) 21 www.imio.polsl.pl DZIEDZICZENIE Przykład bardziej rozbudowany: class Rolki { protected: string nazwa; public: Rolki(string i):nazwa(i) {} void opis() {cout<<"\nMam rolki: "<<nazwa<<endl;} }; // klasa podstawowa // konstruktor // f. składowa klasy podstawowej class Fitness: public Rolki // pierwsza klasa pochodna { private: int srednica; string zadanie; // nowe dane składowe public: Fitness (string n, int sr, string za= "jade sobie..."):Rolki(n) // konstruktor { zadanie=za; srednica=sr; // przypisania smigaj(zadanie);} // wywołanie funkcji składowej void smigaj(string rob) // funkcja składowa { cout<<"\nTo sa rolki do fitnessu: "<<nazwa<<endl; cout<<"Kolka "<<srednica<<"mm"<<endl; cout<<"Cwiczenie: "<<rob<<endl;} }; 22 www.imio.polsl.pl DZIEDZICZENIE Przykład bardziej rozbudowany: class Speed: public Rolki // druga klasa pochodna {private: int srednica; string lozyska, zadanie; // nowe dane składowe public: Speed (string n, int sr, string lo, string za="rozgrzewka..."):Rolki(n) // k. { zadanie=za; srednica=sr; lozyska=lo; // przypisania smigaj(zadanie);} // wywołanie funkcji składowej void smigaj(string rob) // funkcja składowa { cout<<"\n To sa rolki do jazdy szybkiej: "<<nazwa<<endl; cout<<" Kolka "<<srednica<<"mm, lozyska: "<<lozyska<<endl; cout<<" Cwiczenie: "<<rob<<endl;} }; #include <iostream> using namespace std; // to wstawiamy np. na początku pliku... 23 www.imio.polsl.pl DZIEDZICZENIE Przykład bardziej rozbudowany: int main() {Rolki r1("Znalezione w piwnicy"); r1.opis(); Fitness jakies("Pozyczone do nauki", 76); // funkcja główna // obiekt klasy podstawowej // potem taki obiekt Fitness rekreacyjne("Rollerblade Spark", 84, "jazda tylem"); // inne obiekty Speed szybkie("Powerslide infinity", 110, "ABEC 7 Freespin"); // 4 arg. domyślny rekreacyjne.smigaj("slalom"); szybkie.smigaj("double push"); return 0;} // fitness: inne ćwiczenie // szybkie: inne ćwiczenie 24