uvod u objektno orijentirano programiranje
TRANSCRIPT
Uvod u objektno-orijentirano programiranje u programskom jeziku C++jeziku C++
8.4.2007 autor: dr. sc. Zvonimir Vanjak
Evolucija programskih jezika
prva generacija – strojni jezikdruga generacija asemblerdruga generacija – asemblertreća generacija – Pascal, C, Fortran, Algol, LISP, ...
uvodi se paradigma proceduralnog, strukturnog i modularnog programiranjapojavljuju se i višenamjenski jeziciobjektno-orijentirani jezici kao nova paradigma razvoja (- Smalltalk, C++, Java, C#
četvrta generacija – 4GL jezicijezici specijalizirani za određenu domenu problema
Algoritmi i strukture podataka, 2006/07. 8.4.2007 2 / 46
Razvoj tipičnog programera
uglavnom započinje učenjem nekog programskog jezika treće generacijegeneracije
Basic, Pascal, Csrećom učenje strojnog jezika i asemblera je iza nas (☺)srećom, učenje strojnog jezika i asemblera je iza nas (☺)
koristi se paradigma nestrukturiranog programiranjači j i j lih i j d t ih k ji t j d započinje se pisanjem malih i jednostavnih programa koji se sastoje od
slijeda naredbi i djeluju nad zajedničkim skupom podataka
Algoritmi i strukture podataka, 2006/07. 8.4.2007 3 / 46
Proceduralna paradigma - I
osnovni korak je uvođenje funkcija koje su izgrađene kao skup naredbi i koje imaju dobro definiran ulaz i izlaz (već viđeno na PIPI-ju)rješavamo se problema ponavljanja programskog kôda!!!
definiramo ga na jednom mjestu i zatim samo pozivamo funkciju kad nam zatreba takva funkcionalnost
Glavni program
Podaci
Procedura 1 Procedura 2 Procedura 3
Lokalni podaci Lokalni podaci Lokalni podaci
Algoritmi i strukture podataka, 2006/07. 8.4.2007 4 / 46
Proceduralna paradigma - II
primjeri:matematičke funkcije – sin cosmatematičke funkcije sin, cosfunkcije za U/I – printf, fwritefunkcije za rad s grafikom - DrawLine, DrawCirclej g ,
a što ako je netko već implementirao takve funkcije?!možemo ih (jednostavno) iskoristiti!(j )- većina razvojnih okruženja dolazi s ugrađenom gomilom biblioteka takvih funkcija
reusability – mogućnost ponovnog iskorištavanja programskog kôday g g j g g“write once, use everywhere”ali, nije sve tako jednostavno javlja se problem organizacije velikog broja funkcija u smislene cjeline!
Algoritmi i strukture podataka, 2006/07. 8.4.2007 5 / 46
Modularno programiranje
procedure srodne funkcionalnosti grupiraju se u module koji mogu imati vlastite podatkep
Modul 1 Program
PodaciPodaci 1 Podaci
Procedura 1
Podaci 1
Modul 2Lokalni podaci
P d i 1
Procedura 2 Procedura 3
Podaci 1
Lokalni podaci Lokalni podaci
Algoritmi i strukture podataka, 2006/07. 8.4.2007 6 / 46
I dalje nije sve idealno!
teško je napraviti modul da bude dobro definirana i zatvorena jedinica funkcionalnosti!programski jezici imaju vrlo “tanku” (i često nejasnu) definiciju modula
npr. u C-u modul može biti:- .h datoteka s pripadajućom .cpp datotekom- biblioteka funkcija koja se statički povezuje (linka) u naš program
Windows DLL biblioteka- Windows DLL bibliotekakoncept modula je najčešće implementacijski detalj programskog okruženja u kojem radimo i nije potpuno integriran u sam programski jezik
osnovni problem je što funkcije i podaci ugrađeni u modul nisu povezani u konkretne programske entitete koji bi predstavljali razumljiv i jasan koncept za k j j k i ik d lkrajnje korisnike modula
standardni <stdio.h> predstavlja gomilu struktura i funkcija a mi bismo željeli imati “nešto” kao: File, BinaryFile, TextFile, ...
Algoritmi i strukture podataka, 2006/07. 8.4.2007
kao: File, BinaryFile, TextFile, ...
7 / 46
Potreba za objektno-orijentiranom paradigmom
stvar nije tako kompletno crna jer ovisi i o “razini” funkcionalnosti ugrađenoj u modul:ugrađenoj u modul:
moduli “niske razine” (npr. U/I funkcije u C-u, funkcije za grafičko iscrtavanje u Windowsima) se svakodnevno (i uspješno) iskorištavaju u projektima dilj ijdiljem svijeta- jasno definirani, s dobrom dokumentacijom i “izglačani” dugotrajnim korištenjem
jesmo li (i koliko) uistinu napredovali od asemblera?jesmo li (i koliko) uistinu napredovali od asemblera?MASM (Microsoft Assembler) ima i varijable, i mogućnost definiranja potprograma i mogućnost kreiranja modulapotprograma i mogućnost kreiranja modulazašto nam je onda uopće C zanimljiv?- jednostavnija sintaksa, i (ipak) moćniji skup osnovnih naredbi
traži se potpuno nova paradigma programiranja“odgovor”: objektno-orijentirana paradigma
Algoritmi i strukture podataka, 2006/07. 8.4.2007
g j j p g
8 / 46
Malo povijesti
Simula (1967.)prvi programski jezik sa svojstvima objektno-orijentirane paradigme
ij j i d ji t i l ijnamijenjen izgradnji sustava za simulacijuuveden pojam klase / razreda
Smalltalk (1972.) ( )prvi “pravi” (čisti) objektno-orijentiran programski jezik (“sve je objekt”)razvijen u laboratoriju Xerox PARC Smalltalk-80 je najkorištenija verzijaSmalltalk 80 je najkorištenija verzija
C++“hibridni” objektno-orijentirani jezik nastao iz C-a - ispočetka se zvao “C s razredima” (“C with Classes”)with Classes )razvio ga je Bjarne Stroustrup (1983.) u Bell Labsinicijalna ANSI standardizacija je dovršena (tek) 1998., a 2003. je izdana verzija standardna s ispravljenim pogreškamastandardna s ispravljenim pogreškamatrenutno se radi na razvoju novog standarda C++0xC++ je “predak” danas široko korištenih jezika - Java, C# i VB.NET
Algoritmi i strukture podataka, 2006/07. 8.4.2007 9 / 46
Kako ćemo “savladati” OOP?
krećemo od (jednostavnog) problema koji ćemo riješiti u C-uidentificirat ćemo nedostatke tog rješenja i kroz postupno uvođenje identificirat ćemo nedostatke tog rješenja i kroz postupno uvođenje koncepata OO paradigme vidjeti kako se oni mogu riješiti u C++ implementacijiimplementacijiproblem:
zadana je datoteka u kojoj se nalazi određeni (nepoznat) broj podataka (radi jednostavnosti, datoteka je slijedna formatirana i sadrži u svakom retku samo jedan podatak tipa int)retku samo jedan podatak tipa int)treba napisati program koji će učitati podatke iz datoteke u memoriju (u strukturu polja nakon učitavanja možemo dohvatiti podatke po indeksu) i strukturu polja – nakon učitavanja možemo dohvatiti podatke po indeksu) i omogućiti njihovu obradu- s obzirom da podaci moraju ostati u memoriji nakon učitavanja, nije moguće
Algoritmi i strukture podataka, 2006/07. 8.4.2007
p j j j , j gjednostavno rješenje slijednog čitanja podataka (jedan po jedan) sve do kraja datoteke!
10 / 46
Jednostavno rješenje u C-u
rješenje:pročitamo sve podatke iz datoteke u jednom prolazu radi utvrđivanja koliko pročitamo sve podatke iz datoteke u jednom prolazu radi utvrđivanja koliko ih ukupno imazatim alociramo polje potrebne veličine pomoću malloczatim alociramo polje potrebne veličine pomoću mallocponovno prolazimo kroz datoteku i iznova učitavamo podatke (s time da ih sada spremamo u alocirano polje)sada spremamo u alocirano polje)
ne zadovoljava zadani uvjet!!!primjenjivo kada učinkovitost programa (vrijeme izvršavanja) nije primjenjivo kada učinkovitost programa (vrijeme izvršavanja) nije problem
Algoritmi i strukture podataka, 2006/07. 8.4.2007 11 / 46
Bolje rješenje
možemo koristiti funkciju reallocalociramo inicijalni blok memorije (npr za 100 podataka) i zatim ga po alociramo inicijalni blok memorije (npr. za 100 podataka) i zatim ga po potrebi povećavamo tijekom učitavanja
sada imamo 2 veličine koje “opisuju” učitane podatkesada imamo 2 veličine koje opisuju učitane podatkepokazivač na alociranu memorijukoličinu alocirane memorijekoličinu alocirane memorije
dobro je “povezati” podatke – definiramo strukturustruct DinamickoPolje{
int *Podaci;int BrojElem;
};
Algoritmi i strukture podataka, 2006/07. 8.4.2007
};
12 / 46
Još bolje rješenje
definiramo i određeni skup funkcija koje će raditi s tom strukturomklasični C idiom klasični C-idiom - struct FILE <=> (fopen, fscanf, fread, ...)
funkcije za DinamickoPolje:funkcije za DinamickoPolje:
int Inicijaliziraj (struct DinamickoPolje *Polje,j j j jint InicijalniBrojElem);
void Izbrisi (struct DinamickoPolje *Polje);int PostaviNovuVelicinu (struct DinamickoPolje *Polje,int PostaviNovuVelicinu (struct DinamickoPolje Polje,
int NoviBrojEl);
P01 DinamickoPolje C osnovna impl
Algoritmi i strukture podataka, 2006/07. 8.4.2007
P01_DinamickoPolje_C_osnovna_impl
13 / 46
Što nije dobro?
tehnički nedostaci implementacije u C-u:sami moramo paziti na iskorištenost prostora (BrojUcitanih)sami moramo paziti na iskorištenost prostora (BrojUcitanih)- problem je što je ova struktura samo vrlo jednostavan “omotač” (engl. wrapper) oko
pokazivača („sakrili“ smo malloc i realloc od korisnika strukture, ali nismo definirali nikakvo dodatno ponašanje)
pristup podacima ide preko izravnog korištenja pokazivača koji je dio strukture (P lj P d i[])strukture (Polje.Podaci[])- nameće se primjenjivanje idioma get/set za dohvaćanje i postavljanje vrijednosti
elemenata u poljuelemenata u polju
poboljšanja:u strukturu dodajemo i podatak o iskorištenosti alociranog prostorau strukturu dodajemo i podatak o iskorištenosti alociranog prostoradefiniramo dodatne funkcije za rad sa strukturom
Algoritmi i strukture podataka, 2006/07. 8.4.2007 14 / 46
Primjerstruct DinamickoPolje{
int *Podaci;int BrojElem; // koliko stvarno ima elemenata u poljuint BrojElem; // koliko stvarno ima elemenata u poljuint MaxBrojElemenata; // koliki je maksimalno raspolozivi
prostor};
int Inicijaliziraj (struct DinamickoPolje *Polje,int MaxBrojElem);
void Izbrisi (struct DinamickoPolje *Polje);
int PostaviNovuVelicinu (struct DinamickoPolje *Polje, int NoviBrojElem);
id P t iEl t ( t t Di i k P lj *P lj i t I dvoid PostaviElement (struct DinamickoPolje *Polje, int Ind, int Vrijednost);
int DodajElementNaKraj (struct DinamickoPolje *Polje, int Vrijednost);
int DohvatiElement (struct DinamickoPolje *Polje, int Indeks);
int BrojElemenata (struct DinamickoPolje *Polje);
8.4.2007 15 / 46Algoritmi i strukture podataka, 2006/07.
Tehnički problem!
funkciju DohvatiElement() smo deklarirali kaoint DohvatiElement (struct DinamickoPolje *Polje, int Indeks);
a što ako se zatraži vrijednost elementa polja za nepostojeći indeks?treba nekako naznačiti pogrešku!
int DohvatiElement (struct DinamickoPolje Polje, int Indeks);
treba nekako naznačiti pogrešku!standardni način u C-u je signaliziranje pogreške preko povratnog argumenta funkcije
novi prototip:
int DohvatiElement2 (struct DinamickoPolje *Polje, int Indeks, int *DohvacenaVrijednost);
preko povratnog parametra (return) signaliziramo pogrešku (ako je bude)preko call by reference vraćamo dohvaćenu vrijednost
int DohvacenaVrijednost);
p y jalternativa: pozvati exit() pa neka programer koji koristi DinamickoPolje popravi pogrešku u svom kodu
P02_DinamickoPolje_C_get_set
8.4.2007 16 / 46Algoritmi i strukture podataka, 2006/07.
Ozbiljan nedostatak!
naše DinamickoPolje se može iskoristiti samo za podatke tipa int!p
što ako imamo datoteku u kojoj su zapisani podaci tipa float?kako poopćiti našu implementaciju strukture DinamickoPoljea o poopć t ašu p e e tac ju st u tu e a c o o jeda se može iskoristiti za bilo koji tip podatka?
klasično rješenje u C-u – korištenje typedefj j j ypbolje (i složenije) rješenje – koristimo void * kao tip podataka u polju- programer kod iskorištavanja dinamičkog polja mora koristiti cast operatore!
Naputak: u C++ se učinkovito i programski “čisto” rješava pomoću predložaka (template)
.NET i Java – pojam genericsP03_DinamickoPolje_C_typedef
P03_DinamickoPolje_C_void
8.4.2007 17 / 46Algoritmi i strukture podataka, 2006/07.
Nedostaci sa stajališta dizajna programa
svakoj funkciji moramo prenositi pokazivač na strukturuovo je primarno sintaksni “nedostatak”ovo je primarno sintaksni nedostatakprogrameri u C-u (ali i Pascalu, Fortranu, Basicu) s takvom paradigmom “žive” već 20-ak godina ☺žive već 20 ak godina ☺
pozivi funkcija iz biblioteke su isprepleteni s pozivima drugih funkcija i sintaksno izgledaju isto i sintaksno izgledaju isto
smanjuje se razumljivost programa i i i l d idlji ti d kl i nema izravne i na prvi pogled vidljive povezanosti deklarirane
strukture i funkcija koje nad njom operirajusve dobivaju pokazivač struct DinamickoPolje *, ali će korisnici i sami definirati mnoge funkcije koje dobivaju takav pokazivač!
8.4.2007 18 / 46Algoritmi i strukture podataka, 2006/07.
Nedostaci – dio drugi
mogućnost sukoba imena (engl. name clash)što ako je u nekoj drugoj biblioteci definirana funkcija s istim imenom?što ako je u nekoj drugoj biblioteci definirana funkcija s istim imenom?koristimo hrvatske nazive za varijable i funkcije pa i nije toliki problem!
kod korištenja engleskih termina (kod izrade biblioteka funkcija bitan zahtjev ako se želi - kod korištenja engleskih termina (kod izrade biblioteka funkcija bitan zahtjev ako se želi omogućiti široko/internacionalno korištenje razvijene biblioteke) je situacija značajno gora (funkcije: initialize, setSize, cleanup ili delete )
što ako netko izravno promijeni vrijednost podatka u strukturi?definirane funkcije se oslanjaju na činjenicu da samo one izravno operiraju nad podacima u strukturi- situacija: korisnik izravno promijeni podatak BrojElem
podaci u polju se nisu promijenili ali će se funkcije drugačije ponašatipodaci u polju se nisu promijenili ali će se funkcije drugačije ponašati
- čak i ako u dokumentaciji eksplicitno piše da se to ne smije raditi, prije ili kasnije će netko to i napraviti (greškom, neznanjem, lijenošću – tako mu je “lakše”)
8.4.2007 19 / 46Algoritmi i strukture podataka, 2006/07.
Kako riješiti nedostatke? Jedan po jedan!
uvodimo pojam članske funkcije!u C u (i ostalim proceduralnim jezicima) podaci i funkcije su u programu u C-u (i ostalim proceduralnim jezicima) podaci i funkcije su u programu odvojeninije problem samo po sebi osim u slučajevima koji su slični našem!nije problem samo po sebi, osim u slučajevima koji su slični našem!- funkcije koje smo definirali za rad sa strukturom DinamickoPolje su “intimno”
povezane s tom strukturom- pitanje je kako dodatno naznačiti tu povezanost!
sintaksno – deklaraciju funkcije stavljamo unutar deklaracije strukture
time funkcija postaje “član” struktureterminološka promjena
element strukture (varijabla deklarirana kao dio strukture) postaje članska ( j ) p jvarijabla strukture
8.4.2007 20 / 46Algoritmi i strukture podataka, 2006/07.
Jednostavan primjer
struct StrukturaC {int NekiPodatak;
struct StrukturaCPP {int NekiPodatak;int NekiPodatak;
};void Funkcija(StrukturaC *s){ }
int NekiPodatak;
void Funkcija() { }}} };
int main(int argc, char* argv[])int main(int argc, char argv[]) {
StrukturaC objC;Funkcija (&objC);
StrukturaCPP objCPP;objCPP.Funkcija();
return 0;}
P04_PrimjerClanskeFunkcije8.4.2007 21 / 46Algoritmi i strukture podataka, 2006/07.
Što smo postigli?
riješili smo “problem” stalnog prenošenja pokazivača na strukturu kao parametrap
“problem” je samo prividno riješen – sada se mora naznačiti za koju varijablu (instancu strukture) se poziva funkcija
riješili smo problem sukoba imenamožemo imati funkcije istog imena, sve dok su one elementi različitih strukturai f k ij k j “di ” t kt i t k j lik j d i poziv funkcija koje su “dio” strukture se sintaksno jasno razlikuju od poziva
“običnih” funkcijakoristimo drugačiji način pozivanjakoristimo drugačiji način pozivanjainstanca_strukture.ime_funkcije(parametri)
funkcije koje izravno djeluju nad podacima u strukturi imaju izravnu vezu s u c je oje a o dje uju ad podac a u s u u aju a u e u skonceptom strukture
jasno, jer su njen integralni dio
8.4.2007 22 / 46Algoritmi i strukture podataka, 2006/07.
A kamo je nestalo DinamickoPolje *?
odnosno, kako pozvana funkcija “zna” za koju je varijablu strukture pozvana?funkciji se implicitno prenosi pokazivač this j p p p
this je pokazivač koji pokazuje na varijablu strukture za koju je članska funkcija pozvana“lokalna varijabla” za čiju se “deklaraciju” i inicijalizaciju brine prevodilaclokalna varijabla za čiju se deklaraciju i inicijalizaciju brine prevodilac
Primjer:
int DinamickoPolje::Inicijaliziraj(int inMaxBrojElem) {// implicitno korištenje this_BrojElem = 0;_
// ili eksplicitnothis->_BrojElem = 0;...
}
P04_DinamickoPolje_Cpp1_clanske_funkcije8.4.2007 23 / 46Algoritmi i strukture podataka, 2006/07.
Operator određivanja dosega (scope resolution)
pojavile su se neke dvotočke u prethodnom primjeru?
= operator određivanja dosega (scope resolution operator)
int DinamickoPolje::Inicijaliziraj(int inMaxBrojElem)...
:: = operator određivanja dosega (scope resolution operator)u C++: doseg (scope) = “mjera” vidljivosti identifikatora (varijable, funkcije, klase) u programuu našem primjeru je bitan jer njime kod implementacije funkcije j j j j j jInicijaliziraj (a i svake druge članske funkcije) naznačavamo njenu pripadnost razredu DinamickoPolje!
8.4.2007 24 / 46Algoritmi i strukture podataka, 2006/07.
Što je ostalo?
i dalje imamo problem – moguće je izravno promijeniti sadržaj varijabli u strukturi
utječemo na kasnije ponašanje članskih funkcija (najčešće s nedefiniranim posljedicama!)rješava se uvođenjem prava pristupa
korištenjem ključnih riječi i t i bli graditelj strukture može odrediti koji njen korištenjem ključnih riječi private i public graditelj strukture može odrediti koji njen dio će biti dostupan svima, a koji dio će biti dostupan samo članskim funkcijama strukture
sintaksa:
struct PrimjerStrukture {public:public:
int _JavnoDostupnaVarijabla;void JavnoDostupnaClanskaFunkcija(int Parametar);
private:private:int _PrivatnaVarijabla;float PrivatnaClanskaFunkcija();
};};
8.4.2007 25 / 46Algoritmi i strukture podataka, 2006/07.
Pristup privatnim dijelovima strukture
što se misli pod “dostupan”?može se ograničiti skup mjesta (lokacija) u programu s kojih se može može se ograničiti skup mjesta (lokacija) u programu s kojih se može pristupiti privatnim dijelovima strukture
PrimjerStrukture var;
prevodilac će kod prevođenja programa javiti pogrešku!
PrimjerStrukture var; var._PrivatnaVarijabla = 0;
- prevodilac će kod prevođenja programa javiti pogrešku!
privatnim dijelovima strukture se može pristupiti samo unutar definicije (tijela) članske funkcijedefinicije (tijela) članske funkcije
i članske funkcije mogu biti privatne!napomena: P05 PrimjerStrukturePravaPristupanapomena:
postoji i protected pravo pristupa važno je samo kod uspostavljanja hijerarhije struktura putem nasljeđivanja
_ j p
važno je samo kod uspostavljanja hijerarhije struktura putem nasljeđivanja
8.4.2007 26 / 46Algoritmi i strukture podataka, 2006/07.
Konačno – razredi (klase)!
uvodimo ključnu riječ classklasa (razred) poopćava pojam strukture iz C aklasa (razred) poopćava pojam strukture iz C-a
koja je razlika? t išt C dit lj i i t k k d t kt j sa stanovišta C++ prevoditelja primarno sintaksna – kod strukture je sve
podrazumijevano public dok je kod razreda sve podrazumijevano privateprivate
konceptualna razlika:- struktura je (ipak) namijenjena modeliranju skupa jednostavnih podataka nad kojima - struktura je (ipak) namijenjena modeliranju skupa jednostavnih podataka nad kojima
ostali dijelovi programa direktno operiraju- razred kao primarni koncept OO paradigme (prisutan u svim OO jezicima!) namijenjen
j d li j ( d t lj j ) k t i d čj bl k ji j š je modeliranju (predstavljanju) koncepata iz područja problema koji rješavamo (DinamickoPolje, Stog, HashFile, ...) koji imaju složeno ponašanje realizirano preko skupa članskih funkcija
P05_DinamickoPolje_Cpp2_prava_pristupa8.4.2007 27 / 46Algoritmi i strukture podataka, 2006/07.
Malo teorije
dva osnovna elementa OO paradigme: apstrakcija i enkapsulacijaapstrakcija razredi / objekti predstavljaju koncepte iz domene apstrakcija – razredi / objekti predstavljaju koncepte iz domene problema koji rješavamo
d Di i k P lj j t k ij k t di ičk lj razred DinamickoPolje je apstrakcija koncepta dinamičkog polja s dobro definiranim karakteristikamanije li to isto i struktura u C u?nije li to isto i struktura u C-u?- struktura predstavlja agregatni skup podataka nad kojima operiraju “vanjski” elementi
programa (funkcije)p g ( j )- vanjske funkcije nisu dio strukture – zbog toga struktura nije “potpuna” jer je za
razumijevanje koncepta koji predstavlja potrebno proučiti nešto što nije dio same definicije strukturedefinicije strukture
- struktura nije “zatvorena” u smislu da ne upravlja sama svojim ponašanjem i stanjem!modeliranjem koncepta pomoću razreda rješavamo navedene problememodeliranjem koncepta pomoću razreda rješavamo navedene probleme
8.4.2007 28 / 46Algoritmi i strukture podataka, 2006/07.
Enkapsulacija
niti jedan dio sustava ne bi smio ovisiti o unutrašnjim detaljima drugog dijeladrugog dijela
korisnika razreda DinamickoPolje ne bi trebalo zanimati kako je realizirana njegova funkcionalnost realizirana njegova funkcionalnost - napomena: koncept dinamičkog polja je vrlo jednostavan i praktički implicira način
implementacije (dinamička alokacija memorije za elemente polja), ali kod složenijih d t i k j l č j ij t k !razreda to ni u kojem slučaju nije tako!čak i kod dinamičkog polja možemo imati varijabilnost u implementacijinpr., ako je rukovanje memorijom “skriveno” od korisnika razreda, može se izgraditi l i i ( k i i i ć l ivlastiti memory-manager (ne koristimo malloc i realloc, već vlastitu
implementaciju – npr. radi efikasnosti)
postižemo deklariranjem unutrašnjih detalja razreda kao privatepos e o de a a je u u aš j de a ja a eda ao p atebudući da tada ionako ne može pristupiti tim dijelovima, korisnik razreda DinamickoPolje ne može o njima ni ovisiti (zato jer ih ne može j j ( jizravno referencirati u programskom kodu koji on piše)
8.4.2007 29 / 46Algoritmi i strukture podataka, 2006/07.
Javno sučelje razreda
sve što je u razredu deklarirano kao public dio je javnog sučeljajavno sučelje razreda predstavlja “prozor u svijet” kroz koji razred javno sučelje razreda predstavlja “prozor u svijet” kroz koji razred komunicira s ostalim dijelovima programa
d fi i j čl kih ij bli k i t d “ k i ” j t jdefiniranjem članskih varijabli kao private, razred “skriva” svoje stanjeprimjer enkapsulacije u stvarnom životu:
DVD player – javno sučelje čini par kabela i daljinski upravljač- “običnog” korisnika u biti ne zanima kako DVD player radi sve dok on ispravno reagira
na “poruke” zadane preko sučelja (Play Stop Eject )na poruke zadane preko sučelja (Play, Stop, Eject, ... )
slično vrijedi i za razrede k i ik d Di i k P lj bit j d d i za korisnika razreda DinamickoPolje bitno je da razred ima
očekivano ponašanje, a kako je unutar razreda omogućeno takvo ponašanje korisnika (uglavnom) ne zanima!ponašanje, korisnika (uglavnom) ne zanima!
8.4.2007 30 / 46Algoritmi i strukture podataka, 2006/07.
Pojam objekta
ovo je deklaracija razreda (novi tip podatka):
class MojRazred {class MojRazred {...
};
slično kao i kod struktura, razred predstavlja predložak iz kojega će se kreirati objekti!obje t
kod struktura koristimo termin varijabla strukture ili instanca strukture kod razreda se konkretna instanca naziva objektom
d j j d i j ž i t i ti i lj b j bj k trazred je jedan, a iz njega se može instancirati proizvoljan broj objekata- svi će biti “isti” u smislu da svi imaju isti skup članskih varijabli i članskih funkcija- objekti se razlikuju po vrijednostima koje imaju njihove članske varijable (te vrijednosti
d t lj j t j bj kt )predstavljaju stanje objekta)- analogija sa strukturom polje – svi članovi su istog tipa, a vrijednosti im se razlikuju za svaki
indeks polja
8.4.2007 31 / 46Algoritmi i strukture podataka, 2006/07.
Kreiranje objekata
slično kao i kod struktura, kreiranje objekta primarno podrazumijeva alociranje prostora u memoriji gdje će objekt biti smještenalociranje prostora u memoriji gdje će objekt biti smješten
odnosno, treba alocirati prostor za članske varijable razredamoguća su dva standardna načina:moguća su dva standardna načina:
smještanje objekta na stog bj kt d kl i k l k l i bj kt t f k ij- objekt se deklarira kao lokalni objekt unutar funkcije
smještanje objekta na gomilu (heap) “životni vijek” objekta nije vezan uz kontekst izvođenja funkcije već se objekt - životni vijek objekta nije vezan uz kontekst izvođenja funkcije već se objekt eksplicitno mora “uništiti” (izbrisati iz memorije)
za potrebe rada s objektima na heapu, uvode se operatori:za potrebe rada s objektima na heapu, uvode se operatori:new – operator za kreiranje objekata na heapudelete – operator za brisanje objekata s heapadelete operator za brisanje objekata s heapa
8.4.2007 32 / 46Algoritmi i strukture podataka, 2006/07.
Primjer za new i delete
class MojRazred {{public:
int _MojPodatak;};
int main(int argc, char* argv[]) {MojRazred objStog; // objekt na stoguobjStog MojPodatak = 10;objStog._MojPodatak = 10;
MojRazred *pStog = new MojRazred(); // objekt na heapupStog->_MojPodatak = 10;
delete pStog; // moramo eksplicitno osloboditi memoriju
return 0;return 0;// po završetku funkcije, objStog će se automatski // ukloniti iz memorije
}
8.4.2007 33 / 46Algoritmi i strukture podataka, 2006/07.
Brisanje polja
new i delete nisu namijenjeni isključivo za kreiranje i uništavanje objekata:predstavljaju općenitu zamjenu za malloc i realloctype safe verzija – točno se zna za kakav tip podatka se alocira memorija
primjeri:float *pFloat = new float;int *pInt = new int[10];char *pString = new char[20];p g [ ];
delete pFloat;delete [] pInt;
za brisanje polja mora se koristiti operator delete []
delete [] pString;
j p j p []
P06_Primjer_new_delete8.4.2007 34 / 46Algoritmi i strukture podataka, 2006/07.
Inicijalizacija objekta
kreiranje objekta ipak ne znači samo alokaciju memorije za smještanje objektabitno je u kakvom stanju se objekt nalazi nakon kreiranja, odnosno kakve su mu vrijednosti j j j j , jčlanskih varijabli problem inicijalizacije
javlja se i u C-u:nakon deklaracije int a; nije jednoznačno definirano kakvu vrijednost ima varijabla a
k d bj k t j t l l ž ij j ( j j t ) i j iš čl kih ij blikod objekata je stvar malo složenija jer (vjerojatno) imaju više članskih varijablikako inicijalizirati pokazivače koji su dio razreda?
rješavanju ovog “problema” kod razreda DinamickoPolje namijenjena je rješavanju ovog problema kod razreda DinamickoPolje namijenjena je funkcija Inicijaliziraj() koja dovodi kreirani objekt u ispravno stanje
a što ako kreiramo objekt i zaboravimo pozvati Inicijaliziraj()?j p j j()
pogreška pri korištenju objekta!
8.4.2007 35 / 46Algoritmi i strukture podataka, 2006/07.
Pojam konstruktora objekta/razreda
uvodimo pojam konstruktora objektaposebna članska funkcija namijenjena inicijalizaciji stanja objekta kod njegovog kreiranjaprepoznaje se po imenu funkcije – mora biti isto kao i ime razreda
sintaksa:class MojaKlasa {class MojaKlasa {public:
MojaKlasa() { ... } // konstruktor bez parametaraMojaKlasa(int a) { } // konstruktor s parametrom
Primjer preopterećenja (overloadinga) funkcije
MojaKlasa(int a) { ... } // konstruktor s parametrom};
j p p j ( g ) jimamo funkcije istog imena (u C-u nije dozvoljeno) a prevodilac ih razlikuje po parametrima
konstruktor nema povratnog parametra – ne vraća i ne može vratiti nikakav d t k k i š jpodatak nakon izvršavanja
a ako dođe do pogreške koju treba signalizirati ostatku programa – treba “baciti” izuzetak (engl. exception)( g p )
8.4.2007 36 / 46Algoritmi i strukture podataka, 2006/07.
Podrazumijevani konstruktor
Primjer korištenja:void main() {void main() {MojaKlasa a;MojaKlasa b(10);M j Kl * M j Kl ()MojaKlasa *c = new MojaKlasa();MojaKlasa *d = new MojaKlasa(10);
}
a kako su onda radili naši prethodni primjeri (bez definiranog konstruktora)?konstruktora)?prevodilac za svaki razred za koji nije eksplicitno definiran konstruktor sam dodaje podrazumijevani (engl default) konstruktorkonstruktor sam dodaje podrazumijevani (engl. default) konstruktor
konstruktor bez parametara koji članske varijable inicijalizira na neke podrazumijevane vrijednostipodrazumijevane vrijednosti
8.4.2007 37 / 46Algoritmi i strukture podataka, 2006/07.
Destruktori
definiranjem konstruktora smo “pokrili” kreiranje objekta, a što je s brisanjem (uništavanjem)?brisanjem (uništavanjem)?možemo definirati destruktor razreda
čl k f k ij k j ć i ti ilik išt j bj ktčlanska funkcija koja će se pozivati prilikom uništavanja objekta“uništavanje” objekta = brisanje objekta iz memorije
tehničkim žargonom – objekt izlazi iz dosega (engl. goes out of scope)za objekte kreirane na stogu – trenutak kada funkcija u kojoj su deklarirani završava i briše sve svoje podatke sa stogaza objekte kreirane na heapu – trenutak kad se nad njima poziva delete
ako je u razredu definiran destruktor, prevodilac će ga automatski pozvati u trenutku uništavanja objekta
8.4.2007 38 / 46Algoritmi i strukture podataka, 2006/07.
Primjer sintakse
class MojaKlasa {public:public:
MojaKlasa() { ... } // konstruktor 1MojaKlasa(int a) { ... } // konstruktor 2
//~MojaKlasa() { ... } // destruktor (jedan!)};
void main() {MojaKlasa a;MojaKlasa *b = new MojaKlasa();j j ();... // tijelo funkcijedelete b; // poziva se destruktor za b(eksplicitno)
} // prije samog završetka funkcije (return) se} // prije samog završetka funkcije (return) se // poziva destruktor za a
P06_PrimjerKonstruktorDestruktor
8.4.2007 39 / 46Algoritmi i strukture podataka, 2006/07.
Curenje memorije
isto pitanje – kako su radili naši prijašnji primjeri u kojima nije bilo destruktora?uništavanje objekta je podrazumijevalo samo oslobađanje memorije (alocirane za smještaj samog objekta) i to za to se pobrinuo prevodilacdestruktor je “glumila” funkcija Izbrisi() koja je oslobađala zauzetu memoriju
a što da smo je zaboravili pozvati?a što da smo je zaboravili pozvati?Imamo curenje memorije (memory leak) u programu – zauzeli smo resurse računala ali ih nismo oslobodili iako ih više ne koristimo“ b t” t k i l č j i ž diti i it d i “zaboravnost” programera u takvim slučajevima može voditi izrazito nezgodnim pogreškama
prednost destruktora – prevodilac će se pobrinuti da se pozove funkcija za p p p p juništavanje objekta
nakon što definiramo destruktor, sigurni smo vrijedi samo za objekte kreirane na stogu kod objekata kreiranih na heapu (pomoću vrijedi samo za objekte kreirane na stogu - kod objekata kreiranih na heapu (pomoću new) mora se pozvati delete!
- kreator objekta određuje kada će se on uništiti
P06_DinamickoPolje_Cpp3_konstruktori
8.4.2007 40 / 46Algoritmi i strukture podataka, 2006/07.
Kopiranje objekata
što je s kopiranjem objekata?npr poziv funkcije u koju se po call by value prenosi objektnpr. poziv funkcije u koju se po call by value prenosi objekt
za obične tipove (int, float, char) je to jednostavno – u funkciji se kreira lokalna varijabla istog tipa i (automatski) inicijalizira s prenesenom j g p ( ) j pvrijednošću
a što ako se prenosi objekt?
void NekaFunkcija(MojaKlasa obj) {...
}void main() {MojaKlasa a;
NekaFunkcija(a);}
8.4.2007 41 / 46Algoritmi i strukture podataka, 2006/07.
Sintaksa copy-constructora
osnovno pitanje – pomoću kojeg konstruktora se kreira lokalni objekt objprilikom poziva funkcije NekaFunkcija()?poziva se tzv. copy-constructor
a gdje je on u našem razredu? – nema ga eksplicitno, ali je prevodilac sam definirao “standardnu” (default) verzijustandardnu (default) verziju
Sintaksa:class MojaKlasa {class MojaKlasa {public:MojaKlasa() { ... } // konstruktor 1MojaKlasa(int a) { ... } // konstruktor 2M j Kl ( t M j Kl i itObj) { } // t tMojaKlasa(const MojaKlasa &initObj) { ... } // copy-constructor~MojaKlasa() {} // destruktor
};
copy-constructor se prepoznaje po svom parametru – prima referencu na objekt istog tipa koji će poslužiti kao osnova za kreiranje novog objekta
referenca = sakriveni pokazivač (detalji uskoro)referenca = sakriveni pokazivač (detalji uskoro)
8.4.2007 42 / 46Algoritmi i strukture podataka, 2006/07.
Problem s copy-constructorom
podrazumijevana implementacija copy-constructora radi samo kopiranje vrijednosti članskih varijabli iz predanog objekta u instancu kopiranje vrijednosti članskih varijabli iz predanog objekta u instancu novostvorenog objektaispravan pristup za jednostavne objekteispravan pristup za jednostavne objekte
objekti koji u sebi nemaju pokazivače na alocirane resurse (memorija, datoteke konekcije na bazu )datoteke, konekcije na bazu, ...)
neispravan za naš razred DinamickoPoljeobjekt kreiran pomoću podrazumijevanog copy-construktora će pokazivati na istu memoriju alociranu za poljenije li to ono što želimo kad Di i k P lj predajemo u funkciju?nije li to ono što želimo kad DinamickoPolje predajemo u funkciju?- NE! – od početka se radi o call by value!
ako želimo da funkcija radi s istom instancom objekta u funkciju se prenosi se - ako želimo da funkcija radi s istom instancom objekta, u funkciju se prenosi se pokazivač na objekt
8.4.2007 43 / 46Algoritmi i strukture podataka, 2006/07.
Dva načina kopiranja objekata
postoje dva načina kopiranja objekatadeep copy copy constructor se implementira tako da kreira u potpunosti deep copy – copy-constructor se implementira tako da kreira u potpunosti novu kopiju objekta- za razred DinamickoPolje to znači alociranje nove memorije i inicijalizaciju j j j j j
elemenata u tom polju s vrijednostima iz objekta predanog copy-constructorushallow copy – kreira se novi objekt, ali on nastavlja “dijeliti” određeni dio stanja s objektom na temelju kojega je nastao- za DinamickoPolje to znači da nakon kreiranja objekta pomoću copy-
constructora imamo dva objekta koji pokazuju na istu alociranu memoriju (polje)constructora imamo dva objekta koji pokazuju na istu alociranu memoriju (polje)- doći će do problema kad se pozovu destruktori za ta dva objekta
prvi poziv destruktora će proći u redu, ali kad se pozove destruktor za drugi objekt, k š j l b đ j ć l b đ ij ć k ti škpokušaj oslobađanja već oslobođene memorije će uzrokovati pogrešku
P07_DinamickoPolje_Cpp4_copy_constructor
8.4.2007 44 / 46Algoritmi i strukture podataka, 2006/07.
Reference
referenca = pokazivač s malo drugačijom sintaksomnema adresnog operatora i operatora indirekcije (dereferenciranja)nema adresnog operatora i operatora indirekcije (dereferenciranja)
prevodilac to obavlja automatskid kl ij f j fik deklaracija reference se prepoznaje po prefiksu &Primjer: P07_PrimjerReference
void main() {int a = 5;
int *pa = &a; // pokazivač pa pokazuje na varijablu aint &ra = a; // referenca ra također referencira varijablu a
*pa = 10; // varijabla a sada je jednaka 10
ra = 15; // a je sada jednako 15; // j j}
8.4.2007 45 / 46Algoritmi i strukture podataka, 2006/07.
Primjeri:
razred Trokut:izgraditi razred Trokut koji će predstavljati koncept trokuta kao izgraditi razred Trokut koji će predstavljati koncept trokuta kao geometrijskog lika koji ima definiranu duljinu svake od tri stranice i ugrađenu funkcionalnost za izračunavanje površine i opsega trokutag j p p g
razred KompleksniBroj:P08_Trokut
razred KompleksniBroj:izgraditi razred KompleksniBroj koji će predstavljati (matematički) koncept kompleksnog broja. Razred mora sadržavati dvije varijable koje će koncept kompleksnog broja. Razred mora sadržavati dvije varijable koje će predstavljati realni i imaginarni dio i pružati funkcionalnost za obavljanje matematičkih operacija s kompleksnim brojevima (zbrajanje, oduzimanje, množenje i dijeljenje)
P09 KompleksniBroj_ p j
8.4.2007 46 / 46Algoritmi i strukture podataka, 2006/07.