Prgramwanie biektwe Wykład 1 1 Histria i cechy C++ Autr - Bjarne Strustrup (Dania, Cambridge, AT&T), 1983 Cel: rzszerzenie języka C biektwe mechanizmy abstrakcji danych i silną statyczną kntrlę typów. Zachwanie zgdnści z językiem C na pzimie kdu źródłweg pzstaje jednym z pdstawwych celów prjektwych klejnych standardów języka. Standardy Od 1998 - standard ISO/IEC 14882:1998 (Standard fr the C++ Prgramming Language) z drbnymi pprawkami zatwierdznymi w 2003 r. (ISO/IEC 14882:2003) - ISO C++ (-std = c++98). W 2009 rku głszn nwy standard (tzw. C++0x) (-std=c++0x), który zaczął bwiązywać d 12 sierpnia 2011 rku i dtąd jest nazywany (ISO/IEC 14882:2011) (-std=c++11). 2 PRZYDATNE KONSTRUKCJE 2.1 Parametry dmyślne Język C++ pzwala przypisywać parametrm funkcji wartści dmyślne. Funkcja taka mże być wywłana ze wszystkimi parametrami, wtedy wartści dmyślne nie są brane pd uwagę, lub z mniejszą liczbą parametrów, wtedy kmpilatr uzupełni wywłanie funkcji brakujące argumenty. Przykład: #include <istream> using namespace std; vid fun(int a=0, int b=10); int main() int n=1, m=5; fun(n,m); // przekazan d funkcji 1 i 5 fun(n); // przekazan d funkcji 1 i 10 fun(); // przekazan d funkcji 0 i 10 vid fun(int a, int b) cut << "Pierwszy argument: " << a << endl; cut << "Drugi argument: " << b << endl; UWAGA: Ograniczenia stswania parametrów dmyślnych: jeśli parametr nie ma wartści dmyślnej, t nie mże jej psiadać żaden z pprzedzających g parametrów! 1
Prgramwanie biektwe Wykład 1 2.2 Przeciążanie nazw funkcji W języku C++ mżna definiwać dwlnie wiele funkcji takiej samej nazwie. Muszą się ne różnić sygnaturą czyli liczbą parametrów frmalnych i (lub) ich typami. Jest t tzw. plimrfizm nazw funkcji. Przy wywłaniu kmpilatr użyje tej definicji funkcji, dla której liczba parametrów frmalnych i ich typy dpwiadają argumentm wywłania funkcji. Uwaga: W skład sygnatury funkcji nie wchdzi typ zwracaneg wyniku. Nie jest zatem mżliwe rzróżnienie funkcji na pdstawie zwracanych wartści. Definiwanie funkcji plimrficznych nazywa się przeciążaniem. Używana jest również nazwa przeładwanie funkcji (ang. functin verlading). Przeciążanie funkcji stsujemy w przypadku funkcji realizujących te same zadania, ale na danych różneg typu lub ich różnej liczby. Przykład: #include <istream> using namespace std; duble srednia(duble n1, duble n2); duble srednia(duble n1, duble n2, duble n3); int main() cut << "srednia 1: " << srednia(2.,5.) << endl; cut << "srednia 2: " << srednia(1.,3.,5.) << endl; duble srednia(duble n1, duble n2) return ( (n1+n2)/2.); duble srednia(duble n1, duble n2, duble n3) return ( (n1+n2+n3)/3.); 2.3 Dpaswywanie funkcji Brak prttypu pasująceg d wywłania funkcji spwduje, że C++ będzie próbwał dpaswać funkcje pprzez standardwe knwersje typów. Szczegóły dpaswywania funkcji: Prata, Szkła prgramwania. Język C++, wyd.v, 2006, str. 387-393. 2
Prgramwanie biektwe Wykład 1 2.4 Funkcje twarte (inline) Wywłanie funkcji jest prcesem czaschłnnym. W przypadku prstych funkcji kszt ich wywłania mże znacznie przewyższyć kszt wyknania właściwych instrukcji funkcji. D rzwiązania teg prblemu w C++ zaprpnwan funkcje twarte, rzwijane w miejscu wywłania. Jeśli deklarację funkcji patrzymy słwem kluczwym inline, znacza t, że preferujemy rzwinięcie ciała funkcji w miejscu jej wywłania zamiast zastswania zwykłeg mechanizmu wywływania funkcji. Przykład: Ten prgram: #include <istream> using namespace std; inline vid zwieksz(int &a) ++a; int main() int x=0; zwieksz(x); //++x; cut << "x=" << x << endl; zstanie skmpilwany tak, jakby zstał napisany następując: #include <istream> using namespace std; int main() int x=0; ++x; cut << "x=" << x << endl; Mechanizm ten jest wykrzystywany dmyślnie w większści kmpilatrów, działających w trybie ptymalizacji kdu, nawet dla funkcji, które nie są znaczne jak inline. Oznaczenie funkcji inline t tylk wskazówka dla kmpilatra, d której nie musi się stswać. 3
Prgramwanie biektwe Wykład 1 3 PODSTAWOWE POJĘCIA PROGRAMOWANIA OBIEKTOWEGO 3.1 Prgramwanie prceduralne Paradygmat: Zadecyduj, jakie chcesz mieć prcedury; stsuj najlepsze algrytmy, jakie mżesz znaleźć. Prcedura: wydrębnina z prgramu główneg sekwencja instrukcji nadanej nazwie, wskazująca knkretne zadanie d wyknania. Przykład: // Funkcja bliczająca pierwiastek kwadratwy duble sqrt(duble arg) // kd bliczania pierwiastka kwadratweg // Funkcja główna int main () duble pierw; // Wywłanie funkcji bliczania pierwiastka pierw=sqrt(2.0); 4
Prgramwanie biektwe Wykład 1 3.2 Abstrakcyjne typy danych, czyli typy zdefiniwane przez użytkwnika (prgramwania w stylu biektwym) Paradygmat: Zadecyduj, jakie chcesz mieć typy; dla każdeg typu dstarcz pełny zbiór peracji. Przykład: class cmplex private: duble re, im; public: cmplex() //dmyślna liczba zesplna re=im=0; cmplex(duble r, duble i) //twrzenie z dwóch składników re=r; im=i; cmplex(duble r) //twrzenie ze skalara re=r; im=0; // definicje funkcji peracji // na liczbach zesplnych: // +, -, *, / ==!= ; vid f() cmplex a(2), b=1/a, c; c=a+b; 5
Prgramwanie biektwe Wykład 1 Paradygmat: 3.3 Prgramwanie biektwe Zdecyduj, jakie chcesz mieć klasy. Dla każdej klasy dstarcz pełny zbiór peracji. Krzystając z mechanizmu dziedziczenia jawnie wskaż, c jest wspólne. Cechy języka prgramwania biektweg: abstrakcyjne typy danych (klasy), hermetyzacja danych (ukrywanie), dziedziczenie, plimrfizm. Hermetyzacja (ang. encapsulatin, kapsułkwanie, enkapsulacja) - graniczenie dstępnści danych i funkcji wewnętrznych klas i biektów, udstępnianie ich jedynie za pmcą specjalnych funkcji nazywanych metdami. Dziedziczenie: jedna klasa biektów mże być zdefiniwana jak przypadek gólniejszej klasy, a definicje metd i pól danych klasy gólniejszej umieszczane są autmatycznie w klasie szczególnej, klasa gólna nazywana jest klasą bazwą a klasa szczególna klasą pchdną, klasy pchdne mgą definiwać swje własne metdy i pla danych, które mgą przesłaniać dziedziczne metdy i pla danych, klasa mże dziedziczyć właściwści więcej niż jednej klasy - dziedziczenie wielbazwe. Plimrfizm: wielpstaciwść - mżliwść istnienia wielu metd tej samej nazwie, pwiązana z mżliwścią wybru knkretnej metdy pdczas wyknywania. 6
Prgramwanie biektwe Wykład 1 3.4 OBIEKTY I KLASY W C++ Obiekt: abstrakcyjny byt reprezentujący lub pisujący pewną rzecz lub pjęcie bserwwane w świecie rzeczywistym Obiekt przechwuje pewne infrmacje na swój temat (atrybuty). Obiekt charakteryzuje się pewnym zakresem zachwań. Mżna pprsić biekt wyknanie pewnej peracji na samym sbie. Klasa: ugólnienie pdbnych d siebie biektów. Opisuje atrybuty biektu i jeg peracje (zachwania). Twrząc klasę kreślamy cechy i mżliwści wszystkich przyszłych biektów tej klasy. Obiekt jest t egzemplarz (instancja) danej klasy. Metdy: peracje wyknywane na biektach. Są wyknywane na skutek wysłania d biektu kmunikatu, który wywłuje kreślną metdę (perację). Metdy nszą również nazwę funkcji składwych. Autr klasy mże: kreślić wszystkie peracje, jakie użytkwnik biektów klasy będzie na nich wyknywać, zagwarantwać, że każdy biekt będzie pprawnie zainicjwany, zapewnić, że biekt p wyknaniu każdej dpuszczalnej peracji będzie spełniał kreślne kryteria, zapewnić, że p zwlnieniu przez prgram pamięci zajmwanej przez biekt zstanie zwlnina pamięć pbrana w związku z funkcjnwaniem biektu, całkwicie ukryć reprezentację danych przed użytkwnikiem. 3.4.1 Hermetyzacja danych Tradycyjna struktura: dstęp d składwych jest niegraniczny. Hermetyzacja danych: dstęp d składwych jest graniczny za pmcą interfejsu. Prgramista aplikacji mże wyknywać na biekcie tylk te peracje, które przewidział prjektant klasy i które udstępnił publicznie. W języku C++ dstęp d składwych klasy jest kreślany za pmcą słów kluczwych: Zalety: private: składwe nie są dstępne dla klienta klasy (aplikacji krzystającej z klasy), dstęp d tych składwych mają tylk metdy klasy, public: składwe są dstępne dla klienta klasy, prtected: wykrzystywane pdczas dziedziczenia. zapewnienie spójnści atrybutów biektu, mżliwść weryfikacji teg, czy wyknywana peracja jest dzwlna w kreślnej sytuacji i dla kreślnych parametrów funkcji. 7
Przykład wersja A: Prgramwanie biektwe Wykład 1 #include <istream> using namespace std; // DEFINICJA KLASY class TV private: int prgram; // nr prgramu Atrybuty biektów klasy TV bl wlaczny; // czy dbirnik włączny? public: // INTERFEJS KLASY Operacje dstępne dla biektów klasy TV // --knstruktr - przypisanie wartści pczątkwych składwym prywatnym TV() prgram=2; wlaczny=false; // ---metdy klasy vid zmienprgram(int p) if (wlaczny) prgram=p; else cut << "Najpierw wlacz TV" << endl; vid wlacz() wlaczny=true; cut << "Wlaczylem TV" << endl; vid wylacz() wlaczny=false; cut << "Wylaczylem TV" << endl; int gladam() return prgram; ; // // KLIENT KLASY int main () TV kuchniatv; twrzymy biekty TV pkjtv; kuchniatv.zmienprgram(4); kuchniatv.wlacz(); cut << "Prgram: " << kuchniatv.gladam()<<endl; kuchniatv.zmienprgram(4); cut << "Prgram: " << kuchniatv.gladam()<<endl; kuchniatv.wylacz(); wysyłamy kmunikaty d biektu pkjtv.wlacz(); cut << "Prgram: " << pkjtv.gladam()<<endl; pkjtv.wylacz(); return 0; 8
Przykład wersja B: Prgramwanie biektwe Wykład 1 #include <istream> using namespace std; // DEKLARACJA KLASY class TV private: int prgram; // nr prgramu bl wlaczny; // czy dbirnik włączny? public: // INTERFEJS KLASY // knstruktr - przypisanie wartści pczątkwych składwym prywatnym TV(); // metdy klasy vid zmienprgram(int p); vid wlacz(); vid wylacz(); int gladam(); ; //Kniec definicji klasy // DEFINICJE METOD KLASY TV::TV() prgram=2; wlaczny=false; vid TV::zmienPrgram(int p) if (wlaczny) prgram=p; else cut << "Najpierw wlacz TV" << endl; vid TV::wlacz() wlaczny=true; cut << "Wlaczylem TV" << endl; vid TV::wylacz() wlaczny=false; cut << "Wylaczylem TV" << endl; int TV::gladam() return prgram; // // KLIENT KLASY int main () TV kuchniatv; kuchniatv.zmienprgram(4); kuchniatv.wlacz(); cut << "Prgram: "<< kuchniatv.gladam()<<endl; kuchniatv.zmienprgram(4); cut << "Prgram: " << kuchniatv.gladam()<<endl; kuchniatv.wylacz(); TV pkjtv; pkjtv.wlacz(); cut << "Prgram: " << pkjtv.gladam()<<endl; pkjtv.wylacz(); return 0; 9
Prgramwanie biektwe Wykład 1 Definicja klasy ma pstać: 3.4.2 Klasa - definicja class nazwa_klasy private: // pla danych i funkcje prywatne typ nazwa_zmiennej; public: // pla danych i funkcje publiczne typ nazwa_funkcji(); prtected: // pla danych i funkcje chrnine ; W skład klasy wchdzą: pla danych: zmienne, które służą d przechwania wartści atrybutów biektu, metdy (funkcje składwe): funkcje, które kreślają zachwanie biektu, pzimy dstępu d składwych: d teg, na którym pzimie znajduje się składwa zależy mżliwść dstępu d niej z innych miejsc prgramu. Składwe (dane i metdy) zadeklarwane w sekcji public są dstępne w całym prgramie. Twrzą ne publiczny interfejs klasy, za pmcą któreg krzystamy z biektu. Składwe (dane i metdy) zadeklarwane w sekcji private są dstępne jedynie w funkcjach składwych klasy. Ich zadaniem jest ukrycie danych i wewnętrznych prcedur biektu. Składwe (dane i metdy) zadeklarwane w sekcji prtected są dstępne jedynie w funkcjach składwych klasy i w funkcjach składwych jej klas pchdnych (dziedziczących). (Patrz: dziedziczenie). Specyfikatry dstępu (ang. access specifiers) public, private i prtected mgą w definicji klasy występwać wielkrtnie. Jeśli pierwszą grupą składwych knstrukcji class są składwe prywatne, t mżna przed nimi pminąć kwalifikatr private. Obwiązuje zasada, że dpóki w brębie definicji klasy nie wystąpi w spsób jawny inny kwalifikatr (na przykład public lub prtected), wszystkie dane i metdy są autmatycznie zakwalifikwane jak prywatne. Klasę mżna definiwać za pmcą knstrukcji class lub struct. Klasa pisana za pmcą słwa class jest klasą, w której wszystkie składwe są prywatne ( ile teg nie zmienimy za pmcą na przykład słwa public). Klasa pisana za pmcą słwa struct jest klasą, w której wszystkie składwe są publiczne ( ile teg nie zmienimy za pmcą na przykład słwa private). Czyli zapis struct S ; jest p prstu skrótem zapisu class S public: ; 10
Prgramwanie biektwe Wykład 1 Pla danych: Metdy: 3.4.3 Klasa - składwe W ciele klasy mżna używać deklaracji dwlnych danych i struktur danych istniejących w języku C++. Nie wln inicjwać składwych. Mżna umieszczać w ciele klasy prttyp funkcji składwej (deklarację), zaś definicję funkcji umieszczać na zewnątrz; należy ją wtedy pprzedzić identyfikatrem klasy wraz z peratrem zasięgu. Każda metda zdefiniwana wewnątrz klasy jest uważana za funkcję rzwijaną w miejscu (wplataną, ang. inline), bez względu na t, czy zstanie pprzedzna słwem kluczwym inline. Jeśli funkcja składwa definiwana na zewnątrz ma być funkcją typu inline, należy pprzedzić ją kwalifikatrem inline. class MjaKlasa private: // pla danych i funkcje prywatne public: // pla danych i funkcje publiczne // ta funkcja jest definiwana w ciele klasy vid Fun1(int a) // instrukcje funkcji // ta funkcja jest tylk deklarwana w ciele klasy, // jest t zapwiedź funkcji, której definicja // znajduje się na zewnątrz klasy vid Fun2(int, int); ; // Definicja funkcji Fun2 vid MjaKlasa::Fun2(int a, int b) // instrukcje funkcji Metdy (funkcje składwe) mżna pdzielić na następujące kategrie: funkcje zarządzające stswane autmatycznie w mmencie twrzenia biektu klasy (knstruktry) i w mmencie jeg usuwania (destruktry); należą najczęściej d składwych publicznych; funkcje dstępu ich zadaniem jest udstępnienie składwych prywatnych klasy; należą d składwych publicznych; funkcje przetwarzające dknują peracji na składwych klasy, mgą krzystać z funkcji pmcniczych; należą d składwych publicznych; funkcje pmcnicze wykrzystywane przez inne kategrie funkcji; zazwyczaj są t składwe prywatne. 11
Prgramwanie biektwe Wykład 1 3.4.4 Obiekty Obiekt t pjedyncze, indywidualne wystąpienie klasy. Obiekty definiuje się pdbnie d zmiennych, umieszczając listę identyfikatrów za nazwą klasy. // definicja zmiennej int x; // definicja zmiennej x // definicja klasy class MjaKlasa // tutaj definicja składwych klasy MjaKlasa ; // definicje biektów MjaKlasa a; // definicja biektu a typu MjaKlasa MjaKlasa b,c; // definicja biektów b i c Prces twrzenia biektu plega na przydzieleniu mu bszaru pamięci wystarczająceg dla składwych będących danymi i strukturami danych, p czym wywływana jest metda będąca knstruktrem biektu. Odwłania d składwych biektu uzyskuje się za pmcą peratra "." umieszczneg p nazwie biektu. Przykład: MjaKlasa a; // deklaracja biektu a a.drukuj(); // wywłanie metdy Drukuj na rzecz biektu a Funkcje składwe (metdy) muszą być wywływane RAZEM z biektem. Metdy są takie same dla wszystkich biektów danej klasy. Dane przechwywane w biektach są różne. //kniec wykładu 1 12
Prgramwanie biektwe Wykład 1 3.4.5 Budwanie klasy Zadanie: Napisać prgram d bliczania pwierzchni figur. Wersja A: prgramwanie prceduralne #include <istream> using namespace std; struct Figura int dlugsc; int szerksc; int pwierzchnia; ; vid ObliczPle(Figura & f) f.pwierzchnia=f.dlugsc*f.szerksc; vid UstawDl(Figura& f) cut << "Pdaj dlugsc: "; cin >> f.dlugsc; vid UstawSzer(Figura& f) cut << "Pdaj szerksc: "; cin >> f.szerksc; int main() Figura a; UstawDl(a); UstawSzer(a); ObliczPle(a); cut << "Dlugsc=" << a.dlugsc << " Szerksc=" << a.szerksc << " Ple=" << a.pwierzchnia << endl; // Nwa dlugsc UstawDl(a); ObliczPle(a); cut << "Dlugsc=" << a.dlugsc << " Szerksc=" << a.szerksc << " Ple=" << a.pwierzchnia << endl; return 0; 13
Uprszczny schemat pstępwania: Wersja B: Prgramwanie w stylu biektwym 1. Nadać nazwę klasie. Nazwa pwinna być związana z isttą działania klasy. 2. Ddać d klasy pla danych. Prgramwanie biektwe Wykład 1 3. Ddać d klasy metdy (prttypy funkcji), które będą manipulwały wewnętrznymi danymi klasy. 4. Ddać d klasy knstruktr. 5. Zdefiniwać kdy metd i knstruktra. 6. Utwrzyć mduł główny, w który twrzne będą biekty danej klasy i pisane będzie ich działanie. ad. 1 Nadanie nazwy klasie class Figura // klasa jest na razie pusta ; ad. 2 Ddanie d klasy pól danych Język C++ pzwala kreślić graniczenia dla klientów klasy pprzez wprwadzenie pzimów dstępu d składwych klasy. Jeśli nie chcemy, aby klient klasy miał dstęp bezpśredni d składwych, umieszczamy je jak prywatne. class Figura // pla danych są prywatne private: int dlugsc; int szerksc; int pwierzchnia; ; ad 3 Ddanie d klasy metd Musimy wtedy zapewnić dpwiedni zestaw funkcji składwych (metd) dstępnych publicznie, które pzwlą perwać na biekcie. class Figura // pla danych są prywatne private: int dlugsc; int szerksc; int pwierzchnia; // pniższe metdy są publiczne public: int PbierzDl(); // pbiera wartść składwej: dlugsc int PbierzSzer(); // pbiera wartść składwej: szerksc int PbierzPle(); // pbiera wartść składwej: pwierzchnia vid UstawDl(int d); // przypisuje wartść składwej: dlugsc // i aktualizuje wartść pwierzchni vid UstawSzer(int s); // przypisuje wartść składwej: szerksc // i aktualizuje wartść pwierzchni ; 14
ad 4. Ddanie d klasy knstruktra Prgramwanie biektwe Wykład 1 Knstruktr gwarantuje pprawną inicjację biektu. Jest n autmatycznie wywływany przez kmpilatr, w miejscu, w którym twrzny jest biekt, zanim jeszcze klient klasy będzie mógł pdjąć jakieklwiek działania związane z biektem. Knstruktr mże psiadać argumenty kreślające spsób twrzenia biektu. class Figura private: int dlugsc; int szerksc; int pwierzchnia; public: Figura(int d, int s); int PbierzDl(); int PbierzSzer(); int PbierzPle(); vid UstawDl(int d); vid UstawSzer(int s); ; ad 5. Zdefiniwanie metd i knstruktra class Figura private: int dlugsc; int szerksc; int pwierzchnia; public: Figura(int d=0, int s=0); ; int PbierzDl() return dlugsc; int PbierzSzer() return szerksc; int PbierzPle() return pwierzchnia; vid UstawDl(int dl); vid UstawSzer(int szer); Figura::Figura(int d, int s) dlugsc=d; szerksc=s; pwierzchnia=dlugsc*szerksc; vid Figura::UstawDl(int d) dlugsc=d; pwierzchnia=dlugsc*szerksc; vid Figura::UstawSzer(int s) szerksc=s; pwierzchnia=dlugsc*szerksc; 15
Prgramwanie biektwe Wykład 1 ad 6. Funkcja główna (klient klasy) utwrzenie biektów i sprawdzenie ich działania. ; #include <istream> using namespace std; class Figura private: int dlugsc; int szerksc; int pwierzchnia; public: Figura(int d, int s); int PbierzDl() return dlugsc; int PbierzSzer() return szerksc; int PbierzPle() return pwierzchnia; vid UstawDl(int dl); vid UstawSzer(int szer); Figura::Figura(int d, int s) dlugsc=d; szerksc=s; pwierzchnia=dlugsc*szerksc; vid Figura::UstawDl(int d) dlugsc=d; pwierzchnia=dlugsc*szerksc; vid Figura::UstawSzer(int s) szerksc=s; pwierzchnia=dlugsc*szerksc; int main() int x,y; cut << "Pdaj dlugsc: "; cin >> x; cut << "Pdaj szerksc: "; cin >> y; Figura a(x,y); // utwórz prstkąt a cut << "Dlugsc=" << a.pbierzdl() << " Szerksc=" << a.pbierzszer() << " Ple=" << a.pbierzple() << endl; cut << "Pdaj nwa dlugsc: "; cin >> x; a.ustawdl(x); cut << "Dlugsc=" << a.pbierzdl() << " Szerksc=" << a.pbierzszer() << " Ple=" << a.pbierzple() << endl; cut << "Pdaj nwa szerksc: "; cin >> y; a.ustawszer(y); cut << "Dlugsc=" << a.pbierzdl() << " Szerksc=" << a.pbierzszer() << " Ple=" << a.pbierzple() << endl; return 0; 16
Prgramwanie biektwe Wykład 1 3.4.6 Zasięg klasy Klasa wprwadza nwy rdzaj zasięgu nazw: zasięg klasy. Dtyczy n nazw danych raz metd wchdzących w skład klasy. Tylk w definicji funkcji składwej (metdy) nazwa składwej jest znana niezależnie d teg, czy sama definicja metdy znajduje się wewnątrz czy na zewnątrz klasy. Na zewnątrz nazwa z klasy będzie rzpznana: jeśli zstanie użyty peratr przynależnści. (krpka) Figura a; // nazwa knstruktra jest rzpznawana, gdyż jest // taka sama jak nazwa klasy a.ustawdl(x); // dwłuje się d Figura::UstawDl jeśli użyty zstanie peratr zasięgu klasy nazwaklasy:: Przykład: vid Figura::UstawDl(int dl) Figura::Figura(int dl, int szer) dlugsc = dl; szerksc = szer; pwierzchnia = dl*szer; /* równważny zapis */ Figura::Figura(int dl, int szer) Figura::dlugsc = dl; Figura::szerksc = szer; Figura::pwierzchnia = dl*szer; 17
3.5 Knstruktry Prgramwanie biektwe Wykład 1 Knstruktr jest t specjalna metda używana d utwrzenia biektu danej klasy. Za jej pmcą autr klasy wymusza na użytkwniku kniecznść ustalenia stanu pczątkweg każdeg biektu danej klasy. Knstruktr jest wywływany autmatycznie pdczas twrzenia biektów danej klasy. Knstruktr nie zwraca żadnej wartści. Nazwa knstruktra jest identyczna z nazwą klasy. Klasa mże mieć wiele knstruktrów. Są ne rzróżniane dzięki plimrfizmwi nazw funkcji. Przykład: klasa Punkt Cel - chcemy mieć mżliwść inicjwania biektu na różne spsby, z pdaniem lub nie współrzędnych punktu; Realizacja - twrzymy trzy funkcje knstruktrów (bez argumentów bie współrzędne równe zeru, z jednym argumentem bie współrzędne są sbie równe, z dwma argumentami pierwszy kreśla współrzędną x, zaś drugi współrzędną y), wszystkie knstruktry mają tę samą nazwę, właściwy knstruktr jest wybierany na pdstawie liczby argumentów pdawanych pdczas definiwania biektu. Pierwsze rzwiązanie: #include <istream> using namespace std; class Punkt int x, y ; public : // Definicje knstruktrów Punkt () // Knstruktr 1 (bez argumentów) x = 0 ; y = 0 ; Punkt (int xx) // Knstruktr 2 (jeden argument) x = y = xx ; Punkt (int xx, int yy) // Knstruktr 3 (dwa argumenty) x = xx ; y = yy ; ; int main() Punkt a; // wywłaj knstruktr 1 Punkt b (2) ; // wywłaj knstruktr 2 Punkt c (3,6) ; // wywłaj knstruktr 3 return 0; 18
Prgramwanie biektwe Wykład 1 Drugie rzwiązanie: class Punkt int x, y ; public : // Deklaracje knstruktrów Punkt () ; // Knstruktr 1 (bez argumentów) Punkt (int) ; // Knstruktr 2 (jeden argument) Punkt (int, int) ; // Knstruktr 3 (dwa argumenty) ; inline Punkt::Punkt () // Knstruktr 1 x = 0 ; y = 0 ; inline Punkt::Punkt (int xx) // Knstruktr 2 x = y = xx ; inline Punkt::Punkt (int xx, int yy) // Knstruktr 3 x = xx ; y = yy ; int main() Punkt a ; // wywłaj knstruktr 1 Punkt b (2) ; // wywłaj knstruktr 2 Punkt c (3,6) ; // wywłaj knstruktr 3 return 0; 19
Są dwa typy knstruktrów: 3.5.1 Knstruktry deklarwanie i definiwanie Prgramwanie biektwe Wykład 1 knstruktr inicjujący biekt - wykrzystywany d utwrzenia całkwicie nweg biektu i przypisania wartści pczątkwych składwym; knstruktr kpiujący - wykrzystywany d utwrzenia nweg biektu będąceg kpią biektu istniejąceg (patrz wykład 3). Knstruktr inicjujący Knstruktr jest autmatycznie wywływany pdczas pwływania d życia nweg biektu. Celem knstruktra inicjująceg jest przyprządkwanie pamięci dla nweg biektu i zainicjwanie jeg składwych. Knstruktr, który mżna wywłać bez jawneg pdania argumentów nsi nazwę knstruktra dmyślneg. Jeśli nie zdefiniuje się żadneg własneg knstruktra inicjująceg, t kmpilatr autmatycznie stwrzy własny dmyślny (czyli bez parametrów) knstruktr inicjujący. Knstruktr dmyślny stwrzny przez kmpilatr nie przypisuje wartści pczątkwych składwym klasy. Knstruktr jest definiwany tak jak funkcja, ale musi mieć taką samą nazwę jak klasa, mże mieć lub nie parametry, nic nie zwraca i nie ma kreślneg typu wyniku (jest używany wewnętrznie przez kmpilatr). Klasa mże psiadać wiele knstruktrów inicjujących (tylk jeden dmyślny). Każdy z nich inicjuje biekt w kreślny spsób. O wybrze knstruktra decyduje pstać definicji biektu. Zdefiniwanie chć jedneg własneg knstruktra spwduje, że kmpilatr przyjmie, że klasa ma własne knstruktry i nie utwrzy swjeg knstruktra dmyślneg. W tym przypadku, jeśli ptrzebny jest knstruktr bez parametrów, trzeba g samemu utwrzyć. Obiekt mże być inicjwany na dwa spsby: za pmcą jawneg wywłania knstruktra, za pmcą niejawneg wywłania knstruktra. 20
Przykład: ; class MjaKlasa int liczba; public: MjaKlasa(); // knstruktr dmyślny - bez argumentów MjaKlasa(int n); // knstruktr mże mieć parametry Prgramwanie biektwe Wykład 1 int main() MjaKlasa a; // deklaracja biektu: // niejawnie wywłany zstanie knstruktr dmyślny MjaKlasa b(2); // deklaracja biektu: // niejawnie wywłany zstanie knstruktr z jednym // parametrem MjaKlasa c = MjaKlasa(5); // deklaracja biektu: // jawnie wywłany zstanie knstruktr z jednym // parametrem MjaKlasa *wd = new MjaKlasa; // biekt nie ma nazwy, // dstęp d nieg tylk za pmcą wskaźnika MjaKlasa *wd2 = new MjaKlasa(5); // biekt nie ma nazwy, // dstęp d nieg tylk za pmcą wskaźnika 21
Prgramwanie biektwe Wykład 1 3.5.2 Knstruktr z listą inicjatrów W knstruktrze mżna przypisywać wartści pczątkwe składwym za pmcą listy inicjatrów knstruktra. class Punkt int x, y ; public : //Lista inicjatrów knstruktra Punkt (int xx, int yy) : x(xx), y(yy) //zamiast x = xx; y = yy; ; 3.5.3 Knstruktr z argumentami dmyślnymi Knstruktr mże psiadać argumenty dmyślne. Dzięki temu granicza się liczbę niezbędnych knstruktrów. class MjaKlasa public: MjaKlasa(int n=0); ; int main() MjaKlasa a; // wywłany zstanie knstruktr z n=0 MjaKlasa b(2); // wywłany zstanie knstruktr z n=2 Przy jakim załżeniu związanym z deklaracją punktu mżna zaprpnwać dla klasy Punkt jeden knstruktr z argumentami dmyślnymi? Punkt (int xx=0, int yy=0): x(xx), y(yy) 22
Załżenia wstępne: Prgramwanie biektwe Wykład 1 3.6 Przykład: klasa d bliczeń na ułamkach Ulamek ułamek jest reprezentwany przez licznik i mianwnik, licznik i mianwnik są liczbami całkwitymi, licznik mże być liczbą ddatnią, ujemną lub zerem, mianwnik jest liczbą ddatnią, znak jest przechwywany wraz z licznikiem, ułamek 0 jest reprezentwany przez licznik=0 i mianwnik=1, licznik i mianwnik są nieskracalne. Klasa z plami danych - zakładamy, że pla składwe są prywatne: class Ulamek int licznik; int mianwnik; ; Mżliwe inicjwanie biektu ułamkweg: bez pdania żadnej wartści - wtedy licznik=0, mianwnik=1, z pdanymi wartściami licznik, mianwnik, z pdaną wartścią licznika wtedy mianwnik=1. Oznacza t, że ptrzebne będą następujące knstruktry: Deklaracja biektu Ptrzebny knstruktr Ulamek a; Ulamek () licznik=0; mianwnik=1; Knstruktr bez argumentów nazywany jest knstruktrem dmyślnym (ang. default cnstructr). Ulamek b(1,2); Ulamek (int li, int mi) licznik=li; if ( mi < 0) licznik=-licznik; mianwnik=-mi; //brak spr czy 0 Ulamek c(1); Ulamek (int li) licznik=li; mianwnik=1; 23
Prgramwanie biektwe Wykład 1 Knstruktry mżna zapisać w pstaci jednej funkcji - dzięki mechanizmwi argumentów dmyślnych: Ulamek (int li=0, int mi=1) licznik=li; if ( mi < 0) //brak spr. czy m==0 licznik=-licznik; mianwnik=-mi; else if (mi > 0) mianwnik = mi; else UWAGA: Jeśli wszystkie argumenty knstruktra są dmyślne, znacza t, że mże być n wywływany bez argumentów. Otrzymujemy wtedy również knstruktr dmyślny! Ułamek ma być przechwywany w pstaci nieskracalnej: 1/2 3/6 (-2)/(-4) są t te same ułamki. Trzeba zmdyfikwać knstruktr: Ulamek(int li=0, int mi=1) int q=nwp(li,mi); // znajdź największy wspólny pdzielnik if(mi < 0) q = -q; // mianwnik ma być zawsze ddatni licznik = li/q; // skróć licznik mianwnik = mi/q; // skróć mianwnik Ddanie d klasy pzstałych metd Ptrzebujemy funkcji nwp znajdującej największy wspólny pdzielnik dwóch liczb całkwitych, funkcja ta jest funkcją pmcniczą. Składwe licznik i mianwnik są prywatne, ptrzebujemy więc funkcji dstępu zwracających te składwe. 24
Prgramwanie biektwe Wykład 1 Wersja 1 klasy Ulamek: class Ulamek int l; // licznik int m; // mianwnik int nwp(int p, int q); // największy wspólny pdzielnik public: Ulamek(int a=0, int b=1); // Knstruktr int ZwrcLicznik()cnst return l; int ZwrcMian()cnst return m; ; Ulamek::Ulamek(int a, int b) int q=nwp(a,b); if(b < 0) q = -q; // mianwnik ma być zawsze ddatni l = a/q; m = b/q; int Ulamek::nwp(int p, int q) int r; p = abs(p); // bliczenia na wartściach nieujemnych q = abs(q); // Przypadki szczególne if(p == 0) if(q == 0) return 1; else return q; else if(q == 0) return p; // p>0, q>0 r = p % q; while(r) p = q; q = r; r = p % q; return q; Funkcja testująca klasę: #include <istream> #include <cmath> // dla funkcji abs using namespace std; int main () Ulamek f0, f1(1), f2(6,3); cut << "TEST KLASY Ulamek\n"; cut << f0.zwrclicznik() << '/' << f0.zwrcmian() << endl; cut << f1.zwrclicznik() << '/' << f1.zwrcmian() << endl; cut << f2.zwrclicznik() << '/' << f2.zwrcmian() << endl; return 0; 25
3.7 Metdy klasy (funkcje składwe) Prgramwanie biektwe Wykład 1 3.7.1 Przekazywanie biektów za pmcą argumentów funkcji Obiekty mżemy przekazywać d funkcji składwych klasy (metd) tymi samymi spsbami, c zwykłe zmienne. Przykład: Dana jest klasa Ulamek. Chcemy ją uzupełnić metdę sprawdzającą, czy dwa ułamki są sbie równe. Funkcja main() będzie miała pstać: int main () Ulamek f1(1,6), f2(2,12), f3; cut << "Test klasy Ulamek\n"; if (funkcja prównująca) cut << "Ulamki sa rwne\n"; else cut << "Ulamki sa nie rwne\n"; return 0; Funkcja prównująca metda klasy, wersja 1: // Wersja 1: przekazywanie przez wartść bl Ulamek::Rwne(Ulamek b) if ((b.l==l) && (b.m==m)) return true; else return false; // w main() if (f1.rwne(f2)) Wada: funkcja działa na kpii biektu przesłaneg d funkcji, wymaga t ddatkwej pamięci i czasu raz utwrzenia pprawnej kpii. Rzwiązanie: przekazywanie przez adres lub referencję. Zaleta: funkcja nie mże zmienić wartści składwych biektu przekazaneg d funkcji, b działa na kpii. Funkcja prównująca metda klasy, wersja 2, nie jest twrzna kpia: // Wersja 2: przekazywanie przez adres bl Ulamek::Rwne(Ulamek *wsk) if ((wsk->l==l) && (wsk->m==m)) return true; else return false; // w main() if (f1.rwne(&f2)) Wada: funkcja działa na rzeczywistym biekcie, któreg adres jest przekazany d funkcji, c znacza mżliwść zmiany jeg wartści. Rzwiązanie: użycie kwalifikatra cnst: bl Ulamek::Rwne(cnst Ulamek *wsk); 26
Prgramwanie biektwe Wykład 1 Funkcja prównująca metda klasy, wersja 3, nie jest twrzna kpia: // Wersja 3: przekazywanie przez referencję bl Ulamek::Rwne(Ulamek &b) if ((b.l==l) && (b.m==m)) return true; else return false; // w main() if (f1.rwne(f2)) Wada: mżliwść mdyfikacji biektu przekazaneg d funkcji, zabezpieczenie: bl Ulamek::Rwne(cnst Ulamek &b) 27
3.7.2 Przekazywanie adresu biektu czyli wskaźnik this Prgramwanie biektwe Wykład 1 Wywłana funkcja składwa klasy (metda) trzymuje niejawnie adres biektu, na rzecz któreg zstała wywłana. Adres ten jest przechwywany w zmiennej wskaźnikwej nazwie this. ( Który biekt? Ten (this) biekt. ) Mglibyśmy zatem przepisać pprzedni przykład z użyciem this (jest sztuka dla sztuki, nie jest t prawdziwe zastswanie wskaźnika this): // Wersja 2: przekazywanie przez adres bl Ulamek::Rwne(Ulamek *wsk) if ((wsk->l==l) && (wsk->m==m)) return true; else return false; lub bl Ulamek::Rwne(Ulamek *wsk) if ((wsk->l==this->l) && (wsk->m==this->m)) return true; else return false; // w main() if (f1.rwne(&f2)) 28
3.7.3 Zwracanie biektów za pmcą return Prgramwanie biektwe Wykład 1 Chcemy uzupełnić klasę Ulamek metdę zwracającą ułamek większym mianwniku. // Wersja 1: przekazywanie i zwracanie przez wartść Ulamek Ulamek::WiekszyMian(Ulamek b) if (b.m>=m) return b; else return *this; // wskaźnik this zawiera adres ułamka, na rzecz któreg // wywłana zstała funkcja int main () Ulamek f1(1,6), f2(1,2), f3; f3=f1.wiekszymian(f2); return 0; /////////////////////////////////////////////////////////////////////// // Wersja 2: przekazywanie i zwracanie przez wskaźniki Ulamek *Ulamek::WiekszyMian(Ulamek* b) if (b->m >= m) return b; else return this; int main () Ulamek f1(1,6), f2(1,2), f3; f3=*(f1.wiekszymian(&f2)); return 0; ////////////////////////////////////////////////////////////////////// // Wersja 3: przekazywanie i zwracanie przez referencję Ulamek &Ulamek::WiekszyMian(Ulamek& b) if (b.m>=m) return b; else return *this; int main () Ulamek f1(1,6), f2(1,2), f3; cut << "TEST KLASY Ulamek\n"; f3=f1.wiekszymian(f2); return 0; 29
Prgramwanie biektwe Wykład 1 3.8 Tablica biektów Tablica w C++ mże psiadać elementy dwlneg typu, w tym typu klasy. Tablica biektów jest inicjalizwana za pmcą wywłania knstruktrów klasy (jawnie lub niejawnie) tyle razy, ile elementów zawiera. Klasa musi psiadać knstruktry dpwiednieg typu. Przykład: // Inicjwanie niejawne - klasa musi psiadać knstruktr dmyślny Ulamek T1[20]; // // Inicjwanie jawne za pmcą knstruktrów Ulamek T2[3]=Ulamek(1,2),Ulamek(3,5),Ulamek(1,8); // Mżna użyć knstruktry różnych typów Ulamek T3[3]=Ulamek(1,2),Ulamek(),Ulamek(1); Każdy element tablicy jest biektem klasy, więc mże być używany w płączeniu z metdami tej klasy. Przykład: Ulamek T[2]=Ulamek(1,2),Ulamek(1,3); cut << "TEST KLASY Ulamek\n"; cut << T[0].ZwrcLicznik()<<'/'<<T[0].ZwrcMian()<<endl; 30
Prgramwanie biektwe Wykład 1 3.9 Destruktr Destruktr jest t specjalna metda autmatycznie wywływana pdczas usuwania biektu danej klasy, c ma miejsce, gdy: kńczy się zasięg deklaracji biektu, usuwany jest biekt tymczaswy (patrz wykład 3), d wskaźnika biektu zastswan peratr delete. Celem destruktra jest zakńczenie istnienia biektu danej klasy w spsób przewidywalny i uprządkwany. Jeśli nie zdefiniuje się własneg destruktra, t kmpilatr autmatycznie stwrzy własny dmyślny destruktr. Destruktr definiwany przez użytkwnika ma taką samą nazwę jak klasa pprzedzną znakiem tylda (~), jest funkcją bez kreślneg typu wyniku. D destruktra nie przekazujemy żadnych argumentów. W klasie mżna zdefiniwać tylk jeden destruktr. Przykład: class MjaKlasa public: MjaKlasa(int n=0); // knstruktr ~MjaKlasa(); // destruktr ; 3.10 ZADANIA 1. C t jest klasa? 2. Jaki jest związek między biektem a klasą? 3. C t jest knstruktr? Kiedy jest wywływany? 4. C t jest knstruktr dmyślny i jakie daje krzyści? 5. C t jest lista inicjalizacyjna knstruktra i d czeg służy? 6. Które z pniższych stwierdzeń najlepiej pisuje funkcję knstruktra klasy? A. Testuje wszystkie funkcje składwe klasy. B. Inicjuje dane składwe biektu klasy. C. Określa i zwraca ilść pamięci ptrzebnej dla danych składwych klasy. D. Zwalnia pamięć zajętą przez biekt klasy. E. Wyświetla infrmację utwrzeniu nweg biektu klasy. 7. Knstruktr charakteryzuje się pewnymi cechami. Które z pdanych pniżej stwierdzeń jest nieprawdziwe? A. Knstruktr jest wywływany autmatycznie, gdy deklarwana jest nwa zmienna. B. Jeśli klasa nie ma własneg knstruktra, kmpilatr dstarczy knstruktr dmyślny. C. Knstruktr nie mże być składwą prywatną. D. Knstruktr mże nie mieć żadnych parametrów. E. Knstruktr zwraca typ utwrzneg biektu. 8. C t jest this i *this? 9. C t jest destruktr? 10. Jakie części kdu prgramu mają dstęp d części `prywatnej klasy? 11. C t jest hermetyzacja danych? 12. Jaka jest pdstawwa różnica między strukturami i klasami w C++? 13. Czym funkcje twarte różnią się d zwyczajnych funkcji? 31
Prgramwanie biektwe Wykład 1 14. C t jest plimrfizm nazw funkcji? 15. C t jest przeciążanie nazw funkcji? 16. Utwrzyć klasę Punkt zawierającą knstruktr dmyślny, destruktr i dwie składwe: składwą kreślającą numer utwrzneg punktu, składwą kreślającą liczbę punktów dtychczas utwrznych. Zadaniem knstruktra jest wyświetlenie numeru nwtwrzneg punktu. Zadaniem destruktra jest wyświetlanie usuwaneg punktu. Napisać prgram testujący pracwaną klasę. 17. Utwrzyć klasę reprezentującą książkę. Książka jest pisana za pmcą numeru inwentarza, liczby strn i ceny. Funkcje składwe klasy pwinny realizwać następujące peracje: twrzenie biektu i inicjwanie g, wyświetlanie danych biektu (wszystkich razem i pjedynczych, np. numeru inwentarzweg), zmianę ceny. 18. Napisać prgram, który będzie działał na tablicy książek. Pwinien umżliwiać bliczenie średniej ceny książki, znalezienie książki najmniejszej i największej cenie. 19. W klasie Ulamek nie przewidzian sytuacji, w której użytkwnik zadeklaruje biekt: Ulamek A(3,0); Uzupełnij klasę pstępwanie w tym przypadku. 20. Zadania z: Stephen Prata, Szkła prgramwania. Język C++, wyd.v, 2006: str. 413, pytania 1-5; str. 534, pytania 1-10; str. 534-537, ćwiczenia prgramistyczne. 32