You are on page 1of 300

t

Misliri
na jeziku

C++
, ' ,,1:" ., :'

'Bruce Eckel
MindView, Inc.,predsednik , :i.,

Preveli
Lj ilj ana Iovanovii- Stanisavlj evii
IelenaVudiievii
Igor Marid

ffi
E
SaonZnt
Faza I: Stapravimo?.......'.........33
Faza 2: Kako Cemo izgraditi sistem? .35
Faza3: Gradimoiezgro ...... .. -....38
Stale novo u drugom izdanju ....2
Faza 4: Razvijamo sludajeve
Sta se nalazi u drugom tomu kori5denla . .... '..38
oveknjige ........2 Faza5:Evolucija ......... '.39
KakodoCido drugogtoma...'...'....3 Planiranjese ispIati......... ".......40
Preduslovi. .. '....3 Ekstremno programiranje . .' .' . 41
UdenjeC++-a. ...........3 Prvo sastavitetestove.........,....'.41
Ciljevi. ...........4 Programiranjeuparu.... ..,.....,,,,42
Poglavlja .........5 Za5toC++uspeva .......43
Zadaci ...........8 Bolji C.. .... .. .. ..43
.. ...8 VeCstenauzlaznoj liniji . ....... ....44
Relenja zadataka... . .. .. '. '.... .
Efikasnost ........44
Izvornik6d... ...........8 Sisteme je laKe opisati i razumeti . . . .44
Standardijezika.... ..... ' 9 Maksimalna dobit od biblioteka. .. . . .45
Podr5kajeziku ............10 Ponovna upotreba izvornog koda
Prateiikompaktdisk...... .. . .. I0 uzlablone. .... '. '45
Kompakt diskovi, seminari Obrada greSaka . '... .. '....45
isavetovanja ....11 Programiranje sloZenih sistema ..' .. .45
Gre5ke ..... '.. '.11 Strategije unapredivanja. . . . . . . . 46
Okoricama. .....11 Uputswa ......."46
TeSkoCeupravljanja ..... ............47
Dizajn i pripremaknjige. . . ... ..12
Zahvalnice ......13 SaZetak .........49

Razvojapstrakcije. ......16
Objekatimainterfejs ....18 Postupakprevodenja jezika. . . . . 52
Interpretatori ..............52
Skrivenarealizacila. .....19 Prevodioci. .......... " '..53
Ponovna upotreba realizaciie .. .20 Postupakprevodenja................53
Nasledivanje: ponovna Alatke za odvojeno
upotrebainterfejsa. .....2l prevodenje. .....55
Relacije,je"i,,ie-kao" .......24 Deklaracije ili definiciie.............'55
Zamenljivi objekti Povezivanje. .............'59
i polimorfizam.... .....25 Upotreba biblioteka . . . . ..... ... .....60
Inicijalizacija i uni5tavanje VaSprviC++ program .... ...... 61
objekata ........28 Upotreba klasa ulazno-izlaznih
Obrada izuzetaka: tokova.. ..........61
Imenskiprostori ....... . .62
radsgre5kama...... ....29 Osnorma struktura programa... ......63
Analizai projektovanje . .. . .. . ..30
..
,,Zdravo, svete!" ...... ...il
FazaO:Pravimoplan ..... ...,.... ..32 Prevodenje ... '...65
ViSe o Lrlazno,izlazninr
Definisanje raspodele
tokovirna .65 rnemorijskog prostora.
Program make: upravljanje Klase . ......... 193
\P,rj:rrrjr rrrzr zn.rlr^,r . . . . . . . . 103 prevodenjem ...144 Upravljanje pristupom
( tt,tttjr,'.r rrl,tzrtrrg 1,rl;1
. . (i5r Cilobalneprornenljive .....104 Staradimake? ............145 dinamidkom nizu .... .....196
. . . .66 Lokalnepromenljive ...............105
l\rzivarrjt.rinrglh prograrna . Datoteke makefile koriSiene Kontrola pristupa steku......
Rezervis.rnareastatic. .....105
.
. .67
knjizi. Klaserudki
.

Klrra slrirrg. .67 Iiezervisanared{txtern..............107


u ovoj .. .. .l4B .....197
l.lditavanje iz datoteka
Primerdatoreke makefile ...........148 Skrivanjerealizacije .......198
Konstante .......108 SaZetak ........150
i r:ltisrvarrjr' u lliil) Oznaka volatile
Optimizacija prevodenja............lgu
. . 6rl ..... ......t09 VeZbe. ......... SaZetak
Klasa r t,t.tor Operatori i njihova Llpotreba. I50 . .... ...200
.70 . I10
SaZetak I)orleljivanje.
.
.............1t0
VeZbe. .........200
Materlatidki operatori 4: Apstrakcija podataka 155
VeZbe .
............. . l l0
Operarori poredenja. ......1 ll 6: Inicijalizacija i diSienje
Iedna mala biblioteka
3:CuC++-u 7Z
Logitki operatori...................u2
Operatorinadbitovima.............I12
najezikuc ..... ....... 156
memorije 203
Operatoripomeranja ......Ii3 Dinamidko zauzimanje memorije . . .159
Pravljenjefunkcija . ....78 Garantovana inicijalizacija
Losepretpostavke..................163
Rezulrari funkcija . .........79
lJnarnioperatori.....,.............ll5
Stanijeuredu? ........164 konstruktorom.... ....2O4
KoriSienje biblioreke O funkcija .. . ...U0
Ternarnioperator .........116 Garantovano diSienje
Izrad:r hihlioteka pr)n)()ill pr()grat)la
Operatorzarez ...........,116 Osnovniobjekat .......165 memorue destruktorom . . . ... . 206
za uprarllanje bibliotekama.
Uobidajene zamke pri kori5ienju Stajeobjekat? ..... ....t70 Eliminisanje bloka definicija. . .2OB
. ... .. ...81 operatora.
Llpravljanje izvr(ar.3l1jsp. . . . . . . BI .......117 Apstraktni tipovi podataka.
Operatorizakonverziju.............llg
. . . . 171 Petljefor. ........209
'Iatno
i rretadno ............82 Izriiitekonverzije u C++-u..........11g
Detaljiobjekata. .......t21 Dodeljivanjememorije.............210
Iskazif-else . ...82 IIr2pfip6;operarorsizeof. Pravila rada s datotekama Dinamidki niz s konstruktorima
..........122
Iskazu'hile. .......U3 Ilezervisanareiasm. ......122 zaglavlja .......173 i destruktorima . . . . . . . . . . . . . . . 2l l
Iskilztlo while .............84 Izriaitioperatori ...........lZ3 Znahjdatoteka zaglavlja. . . . . . 173 Stek s konstruktorima
Iskazfor ..........ti,l Formiranje sloZenogtipa . . . . .. l2g Problem vi5estruke deklaracije . . . . . .t74 i destruktorima. . . . . . . .. . . . . . .2L4
RcTor\i\dr)c reci Itre;rk rr olrtil.ttre.....g5
Iskazswitch. ......g6
Dodel jivanje pseudonima
pomoiurypedef
Pretprocesorske komande
#define,#ifdefi#endif ..............I75
Grupnainici.jalizacija . ........2t6
tJporreba i zloupotreba
..........123 Podrazumevani konstruktori. .. 219
Kombinovanje promenljivih Standard za datoteke zaglavlja. ... . ..176
rezeruisanereii goro ....... u strukture. -.....L24 Imenski prostori u zaglavljima ......172 SaZetak ........220
Rekr: rzija .......88 Pisanje jasni.jih programa Korisienje zaglavlja u projektima. . . .177 VeZbe. .........220
Ilvod u operatore .....89 pomoiuenum
I'rioritor
............127 UgneZdenestrukture ...177
.
......t]9 lJ5teda memorije pomoiu unija. . . . ,l28 Razre5avan.je globalnog opsega. . . . . .18I 7: Preklapanje funkcija i
Ii\er rnJ(. i rrnlut1t.lt]t, ...... .... ..
Iivod
..89 Niz-ovi .........I29 SaZetak .... .... t8l podrazumevani a-rgum enti 223
rr ripove podaraka .. .....90 Saveti za pronalaZenje
YeZbe. .........t82
O\n,,\ili llgr;t(lelrr tipr;r1
-l
. .. ..90 gresaka . . .. ....138 Jo5 pone5to o obele2avanju
ip lrool, r.rednosti rrrre i falst.
\l)('( rltk.rtiln
.......1)l Irrdikarori za pronala2enje greSaka. . . I38
5. Skrivanje realizacije I85 imena. ........225
I)rctvaranje tr znakome nizove ......140 Preklapanje na osno,vrl
I h'rrl u pok,rzir,rir.. ... . .93 Makro asserrO ..... ...... .l4l Postavljanje ograniaenja. . l86 tipovarezultata ...........226
I)tr)nt(,n.1 \l)()lJl)()*
ol)iIkt,l ....9(; Adresefunkcija ........141 Bezbedno povezivanje ............. .226
l)r,rd rr( ., t(,lercn(.p .... Kontrola pristupa
Ihkazivac.i i reference
Definisanje pokazivaia
u jezikuC++... ........186 preklapanja . .. .227
Primer
na funkcije ......I4I Unije. .........230
kao ntodifikatori...... . .99 Komplikovane deklaracije Specifikator protected . . . . . . . . . . . . . . IBB
OblastvaZenja...... t01 idefinicije .......142 Prijateljistrukture. .....188 Podrazumevani argumenti .... 233
lJsltutno definisanje promenllivilt . 102 KoriSienje pokazivaia na funkcije . . . I43 UgneZdeniprijatelji ................I90 LaZniargumenti ..........234
Nizovr pokazivaca na funkcile..... ..143 Dali je C++,,iist" jezlk? .............193 Sta izabrati: preklapanje ili
Raspored obl'ekata strukture . . . 193 podrazumevane argumente?. . . 234
SaZetak ... .....239
VeZbe. .........239
Misliti na jeziku C++ Sad r2

B: Konstante Pobolj5ano otkrivanje Operatori new I delete


241 I 2: Preklapanje' OpgratoI4' 357
gresaka ........29I zanizove. .. -...421
Zamena vrednosti. ..242 SaZetak Pravljenje pokazivada nalik na niz .421
........293 Na Sta treba obratiti paZnju ' . . .358 ..

Xonstante u datotekama
VeZbe. .........294 Sintaksa. ....."358 Nedostatakmemorije ........ . 422
zaglarlja. . . .243
Operatori koje moZete Preklapanj e oparatora new
Bezttednosrrc konstantt: ....,... . . .243
........423
(inrpr'. . . . . .244 10: Upravljanje imenima Zg7 preklapati . '....360 idelete.
Razlike rr odnosrr na jezik (i Unarnioperatori..........'........360 Preklapanje globalnih oPeratora
.... . . .241r
Pokazivadi.
.
Statidki elemenri iz jezika C . . . . 298 UveCanje i uman.ienje rT ednosti . . . . .364 newidelete. .....424
. .246 PreklaPanje oPeratora new
Pokazivarli na konst:lttc ........ Statidke promenljive u funkcijama. . .298 Binarni operatori'....... .. '.. .. . . .364
aAl
lJpravljanfe povezivanjem ..........3OZ Argumentiirezultati.....'.........'375 i deleteuklasama....... ....... -...425
Xorrstarurrr pokazivaci . . .247 Preklapanje oPeratora new
......... Ostaleklaseza sme5tanje...........304 Neobidni operatori..... ... -........377
Dodela i provera tipova . . .248
Imenskiprostor. .......304 nizove
i delete za ..... . . , "428
Operatori koje ne moZete
Argumenti funkcija i rezultati , .249 Pozivan.iekonstruktora........'....430
Pravljenje imenskog prostora . .. . . ..304 preklapati .......384
Prosledivan je po konstantno, Operatori new i delete
rtcd nosti . . . .?49
KoriSienjeimenskogprostora.......306 Operatori koji nisu za specijalno sme5tanje ........ ...43I
\Iraianje konstantne r,retlrt0sti . . . . . .250
Pravila za koriSienje imenskih funkcije dlanice .......385 SaZetak ........432
prostora. ........311 Osnormesmernice .................387
Prosledivanje i r.raianje adresa .. .. 2s2
Statidkidlanovi ........311 VeZbe. .........433
Klase. . )qc Preklapanje dodele. .. . -387
Deflnisanje skladiSta za staridke Pona5anie operatora dodele (=). . '. ' .3BB
I\on\tante tr klasanta
\Irednosti u klasanta koje str
. .255
dlanove. .........3I1 Automatska konverzija
t*rWasledivurtje i slaganie ,,435
llgneZdene i lokalne klase...........315 .........397
knlt,lalilrte rr tokrr prer',rderrj:r. . .. ..2s8
Zavisr.rost statidkih objekata . . . 3lB
tipova. Sintaksaslagania ......436
Kolrstlrlrri objelti i hrnkcrje Konverzijakonstruktorom ........'.398 -.. .. 437
ilanicc Reienje problema . . . . . . . . . . . . . . . . . .3t9 Sintaksa nasledivania . . ..
. . .2ti I Konverzijaoperatorom...........'.399
Rezerviratta rec vrrltrt rlt, .26s Alternativno povezivanje ......325 ...... .401 Lista za inicijalizaciju
Primerkonverzijetipova...
Sa7-etak .266 SaZetak ........326 Zamke automatske konverzije
ukonstruktoru ..... ...439
VeZbe. tipova.. -......402 lnicijalizacijaobiekata dlanova'....'439
VeZbe . .267 .........327 ..
SaZetak ........405 Ugradeni tipovi i liste
..........440
za inicijalizaci.iu
9: Umetnute funkcije 271 11 : Reference.i konstruktor veZbe. .........405
Kombinovanje slaganja
zakopiranje , . , 33I "'441
Zarnke pretprocresora. . . .. . . . ..272 l3lDinamrko'sftii e:,,,,,.^^'"Tl:Si:il|l,*i;;.;;;*"
Kontrola pristupa u rnakroima .. -...275 Pokazivadi u jeziku C++. . . . . . . .332
Umetnutefunkcije .....275 Reference u jeziku C++ ... ... . .332 skivanjeimena ' ""''444
lIrretnutefunkcijeuklasama .......276 Referenceu funkcijama.............333 Pravljenjeobjekata. ....4I0 Funkcije koje se ne
Pristrrpnt,tirnkcijt:. ........277 Saveti za prosledivanje c-ov pristup dinamidkoj
lJmetnute funkcije argumenata .....335
Operatornew. ......... -..412 Nasledivanje statidkih funkciia
u dinamidkom nizu i r-r steku . . .282 Konstruktorza kopiranje . .. . . . 336
operatordelete ....'......413 dlanica "45I
lJmetnute funkcije Prosledivanje i waianje
iprevodilac. ....286 powednosti .....336 Iednostavanprimer................413 slaganje ili nasledivanje.... '..451
Konstruktorzakopiranje............34I Nedostaciupravljanja Podtipovi """'452
Ograniienja .. .. .286 memorijom. .....414 Privatnonasledivanje "'-""'' 454
Podrazumevani konstruktor
Isturenereference....... ...........297
Skrivene aktivnosti u konstnrktonr
z.akopiranje .....345 Doradaranijihprimera........4l5 Za5tiienipristup. """456
idestruktoru. ZaobilaZenje konstruisania .415
Delete void* ie verovatno gre5ka . . . . Preklapanje opelatora
.............ZB7 kopiranjem
lasnijepisanje..... ......342 ObaveznodiSienjepomoCu i nasledivanje .........457
....288 Pokazivadi na elanove. . . . . . . . . 349 pokazivada ..., .
neke osobine : il: Visestrukonasledivanje.......45B
JoS F-unkci.je. ........350 PokazivadiiklasaStash ...... .....416
pretprocesora .........290 SaZetak ..... ...353 Iedantest. .:..............;i; Postupnirazvoj' "" "459
Nadovezivanje znakorrtilt rrizova . . . .290
VeZbe. .........353
Misliti na jeziku C++ Sadr2aj xlll

Svodenjenavi5e. .......45g Preklapanje operarora. ... . . . . . 505 Kori5ienje imenskih prostora . .568
ZaSto,.svodenjenavlse,,?. .........460 SvodenjenaniZe .......507 C:,Pleporudenaliteratura 581
honstruktor za kOpirarrle
Kori5ienje funkcija require( )
isvodenjenavise,. ........4tjl SaZetak ........509 i assureo...... ........568 Op5teojezikuC++ .....582
Slaganje ili nasledivanje ponovo . . .463 VeZbe. .........510 Spisakmojihkniiga.................5B2
Svoden je naviie pokazivai:a B: Vodid za programiranje Detaljiitajne. .........583
irefererrr:i .......4tj4 16: Uvod u Sablone na C++-u Analiza i projektovanje .. . . . . . . 584
Problenti 515 569
......465
SaZetak .......465 Kontejneri .....516 IezikC .........582 Indeks 587
VeZbe. .........465 Potrebazakontejnerima............5lg
PregledSablona. .......518
15: Polimorfizam i virtuelne Resenjeprimenom Sablona .........520
funkcije SintaksaSablona. ......52I
469 Definicije funkcija koje nisu
.......470
Razvoj C++ programera. umetnute. ... . ...522
Klasa IntStack kao Sablon . . . . . . . . . . .524
SvodenjenaviSe. .......471 Konstanteu Sablonima.............525
Problem. .......472 Klase Stack i Stash
Povezrvarrjepozrr.a frrrrlr.ije .........472 kao Sabloni
Virtuelnefunkcije ......47Z ....527
Sablon dinamidkog niza
ProSirivost .......474 pokazivada .. ....52g
Kako C++ realizuie kasno ProblemvlasniSfva. ....534
povezrvanle .476 SmeStanje objekata
Cuvanje informacije o
Grafitki prikaz rartuelnih funkcija
tipu.. .. .. povrednosti ...536
Iza scelte
. .478
. .480
Uvoduiteratore .......538
Inicijalizacija pokazivaia W)'IR . . . . .481
Steksiteratorima ..................546
Objekti se razlikuju ..481
Sablon PStashs iteratorima .........549
Za5to virtuelne funkcije?. . . . . .482 Zastoiteratori? ..... ...554
Apstraktne osnovne klase Sablonitunkcija ...........557
i potpuno virtuelne funkcije .483 SaZetak ........55g
Potltuno virtuelne de6nicije. ..
.

.. . , .486
VeZbe. .........558
Nasledivanje i tabela WABLE .487
Presecanjeobjt:kra .......... .. . .490
A: Stil pisanja programa '561
Preklaparr je i redcfirrisarrje. .
I'r,,rrrt,r rllivi t t1l rezrrltlt,r
. .491 Op5tapravila ...562
Virtuelne funkcije
..493
Imenadatoteka..... ...563
i konstruktori Oznake za podetak i kaj
...4g5 komentara
Redosled poziva konstruktora.......496 .....563
PonaSanje urruelnih fu nkcija Zagr ade, vitidaste zagr a de
u konstruktorima . . . . . . .. . . . . . . . . . .49tj i uvladenje .....564
Destruktori i virtuelni. Imenaidentifikatora ...567
destruktori .....4g7 Redosled ukljudivanja
Potpunovirtuelnidestruktori .......199 datoteka zaglavlja. .....567
Virtuelne funkcije u destrrrktorinta . .ir00
ZaStita od ukljudivanja
Formiranje hijerarhije zasnovane
naobjektu .......501
u datorekama zaglavlja.. ...... 568
,i:

J.. :.tl
lvr tslttl na JeztKu L++ rr cu9uvur

(.++ .c r.rr.2ete posrratrati sam. kao skup svojstava, jer neka svojstva
smisla sama za scbc. L)elove moZete kombinovati iskJjudivo ako razmisljate o
nemaju Kako doii do drugog toma
Elektronsku verziju drugog toma knjige Misliti na ieziku c++, na engleskom
projekttL, a ne samo o pisanju programa. Da biste na ovaj nadin razumeli c++,
jeziku, naii iete na mojojWeb lokaciji www.BruceEckel.com. Na ovoj adresi naii
morate razumeti probleme c-a i programiranja uopste. ova knjiga razmatra pro-
iete i podatke o odekivanom datumu objavljivanja konadne verzije toma 2.
gramerske probleme, objasnjava zasto predstavljaju probleme i kako se na jeziku
Ova Web lokacija sadrZi i izvorni k6d primera iz oba toma, kao i izmene i
c++ pristupa njihovom resavanju. Zato (e skup moguinosti koje objasnjavam u
informacije o drugim seminarima na CD-ovima kompanije MindView.
svakom poglavlju biti zasnovan na mom nadinu posmatranja konkretnog tipa
problema. Nadam se da iu vas na ovaj nadin, postepeno, dovesti od razumevanja
(l-a do tadke Lr kojoj principi c++-a postaju vas prirodni nadin razmisljan.l'a.
U potpunosti iu se drZati stava da ditaoci treba da izgrade misaoni model koji
Preduslovi
U prvom izdanju ove knjige, pretpostavljao sam da ste od nekog drugog naudili
omoguiava shvatanie ovog jezika sve do nivoa masine; ako naidete na teZak
C i da bar lako ditate k6d. Usredsredio sam se na pojednostavljenje onoga sto
problem, biiete u stanju da ga unesete u svoj model i izvedete odgovor. sam smatrao teskim: jezika C++. U ovo izdanje sam dodao poglavlje koje brzo
Pokusaiu da vam prenesem saznanja koja su reorganizovala moj um tako da
uvodi u C, uz seminar na CD-u, ali i dalje pretpostavljam da vei imate progra-
sam podeo da ,,mislim na jeziku C++".
mersko iskustvo. Osim toga, kao Sto intuitivno udite nove redi stranih jezika kada
ih vidite u odredenom kontekstu u romanu, moguie ie puno nauditi o c-u iz pri-
Sta je novo u drugom izdanju mera u knjizi.
ova knjiga ie terneljno preradeno prvo izdanje i odraZava sve promene koje su
uvedene u c++ po dovr5avanju standarda i sve ono sto sam ja naudio posle
pisanja prvog izdanja. celokupan tekst prvog izdanja je ispitan i preriden.
Udenje C++-a
Svoj put u C++ prokrdio sam sa iste pozicije u kojoj odekujem da se nalaze mnogi
Ponekad su uklon jeni srari primeri, desto su izmenjeni postojeii primeri i dodati
ditaoci ove knjige: programer s neposrednim, praktidnim stavom prema pro-
novi, a dodati su mnogi novi zadaci. Znadajno preuredenje i promena redosleda
gramiranju. Sto ;e loS te1e, pre toga sam se bavio programiranjem hardvera, u
izlaganja odrazavaju dosrupnosr boljih alatki i moje bolje razumevanje nadina
kome se C desto smatrao jezikom visokog nivoa i neeflkasnim preterivanjem u
na koji ljudi ude c++. Dodato je novo poglavlje, koje predstavlja brzi uvod u kon-
manipulaciji bitovima. Kasnije sam otkdo da dak nisam bio ni narodito dobar c
cepte jezika c i osnovne moguinosti jezika c++, za ditaoce bez predznanja c-a
programer. Krio sam da ne poznajem strukture, funkcije malloc( ) i free( ), set-
neophocinog cla bi raztrmeli ostatak knjige. prateii cD sadrZi seminar, jos pos-
jmp( ) i longjmp( ) i druge ,,napredne" koncepte, beZeii posramljeno kada se u
tr.rpniji uvod u programiranjc na C-u, sto je neophodno za shvatanje c++-a (ili
razgovoru dode do ovih tema, umesto da tragam za novim saznanjima.
Iave). Pripremio ga je Chuck AIIison za moju kompaniju (Mind View Inc.), a
Kada sam se uhvatio u ko5tac s jezikom C++, jedina pristojna knjiga bila je
naslov je Thinking in c: Foundations for Jaua and c++ (Misliti na c-u: osnoue
,,vodid za strudnjake"l - barem ju je tako naslovio njen autor Bjarne Stroustrup -
Jaue i C++-a). Seminar uvodi korisnika u aspekte c-a neophodne za prelazak na
tako da sam morao sam sebi da razjasnjavam osnovne koncepte. To je dovelo do
c++ ili Javu, bez ulaZenja u teske detalje kojima se c programeri svikodne'rmo
moje prve knjige o C++-u,2 koja je u suStini bila ispovest o sopswenom iskustvu.
bave, ali nisu bitni za programere na jezicima C++ i Java.
Bila je organizovana kao vodid za iitaoca, namenjena istowemenom uvodenju u
Kratak odgovor na pitanje: ,,U demu se razlikuje drugo izdanje?,, glasi,,ono Sto
C i C++. Citaoce su odu5evila oba izdanja ove knjige.r
nije sasvim novo, preradeno je, ponekad toliko da ne prepoznajete prvobitne
Otprilike u weme kada je objavljena knj iga Ilsing C++, podeo sam da predajem
printere i materijal".
ovaj jezik na seminarima i prezentacijama. Podudavanje C++-a (kasnije i Iave)
postalo je moja profesija; Sirom sveta sam od 1989. gledao publiku koia klima
Sta se nalazi u drugom tomu ove knjige glavom, bezizraiaina lica i s nerazumevanjem. Kada sam podeo da obudavam
Upotpunjeni srandard c++-a dodao je i vise novih znadajnih biblioteka, koje man;'e grupe unutar preduzeia, na veZbama sam doSao do jednog otkdia. eak i
obuhvataju klasu string, kontejnere i algoritme standardne c++ biblioteke, kao one koji su se smeSkali i klimali glavama zbunjivala su mnoga vaZna pitanja.
i Sablone. Napredne reme su prebadene u drugi tom ove knjige, ukljudujuii Tokom visegodisnjeg organizovanja i predsedavanja odsecima za C++ i Iar'u na
ivaina pitanja kao sto su visestuko nasledivanje, obrada izuzetaia, obrasci pro- Konferenciji za razvoj softvera, otkrio sam da smo i drugi govornici i ja teZili da
jektovanja i reme o izgradnji i otkrivanju gresaka u stabilnim sistemima. pruZimo odredenoj publici Sto vi5e informacija za Sto kraie weme. Usled razlika u
nivou znanja publike, odnosno nadina izlagania materijala, do kraia bih izgubio

I Bjarne Stroustrup: The C++ ProgramminS Inngnge, Addison-Wesley, t 986. (prvo izdanje)
2 UjlngC++, Osbome/Mccraw-Hill, 1989.
3 Using C++ i C++ htside & Out, Osborne/Mccraw-Hill, 1993.
4
Misliti na jeziku C++ Predgovor 5

de, publike. Mozda ]e to previse


zahter..no, ali kako imam otpor prema tradicio_
nalnirn predavanjirna (verujem da je, u veiini sludajerr, 5. Usredsredi svaki odeljak tako da weme potrebno za lekciiu i razmak izmedu
oiul ffir posredica veZbanja bude prihvatljiv. Time se odrZava aktirmost i paZnja publike tokom
dosade), hreo sarr da svima odrZim paZnju.
Neko vrcme sam organiz-ovao viie .uriiaitih izlaganja seminara sa veZbama, a ditaocu se pruZa bolji oseiaj Sta je savladao.
u prilidno kratkom peri- 6. Obezbedi ditaocima dobru osnovu, tako da dovoljno dobro shvate vaZna
odu Tako sam na kraju uiio kroz eksperimente i ponavijanje (ista
tehnika je pitanja, kako bi pre5li na sloZenije kurseve i knjige (konkretno, drugi tom
sasvinr prirlenljiva i na projektovanje programa).
Na kraju sam razvio stil ove knjige).
pori.cavanja koristeii sve sro .r'.,.,, no,iiio k.oz svoje
i.t".t* prJavada. prob-
lem ucenja se savradava r.r posebnim, lako svarljivim
koracima, a na seminaru sa Poku5ao sam da izbegnem verzije C++-a konkretnih proizvodada, po5to mis-
veZbama (savrsen naiin udenja) postoje zadacikoli
p*,""r..-iri"ganle. Infor_ Iim da pojedinosti odredene reaiizacije nisu toliko vaLne za uienje koliko sam
macije o mojim javnim seminarima naii iete na adresi
www.Brucebcker.com, a jezik. Dokumentacija veiine prevodilaca je sasvim odgovarajuia z-a uvod u
tu moZete nabaviti iseminare na CD_ovima. njihove specifldnosti.
Prvo izdanje ove knjige.razvijano je dve godine,
a obuhvaieni materijal je
testiran u praksi, u vise obrika, na mnogim razriditim
seminarima. powatne
informacije koie sam dobijao sa svakog r.I-inu.u pomagare
r, -iau menjam i Poglavlja
reorga,izuiem ovaj rnaterijal, sve dok nisam stekao utisa"k C++ je jezik u kome su nove i drugadiie moguinosti izgradene povrh postojeie
da je p;.;o pogodno
srcclstvo z-a podrrdava.je. Medutim, ovo nisu samo
beleske sa sintakse. (S obzirom na ovo, naziva se hibridnim objektno orijentisanim pro-
ia. sarn da na ove srranice smesrim sto vise informacija i d. ih seminara; poku- gramskim jezikom.) Posmatrajuii kako ljudi ude ovaj jezik, stekao sam oseiaj za
,;;;;irujem tako
cia vas vodedr sredeie teme. Knjiga je, pre svega, zamiSljena tako da posruzi nadin na koji programeri prolaze kroz nivoe moguinosti jezika C++. Zbogtoga
pojedincu koji se bori s novim progiamskim jezikom. Sto to deluje kao prirodno napredovanie uveZbanog proceduralnog nadina
misljenja, odludio sam da sledim istu putanju i podstidem proces postavljajuii i
odgovarajuii na pitanja koja su se pojavljivala dok sam udio jezik ili su stizala iz
C ilj evi publike dok sam taj jezik predavao.
Ciljevi ove knjige su da: Ovaj tedaj je organizovan sa jednom stvari na umu: da se racionalizuje proces
1 . lz'loi-i materijal u pojedinadnim jednostavnim udenja c++-a. Powatne informacije od publike pomogle su mi da razumem koji
koracima, tako da ditarac su delovi bili teski i zahtevali dodatno objasnjenje. Shvatio sam sledeie: ako pre-
lako moZe da savlada svaku ideju pre nego Sto prede
na sledeiu.
2' Predstavi Sto jednostavnije ikraie primere. ovo rhe ambiciozno ukljudite veliki broj novih moguinosti, morate ih sve i objasniti, da
desto spredava da se studenti ne bi bili zbunjeni. Rezultatje da sam uloZio veliki napor da uvodim Sto
bavim problemima iz ,,stvarnog sveta,,, ali sam otkrio
aa potet.,ici;r;"o manje novih osobina odjednom, a idealno je da postoji jedan osnormi koncept
viSe vole da razumeju svaki detalj jednog primera
nego da budu impre_ po poglavlju.
sionira.ni opsegom probJema koji on re5iva. Osim
tola, po.,of offino Cilj svakog poglavlja je da obradi jednu temu ili mali broj povezanih tema,
ograniden je kolidine koda koji se moze usvojiti
u ueio"nici. z-"tJ p"""i"a tako da ne zavise od bilo kakvih dodatnih moguinosti. Na taj nadin svaki deo
rlobijam kritike za koriSienje.,,primerar,aigru,,, ali .u-
rp."_u., i" if-, p.i moZete usvojiti pre nego Sto krenete dalje. Da bih to postigao, pominjem neka
hvatim jer smatram da su pedJgoSki opraviani.
svojstva jezika C duZe nego Sto bih Zeleo. Korist od ovog pristupa je Sto vas
3 Pazljivo rasporedi izlaganje moguinosti jezika, tako da ne vidite nesto neiete zbuniti upotreba svih moguinosti c++-a pre nego Sto budu objasnjene,
cemu niste ranije bili izloZeni. Nararmo da to nije
uvek moguie, , tako da ie uvodenje u jezik biti postupno i odraZavaie nadin na koji biste samo-
situacijama biie dat saZet uvodni opis. ""ru_ stalno usvajali ove moguinosti.
4. Prui.i ditaocima podatke o jeziku koje smatram Sledi saZet opis poglavlja obuhvaienih knjigom:
vaZnim, a ne sve Sto ja
znam. Verujem da postoji ,,hijerarhija znaiaja informacija,,,
u portol. i Poglavlie 1: uvod u objekte. Kada su projekti postali previse veliki a njihovo
iinjenice koje 95 procenara programera nikada neie morati
da zna i (oje odrZavanje suvise komplikovano, nastala je ,,softverska kriza", a programeri su
bi ih samo zbunile i navele da pomisle da je C++ srrlse
stoZen. E;;
iz (l-a: ako naudite napamet tabelu prioriteta operatora (lidno ;;;" govorili: ,,Ne moZemo zawsiti projekte, a i preskupi su!" To je izazxalo niz odgo-
je nisam vora koji se razmatraju u ovom poglavlju, uporedo sa idejama o objektno orijen-
rrikada naudio), moZetc ve.to pisati iziaze. Ali,ako yimorate
d; ;;;;;Ifi" tisanom programiranju (OOP) i kako bi ono moglo resiti sofWersku krizu. Ovo
o tome Sta ti izrazi rade, onaj ko dita/odrZava k6d
biie zbunjen. Z;;;;;" poglavlje vas vodi koz osno'rne koncepte i moguinosti OOP-a i uvodi postupke
ravite prioritcte i koristite zagrade ako vam stvari
nisu ,u.ri-;urn". irti analize i projektovanja. Saznaiete i prednosti i zna(ai usvajanja ovog jezika i
stav ie bi ti t auz'et i Lr pogledu ne-kih informacija
o c++-u, za kojemislim da preporuke zaprelazaku svet C++-a.
su vaZnije projektantima prevodilaca nego programerima.
Misliti na jeziku C++ Predgovor

Poglavlje 2: pravrienie i upotreba objekata.


ovo poglavrje objasnjava proces kako se znadenje redi const razlikuje ako se koristi u klasama i izvan njih i kako u
izgradnje p.rograrna ponroiu prevodiraca
i biblioteica. p.#,Ji;'.:;p-rvi c++ weme prevodenja napraviti konstante unutar klasa.
prograrn u knjizi i pokazuje se kako se pisu
i prevode programi. luti. !" uuoo"
rcke orl osn.v.ih bibrioteka obj"krta, ciostupnin Poglavlie 9: Umetnute funkcije. Pretprocesorski makroi uklanjaju suvisne
u c+* u'-raJ-r,ii.,"i"ao uu;u pozive funkcija, ali pretprocesor zaobilazi i dragocenu proveru tipova iezika
owrg poglavlia, biie vam prili-no jasno sta
znadi koristiti gotore Uiltioteke obje-
kata prilikorn pisanla programa na jeziku C++. Umetnuta funkcija pruZa sve prednosti pretprocesorskog makroa i sve
C++.
Poglavlje 3: c u c++-u. ovo p.glavlje daje prednosti pravog poziva funkcije. Ovo poglavlje detaljno istraZuje realizaciju i
sazeti pregled osobina c-a koje se
koriste u c++-u, kao iviseosnov'ni[ n-,ogrcnnJdostupnih upotrebu umetnutih tunkcija,
samo u c++-u. pred- Poglavlje l0: Upravljanie imenima. Deflnisanje imena je osnovna akti'r-nost
stavljam i pop,raran .srr-rzni.pr,gram make
koji se koiisti prurry*j" ilwsnih
verzija svih primera navedenih Lr lnjizi (izvorniidd u programiranju, a kako projekat raste, broj imena moZe postati prevelik. C++
primera^ ir-ou" i..r;ig., ao.tr-
pan na adresi uttLtrrt.rJntceEcker.com, sadrzi vam omoguiava prilidnu kontrolu nad imenima, pa moZete upravljati
cratoteke makefile ru ruJ"ipTgrrur;.1.
Poglavlje 3 prctposravrja da imate soricrne
osnove iz nekog pro.Jr.ur,io'i;.r,tu,
definisanjem, vidljivo5iu, sme5tanjem u memoriju i povezivanjem. Ovo
kao st. su l)ascar. (.. r-:ak i neke verzije llasica (ako poglavlje pokazuje dve tehnike upravljanja imenima. Prvo, rezervisana red static
ste u tom jeziku napisali mnogo
k.da, nar.r.iro tu.kcija). se koristi za kontrolu vidljivosti i povezivanja, a ispituje se i njeno specijalno
.Af9
procletc kroz serninar 't'h.irtking
vam l" oro pogtrrlje prete.lo, p.ro-6i *"Uufo Ou znaienje u klasama. Mnogo korisnija tehnika za upravljanje imenima u global-
in i koil ie nalazi na priloZenom CO_riao.tr- nom opsegu jeste kori5ienje rezervisane redi namespace, koja omoguiava da
pan jc i na u,rrtrt,.llrttcel,ckel.com\.
Poglavlje 4: Apstrakcija podataka. Veiina svojstava C++_a odnosi globalni imenski prostor podelite u posebne oblasti.
prar ijen jc nrvih ripova podhtaka. fo se na Poglavlje 1l: Reference i konstruktor za kopiranje. Pokazivaii jezika C++ su
omoguiuje hoiju organiza.i;, toau i por,-
avlja osnove naprednijih moguinosti ciop-u. slidni pokazivaiima jezika C, uz dodatnu prednost stroZe provere tipova u C++-u.
Videieie kako se ova ideja C++ obezbeduje i dodatni nadin rukovanja adresama: izAlgola i Pascala preuzima
prime njrrje jednosravnim snres.tanjem
frrnkcija u strukture, kako mozete praviti
no'e ripo'e i kakav kod se crobija. Llpoznaiere referencu koja prepuSta prevodiocu rad s adresama dok vi koristite uobidajeni
i najborji nadin
organizovanja
koda u,daroteke zaglavlja i datoteke .eatizaciye. - zapis. Susre5iete se i s konstruktorom za kopiranje, koji odreduje nadin
Poglavlie 5: skrivanie rearizacije. MoZere preno5enja objekata po vrednosti u funkcije i iz funkcija. Na kraju se razjadnjava i
odruditi da neki podaci i funkcije u
strr'rktLrri-.brrd. nedostLrpni korisniku novog C++-ov pokazivad na dlan.
'tb tipa tako Sto iete ih proglasiti pri-
varnim. znadi da moZerc odvojiti reatizaliyu od interfelsa Poglavlje 12: Preklapanie operatora. Ova moguinost se ponekad naziva
klijent i tako omog,iiti jednostavnu izmenu'rearizacije
tllirii;;;;;rr".. ,,zasladivad sintakse"; omoguiava vam da pojednostavite sintaksu upotrebe tipa
bez narusavanja krijen_
tovog koda. ,vodi se i rezervisana red crass dozvoljavajuii pozive operatora kao i funkcija. U ovom poglavlju iete saznati da
kao elegantniji nadin opisivanja
novog tipa podatka, a objaSnjava se i znadenje je preklapanje operatora samo tip preklapanja funkcija i naudiiete kako sami da
redi ,,objekat,, (to je novi tip
promenljive). preklopite operatore. Naudiiete kako da navedete argumente, kako da odredite
Poglavlje 6: Inicijalizacija i tiSdenje memorije. tip powatne wednosti i kako da donesete odluku da Ii operator treba da bude
programima na c-u poride od neinicijalizovunih Iedna od najde5iih greiaka u dlan ili prijatelj klase.
p.o-.rljivih. u c++-u vam
ko'stntktor omoguiava da garant.jer" au c" Poglavlje f 3: DinamiCko stvaranje obiekata. Kolikim brojem aviona treba da
(,'obiekti vasc klase") ,vek bir,i is_pravno fromentjive novog tipa podatka upravlja sistem za kontrolu leta? Koliko oblika ie sadrZati jedan CAD sistem? U
inicijaiizovane. Ako objekti zahtevaju i
brisanje, mozere garantovati da ie se ono opStim programerskim problemima ne moZete znati kolidinu, vek trajanja i tip
,u"i oluviti pomoiu destruktora.
Poglavlje 7: Preklapanje funkcija i
podrazumevani argumenti. Namena objekata potrebnih programu za weme izw5avanja. U ovom poglavlju iete
^
('++--a je da vam pomogne cra izgraciite vLIike, saznati kako rezervisane redi new i delete elegantno re5avaju ovaj problem, bez-
srozene pro,eite. za weme .aaa
mozeto k,ristiri,isc brbrioteka sa isroimenim bedno praveii objekte u dinamidkom memorijskom prostoru. Videiete i kako se
funkcijama, a mozere odluditi ida,
ru okr'r.r iste bibrioteke, koristite isto
ime .u ,uriiaiti- ,nre"n;r,,,u. c** to operatori new i delete mogu na razlidite nadine preklopiti, tako da moZete kon-
olaksava preklaTtan.jenr
ftrnkcij.a, sto omoguiava da vise tunkcija ima isto ime,
trolisati dodeljivanje i oslobadanje memorijskog prostora.
sve dok se razriktrju Iiste njihovih argumenata. podrazumevanr Poglavlje l4: Nasledivanje i slaganje. Apstrakcije podataka omoguiavaju da
omoguiava ju da na razlidite nadine pozovete ,.g.,-"nti deflniSete nove tipove od podetka, ali pomoiu omotavanja i nasledivanja
obezbedtrjuii podrazumevane vrednosti za neke
istu funkciju, urt?,,.,utsti moZete napraviti nove tipove od postojeiih. Slaganjem moZete napraviti nov tip
od argumenata.
Poglavlje B: Konstante. ovo pogravlje obraduje diji su delovi postojeii tipovi, a nasledivanjem pravite specijalnu verziju postoje-
rezervisane redi const i vora_
tile' koje imaju dodatno znaienje u cn*-r, ,u.ori ieg tipa. U ovom poglavlju iete nauditi sintaksu nasledivanja i slaganja, nadin
o unutar klasa. Saznaiete Sta
znadi primcniri const na ciefiniciju pokazivada. redefinisanja funkcija rzna(aj konstruktora i destruktora.
U ovom pogravrju se pokazuje i
8 Misliti jeziku C++ 9
na Predgovor

Poglavlje ls: porimorfizam i virtuelne funkcije. Mozda bi vam K6d je spakovan u arhivu i moze se raspakovati na svakom sistemu koii ima
bilo potrebno
ditavih devet meseci za samostarno otkrivanje i rizumevanje ovih usiuZni program zip (veiina ima, a ako nije vei instaliran, na Internetu moZete
osnovnih poj-
mo,a ooP-a. Kroz kratke i jednostavne primere, viieiete kako da uz pronaii verziju pogodnu za svoj sistem). U direktorijumu gde ste raspakovali
nasledivanje napravite porodicu tipova i kako da radite s objektima k6d, pronadi iete slededu napomenu o autorskom pravu (na engleskom):
porodice
preko njihove zajednitke osnovne krase. Rezervisana red viituat
omoguiava
zajednidki rad sa svim srodnim tipovima objekata, tako da se veliki //: ! : Copyri ght. txt
deo koda ne Copyrjght (c) 2000, Bruce Eckel
oslanja na informacije o odredenom tipu. io doprinosi prosirivosti jz kniige,,Misliti
programa, Izvorni kOd na jeziku C++"
pa je pisanje i odrZavanje koda jednostavnije ijefiinije.
Sva prava zadrZana, 0SIM sledefih:0vu datoteku moZete s.lobodno kori-
Poglavlje l6: uvod u sablone. Nasledivanje i slaganje omoguiavaju
koristite objektni kod, ali ne zadovoljavaju sve potreb" ,u poio-rom
da ponovo stiti u svom radu (lidnom i1i komercijalnom)' ukliuiujuci izmene i
koda. sabloni o moguiavaju ponovnu upotrebu i"rorro gioduJu;uJi
upotrebom distribuciju iskljuiivo u izvrSnom obliku.0dobrava se kori5eenje ove
p..uoaio., datoteke u obuci, ukliuduiu6i i prezentacije, a1i se kao'izvor mora
sredsrvo z,a zamenu imena ripova u telu krase ili funkcijelro je pririrenjeno
na bib_ navesti kniiga,,Misliti na jeziku C++".Osim radi obuke, ovaj k6d ne
Iioteku klasa kontejnera, koje su vaZne alatke ,u ai, ,uiuoj smete kopirat'i niti distribu'irati; moZe se preuzeti iedino sa adrese
orijentisanih programa (standardni C++ obuhvata znadajnu biblioteku-"e"in objektno
zvanidne kopije servera)' gde je besplatno
(i
klasa kon- http://www.BruceEckel.com
tejnera). Poglavlje vam daje kompletnu osno\,.Il ove bitne teme. dostupan.0vu oznaku o autorskom pravu ne smete brisati. Ne
i napomenu
Dodatne tcme (i napredniji sadrZaji) dostupni su u drugom tomu
ove knjige, smete djstribuirati izmenjene verziie izvornog koda iz ovog paketa.Ovu
dija se radna verzija na engreskom jeziku moZe prerizeti s web rokiJrje datoteku ne smete korjstiti u Stampanom obliku bez izriditog odobrenia
tLr tu ut. Br u ce Ec ke l. co m. autora. Bruce Eckel ne tvrdi da ie ovai softver pogodan za bi'10 koju
svrhu. PrjloZen ie u ovom obliku, bez izridjte i1i podrazumevane gara-
ncije bilo koje vrste, ukliuduiufi bilo kakvu podrazumevanu garanciju
Zadaci trZisne vrednosti, pogodnosti za odredenu svrhu ili kr5enje nedjiih
otkrio sam da su z.adaci posebno korisni da bi se tokom seminara prava. Preuzimate kompletan rizik za kori5fenie ovog softvera. Nj Bruce
upotpunilo ni izdavad neee biti odgovor.ni za bilo kakva o5tecenja naneta vama
znanje polaznika, tako da iete ih pronaii na kraju svakogpoglavlja. Eckel
Brojzada- 'il i tre6em licu koja su rezultat upotrebe ili djstribucije ovog soft-
taka je mnogo veii nego u prvom izdanju.
Mnogi zadaci su sasvim jednostar,ni, tako da se mogu uraditi vera. Ni u iednoi situaciji Bruce Eckel ni izdavad neae b'iti odgovorni
na dasu, pod nadzorom predavada, dime se obezbedujl da
rerati,rno brzo za bilo kakav gubitak prihoda, profita, podataka i1i za neposrednu,
svi polaznici usvoje posrednu, posebnu, posledidnu, sludainu ilj kriv'iinu 5tetu, nastalu pod
gradivo. Neki zadaci su tezi, kako bi se odrZara paLnja.,ap.ea.rilrt
polaznika.
Veiina zadataka je sastavljena tako da se moZe brzo iesiti, na-..r]..,u je bjlo koiim okolnostima i bez obzira na teoriju o odgovornosti koja proi-
samo zlazi tz upotrebe ili nemoguenosti upotrebe softvera, iak j ako su Bruce
ispitivaniu i upotpuny'avanju znanja, a ne predstavlja veliki izazov
iete takve pronaii sami ili, verovatnije, oni ie pronaii vas).
lverovatno Eckel i izdavad bili upozoreni na mogucnost takvih 5teta. Ako se ispoije
greike ovog softvera, vi snosite troikove svih neophodnih usluga i
popravki. Ako mislite da ste otkrili gre5ku, molim da predloZite ispra-
Reienja zadataka vku preko obrasca kojj cete pronaei na adresi www.BruceEckel.com. (Mo1im
Re5enja izabranih zadataka se nalaze u elektronskom da konist'ite isti obrazac i za otknivene gre5ke u tekstu ove kniige')
dokumentu The Thinking
irt c++ Annotated sorution Gttitrekoji se, uz maru nadoknadu, moZe preuzeti
Io kacije wutw. Bruce Eckel. co m.
s
K6d moZete koristiti u svojim projektima i pri obuci sve dok se po5tuje
napomena o autorskom pravu.

lzvorni kod
Izvorni kdd primera iz.knjige zastiien je autorskim pravom i
besplatan, a distri-
Standardijezika
buira se preko web lokacije www.BruceEcker.com.2astita u",o.'rtog
prava vas U ovoj knjizi Cu navesti samo'C'kada podrazumevam daverziiaiezrka odgovara
spredava da reprodukujete k6d u stampanom obliku bez
dozvore, ali imate ISO C standardu. Praviiu razliku samo ako je neophodno razgraniditi standardni
pravo da ga koristite u mnogim drugim situacijama. C i starije verzije.
IO jeziku C++
ll
Misliti na Predgovor

ll
Vrcnrt'Pisanja ovc knjigc, Korlitct za standardizaciju c++-a zawsicl je diska potreban Web ditad' trcbalo bi
rad Po5to je za gledanje sadrZaja sa kompakt
Irao\()nl jeziktl. Krlrisliitt termin stcntdardni(.'++ kada ukazujem na standardj- da, pre ,potr"b. CD-a, instalirate
z.va.i;czrk. Kada jt'rrapisa.. sarro (-++, z.ajte da podrazurnevam,,standardni 'itad'
(_++
Ibstoji izvi'slla zabtttra oko stvarnog naziva Komiteta za standardizaciju
C++-a
naziva sranclarcla. predsedavajuii komitera, Sreve Clamage, razjasnio je
Kom pakt d is kovi, sem inari .i savetovanja
Predvidenojedaseminarinakompaktdiskovimapokrivajutomlitom2ove
l,;::r,"* moilh nrfav,anja' uz slajdove
knjige. oni .u"r,*?i"-"lit tuti '*r"ih zapisa
ove kompakt diskove
knjige'
lbstoje dun kontiteta za stan.darriizacijrr jezi.ka c++: komitet NCITS (pret_ koii sadrZe graoiv;;haurano iz svakog poglavlia
gde iete pronaii vi.e infor-
hodno X3) 116 i
komirer ISO JTC\/SC2biWCtS. ANSI oulaiiuje NCITS da moZete poruditi ;";;;'w'Bruciictcit'com'
Jbrrnira telmiike komitete za razuoj ameriikih nacionarnih standarda. macija i Primera lekcija'
sa praktidnim veZbama'
116 1e r989. o.uraiien da rlefiniie arneriiki standa.rd za c++. oko 1991. je Kompanija fvfinaVi"* organizuje jarme seminare
lu(, r 4 oulaicen rla rtaprruri nredrmaroclni stand.ard. projekat zasnovane nu .rraierilatu izl"ozenom u.ovoj knjizi i na nap,rednijim temama'
J r 6 je pretuoren u iz svakog poglavlja, posle dega sledi
".1-ip l" (irttertracionarrti) i Ttodreden rctcru na ISo stancrirdizaciji. Lekcije su sadinjene od izabranog materijala
pojedinainom polazniku posveiuie
Oua dra komiteta se sastaju Lt. i.sto t)reme na istom mestu, i
Jl6 glasanjem veZbanje ,r, .ruaro,, iuto da sJ svakom
obrazttje nnteriiki deo wGI4. wGrr prenosi tehniiki deo potsla komitetu paZnja.Miobezbedujemoiobuku,savetovanie,vodenjeiprolazakkrozprojekat kao i
lr6. i prijami obrasci za predstoieieseminare'
\A/G l4 glasanjenr odluiuje o rehniikont raclu komiteta
J j6. i k6d na fi.., -.rtu-iilformacije
Prt'obitno je C++ standard forntiran kao ISo standarcr. ANSI je arugi poaaci ru tot'iutt, rnogtt tt t'uii na adresi www'BruceEckel'com'
izglasao (po preporuci komiteta Jr6) usuajanje ISo c++ standarda
kasnije
Ja pruZam i t;t;;;t"usl'g"
u projektovaniu' proceni projekta i pregle-
kao
anrcritkog standarda za jezik C++. danjukoda.Kadasampoieodapisemo.radunarima'osnovnimotivmi'ebioda
je to izazovno, poYo i iedno od
Zato je ISO ispravan nadin opisivanja standarda C++_a. sevise bavim rur.",r:r-u'rj* po$to mislim da (u dati
Zato sve od sebe da vas
mojih najpriiutniin pioiesionutnih iskustava'
od svojih saradnika (to su
uklopim.r rro; ,u'rpoltJili Ju tu* obezbedim nekog
PodrSka jeziku iesto udeswuju i u organizovanju
ljudi koje aoUro po""u;trn i tolitnu uerujem' a
Vas prevodilac mozda ne podrZava sve moguinosti razmotrene i izvodeniu seminara).
u ovoj knjizi,
.arociro ako nemate najnoviju verziju. Reariz-acija prevodioca za jeztkkao
sto Je
o++ predstavlja herktrlovski poduhvat i mozete odekivati da ie
se osobine jeziia
pojavljivati po grupama, a ne sve odjednom. Ako isprobate neki primer
iz ftnjige Cre5ke
i.prevodilac vam prijavi rnnostvo gresaka, tn n. ,r,oiu ukazivati Bezobziranatokolikove5tinepisaculoZidabiotkriogre5ke,nekeseuvekpro-
i pravo sa stranice zaslode novog iitaoca'. Ako otkrijete bilokoji
na greSku u kodu Sta Sto
iii greskLr rr prevodiocu - mozda prevoriilac jos uvek ne podrzava o"val primer. rT-rku iete
smatrate gr.stolnl.noiirn au pop,rrrlte i posaljete obrazac za ispravke,
'www'BruciEciel'com'
pronaii ni adresi Po5tujem vaSu pomoi'
Prateii kompakt disk
osnovni sadrzaj prateieg cD-a je ,,seminar na cD-u" pod nazivom Thinking
in
C:. Founrlntiorts for /a,n a.nd c++ (Mistiti na c-u: osnoue
Jaue i c++-a) auLora O koricama moj lik Zel:o.:urn.d: korice drugog
Chucka Allisona. CD je objavila kompanija Mind View a seminar Na koricama prvog izdanja ove knjige bio 'ie
se moZe a"hu' popui korica knjige.' M^is.liti na laui' lz
preuzeti isa adrese u.,rrtttt.BruceEckel.cont. SadrZi vi5e dasova
audio lekcija islaj- izdanja UuOu vlse'u umetttietoT ' jed-
do'"'a i nroze se preglecrati na veiini radunara ako imate dita-
kompakt diska i nekog razloga, ;;;;ij;;metnuo ideju da se upotrebi stil Art neco sa
sam hteo da korice lide na
audio karticu. nostarmim linijama i ,,hromiranim" povr5inama' Ja
cilj sc,inara je da vas pazljivo provcde kroz osnove jezika C. Usredsreduje dugim telima u pokretu'
se f ostere brodova i aviona sa koga sam upoznao u
na znanje koje vam je neophodno da biste bili u stanju
da predete na jezike Moj prijatelj DanielWill-Hairis (www'Will-Harris'com)'
ili Java, umesto da nastoji da od vas napravi strudnjaia za sve pojedinosti jezika
c++
sil;:;"t;" je dizajner i pisac svetskog nivoa- on mi ie uradio
horu osnorme
c. ( Iedan od raz.loga z-a korisienje jezika viseg nivoa, kao sto su c+* ili skorosavoiza;n,u-ru-ueujucikoricezaprvoizdanjeoveknjige.Dokjeosmi-
Iava, jeste se neprekidno pitao: "Kako ovo
upravo nroguinost izbegavanja ovih pojedinosti.) SadrZi i zadatke
i uputstva za Sliavao tori.", .r.,uJJuotlu" t'upt"tkom'banijel
njihovo resavanje. Imajte na umu da, posto poglavlje 3 ove knjige po
o-bi-u p.e- porerule ljude i radunare?" Bili smo u klopci'
vaz'ilazi seminar na kompakt disku, cD nije zamena za to pogravlje,
nego bi ga
trebalo koristiti kao pripremu za knjigu.
l2 Misliti na jeziku C++ Predgovor
l3

Sasvim iznenada, bez ideje o konadnom ishodu, zafialio je da stavim lice na


Zahval n i ce
skener. Daniel je u programu za obradu slika Corel Xara vektorizovao moj lik. po
njegovim redima, ,,automatska vektorizacija je naiin na koji radunar pretvara Prvo,hvalasvimakojisuputemlnternetaposlaliignravkgipredloge;vasa
sliku u linije i krive po svom ukusu". Zatim se igrao s tim sve dok rezultat nije pornocjebiladragocenazapobolj5anjekvtlitetaoveknjigeitonebihmogao
-obu.riti
postao nalik na topografsku mapu mog lica, sliku koja bi mogla predstavljati b", uus. Poiebnu zahvalnost upudujem Iohnu Cooku'
p^rijatelja' tcao-Slg
Ideje i podr5ku ru o"u knjigu do5li sp iz' mnogih izvora: od
nadin na koji radunar vidi ljude. Scott Meyers' Charles Pezold i
Uzeo sam or,u sliku i fotokopirao je na papir za akvarele (neki fotokopir apa- su Chuck Allison, Gat"u riolvagtio, Dan Saks'
ovog j"ezika, kao Sto su Bjarne Stro.ustrup' Andrew
rati u boji mogu da prime i tako debeo materijal), a zatim sam dosta ekperimen- Michael Wllk; zadetnika
za standardizaciju c++-a, medu
tisao dodajuii slici vodene bol'e. Izabrali smo slike koje su nam se najvi5e Koenig i oa eri"o"u Komiteta
nou rrluriav;
"Myers
fco;iml su Nathan (njegova zapaiartia su bila posebno korisna i
svidele, zatim ih je Daniel ponovo skenirao i od njih napravio korice, dodajuCi Penello,' Torn PIum'
tekst i druge elemente. Ceo proces je trajao nekoliko meseci, uglarmom zbog velkodusno itr je saopStio), Bili P"lauger, Reg Charney'-Tom
govorili na mom odseku za c++
wemena koje sam utro5io slikajuii. Posebno sam uZivao u tome, po5to sam sam Druker i u*" st"irr*.r.uer; od ljirdi koji su
eesto i od polaznika mojih seminara' koji su
udestvovao u stvaranju dela na koricama, a i zato Sto mi je to dalo podsticaj da na Konferenc riizaiaz'tojsofweia; jasnijim.
postavrlau piturrlrtoju s" mi bila potrebna da bih ovaj materijal udinio
crtam vodenim bojama (zaista je tadno ono Sto kaZu o veZbanju). je kompanija
Posebnu zahvalndst zasluZuje moj prijatelj Gen Kiyooka' dija mi
Digigami obezbedila mreZni server'
Dizajn i priprema knjige ffij prijatelj ni"t *a Hale shaw i ja zajedno smo predavali c++; Richardova
UnutraSnjost knjige dizajnirao je DanielWill-Harris, koji se u osnovnoj Skoli igrao
pronicSivostipodrSkabilisuveomakorisni(tovaZiizaKim).Zahvalnostzas-
Arrowood' Marco
iuzuju i KoAnn Vikoren, Eric Faurot, Jennifer Jessup' Tara
i
samolepljivim slovima, dekajudi pronalazak radunara stonog izdava5wa.
Pardi,NicoleFreeman,BarbaraHanscome,ReginaRidley,AlexDunneiostalo
Fotoslog sam lidno napravio, tako da su i gre5ke uredivanja teksta moje. Za
pisanje knjige i pravljenje fotosloga, kao i za generisanje sadrZaja i indeksa, druswo iz MFI-ja.
kori5den je MicrosoftovWord zaWindows,verziie B i 9. (U pythonu sam napravio
Posebnozahvaljujemsvimsvojimuditeljimaisvimsvojimstudentima(koii
su istovremeno i moji uditelji).
COM komponentu, koja se poziva iz VBA makroa, kako bi mi pomogao u ozna- To su: fohn Irving,
Duboko posto"ari;e izraiavartsvojim omiljenim piscima.
davanju indeksa). Python (ideti www.Python.or$ je kori5den za pisanje nekih (nedostajadete-nam)' Tom Robbins'William
Neal Stephenro.r, no6"rt,on Davies
ala&i za proveru koda i bio bi upotrebljen kao alat zaizdvajanje koda da sam ga Castaneda i GeneWolfe'
Gibson, ilichard Bach, Carlos
otkrio ranije. i velikodusno
Zahvalnost ,i;"j"Guido van Rossum koji je izumeo Python
Dijagrame sam napravio koristeiiVisio - hvala kompanijiVisio Corporation obogatili moj Zivot'
ga dao svetu' Svojim doprinosom-ste
zato sto je napravila korisnu alatku. Scott Disanno'
Hvala ljudima iz prentice Halla' To su: Alan Apt' Ana Terry
Konadna verzija fotosloga napravljena je pomodu Adobe Acrobata 4 i poslata kopije, stephanie English, a u marketingu
je u Stampu neposredno iz te datoteke - mnogo hvala kompanijiAdobe na alatki Toni Holm i moj iedaktor elektronske
Bryan Gambrel i Jennie Burger'
koja dopudta slanje dokumenata spremnih za Stampu elektronskom po5tom, Danielwill-Harris
po5to to omoguiava veii broj reizija u jednom danu, tako da ne moram da se sonda Donovanl. po*ogru u prozvodnji kompakt diska.
(nararmo) rasko5no je dizajnirao sdm disk'
oslanjam na svoj laserski Stampad i nodne postanske usluge. (postupak sa Acro- udinili izuzetnim
batom isprobali smo na knjizi Misliti na Jau,; tako da sam konadnu verziju te Zahvalnost a"g"j.* divnim Ijudima koji su crested Butte
(worac Camp4 Coffee Gardena)' moji
knjige mogao iz JuZne Afrike preneti na Stampu u Sjedinjene DrZave.) mestom, u to ,r rr"u.odito Al Smith sjajnog
Dave i grita, f,farsfta iz knjiZare Heg;s PIa-e' Pat i John iz Teocalli Tamale'
susedi
HTML verzija je napravljena pretvaranjem dokumenta iz Worda u format zvuka' Hvaia i svim
Sam iz Bakery Caf6a i Tiller koji mi je pomogao u istraZivanju
RTE a zatim je RTF2HTML (idetihttp:llwww.sunpack.comlRTFl) uradio najvedi moja-jutra'
divnimljudimaiz Camp4 koji su dine zanimljMm
deo konverzije u HTML. Hvala Chrisu Hectoru zato Sto je napravio tako koristan
Na listi ptij;"tj;6ri me podrZavali nalaze se' izmedu ostalih'
i: Tack
i veoma pouzdan alat. Dobijene datoteke su predi5dene upotrebom programa nubentcing, Icaig Brockschmidt, Steve sinofsky,
na Pythonu, a IVMF datoteke su pretvorene u format GIF pomodu programa urlocker, Andr"* s'i.rrto"t, Neil
Larry- o'Brien' Bill Gates iz
IASC PaintShop Pro 6 i njegovog alata za paketnu konverziju (hvala kompaniji JD HildebranAt, nti* trlcbU:inney, Brinkley Barr'
i"gi",T ingLarry Constantine' Lury Lockwood' Tom Keffer'
iasopisa Mid
IASC, diji je odlidan proizvod re5io mnobtvo mojih problema). perl skript za putterman,"ight irtay"r, David Intersimone, Claire Sawyers,
Dan CenJWang,bave
oznadavanje sintakse razliditim bojama ljubazni je doprinos Zafira Anjuma. piovaglio, Fallai, Marco i Lella cantu' cor-
Italijani (Andrea Rlsselta Gioia, Laura
Chris i Laura Strand (i Parker), porodica Alm-
rado, IIsa i Christina G"iustozzi),
qriri, ntua 1".1rc, rrr*ilytt Cvitanic, porodica Mabry porodica Haflinger'
Misliti na ieziku C++

porodica Pollock, Peter Vinci, porodica Robbins, porodica Moelters, Dave


Stoner, Laurie Adams, porodica Cransron, Larry Fogg, Mike i Karen Sequeira,
Gary Entsminger i Allison Brody, Kevin, sonda i Ella Donovan, chester i stran-
non Atrdersen, Ioe Lordi, Dave i Brenda Bartlett, porodica Rentschler, L1.nn i
Todd i njihove porodice. I, naravno, moji mama i tata.

e r,r'
,.:.

P,iogramski jezici
t6
Misliri na jeziku C++ Poglavlje l: Uvod u objekte t7
Racrrnari nisu loliko nraSine, koliko
su pojaeala za misli (,,bicikli za
reka. Srcvt' Jo.:) i sredstvn ,u pnr.Jn, um,,, bto bi Objektno orijentisani pristup ide korak dalje, pruZa programeru sredstva za
nrarje prc'crsta'rjaju nrasirrc, a sve
il;,';;oi;;.'il*',#raiunari sve predstavljanje elemenata iz oblasti problema. Predstavljanje je dovoljno
r.ise cieo naseg miSljenja, kao
izraz.rtrrrj. r,,,,,,l,,],i:,,1,,1, stikanja, i drugi nadini uop5teno, pa programer nije ograniien na odredeni tip problema. Elemente u
r.,;;l; animaciie ihr*". oui"ttno orijenri_
sarro prograrniranje je de. ovog
pomeranja f.u toriSl"n;u;;;r;;i" oblasti problema i njihovo predstavljanje u oblasti reSenja nazivamo ,,objekti".
izraZavanja. k." sredsrva (Biie vam svakako potrebni i drugi objekti koji ne potidu iz oblasti problema.)
o'rr ,ogrrrvrj* cr ras ,vesti , osnovne Idejaje da se, dodavanjem novih tipova objekata, program prilagodava specifid-
koncepte objektno orijentisanog pro_
gramiran ja (oor'}). rrkrjrrt'rrj,trii i pregled obiektno orifentisanih nom jeziku problema, tako da pri ditanju koda koji opisuje resenje, aitate i tekst
[)rt'rp.sravr;a sc rra_irrrarc iikrrstva razvojnih metoda. koji izraZava problem. ovo je fleksibilnija i mocnija jezidka apstrakcija od pre-
,,'ruJu , pro."durarnim progruarki- jezicima,
mada t nije obavez-an. Ako vam thodnih. OOP vam omoguiava da opi5ete problem njegovim terminima, a ne
t..n, anJitno obuka za programiranje i
jezika C prc nego sro prisrupire sintaksu terminologijom radunara na kome ie se program izwsavati. I dalje postoji veza
pogredajte multimedijski seminar
,.'l hinking irr (.: I-orrrrtl,irinn. "r";-ffii
ioI- t.*n j,_,J'iow
na prareiem kompakr disku.
sa radunarom. Svaki objekat je kao mali raiunar: ima svoje stanje i operacije koje
or.o pogtavlje n::^11i:li'ndlogu moZe izvrSavati na zahtev. Analogija sa objektima u svetu oko nas nije tako lo5a:
i dopunski marerijat. Lak.e iete
vode objektno orijentisanog progiamiranja se otisnuti svi imaju osobine i pona5anja.
'
navedenih ideja sreci ..,. .Jriaui pr.gr"i
ako ga prvo sagledate kao celinu.
Iz Neki projektanti jezika zakljuduju da objektno orijentisano programiranje ne
obrasi oop-a. "M;;H mnogi ne
mogu da sagledaju cerinLr ciok
uia""niene omoguiava jednostavno resavanje svih programerskih problema i zalaZu se za
.dnrah ne poinrr da programirai, ". nr." prip.aaremehanizme i obeshrabre se ako kom6inaciju razliditih pristupa.,, prog.u-tkim jezicimasa uiie paradigmi'l
drugoj grupi i ako iedva dekate
ria saznarc karaktensrikiyczika,'sro[od'no"pre.kodite Alan Kay je saZeto prikazao pet osnovnih osobina Smalltalka, prvog uspeSnog
spreciti ovo pogravrje, to vas neie objektno orijentisanog jezika i jednog od jezika na kojima je C++ zasnovan. Ove
da piiete pfog,ra:nel niti da naue
ite jezik. Mozda iete poZereti da
i da dopunite znanje, kako biste
rhrri,i;;;;rj se watite osobine predstavljaju potpuni pristup objektno orijentisanom programiranju:
objekata i nadin projekrovanja.
I . Sve je obiekat. Mislite o objektu kao o drugadijoj wsti promenljive: on duva
podatke, ali mu moZete i ,,slati zahteve", traZeii da sam izw5i operacije'
Razvoj apstrakcUe Teorijski, moZete uzeti bilo koju konceptualnu komponentu problema koji
svi programski iezici sacrrze apstrakcije. resavate (psi, zgrade, usluge itd.) i predstavitije u programu kao objekat.
MoZe.se reii da je sloZenost probrema
koje re.avatc tirektno povezana s
wstom i kvalitetom apstrakcije. pod 2. Program je kolekciia obiekata koii, porukama, iedan drugom saop5ta-
podrazunre'am ,.Sra apstrarrujete?". ,,wstom,,
Asemblerski jezik je mala apstrakcija
ma.ine vaju Sta da rade. Zahtev se objektu Salje kao poruka. Poruku shvatite kao
rrr kojoj rarii Mrrogr irnpt'rarrrrri
i,'ri.i tnll .,, kasnije rr.,.ri rtl"'sr" r, rortrar, poziv funkcije koja pripada odredenom objektu.
BASI(' i(.r srr arr51;-3(6ij1' or.niur"ro.'O,
.rin.srr ra 'iri lezici predsravrjaju veriki napredaku 3. Svaki objekat ima sopstvenu memoriiu sadinienu od drugih objekata'
irsembrer,riri .i"rr" ,.n,.rrlr"o.'J"rn-,,,,rjare
, strtrkturi probrerna,koji o srrukturi raiunara, a ne Drugim redima, od postojedih objekata moZete napraviti nolu wstu
programer mora
mrrlera rnasine (rr ,,ohlasti.resavare. da uspostavi vezu izmedu objekta. Na taj naiin poveCavate sloZenost programa, ali ie skrivate jedno-
u io j. ruernuo i
rcsenja" ga.'*oa.ru;"," proul"il, starmo5du objekata.
se resava (u
Hiil"i#::'I: I"j' ""ur,ii'p,"tr.#;;H o'liloi,,. *uoo, 4. Svaki objekat ima tip. U strudnom Zargonu, svaki objekat je primerak ili

*i{1rf ;iaili;,:c[I[ ji3"";:i:n]::1:ffiX*;,*:inr::*; instanca klase, pri demu je ,,klasa' sinonim za ,,tip". Najznadajnija odlika
1e nastanak
citavc industrijc klase je,,Koje poruke joj se mogu poslati".
,,metoda progrurnirunju,..
Alternatira morreriranjir maiine 5. Svi objekti odredenog tipa mogu primati iste poruke' Ovo nrdenje je
re.ire' prri jezici, kao iro srr LISp rI ,""i.ri*,,je probrema koji nastojite da neprecizno, kao Sto iete videti kasnije. PoSto je svaki objekat tipa ,,krug"
i ner, ,ognuurari su specifidne
('s.'i prohrerni se svodt'na pogrede na svet istowemeno i tipa,,oblik', krug moZe da prima i poruke za oblik. To znadi da
ko.aane-llr,.t,i, ,,Svi probremi su algoritamski,,).
PRo'oG sr,ocii sve proble,e L"r*. moZete napisati k6d koji se odnosi na oblik i automatski obraduje sve Sto
gra m i ra n j e zasn o\ra o n a o gran"" "ilrr,"r.,rrJi-l:::::,:iq:l
i za;ff#_H]f,:UX odgovara opisu nekog oblika. Ova zamenliiuost je jedan od najmoinijih
simbolima. (Dokazano je da su
n idenj i ma
#,o,
;";;;;;i previ5e restrikti\,,ni.) Svaki od ovihffi #I koncepata OOP-a.
pristtrpa predstavlja dobro.re.enje ", ;; k;;il;,", klasu problema koju treba da
re5ava, ali su teiko Lrpotrebljivi
irr^n ,uo;ln'a"u-"nu.

I videri Multiparadigm Programming in lada.Timothy Budd, Addison-Wesley, 1995.


l8 jeziku C++ l9
Misliti na Poglavlje l: Uvod u objekte

interface) koii je odreden


Objekat ima interfejs objektu definisani su njegovim interfeisom engl.
(

.\ristott'l jc vcrorarno prvi zapoieo paTljivo proudavanje pojma tip: govorio je o tipom. Iednostavan primer Predstavlja sijalica:

g
.,klasi riba i klasi ptica". U prvom objektno orijentisanom programskom jeziku,
SinrLrla-67, dija osnovna rezervisana rei class (klasa) uvodi nov tip u program,
pn'i put je neposredno iskoriSiena idcja da su svi objekti jedinstveni, ali su i lme tipa
rlclo.,'i klasc objckata sa zajcdnidkim osobinarna i pona5anjem.
Sirnrrla jc, kao ito sanro imc.jezika govori, napisana radi razvoja simulacija u klju ci0
poput klasii:nog,,bankarskog problema".2 l.l bankama imate mnostvo bankarskih isklj uci0
I nte rfej s
slLrTbcnika, klijenat:r, raduna, transakcija inovdanih jedinica - veliki broj pojacaj0
,,otrje'kata". objckti koji su identidni po svemu osim po unutrasnjem stanju tokom prigusi0
izrrr(avanja I)rogritnra, grtrpi5Lr se rr ,,klase objekata", i otuda potide rezeMsana
rci class. Irornrirarrjc apstraktnil.r tipova podataka (klasa) je osno,una tehnika
objcktno orijentisanog programiranja. Apstraktni tipovi podataka funkcionibu Siialica lt;
skoro potpuno isto kao tipovi ugradeni u jezik: mozete napraviti promenljive It.ukljuci 0;
odrcdenog tipa (u objektno orijentisanom Zargonu nazivaju se objektiili insta- Interfejsdeflni5ezahtevekojemoZeteuputitiodredenomobjektu.Medutim,
rcc) i raditi s njima (to je slanje porukalli zahteua, pri demu objekat otkriva sta da negde mora postoja;I;J k;ji oago'utu t'uiaj zahtev' KOd' zajedno sa skrivenim
nije tesko ra7'umeti sa
radi na osno\rl poruke koju ste rnu poslali). elanovi (elementi) svake klase imaju p"i".,.t", e- i ,"itiiiiii" r.jngl' impten'tentation) ' Sve ovofunkciiu pridruT'enu sva-
nesto zajednicko: svaki radun ima saldo, svaki sluZbenik moze primiti utog itd. stanoviSta pro."ar.ui.rJg pto[ramiranla' Tip.poseduje
objektu po-zivanie.m tih funkciia'
Istovremeno, svaki dlan ima sopstveno stanje, svaki radun ima drugadiji broj, kom od moguiih ruf,,."i,'i 'uitevi se upuiuju (upuiivanje zahteva)
svaki sluTbenik ima irne. Zato se sluzbenici, kiijenti, raduni, transakcije itd. mogu il""J p"""p"t r. ,rt.uito .noze opisati t"o poruke"
"sianle (izr'r5ava
k6d)'
prcdstaviti kao jedinsrveni entiteti u programu. ovaj entitet je objekat, a svaki koji odreduje Sta da udini s tom porukom Sijalica
"U;.j[", je lt:
objekat pripada odredenoj klasi koja defini5e njegove osobine i pona5anja. Ime tipa/klase;" 3i;ufi"u, ime konkretnog objekta ".b]:51*,1se
"prigusi. klase
ili objekat
Iako u objektno orijentisanom programiranju pravimo nove tipove podataka, mozere uputiti rur,t"i" au'r. ukljudi, isktluei,-pojada
poruku
Da.biste
svi objektno orijentisani programski jezici koriste termin ,,klasa". Kada vidite red sifalica pravite aer.ra.isanl"m imena (lt) za tal oUietat. loslali
Posmatrano sa
,,tip", pomislite na ,,klasu", i obrnuto.ll ime oblLkta i tadkom ga poveZite s porukom'
"ili"ti",'"ur.dite definisane [ui., to ie sve Sto se tiie programirania
PoSto klasa oprsujc skup objekata koji imaju identidne osobine (podatke) i stanovista torirrritu r.rup""J
ponaSanja (funkcije), klasa je zapravo tip podataka, zato ito, na primer, i broj u objekata.
is obiedini enog. j ezika modelirania
formatu pokretnog zareza poseduje skup osobina i ponasanja. Razlika je u tome U prikazanom dijagramu koris,ti se. zap
5to programcr deflniSe klasu koja odgovara problemu i nije prinuden da koristi klasa je predstavljena pravouga-
l"ngt.'Urfp"a UoaeiniLanguage,UML)'.Svaka navedenim u
podacima dlanovima
postojeie tipove podataka, koji samo opisuju nadin belezenja informacija u onikom, ,u i-".ro* ffi'"'go.""j.* delu,
koje pripadaju ovom objektu i
raeunaru. l)rogramski jezik prosirujete dodavanjem tipova podataka prema sredisnjem aat {"iii,loiiiiii**ottunkcile
delu pravougaonika' U UML dija-
svoiim potrebama. Programski sistem prihvata nove klase i na isti nadin radi s primaju rr" por.rt. koiJ*" Sul;tttl u donjem
njirr-ra, kao i sa rrgradenim tipovima. se desto p;li;il i"tt klase i javne funkcije dlanice' tako da se
gramima
'u*o i*t klase' tada se ne mora prika-
objektno orijentisani pnstup nijc ograniden na simulacije. Bez obzira na to sredi5nji deo izostavlja' Ako vas zanima 'u*o
cla li sc slaTctc rla je svaki program siniulacija sistema koji projektujete zati ni donji deo.
- kori-
ifcnicnr OOI, tchnika, veliki skup problema se lako upro5iava i re5ava.
Kada definiiete klasu, mozere napraviti proizvoljno mnogo njenih objekata i
rarliti s njin'ra kao da su elementi problema koji reiavate. Iedan od izazova objek- Skrivena realizacija klasa (oni koji prave nove tipove
tno orijcntisanog programiranja svakako je uspostavljanje jednoznadnog pre- Korisno je podeliti ,u^iini tim u proiektante
(lotLnike klasa' koji koriste ove tipove poda-
slikavanja izmcdr-r elemenara u oblasti problema i objekata u oblasti resenja. podataka) i progr";,,i[iii'nt'n
Kako da iskoristite objekat? Mora postojati nadin da objektu uputite zahtev Cilj programera kliienta je da prikupi kolekciju
taka u svojim aplikacijama)' je da napravi klasu koja
klasa
cla neiro uracii, na primer da izvrsi transakciju, nacrta nesto ili ukljudi prekidad. klasa radi orrogru,uq;"pru"ti;tj' bitl"prolettanta
S'aki objckat isptrnjava samo oclrcdene zahteve. Zahtevi koje moZete poslati p-rogrameru klijentu' a.sve ostalo skriva'
prikazuje ,u-o o,,o sio ii
"topiodno ono .to skriveno, Sto znadi
je
Zaito? Zaroa,o proi."u*|, f.fi;"", ". moZe foristiti
deo ne vodeii raduna o uticaju na
latlinlljilo reirrllr (r\1)ll prohlettta na('i aetc ll ronru 2 ove knjigc, koji se preLrzima s adresc ww.Bruce-
da projektant nasJmoze da menla skriveni
lrckcl corn
\t'ki lrtave tazltkLt. tvrtloir rlrr trp rrriretlrrjt'intcrfejs, dok je klasa konkrctna realizaciia tog interfejsa. 4 Ovaj termin je izmislio moj prijatelj Scott
Meyers
20 zl
Misliri na jeziku C++ Poglavlje l: Uvod u objekte

drLrge del.r'e. Skrivt'ni deo.biino predsravria


granrer klrle nt Iako rnoze.da oireti trsred
osetljivi sadrzaj objekta, koji pro_ opstije, agregacija). Za kompoziciju se kaZe da ie relaciia ,,sadrZi", kao u primeru
nepaznje iri neznanja, tuto ou'rt .iuun;. ,,Kola sadrZe motor".
.manjuje broj greiaka u prog.u.,r. Skrivanye ,"uriru.ti"l"i
l:illi:.,j. zuzetno
lJ s.'akonr .cr.osu je vazno
,ostaviti granice koje postuju
pra'ite bibliotekLr, ,spo^stavljate odnos'sa programerom svi udesnici. Kada
krijentom koji pravi
aplikaciju korisreii vasu biblioteku, ili mozria prlu veiu biblioteku.
Ak. su svi iranovi krase dost,pni svima, tada programer klijent moze uiiniti
bilo .ta s kltrsom i ne postoji nikakav nadin
dase'prisili da po.tu.ie pravila. Iako (Popunjeni romb gornjem UML dijagramu ukazuje na kompoziciju, sto omo-
ratn r iie odgovara da programer klijent ne
rukuje neposredno nekim dlano,rima gr.uru da postoje samo ledna kola u relaciji. Uglar,nom iu koristitijednostavniji
postoii nadin da to spreiire bez konirole'pristupa. oblik: Iiniju bez romba, Sto oznadava asocijaciju.)'
IJ:i:J: S";i;;;;;rpro Kompozicija je veoma fleksibilna. objekti ilanovi nove klase obidno su pri-
Pristup treba kontrolisati da bi se programeri
krijenti drZari dalje od delova vatni, Sto ih Eini nedostupnim programerima klijentima koji koriste tu klasu.
koje ne bi trebalo da diraju delova
- za unutrasnje operacije nad MoZete ih promeniti bez narusavanja postojeieg klijentovog koda. objekti dla-
""""pt "a",r,
tiporn podataka, koji ne pripadaju interfEsu
,u ,.iuuu'r,;. toitr.,- novi se mogu menjati i tokom izwsavanja, iime se dinamidki menja ponasanje
-ro foi."u"o,,,
nih problema. je istovremeno i usluga korrsnicima,
jer rako mogu uoditi sta je programa. ilasledivanje, koje se opisuje u nastavku, nije toliko fleksibilno, po5to
znadajno, a ita se moZe zanemariti. prevodilac mora postaviti ograniienja na izvedene klase'
PoSto je nasledivanje tako znadajno u objektno orijentisanom programiranju,
, Konrroronr pristupa' projektanru biblioteke se omoguiuje menjanje unutra-
Snjeg rada krasc, bez obzira na uticaj promene
na programera klijenta. Na desto se posebno naglasava, i programer novajlija moZe pomisliti da nasledivanje
prirncr, moze(e na jednostavan nadin reirizovati
neku krasu, a zatim otk_riti da treba svuda koristiti. To dovodi do nespretnih i preterano komplikovanih reSenja'
rnorarc da je urrrzate. Ako su interfcjs i
rcarizacija jasno odvojeni iza5tiieni, ovo Pri definisanju novih klasa, prvo Iazmotrite kompoziciiu koja je jednostalnija i
se rrr,2c lak. rciiri izatinr sa,. trcba
zahtevatioi torisnita a, p"r"r" p"*za fleksibilnija.vasi projekti ie biti distiji ako prihvatite ovaj pristup. Kada steknete
p roj eka t. malo iskustva, biie vam sasvim odigledno kada treba primeniti nasledivanje.
(_++ kr;risti
tri rezervisane rcdi za definisanje granica klase: public (javni),
vare (privar'i) i protected (zastiieni). Njihova"upotreu" pri_
il,I"el"l. su sas,rim
jasrrr' ovi s!:ecilikatori pristttpa
odrecluju ko moZe da koristi naredne definicije. Nasledivanje: ponovna upotreba interfejsa
Rct pubric znadi da, str .arecine tlefinicile
svima dostupn". n.r.rurru.,a red pri_ objekat je sam po sebi zgodna alatka, omoguiava vam da grupiSete podatke i
vate oznaiava da niko osimprojektanta
tipa ne moZe piistupati dlanovima, a i to funkcije'prema konceptu, tako da pri opisivanju oblasti problema ne morate
je .oguie samo unutar funkcije
dlanice tog tipa. Red private postavrja visoki koristiti idiome masine. Ovi koncepti su osnormi elementi programskog jezika
zid
izmedu vas i programera krijenta. ako neko'pokusa
aa pristupi p.irut.,o- eru.,r, i defini5u se pomoiu rezervisane redi class (klasa).
dobiic gresku prilikom prevodenja. Rcd protected..
ponusu'kJo fiiuu,", irrr"u Steta 1e ako prodemo kroz sve nevolje deflnisanja jedne klase, da bismo zatim
5ro izvecie.a krasa inra pristup zastiienlrn,
ari nc i privatnim iranovima. Izvo- bili prinudeni da napravimo potpuno novu klasu sa slidnom funkcionalnosiu'
denjc klasa nasledivanjem biie opisar.ro ubrzo. Bilo bi bolje kada bismo uzeli postojeiu klasu, klonirali je, a zatim dodavali i
menjali elemente klona. To, u sustini, dobijate naslediuaniem (engl. inheri'
tanc'e), samo Sto izmene originalne klase (nazvane osnounaklasa, natklasa ili
Ponovna upotreba realizacije rorliteljska) utidu i na ,,VJon" (izuedenaklasa, potklasaili potomak)'
Karra se kiasa jednom crefinise i testira,
trlbulo bi da, u idealnom slucaju, pred_
sravlja koris.u cerin, koda. rspostavrl'a se
da p"r;;;" i;;iszffi ,ri;. ,i pri_
bri2no rako postiii kako se mnogi nadalu
- potrebno je rrturtro L*nje da bi se
..pra'iro drbro resc,jc i tada ono simo traZi da
bude poro* i.ko.isieno.
[)onovna uporreba koda je jedna od najveiih
jezika.
p."a,roriiou]"r.iio"oii;..,ti.u.,it

. N'aijednostavnije iL.te ponovo upotrebiti klasu kada neposredno koristite


.'jckat te klasc, a rnozete ga smestiti i u novu klasu. zvedena
rbjckta rira.a" N.va krasa mozc sacrrzati proizvorjan
ovo
,ou"n,o ,,aan.ri.un,. I

broj d;;il^;b,-ekata, u biro


kojoj kornbinaciji koja vam Ireba za postizanye
potrebne funkcionalnosti. posto
sasrar"ljate ,o'ri klasrr ocr postojeiih,
ovaj koncep, ;.';";i;;;,)tpozicija
riti,
s ovo je obidno dovoljno detaljno za veiinu dijagrama, pa ne morate precizirati da li koristile agregaciju ili
kompoziciju.
22 Misliti na jeziku C++ Poglavlje l: Uvod u objekte 23

(Strelica na prethodnorn UML dijagramu usmerena je od izvedene klase ka kodu. eudno zvudi, ali ljudi mogu imati problema s obiektnim oriientisaniem
zato sto je jednostavno. Um, izveZban da traZi sloZena resenja, moze zbuniti
osrrovnoj, Kao ito clete videti, mo7e postojati vi5e izvedenih klasa.) ovo-
'l'ip je ncSto viSe od opisa ograrricenja definisanih za skup objekata on ima
- lika jednostawost.
rclacije s rinrginr tipovil-na. I)va tipa rnogu imatiz-ajednidke osobine ipona5anja, Niasledivanjem postojeieg tipa, pravite nov rip. ova; novi tip sadrzi sve dla-
je jos
ali jeclan tip n'roZe inrati viSe osobina i moZe obradivati vi5e poruka (ili obradivati nove postol'eieg tlpa (iako su privatni dlanovi skriveni i nedostupni), a sto
iste poruke na drugi nadin). Nasledivanje izraZava ovu slidnost izmedu tipova znadajnije,'saaizi i aupUtat interfejsa osnovne klase. Znadi da sve poruke koje
koriSienjem osnovnih i izvedenih tipova. Osnovni tip sadrZi sve osobine i mozeie poslati objektima osnovne ktase takode mozete slati objektima izvedene
klase. Po5to tip klase prepoznajemo po porukama koje joj moZemo
pona5anja koje imaju i tipovi izvedeni iz njega. Osnomi tip treba da predstavlja poslati' znadi
jezgro vaSih iclela o r.rekim objektima u sistemu. Iz osnovmog tipa izvodite ostale da je izvedeni ttasa rsrog fipa kao osnouna klasa.lJ prethodnom prim.eru, ,,krug
tipove koji izraiavaju razlidite nadine realizacije togjezgra. je ottit". ova ekvivalentnost tipova dobijenih nasledivanjem, kljuina je za razu-
Na primer, aparat za recikliranje razwstava delove otpada. Osnovni tip je mevanje objektno orijentisano g pro gramiranj a.
,,otpad" i svaki komad otpada ima teZinu, vrednost itd. i moZe se usitniti, otopiti Kako i oinorma i izvedena klasa imaju isti interfejs, mora postojati realizaciia
ili raz-loZiti. Iz ovoga mogr"r biti izvedeni posebni tipovi otpada s dodatnim karak- uz taj interfejs. Drugim redima, mora postojati k6d koji se izwsava kada objekat
teristikama (fla5a ima boju) ili pona5anjima (aluminijum se moZe savijati, delik primi odreden, po*kr. Ako samo izvedete klasu i ne udinite ni5ta vi5e od toga,
se moZe namagnetisati). Osim toga, neka pona5anja mogu biti razlidita (vred- metode iz interfejsa osnovne klase se prenose u izvedenu klasu. Znadi da obiekti
nost hartiie zavisi od vrste istanja). Primenom nasledivanja, moZete izgraditi izvedene klase imaju isti tip, ali i isto ponasanje, Sto i nije narodito zanimljivo'
hije rarhiju tipova koja izraiava problem. Postol'e dva nadina da napravite razlike izmedu nove izvedene klase i
izvorne
Drugi klasidni primer su oblici, koriSieni u sistemima za projektovanje osnovne klase. Prvi je prilidno jednostavan: dodajte nove funkcije izvedenoj
pomoiu radunara ili za simulaciju igara. Osnomi tip je,,oblik", a svaki oblik ima klasi. ove nove funkcije nisu deo intefejsa osnovne klase. Znadi da osnorryta
jedno-
veliiinu, boju, poloZaj i slidno. Svaki oblik se moZe nacrtati, izbrisati, pomeriti, klasa nije radila sve ono sto ste Zeleli, pa ste dodali nove funkcije. ova
obojiti itd. Iz- ovoga se mogu izvesti posebni tipovi oblika: krug, kvadrat, trougao, stavna upotreba nasledivanja je ponekad sawseno resenje problema. PaZIjivo
i ostali, od kojih svaki moZe imati dodatne osobine i ponaSanja. Odredeni tipovi razmotriie da Ii su ove dodatne funkcije potrebne i osnovnoi klasi. ovaj proces
se mogu, na primer, osno preslikati. Neka pona5anja mogu se razlikovati, kao Sto otkrivanja i iteratimog projektovanja uobidajen je za objektno orijentisano
je sludaj sa izraiunavanjem povrSina oblika. Hijerarhija tipova obuhvata i programiranje.
slicnosti i raz-like medu oblicima.

crtaj0
bris i0
pomeri0
citaj Boju0
dodel iBoju0

Pres I i kajVe rt ikal no0

Kori5ienje istog rcdnika za formulisanje reSenja i problema naroiito je zgodno i.:


zato Sto vam ne treba mnoStvo razvojnih modela da biste od opisa problema do5li i;
do opisa re5enia. Kada koristite objekte, hijerarhija tipova je primarni model, tako ili Nasledivanje samo ponekad podrazumeva dodavanje novih funkcija inter-
jeste promena
da od opisa sistema u stvarnom svetu neposredno stiZete do opisa sistema u arii
d,l
fejsu. Drugi i inadajniji nadin da udinite novu klasu drugadijom
ri!
i:]}
t*'
;1.
24 jeziku C+-r
Misliti na

ponaSanja funkcije postojeie osnovne klase. To


se naziva redefinisanje (engJ, rashladni uredaj, ali ima vede mogudnosti. Kako je sistem za regulisanje tempe-
ouerriding) funkcije.
rature u vasoj kudi projektovan da upravlja samo hladenjem, on je ogranilen na
komunikaciju s ruihiud.rim delom novog objekta. Interfejs novog objekta je
pro5iren, a posto;edi sistem i dalje prepoznaje samo prvobitni interfejs'

Naravno, kada pogledate ovo resenje, postaje jasno da osnorna klasa,,rashla-


dni sistem" nije dovoljno opsta i treba da bude preimenovana u,,sistem za reguli-
Da biste redefinisali funkciju, uvedite novu definiciju
funkcije u izvedenu sanje temperiture", tako da moZe da ukljudi i grejanje. Tada se moZe primeniti i
klasu. KaZite: ,,Koristim istu funkciju iz interfejsa, princip zamene. Gomji d.ijagram je primer onoga Sto se moZe desiti pri projekto-
u novom tipu".
ali Zelim da uradi .r.sio i*go vanjuiuswarnomsvetu,
Kada razmotrite princip zamene, pomislicete da se samo primenom ovog
principa moZe obaviti posio i,zustaieste dobro ako imate takvo resenje. Medu-
Relacije ,,je" i ,,je-kao" ii*, oikrid.tu situacije kada je jasno da morate dodati nove funkcije interfejsu
Pri razmatranju nasredivanja moze nastati dilema:
da ri nasledivanj e treba samo izvedene klase. Oba sludaja su prihvatljiva.
da redeflniSe funkcije osnovnelclase (ne i da dodaje
nove funkcije dlanice -tuo
koje ne
postoje u osnormoj klasi)? To bi znadilo da je izvedenirrp poipurii*i
up
osnovne kiase, posto imaju isti interfejs. u fom srudaju,
ir"J".r" uur" Zamenljivi objekti i polimorfizam
moZete zameniti objektom osnovne kiase. ovo se
smatra"tj"d,
potpunom zamenont ' pri rad--u s hijerarliijama tipova, Iesto treba postupati s nekim tipom objekta kao
(engl- pure substitution) i desto se naziva
princip zamene (eng). substitution prin_ : sa njegovirn-osnovnim tipom. To vam 9m-ogudava da pisete kod koji ne zavisi od
ciple).u izvesnom smislu, to je sawlen nadin posmatranja
izmedu osnovne krase i izvedenih klasa tada nazivamo
nasledivanja. Reraciju " tontr.tnih tipova. U primeru oblika, funkcije rade s opstim oblicima bilo da su
relacijom je t""li. ;r-rl, krugovi, kvadrati, trouglovi ili neSto drugo. Svi oblici se mogu nacrtati, izbrisati,
posto.mozete reii ,,krug
7eoblik". Nasredivanje iete ispitati ato utwaite silirte.r,, porieriti, tako da ove funkcije jednostavno Salju poruku objektu oblika i ne vode
relaciju,,je" izmedu klasa.
:. raduna kako Ce objekat izaCi na kaj s tom porukom' .
U nekim situacijama morate dodati nove eremente interfejsu
izvedenog tipa: Dodavanje nwih tipova ne utide na takav kod i to je najdesdi naein prosirenja
prosiriiete interfejs i rako srvoriri nov tip. Novi rip
;os #lzJiai ,u-?"p" objektno orijentisanog programa radi obrade novih sludajeva. Na primel moZete
osnomim tipom, ari ta zamena nije sawslna posto nove "r"t
funkciju ao.rufr,u i, izvesti nov p-odtip obliki, petougao, bez izmene funkcija koje rade samo sa opdtim
osnovnog tipa. Ovaj sludaj se.moZe opisati reiacijo je-kaot""gl."i*
m ,ir_/ik _;iI.rori oblikom. Mogudnost jednostavnog pro5irenja programa izvodenjem nwih podti'
tip ima interfejs starog tipa, ali sadrZi i druge funicije,
tako da ne moZete reci da su pova je znadajna, pbsio se u velikoj meri pobolj5avaju re5enja i pojevtinjuje odrZa-
erutport"rri-o j"ll *Su
potpuno isti. Na primer, razmotrimo rashladni ,r."aa.i.
kuia opremljena svim elementima za hladenje znati, ima - vanje softvera.
omoguiav.a da upravljate h-radenjem. Zamisrite da se
- interfejs-[,iii ** Problem nastaje kada pokusate da radite sa objektima izvedenih tipova kao sa
rastrradni ureaa; porclii i aa opstim osnovnim tipovima (sa krugovima kao oblicima, biciklima kao vozilima,
ga zamenire klima-uredajem koji moZe i da greje
i da hradi. lci."""i.!Giz-r", k6rmoranima kao pticama itd.). Ako neka funkcija zatraZi da se opsti oblik nacrta
26 27
Misliti na jeziku C+r Poglavlje l: Uvod u obj4!9

ili da se op.tim voz,om 'rpravlja ,i da


se op.ta ptica pomeri, prevod,ac da ima fleksibileost kasnog
tadno koji deo koda ie se.izwsivati. ne zna Rezervisana red virtual oznadava da funkcija treba
gramer ne zeLi da zna koji deo koda
sustiffi u tome sto pri slanju poruke pro- novezivania. Ne *orat" L.rm"ti kako taj mehanizam radi da
biste ga koristili' ali
ie se izw.avati: funkcija prograrmranJe u
podlednako primeniti n1.kyg: kvadrat ,u ,,,oz" ," 'gu*oru,6 koristiti da biste primenili objektno orijentisano
juii iti
deo koda, u zavisnosri od iipa.
,;";;" "itu'rr;""
i objekaf ie i^rsiiioagouu.u_ C++-u. podrazumeva s" au-n rirci;" dlanice nlsu dinamidki
povezane' pa to svoi-
ako.r"
-o*i" redi virtual' Virtuelne
vati, kdd u novom oodtipu moZe biti r.rati koji deo koda ce se izvrsa- r*" ;;;; izridito zahtevati nivodenjem rezervisane
tunkcije. sta prevodira.,idi kudu
a*g"aiji, pri demu ," .r" *".,iu poriu i;rk;ii vam izrazite t-ry" u ponasanju klasa iste porodice'
omogucG; a"
objekat Upravtiacptic" "",r"'[3;i7"" i"a","L*sur"r'fr? p.i*",
,-1'no ,.1 ktasu pu"u i.," ,iu tog ru
Ove razlike dovode do polimorfnog pona5anja'
poioaica naia (sve su zasnovane na istom inter-
tiga Iz perspektive objella1l9i "p_s,i*;;;ktima Razmotrimo primer oblika.
upravryaJntice io';. pogoa., o, zatosro se ne mora Da bismo.prikazali polimor-
t9O z-1p.epor.,auar,ye konkretntg f.rr;;;id"taie grafldki ranije u ovom po4uulj"'
ll:i]ry:b":r
ponaSanja.. Kako jg moguie
tipa price s kojom se radi, niri n}"il, [oji zanernarule posebne detalje tipa i odnosi se
ll_.1"9 da poziv"tunt.i;e pomZriO a"o*ai ao ""pit"cemJdeotoda
samonaosnovnunasu'Ova;k6d'ieodvoienodit'fot*ucijasvojswenihtipui
rspravnog pona5anja iako nije poznato
kog je tipa ptica (buska t.eii"Jiiipriru,
Pingrrin trdi ili pliva)? u ,"i" t"l"a""stavnije pi5e i lak5e razume' Kada se novi tip' na primer Sestougao'
kao Sto je
aoJu pi,t"- napisani k6-dde.raditi dobro s novim tipom'
;di; i t postojecim
-- tipoui-u. to ,nadi da je progtatrt proiiriv'
"asledivanja,
je
frnt"ilu.ri C++-u-(uskoro Cete saznati kako da napisete):
void uradiNesto(0blik& s) {
s.brisi0;
il...
s.crtai0;
)
konkretnog tipa objekta koii
obraia se bilo kom objektu tipa oblik i ne zavisi od
se crta i brise (,&, ,"uJi,,Ur*i adresu objekta
koji se prosleduje fuikciji", ali u
luo* tr"rr,rtto nij e bitno da razumete detalje)' U nekom drugom delu pro grama
moZemo da koristimo funkciju uradiNestoQ:
Krug c;
Trougao t;
Odgovor na ovo pitanje je pM preoket Liniia 1;
u objektno orijentisanom programi_
ranju: prevodilac ne moze po-uti urad i Nesto (c) ;
r.r"t.i;" *iradicionalni .rueirr. eoril, ru.rt"i;"
koji pravi proceduralni prevod,ac aoroai
ao ,o, og poueziuanja (engt. earry bind- uradi Nesto (t) ;
inp, o kome moZda nisie duli zato sto uradi Nesto (l ) ;
Znati da prevodilac poziva konkr",", "it"a"'"irt" ni razmisljali o alternativama. tip objekta'
r',rnr..i;, po imenu, a povezivad razresava Funkcija uradiNestoQ radi ispravno, bez obzira na konkretan
poziv pomoiu apsorutne adrese j" slededi red:
k"d" k;j;-;;;ba izvr.iti. objektni proSram ne Oro tw*"o zadudujudi trik. Razmotrimo
moze da odredi adresu koda do wemena
nom.poslati poruku opStem objektu.
ii*lui*;u, tako da irJ; o'*ir.r.ruri- uradi Nesto (c) ;
O'.O]I Xrug je Oblik'
objektno orijenrisani jezici're.avaju taj problem Krug se prosleduje tunkciji koja odekuje. objekat-tipa
primenom kasnog poue- moZe da primi svaku
ziuanja (engr' rare bindi.np. K6d koji'""u7 puit r,inr."Uu *"diiJ;;i;, ptt*lt u naiiti.nirin' Krug
i"r."".i. pri slanju poruke objektu, tipa oblik. Znadi, ovo je sa-
odreduje se tek u weme izJrsavu";u.
rru"oairJJorezteouje aa tJnrnkcila postoji ;;rrk" koju uradiNerto0 *oz" da posalje objektu
i proverava saglasnost tipova arg,menata svim bezbedno i logidno.
i powatne wednosti (jezik u kome ovo je osnormog tipa' postupak
Kada sa objektom fredenog tipa radimo kao da
'. :dijg slabo ripiziran), ati ne ina taeno tJlitoa ce se izvrsavati. konuerziia.(engl' casr)
Da bi se osffarilo kasno povezivanjg,
c+i prevoditac;;;;";lj; nazivamo konuerziialnuXe (6nil. upcastin$. Termin
specijatni deo oblika, atrau1e (e.,gl. up) na nadin-uredenja dijagrama
koda umesto apsolutnog-poziva.
ovalkoa ir.Iru.ruru adresu tera funkcije odnosi se na promenu
kori- izvedenih tipova ispod njega'
sienjem informacija smirjgln, nasledivanja, ,u orrror'rri* tipom navrhu i lepezom
;e.aetarjno fr "g"dj, j"lomeranle navi.i u dijagramu nasledivanja' tj'
"ui"lrifp"-r,rpat
15)' Svaki obiekat se Donasa razlidiio,
"p[*
, rurrir.,o'.ti gd sa$rzaja Lvog sprcijarnog ii""r"iri:" tip
or.ro.,rri "kon-
Kada posaljete poruku objektu, on "
verzijanaviSe".
taau odluduje sta'ce'"uraaiti s
i:ii["j:
28
Misliti na jeziku C++ poglavlje l: Uvod u objekte 29

tokom
memorije koju milroprocesor neposredno koristi za duvanje podataka
izvrdavanja progtur.ru. Promenljive na steku ponekad se nazivaju aunmatske
G"d. ili oAUsne (eng. scoped). Statidka memorija je fiksni deo memo-
se rezervise pre poee=&a iansavanjl programa. upotrebom steka ili
""io"r"tti)
ii;"]m;i sto
,iuiift. -"-orije daje se prednost brzini zauzimanja i oslobadanja.prostora,
fleksibil-
moZe biti znadajno u nekim situacijama. Medutim, time se umanjuje
nost, zato sto morate tadno znati kolidinu, Zivotni vek i tip objekat a tokompisarrja
programa. Ako redavate op5tiji problel, klo Sto je projektovanje primenom
je pre-
iaa,i.r*u, upravljanje skladi5tem ili vazdu5nim saobradaiem, ovaj pristup
vi5e restriktivan.
Drugi pristup je pravljenje objekata t dinamiikoi memorli! @ngl- heap)'
U
ovom iu8a;u, do *"*.r,u izrrrSivan;a se ne zna koliko je objekata potrebno,
objektno orijentisani programeri obidno
koriste konverziju navise, izwsa-
moraju znati s kojim konkretnim tipom.ua".-rogreau;mo ier tada ne koliki je njihov zivotni vek, ni kog su tipa. odluke se donose u trenu&u
k.d u uradiNesto0: ,urr;u.'fuauvamzatrebaobjekat,pravitegaudinamidkojmemoriji'pomodu
s.brisi0;
,"r"*ir*" redi new (novi). Po zavrsetku upotrebe memorije, ona se mora osio-
//... boditi kori5denjem rezervisane reli delete (briSi)'
s.crtaj0; pro-
Posto se memorijom upravlja dinamidki tokom izwSavanja, rezervisanje
zapazimo da u kodu ne postoji:
"&o Krug, neka uradi ovo, ako je Kvadrat, stora tale znadajno duie od iauzimanja'prostora na steku. (Zauzimanje pro-
neka uradi ono itd.,,. Rko piSete'kOa
to
i: stora naiteku desto se osparuje mikroprocesorskom instrukcijom
koja pomera
mozepripadatiobrik,g";;;"j;';;;?:ilTJfl,:',:',*X5:n;;,1"1,*: pot-i*f steka naniie; druga instrukcija pomera pokazivad navi5e.) Dinamidki
dodajete novu wstu oblita. Ovae
." ,ur"o.tZ": ,,Objekat je oblik, znam da moZe polazi od uop5tene logike da su objelci sloZeni, tako da dodatno rneme
uradibrisi0 iristup
da i"Iuio,n"Lu r*alio, ifou.t""r" J*r" iriJii**"l iu ,"r"*ir*;e i osiobadanlJ memorije nema znadajnog uticaja- na ukupno
U tunkciii uradiNesto0, zanimrjivo jI,_q.il"
weme potrebno za inicijalizaciju objekta. Neophodna je i veca fleksibilnost
za
se, na neki nueinl ,u" odvija
treba' Poziv crtai0 za Krug izvrsava kako programiranju.
a*g"eiiitoa ruKvadrat -
-re5avanje op5tih problema u
ili tougao, ali kada ," "ilffi#;;ioror"
n9*t1.g1taffl p%s"rye nepoznarom oUtitu, ponasanje je it"a"c" iitan;e;e zivotni vek objelta. Ako inicijalizujete objekat na. steku ili u
takode ispravno, prema tipu oblika. postojati i moZe
ori i:. rl"o.an;r;;;;;;;ilkao Sto je ranije statidkoj memoriji, prevodilac odredule koliko ce dugo objekat
redeno, c++ prevodilac n" ,.,a
radno s r"i1, tpr{i";.fii;;;r"vodi tunkciju
ga automatsfi uniititi. Medutim, ako inicijali"ujete objekat u dinamidkoj
uradiNesto0. odekivali biste da prevoaitu".qoror"
u"rziju funkcija brisi0 i crtaj0 ilemoriji, prevodilac ne zna koliki je Zivotni vek objekta. Programer mora da
za obrik, a ne za odredeni xr"g,
je porimorfizam. Time
xvaaraiiri n""g*. ir#"ilfrii*og po,asanja odUei tadi da uni5ti objekat i ovu:operaciju iz,r5ava upotrebom r_ezervisane
r" uuu" ir"uoaitu. i i^rsni"irtem. Bitno je
je jos vaZnije, da poznajet" da to znate i, .to ."fi auf"tu. postoji i drugo re5enje: skipliai smeda (en{.. garbage co-lhctor). On
proglama
.rudi, t".isc*;" ouit, mog,rc.roriir projektovanju. automatski otkriva objekte koji sb vise nekoriste i unistava ih. Pisanje
Ako je funkcija dlanica iektarisana je wakako mnogo pogodnije' ali zahteva da sve
kuo oi.a"ur, objekat ce se ponasati pravilno toli t oritt" skupljanje smeda
kada mu posarjete poruku, eur weme koje mu je
i Jo;-" primenjena konverzija
navise. ap'likacije toleri-Su prisurfto skupljadai dodatno procesorsko
ova mogucnost nije bila u skladur s osno'rnim zahtevima c++-a i zato
;il;;
'rri;" za C++ postoje skupljadi sme6a nezavi-
lnicijalizacija i. unjitavanje objekata Uitu rrnlrrienidirektno ,r;"rik, iako
snih proizvodada.
u tehnidkom smislu, oop je obrast ipstrakt.iil
polimorfizma, ari i drugi aspekti lino* podataka, nasledivanja i
-.gr'biii poai"a,iJo i*iilt]bra" r".ur*u_
rraju ra druga vaZna piianli.
Nadin inicijarizacije i unistavanja
Obrada izuzetaka: rad s gre5kama progr-amir-anju' jo5 od na-
objekata posebno je znadajan. Gde Obrada gre5aka je jedan od najsloZenijih postupaka pri
podaci objekta i kako se odr-eduje se na.raze
jezicima primenjeni su razriditi il;Jreiffi
njll'ov zivotni ,"ki ^c* programskim ,tu"tu plogru*stcitr lezita. foSto ;e toliko teSko napraviti dobru Semu.za obradu
pri.iuiiori* pitanjima. gr"Suku, miogi jezici zanemaruju ovaj zahtgv' Problem se prenosi
projektantima
snost najvaznija, tako da izbor oitavrjaprogftrmeru. ,.i"o" da je efika_
Da bi se postigra maksimalna tiUUot"iu, p;;i daju polovidna re5enjaprimenljiva na mnoge situacije, koja se
brzina izvrsavanja, smestaj i zivotniuJt
s9 *ogu definisatitokoL pisanla
pro_
tuto *ogu'r*"**iti.-Ook programer koristi Semu za obradu podataka, mora
grama, postavljanjem objekata
na stek iti u st?tidku-;;r*'stek je veoma p-'ualiro pratiti odgovarajude konvencije koje nisu obavezne. na nivou
obrast lako mogu
samog jizika. eko programeri nisu paZljivi, Sto se desto de5ava u Zurbi'
Misliti na jeziku C Poglavlje l: Uvod u objekte
b'ooo izuzetaka (engl.
tion ha ndl indt excep
sakasaprogramskimi.rik"-,;"k;;;ffi
, ^,.?
':'r"#:i"Tffill'rr,r"Jffi namenjena resavanju najvedih problema. Zapamtite da najvedi broj projekata
[:?31?f,.i, n" spuda u kategoriju velikih problema, tako da analizu i projektovanje moZete
:li"i,#; "ri;,n'::T:l;1i:4: d;*il!g,.".g,
tzuzetaka
a,,hvara, (en st catch)
(enfl" exception hand.ler).our"i" sa .$p"5rro izvesti lrimenom malog podskupa preporuka koje propisuje metodo-
je drugadiji, paralelni
ol'*' gresaka to[i1a.6 Bilo koji postupak, koliko god bio ograniden, izvodi vas na pravi put
,13i,"i"i"i;;;.:ili11X?ffi
koda. rakav k6d
l#lli;,;,,:;:*;;itr#TiHfl"f,f *1
se,"o-l::,u_*l:;;#;ffi|morate
*rrogo brZe nego ako odmah podnete da pi5ete program bez projekta'
Lako je upasti u zamku, u,,paralizu usled analize", kada oseCate da ne moZete
vate.sreske. osim toga, neprekidno da provera-
i1u1!e{ ir*"lir,,i"'roa napredovati-po5to niste razre5ili sve pojedinosti tekude faze.Bez obzira na to
kako b;;;H ;"
c."sk" ki:i;; d;k"ija, niri, koiiko analizirate, neke stvari o sistemu nedete otkriti sve do faze projeltovanja.
IoS viSe Cete saznati kad podnete da pisete program, i]i tek kad se
oe
gresk" - oii ," ,,og, program
ili'fr,iifl1)Iffiia-dennise
uit on.aaln.-io-;H'":
moZe ignorisati, pa se garantui"
"astanaki
ai c" rra.r"ko*- I
prihvatljivom brzinom krs2 analizu i projek-
-"rtu aktMra. Zato je veoma vaZno prodi
u.
",
to iriu.,;;;
zec
il;:1
t o b ez b edul u po uztan rd;;; l;'s,i",
i
tovanje i testirati planirani sistem.
programa,
Drosram2 i,^.r-i^
Sto daje *--^_rma,.desto.noz"i" folfruviti stvari
mnogo.oour"i;",ii""irvvPr<rvru sw6ln Ii nastavid ,*:rj:-"^?,"1
nasre,,iri izvrsavanje I
Posto imamo iikusWa s proceduralnim jezicima, naglasavamo: pohvalno
je da
Vazno je primetiti da- tim paZljivo radi i shvati svaki detalj pre podetka projektovanja i-realizacije. Sva-
sanoS programiranja,
obrada iir*i"i" karakterisrika
ari je uobida-ffiHjJ'; "r,e objektno objektno orijenti- tako je pri irraO sistema za upravljanje bazama podataka neophodno potpuno
o u;'tto'".' oii"i""L,7J,"ra
ori;entisaniil jezicima ,-*rti potrebe kupca., Ovaj sistem pripada kategoriji dobro postavljenih i
:'.Ti!"tl"lfi l::ilf je postojara i pre o bjektno dobro shvadenih prob-tema, a u mnogln takvim programima_struktura baze
Obrada izuzetaka se podataka 7'esre pfoblem nad kojim,se'trebq zamisliti. U ovom poglavlju se rulma-
punosti pokriva ou.uaulffi?powsno uvodi i koristi u ovom tomu. Tom z
r

u pot- ta nasa progrimerqkih prgbl;na ,iz- skup-a,dZokera" (moj inaz).Do re5enja ovih
problema se-ne dolazi freoblikovanjem nekog.dobro poznatog resenja. u pro-
A n ull"i^3_i proj e krova nj e tl"- r" ukljuduie jedan ili vise ,"nepoznatih dinilaca'' - elemenata z1!o]e 39
postoji prethodno dobro razradeno redenje. Neophodno je istraZivanje./ Poku5aj
da se'diokeiski problem sveobuhvatno analizira pre prelaska na projektovanje i
uDJektno orijentisani pristup
ra n j u i m n o gi ,J novi i drugadiji nadin razmisliar .
r ro ru J ;;,; ; # ;:;;r.,,j. r" Jr rn"";i:r;:,T""rgji:T#:
ur u realizaciju dovodi do paralize g 3lalizi, po5to za re5avanje ovakve wste problema
"s
dok udite';";; rls" ne stidete dovoljno informacija tokom faze analize" ReSavanje ovakvog problema
razmisryu* nu ouf"iino
itll':;3r:iil?-i
ooprrii-"."
pudeti da pravite dobre projek," orijentisani
k"jl;.;;;;" rriri p."arrorti zahteva iteraciju koz ceo cikius i prihvatanje rizika (ima smisla, po5to poku5avate
to,,e dauradite ne5io novo i eventualna nagrada jeveda). MoZe izgledati da rizikpotide
Metodologijaje skup posrupaka od ,,uletanja'' u lselizaciju. Upravo ranim otlcivanjem podobnosti konkretnog
programskog probrema. i heuristika primenjenih
l,rnoge da
bop rr","a"r"sr;"
se razroZi sloZenost pristupa pioblemu smanjujete riskantnost dZokerskog projekta. Razvoj progra4-
il'i;;*"# ro nastanka skog proizvoda ukljuduje i rizik od neuspeha.
;:ilttli:1,"lJ'.'#?ifixtril'Jilf ;gji#::,"'?""ffi '#,.i,io,"cu;,i d"rto r" predlaZe di ,,napravite jedan projekat da biste ga bacili". U OOP-u
S met^.1^l^-ii^-^
,,- i- ::gijam a ^-
:" "r
o o ;; ;;;;' ;i:ilff ff liT," moZete odbiciti neki deo, ali kako je k6d kapsuliran u klasama, tokom prve ite-
racije Cete neminovno napraviti neke korisne klase i do(i do wednih ideja o
;i"*;f :ru',l53,l:"::r:;,,#ffi",;:i;l"Xl'iT"."t,?,?';E;;t:ff,1: sistemu, koje ne bi trebalo odbaciti. Na taj nadin, prui brzi prolazak_kroz pro-
y31"q''*,""i;";x;iffi blem pruZa znadajne informacije za sle$edu iteraciju analize, projektovanja i
":"".""fu:,ii:"Hi,:lii;.i,:ffi
1*;;,,t,1*rr,,:: realizacije, i pravi osnovni kdd za.tu iteraciju.
ffi::?i"Tj]:,:f;,.|*T metodorogija-"Idi.r" krasa probrema u c++-u obra-
jamanesouprocear:."r",-'i'"ri.i-r. Ako traZiti metodologiju koja obuhvata mnoswo detalja i preporuduje mnogo
v"zr"i"'."##iil jT^"::-1"-logi
,,metodologUu,, koraka i dokumenata, svakako de vam biti teSko da znate kada treba da se
r.tetoaoloeiia ;". _;;.lX]:,lzraz desro prereZat i ,r"ui.<"
"""n,.,. zaustavite. Imajte u vidu Sta pokusavate da otkrijete:
ilfi:+iEli"t]tff i*i,#:,H:f l.ftr:Tj;"l:Tfi i":;:H:i3"*il1 I . Sta su objekti? (Kako delite projekat na sastavne komponente?)

i:,:li:ti!Tr::I,i:urfrri:fl *:T,:t""?i1i{i,fl :;:t'#;,Tr*f,*


2. Sta su njihovi interfejsi? (Koje poruke treba da Saljete svakom objekru?)
scu r konadnim rezultat

''"il:ir;xli""'*,i#Jf :i*"#;h:J:',ffi ?l*ffi 'Jil"1::1ff'rl;


;;kffi;;"":[J:il,:,;:ffi r.:ltffl:*"":r
preopsiran
6
odlidan primer je uML Distilled.MaiitrFowler, Mdison-wesley, 2000, koji redukuje ponekad
biti io jeste: nemojte
se izgu. UMLproces.
rogr;a analize i projektovanjije 7
Moje pravilo za procenu takvih projekata glasi: ako postoiivise dzokera, nemojte ni pokulavati da planirate
-nitl
totilo ,lugo ie irajati proiekat kotlto ie ko(tati, sve dok ne napravite radni prototip Postoii previse
34 Misliti jeziku C++ 35
na Poglavlje I : Uvod u objekte

Dijagrami sludajeva korisienja namerno su veoma jednosta',ni da bi vas Ako se nadete u zamci, ovu fazu mozete prevazici primenom grube aproksi
macije: opisite sistem u nekoliko pasusa, a zatim potrazite imenice i glagole.
spredili da se prerano upu5tate u detalje realizacije sistema:
Imenice ukazulu na udesnike, kontekst sludaja koriscenja (na primer, ,,pre-
na
dvorje,,) ili worlvine sa kojima se radi u sludaju kori56enja. Glagoli ukazuju
inteiatcile izmedu uiesnika i sludajeva kori56enja i deflni5u korake.unutar
sludaja (ori56enja. Otkriiete takode da imenice i glagoli proizvode objekte i
por,rk" u fazi piojektovanja (primetite da sludajevi kori5tenja opisuju inter-
'akcile
izmedu podiistema, tato, da tetrnitca ,,imenica i glagola' moie da se koristi
,u*b kuo por*Cno sredspo pri razmi5ljanju, po5to se tako ne dobijaju sludajevi
kori5Cenja).e
Granica izmedu sludaja koriscenja i udesnika moZe ukazati na postojanje
korisnidkog okruZenja, ali ona ne dehni5e to okruZenje. Da biste se upoznali sa
Prikaii saldo
raduna {0 fro."ro* iefinisanja i pravljenja korisnidkih_okruZenja, pog]edajte-knjigu
iare yor Use, autora Larry Consiantine i Lucy Lockwood, Addison-Wesley Long-
So/-

)-l- man, 1999. iliWeb lokacij u www.ForUse.com.


[l ovom trenutku je bitan osnovni raspored, mada to moZe delovati mistidno'
Imate pregled orrogu sto gradite, tako da cete verovatno imati idejutoliko dugo
C" t" tia;af. U igriie vetili broj dinilaca. Ako predvidite du-B
Bankomat perigd,.pr.eduze6e
to je
moze odluditi dise sistem ne razvila (i da uloZi resurse u nesto isplatljivije -
Svaki simbol doveka predstavlja,,udesnika, (engl. acto r) ko)i je uglavnom iobra stvar). Rukovbd.gWo moZdaje ved o{lyeilo koliko Ce trajati.-projekat i
ili neka druga wsta nezavisnog izw5ioca. (MoZe Uiti eat i drugiraflnarski i' poku5aCe da utide na vhsu procenu. N.ajbolje je odmah prikazati po5ten raspo-
kao Sto je bankomat.) pravougaonik predstavlja granicu viseg sistema. Elipse ied i dwste odluke. bilo ;e mnogo poku5aja da se Iansiraju pouzdane tehnike
je
predstavljaju sludajeve koriSienja, a ro su opisi koiisnog poslaloji sistem moZe rasporedivanja (poput tehnika predvidanja zbivanja na berzi), ali verovatno
obaviti. unije izmedu udesnika i sludajera koriSienja predstavljajuinterakcije. naltolle da se pouz-date u svoje iskuswo i intuiciju. Podite od svog osecaja koliko
Ce'proces zaisla trajati, zatim udvostrudite weme i dodajte 10 procenata.
Nije bitno kako je sistem stvarno realizovan, sve dok ga korisnik ovako vidi. Vab
sludaj koriSienja ne mora biti uZasno slozen, dak i ako je sistem u njegovoj unutrasnji osecaj je verovatno ispravah ii mozete doci do nekih resenja tokom
osnovi sloZen. Njegova ;'edina namena je da pokaze kako iistem izgteda-kotl tog perioha. ,,Udv-ostrudavanje" de rad udiniti udobnijim, a 10 procenata ostaje
sniku. Na primer: za-konadno doterivanje i detalje.lo Kako god ga objasnili, i bez obzira na zalbe
i
manipulacijekojeceusleditikadaobelodanitesvojraspored,izgiedadataj
nadin vodi ka usPehu.
Staklena basta

Faza 2: Kako iemo izgraditi sistem?


u ovoj fazi morate doci do reSenja koje opisuje kako klase izgledaju i kako ce
saradivati. Odlidna tehnika za piepoznavanje klasa i interakcija
jeste kartica
BaStovan
Klasa-odgouornost-sarad.nia tengl. Cl4ss-naponsibility-collabomtion,-cRC,).
Ovo sredsivo je znadajno zbog svoje jednostavnosti: zapodinjete rad sa- skupom
slutajevi koriSienja proizvode deflnicije zahteva, odredujuii sve moguce ,: jednu
?t,_
kartica dimenzila 7 x 12 cm ipi5ete po njima. Svaka kartica predstavlja
interakcije izmedu korisnika i sistema. pokusajte da otkrijete potpuni skupslu-
klasu i na njoj isPisujete:
dajeva kori5cenja svog sistema i imaiete jezgro onoga sto sistem treba da radi.
Dobra strana usredsredivanja na sludajeve kori5cenjijeste sto vas uvek waca na
ll
' L Ime klase. Bitro je da ovo ime obuhvata sustinu onoga Sto klasa radi, tako
sustinu i spredava da zalutate u zahteve nebitne za zawsetak posla. Ako imate da na prvi pogled ima smisla.
potpuni skup sludajeva korisienja, moZete opisati svoj sistem ipreci na sledecu
fazu. Verovatno neie sve biti sawseno izvedeno u prvom potusaiu, ali
to je u 9 ViSe informacija o sludajevima korisdenja mozete naCi u b)y-lllly"SU:e Caszs.Schneider &winters'
redu. Sve ie se razjasniti wemenom, a ako sada zahtevate sawsenu deflniciju .ladison-Wesley, f 998.i'tJse C-ase DiueiObieet tndeltng with llMl-RosenberS, Addison-Wes1ey,.1999..
prihvadjivo
sistema, upa5iete u zamku. l0 Moi oristuo ovome se qedavno promenio.buplranje i dodavanje 10 procenata Ce vam dati
da
;;",1r:;fir;;;; f-pi.,p"r"j.rhaanemaprevise dzrkershh dinilaca), alidete idalje morativredno
a pri tome
iuait" kuko birt" ,"*Stli posao u roku. lko vam je treba vile uemena za elegantno re5enje,
hodete da uZimte u radu, verujem da ie linilac koiim tleba pomnoziti tri ili Cetid'
Poglavlje l: Uvod u objekte 37

2' "odgovornost" klase: Sta ona treba da radi. Moguce je


njem imena tunkciia dlanica (po.to saZimanje nabraia- da su potrebni posebni dijagrami (primer je sistem za upravljanje). Opis struk-
ovaimenu",
budu opisna), ari se ne iskrjuiuju a"a"i".
aoUio_;;;iki;
-u.rfske. ;;;d, tura podataka sistema ili podsistema moZe biti potreban ako su podaci najzna-
kako zapodnete proces, posmatrajte problem Ako hoiete da makar dajniji faktor sistema (sludaj baza podataka).
gramera: koji objekti bi trebalo
sa stanovi5ta lenjeg pro_ Zna(ete da ste zaw5ili fazu 2 kada budete opisali objekte i njihove interfejse,
aa sL poyave da Or re5ili va5 problem?
3' "saradnja" ili bar ve(inu, po5to neki uvek izmaknu i budu otkriveni tek u fazi 3. To je, u redu.
klasa: s koiim krasamu oru kl"r" komunicira?
bran Sirok pojam ,,komunikacija,,, Namerno je oda- Samo hodete da pronadete sve objekte. Lepo je ako se otkriju na podetku pro-
postojanje neke druse,klase tola ;".
*oZ. okupljanje ili samo cesa, ali OOP obezbeduje dovoljno materijala za rad, pa nije stra5no ni ako ih
oUavry;;;g"^uditi
za objekte posmatftme otkrijete kasnije. Projektovanje objekata se odvija u pet nivoa' kroz proces raz-
ktase. saradnja trebi da uzme'u;;;ir"i;k;;""
napravite klasu vatromet, ko ce je prouda"ati' klase. Na primer, ako voja programa.
He,,r*ar ili posmatrac? prvi
ie Zeleti da zna hemijski ,ur,rv u a*giC"
i""gouuti na boje i oblike koji
nastaju pri eksploziji. Pet nivoa projektovanja objekata
MoZda vam se dini da kartice treba Objekti se ne projektuju samo prilikim pisanja programa, veC se projekat objekta
da budu vece
zbog svih informacija koje ce postupno ranija. Ova perspektiva je korisna, po5to prestajete da odekujete tre-
obuhvatati' ari su one namerno marih
dimenzija, ne samo zato da bi va.e krase nutno saw5enstvo i shvatate da Cete rrremenom uvideti Sta objekat radi i kako
bile male, nego i da se ne biste pre;;; ;il;,i;detalje. Ako
stite na karticu sve Sto treba- du ,.rutu ne moZete da sme- treba da izgleda. Ovaj pogled se moZe primeniti i na projektovanje razliEitih
tiJ, tf^";e previ5e sloZena (moZda ste tipova programa: obrazac za projektovanje odredenog tipa programa nazire se
uneli previ5e detalja ili bi trebalo.da "
."p;;;; il; od jedne klase). SavrSena klasa
treba da bude razumljiva nl tek posle duZeg napora uloZenog u re5avanje problema (Obrasci proiektouania
grvi pogea. CnC tanicepo_uZ, Ju.,ufrJi" g*U su opisani u tomu 2). Za objekle takode postoje obrasci koji nastaju kroz razu-
projekat, tako da steknere gtoUalnusiitr,
i p"i.* a"r.ir;;*d il:;;... mevanje, kori5denje i ponovnu upotrebu"
Komunikacija je jedna od velikih p*a""rii
circ #;;;. N;ib" "l;'re"raaiti u
grupi, neposredno, bez kori.ienja
,";r;;;;. S*k, udesnik preuzima odgovor- L Otkrivanie objekata. Ovo je nivo podetne analize programa. Objekti mogu
nost za nekoriko krasa (one u podetku biti otkriveni dok spoljni Iinioci i granice, ponavljanja elemenata u
se traZe
informacije)' Tako obavriate simuraciju
n.-uj, ,*.na, niti sadrZe b,o kakve sistemu i najmanje konceptualne ceiine. Neki objekti su odigledni ako ved
uziro,iesava;uci jedan po jedan scena-
rio, koje se poruke s^lj, imate skup biblioteka klasa. Slidnost medu klasama, koja,ukazuje na
ovog_odtuculuii
procesa otkrivate koje vam klase "6Jtil;; ali, ,. scenario osrvario. Tokom osnovne klase i nasledivanje, moZe se pojaviti na poeetku ili kasnije, u pro-
irebaju, njihove odgovornosti ir*"a'rr;r,
pri tome popunjavate kartice. xuau prtJuiu
balo bi da imate prilidno to.npletan
;;;.r"." sludajeve koriscenja, tre-i cesu projektovanja.
[*i
nu.ri-p"rl;"*,u. 2. Formiranie objekta. Tokom pravljenja objekta, nastade potreba za novim
Sro s.am podeo da korirtil,, Cnc
t"itiJe, nayrsp"snije konsultantsko elanovima koji se nisu pojavili pri otkrivanju' Unutra5nje potrebe objekta
,^,..0.:::.*o
rsl(usrvo sam srekao kada sam zapodeo projekat
s.timom i.ii",ri"J, mogu zahtevati podrSku drugih klasa.
koristio ooP i crtao obiekte ,""r;"
31,1gri.
objektima, neke od niih smo urisati
il;;;;, smo o komunikaciii "i;,
medu
3.Izgradnja sistema. U prethodnom nivou mogli su se pojaviti dodatni
i-zame'ri;;;il
,io;, .ffi;
#j:,n1i,,X;:Z:;"r", zahtevi. Objekte razvijate dok saznajete nove pojedinosti. Potreba za komu-

doSao je T" li J:t"T: :T: :111_"_"- f


;X,9". ?:
ffi. }F,
do resenia - niieim auto."s"";e, ;,," r e znao namenu p roj ekta,
nikacijom i povezivanjem s drugim objektima u sistemu, moZe izmeniti
i*rii,i"rfrT;r:'#ffi#HT:i potrebe klasa i zahtevati nove klase. Na primer, moZda Ce vam biti potrebne
vodenju projekta samo postavljuo p.u* pomod_ne klase, kao Sto je povezana lista, s malo ili bez ikakvih informacija o
pir"r;'r, testirao sam pretpostavke, pri_
mao powatne informacije. od tima i
menjao polaz"u ,rurrouisiu..i.-uJu.Lpo,u stanju, koje pomaZu rad drugih klasa.
procesa je bila u tome sro tim nije
utio ob;ekini o.i;..,tiruoo 4. Sirenje sistema. Dok dodajete nove osobine sistemu, moZete otkriti da
gledajuii apstraktne primere, nego ffik;;;;1." p."_
su rudili na svom resenju, koje im je prethodno reSenje ne omoguCava jednostavno proSirivanje sistema. Uz
tren_urku bilo najzanimljivije. u tom
Kada prikupite CRC kartice, moZda nove informacije, moZete restrukturirati delove sistema, i eventualno
iete hteti da.formalnije opi5ete svoje dodati nove klase ili hijerarhije klasa.
re5enje primenom UML-a.',uML
,"
koristan' narodito ako Zelite da stavite
...i"," mada moZe biti 5. Ponovna upotreba objekata" Ovo je pravi test opteredenja za klasu' Ako
au"g.""rl""potrebrjavati,
zid, da ga svi mogu prouda-
vati' .to je dobra ideja. Alternatiru neko poku5a daje ponovo upotrebi u sasvim novoj situaciji, verovatno Ce
ururil, i"lulrirurni opis objekata i njihovih otkriti neke nedostatke. Dok menjate klasu da biste je prilagodili novim
interfejsa ili neki pseudokod, Sto ,u"iri
oalo-riJCJrrog programsk og jezika.L2 programima, opSte osobine klase se razjaSnjavaju, sve dok ne dobijete tip
^,
y.r. ,obezbeduje o"f:::i_r*ek" ;;;;il.r'za opis dinamidkog modela koji zaista moZete ponovo koristiti. Nemojte odekivati da Cete vedinu obje-
slstema' To ie korisno kada su promene
stanja sistema ili podsistema tako vaZne kata sistema ponovo upotrebljavati - sasvim je prihvatljivo da veliki broj
objekata bude specifidan za odredeni sistem. Ponovo upotrebljivi tipovi su
ffiunuMLDist,ted-
'' Pytho n (ww. pyrho org) c".to i" io.i.tt Luo, ir*S.'ii."r?"ma.l
n. redi i koriste se za reSavanje op5tijih problema.
38
Misliti na jeziku C+-r PoglavUe I: Uvod u objekte 39

_Uputstva za razvoj objekata ovog perioda imate integrisani, testirani sistem, s vedim brojem moguCnosti.
Evo nekih preporuka raiaruoJ klasa, poseUno je zaninrljiva osnova iteracije: to je jedan slulaj kori5denja. Svaki sludaj
l' Neka klasa nastane iz konkretnog problema,
a zatim je razvijajte tokom kori56enji je pakei medusobno povezanih funkcija koje odjednom ugradujete u
re5avanjadrugih problema. sistem, tokbm ledne iteracije. Ne samo da se ovako dolazi do tadnijeg zakljudka o
2. Setite se da otkrivanje potrebnih klasa (i nji_hovih opsegu sludaja koriscenja, nego se on i proverava, posto se sludaj korisdenja ne
interfejsa) dini najveii
deo razvoja sistema. Da ste vei imali gotove
iclase, pr"j"k;i;ilil]"a.rorru_
oauacule poile analize i projektovanja, vec ostaje osnovna celina razvoja tokom
van. celog procesa izgradnje softvera.
3. Nemojte se prisiljavati da shvatite sve na piekidate sa iteracijama kada dostignete ciljnu funkcionalnost ili kada istekne
samom podetku - udite tokom
rada. U svakom sludaju, sve Cete saznati. rok, a kupac je zadovoljan trenutnom yetzijom; (Prisetite se, razvoj softvera je
4. Zapodnite programiranje,.dodite do nedegsto pladeni posao.) IGko je proces iterativan, za isporuku proizvoda imate mnogo
radi, tako da mozete dokazati mogucnbsti, a ne sarno krajnji termin. Projekti oworenog izvornog koda razvijaju
ili.opowgnuti svoje reienje. Nemojte se
i'rasiti au'c"t" ,u*s1JJu-plo""a*_ ..se iskljucivo g,iterativnom okruienju, uz mnostvo povratnih inforrnacija, i
ralnim spagete kodom - krase raseianlulu p.our"r",
rotair..l',icilloir"^u- upravo to ih eini,uspe5nim. "
tidne delove i nepoznate elemenete. rose nase
ne narusavaju dobre klase. Iterativni procei rawoia je vaLan iz mnogo razloga. Rano moZete otkriti i
5 . zadrzite jednostavnosl Mati jasni
i objekti, od kojih i-ua" oiigludrre korisri, . razreSiti:bitne rizikp; kupci imaju dovoljno mogudnosti da promene mi5ljenje,
bolji su od velikih srozenih interre;si. u iasu donolenja
offutce-tcoristite zadovoljstvo progr.rmera je vece i projektom se moZe preciznije upravljati' Io5
Occamov princip: razmotrite mogu.nosti i . jedna znadajna piednost,je davanje pouatne informacije investitorima, koji po
uzmite nu;;"if,roria"nl;u, poSto
su jednostavne klase._uvek najborje. podnite 'Uenutnom
oa maogf ied"oriu*G i","r- stanlu proizvoda mogu tadno videti u Sta ulaZu. Tako se umanjuje ili
fejsa klase, koji iete.Siriti tek kaaa ga budetebolj.
,"?rl""ii, p"ffi eliminise potreba za iscrpljujucim sastancima i povecava se poverenje i podrska
wemenom odstranjivati elemente iz klase.
"Src ,,investitoral;l;l.:lt:lt::.:ilt'ii1.,ilrii1lj;,,l.1Jl11|l.l.,
' .. '',i ,.':. :',1:., rrt..1, ,r.., 11 .., . 1 ,r i I /

Faza 3: Cradimo jezgro Faza 5: EvolggUa


ovo je prvi prelaz od nacrta projekta u prevodenje
moze.testirati, i koji ce dokazati rii opowfnuti
i izvrsavanje koda koji se Ova talka razvojnog ciklusa obidno se naziva,pdrZavanje". Tai sveobuhvatni ter-
ces nije jednoprorazni, nego je podeiak
ispra,rnost vaSe arhitekture. pro- min moZe znaditi bilo Sta, od,,postizanja da radi na nadin kako je prvobitno
iiza toiata t";i c"llr"ii*lizgraditi zami5ljeno ' do ,dodavanja mogudnosti koje je kupac zaboravio da- spomene" ili,
sistem, kao Sto iete videti u tazi +.
tradicibnahije, ,ptklanjanje otkrivenih grelaka'' i,dodavanje nwih mogudnosti
cilj je da
p-ronadete jezgro. konstrukcije sistema,
koje treba rearizovati da bi se kada se ukai,e potreba''. Mnoge zablude izaziva termin,,odrZavanje"' jer poprima
napravio izwsni sistem, bez obzira na,repotp,rrrort
koji moZete nadogradivati u slededim itoa.!u*u.
., prvom prolazu. pravite okvir sumnjivo znadenje, delimidno zato sto se namece miSljenje da ste zapravo
Osim toga, ,p-""ai[pr* odavno napravili program i potrebno je samo da zamenite delove, podma}ete ih
p:og.t faza integracua i testiranja. sistema, i pruzate
d*,iG;'-pI*u*,, "a i ne dozvo[te da:zardaju. MoZda postpji bolji izrazkoji opisuje Sta se tokom ove
informaci.l'u o izgledu i napredovanju sisterna.
neke znadajne rizike. Verovatno ceie otkriti
i najboljem ,frrfujr,-o-tiluut" i fazezaistade5Svit.',;r',;,.,.'i'1"
sta promeniti u prvobitnoj Koristicu termin euolucija.rl znati, ,prvi put nece uspeti, zato dozvolite sebi da
arhitekturi i kako iete je pobolj5ati da niste r;;tizovali
_treba
saznali.
- sistem, ovo ne biste ni udite, a zatim se wptite i napravite izmene". MoZda Ce biti potrebno mnogo izmena
Deo izgradnje sistema. je provera podobnosti nakon Sto.dublje razumete osnoule zahteve. Elegantan kdd koji Cete napraviti
s]s1e1a (u kakvom god obliku postojali).
analize zahteva i definicije tokom daljeg razvoja dok se ne dobije sasvim odgovarajuci sistem, isplatice se, i
Obezbedite au t"rt pror"ruru rlt t"rr" i kratkorodnol dugorodno. Evolucija je procesukome dobarprogrampostaje sjajan
sludajeve koris.enja. po usposfavljan;u staUitnogl"rgru.irtu^*u, ,p."_Jr,u
au i u kome se razjasnjavaju spoma pitanja iz prvog prolaza.ll tom procesu se kJase
nastavire dodavanje novih moguCno jti.
za upotrebu u jednom projektu razvijaju u ponovno upotrebljive klase. -
,,bagovaraluCi sistem" ne znadi samo da program radi prema zahtevima i
4: Razvijamo slucajeve koriiienja sludajevima korisdenja. To znadi i da razumete unutrasnju strukturu proglama,
l?1u
Kada se napravi izvrsni okvir j.rg.u da se sve dobro uklapa, da nema nejasne sintakse, prevelikih objekata ili nespre-
,i-rt"-u, svaki skup o."obi.ru koji dodajete je
jedan mali projekat. skup osobiia tno izloZenih delova koda. Osim toga, morate imati i uvid da Ii Ce struktura pro-
aoaaiete totom itiracije,rrurrrrl.ro tJu*og grama preZiveti promene krozko)e Ce neminovno prolaziti tokom svogZivotnog
perioda razvoja.
Koliko traje iteracija? u najboljem srudaju, iteracija veka i da li se te promene mogu uneti lako i jasno. To nije mali podvig. Ne samo
. traje od jedne do tri sed-
mice (moZe varirati u zavisnoiti od jezika nu ko-, ls
." p.ojekat realizuje). Na kraju Barjedmaspektevoluciieopisanleuk$idRefrcaring:lmprovtngthedesignofexisttngadaMutinFow'
lec iddison-Wesley, 1999. Upozoravam vas da hxiiga korlsd isklju6ivo primere na jeziku Jaua-
-
40
Misliti na jeziku C++ Poglavlje l: Uvod u objekte 4l

da nrorate razrrmcli ira pravite, nego i kako


ce s uklapaju mnogo jednostavnije nego ako se odmah bacite na programiranje.
rraz varr ,okro, p,o,n",,;ril; o;i";;,l;;;,;"#;,"r?:?-JilfiJ;J,'rT,;:'.f;::
u stanju cla podrze ovu wsru neprekidnih promena Moje iskustvo govori da je elegantno re5enje izvor zadovoljstva na sasvim pose-
rrl:iekri spreiavaju raspad srruki,,re. rutoi.-uam -
granice koje postavrjaju ban nadin: bliZe je umetnosti nego tehnologiji. Dostizanje elegancije se uvek
zivarr ja ver'ih lrorresa u koclu, unosite
omoguiavaju da, bez iza- isplati i to nije beznaiajan posao. Dobijate program koji se jednostar,nije pi5e i
izmene kakve bi dei-ovare i.uri[ro u pro- gredke se lakie otklanjaju, program se lak5e razume i odrZava, a tu se leZi i finan-
prosramu. PodrSka evolutivnom ,uruo;, je
moZda i sijska dobit.
::i[1::. "";r.c"i"rirt
U evolutivnorn razvojrt pravite nesto
bar pribliZno onome Sto mislite da treba
izgraditi' zarrm ro isprobavate uporedujuii sa ,atrtevima
statke Mo,ete se vratiti i.ponovo projektovati i pronarazite nedo- Ekstremno programi ranje
i realizovati derove programa koji Tehnike analize i projektovanja sam detaljno proudavao, jo5 od studija. Koncept
nisu radili ispravno da biste otkronili'nedostatke.,,
MoLd.aiete morati da resa_ ekstremnog programiranja (engl. Extreme Programming, W ) ie najdetaljniji i
vate problem, ili neki niegov asp.ekt,
nekoriko puta pre nego Sto dodete do pra- najbolji koji sam video. Hroniku moZete pronaii u knjizi Extreme Programming
reSenja. (ovde moZe biti korisno p.ordrrurj"
'og
opisar.rih u tomu 2.)
obiazacaiiiiiir""ir, Explained, autor je Kent Beck, izdavad Addison Wesley, 2000. i na Web adresi
Evolucija w w w. xp ro gramm in g. co m.
se desava i kada napravite sistem koji
odgovara zahtevima, azatim XP je i nadin programiranja i skup uputstava. Neka od ovih uputstava odrrta-
orkrijete da to nije ono 5ro ste ht"li. rada viditeiirtJ-
u oa", olni;'"i"-au r,. vaju se i u drugim sawemenim metodologijama, ali dva najvaZnija posebna
zeleli da resite neki drugi probrem. ato
oe"tuf"t" oraka, tok razvoja, sto pre doprinosa su ,,prvo sastavite testove" i ,,programiranje u paru". Iako se dwsto
napravite.prvtr verziju, da biste rano otkili
da li je rezultat ono Sto ste zaista zalaLe za proces u celini, Beck naglaSava da iete znadajno poveiati produk-
nameravali.
Najvaznije ie zapamriri da ie, po definiciji, tivnost i pouzdanost ako usvojite bar ova dva nadela.
ako menjate klasu, njene narklase
i potklasc i daljc racliti. Ne'morate se
bojati ir..nu
(narodito ako imate ugradeni
skLrp 1esto,,,a za
I)roveru njihove ispravnosti). fr-"n, ne mora obavezno naru5iti Prvo sastavite testove
ceo prograrr, a rezurrar biro k.je promene moTe biti ograniden,.,, po,ir"." irili Testiranje se tradicionalno ostavljalo za sam kraj projekta, po5to ,,sve radi, samo
pojedine saradnike promenlene klase.
se treba uveriti". Samo po sebi je imalo nizak prioritet, Ijudi koji su se specijali-
zovali za testiranje nisu uZivali naroiit ugled i desto su preme3tani u suteren,
Planiranje se isplati daleko od ,,pravih programera'. Timovi za testiranje su odgovarali na svo; nadin,
Svakako ne biste zidali kuiu bez mnoStua iduii dotle da se oblade u crno, a veselo su se razmetali svaki put kada otkiju
paZrjivo iscrtanih pranova. Ako pravite neku gre5ku (iskreno redeno, i ja sam se tako oseiao dok sam obarao C++ prevo-
kovili kuiicu za psa, pranovineie biti t"rto h.iaf"i,;i;.1;*n,l;i,1"ouru.*u
koji ie vas voditi. Razvoj softvera je otisao dioce).
stupalirazvoju,pasuverikiprojektipoietidapropadalu
t
u ri"ortr. Dugo ljudi nisu pranski pri_ XP u potpunosti preokreie koncept testiranja, dajuii mu jednak (dak i vi5i)
Kaoreakcijasunastajale prioritet od pisanja programa. Testove pi5ete preodgovarajuieg koda i oni ostaju
metodologile s neverovarno sioZenom ,trrkirrJ_
namen.iene veljkim projektima. Bilo je previSe
i obiljem a.tiiu, ,slu*o,,, zauvek uz k6d. Uspe5no izw5avanje testova je obavezno posle svake integracije
zastra.ujuie koristiti te metodo_ projekta (to se deiava desto, nekada i vi5e puta dnermo).
Iogije - izgtedalo je kao da i_ete sve ;;;;
nimalo neiere programirati. (,b je iesto i ;;riti pisanju dokumentacije i Pisanje testova ima dve posebno vaZne posledice.
uio srueaj.r Nadam se da pristup koji Prvo, pisanje testova primorava da se jasno defini5e interf'ejs klase. Cesto sam
sam vam ovcle prikazao preporuduje srednji
put _ liniju ;;p;;;;;.'rliirti,. kao pomodno sredstvo pri projektovanju sistema preporudivao ljudima da
pristup koji odgovara vaSim potrebama
fi ,aSim osobinama). Bez obzirana to Sto ,gamisle savr5enu klasu za re5avanje odredenog problema'. XP strategija testi-
nro2e biti i mininralan, neki pran ie
svarcako puno poboljsati r"s p*ri.;;',*za
Iiku od rada bez plana. Zapamtite aa, po raz- ranja ide joS dalje: tadno se defini5e kako klasa mora izgledati njenom korisniku i
,eeiL.,i f .o."ru, preko 50 procenata pro_ kako se mora pona5ati. Nije dozvoljena nikakva neizvesnost. MoZete sastaviti
jekata propada (neke procene
idu do io p.o."nitul.
Radeii prema planu, po kompletan tekst ili nacrtati sve dijagrame koji opisuju pona5anje i izgled klase, ali
jednostavnom i kratkom, i projek- nista nije tako stvarno kao skup testova. Tekst i dijagrami su iista Zelja, a testovi su
-moguinoiti
tovanjem strukture pre nego Sto podnete da programirate, otkriiete da
se stvari ugovor koji podrZavaju prevodilac i izw5ni program. Te5ko je zamisliti realniji
opis klase od testova.
groglrvljrr ()hra{i t)roic^.t,ilnrua u
l] ,lerrlin,., ,kori.rirr
( ,\ r) r/gterta k,to ..lrrza izr ar la Pr.totrlla,., rr Lo1, lj s
lomu 2. Pri sastavljanju testova primorani ste da paZljivo pregledate klasu i desto iete
rc naprauili brzu i grubu verziiu,
.r.ir , r. ir()\le rtsl.iil odlr.rcrrt.re
Irrororr, i.rzgraduicre piari
ta ko da moZete upo/naLi otkriti neophodne funkcije koje mogu biti propudtene tokom eksperimenata sa
, si","_. n-Uf <i;;r%;;;,;,"r;;1".,r"-
rrrrr pr,)rurip. .cHo * *:r ,r"U:lil"!ll,:r,l rada ".;" r
re bizi protoiip tomUtnr;" reri.";k;;.;;;;;;;"., p."- UML dijagramima, CRC karticama, sludajevima kori5ienja itd.
( e(i u ra I n rn l)rogrinr ir.inju, cesto nasraj u zamrS".i
r )
,iJ,"ai e'i" ;. skupo.
"drzavanje
42 43
Misliti na jeziku C++ Poglavlje l:Uvod u objekte

u
l)ruga vazna posledica pisanja testova na podetku jeste to sto se testovi sejedno provuii sa stavom: ,,Neiu da pi5em testove"' Ako programer upadne
upadnu u problem' neko
izvr5avaju svaki put kada sklapate program. Izwsavanje testova se nadovezuje pi6Ul.^,'-ogu zameniti mesta. Desili se da oboje
na provere koje sprovodi prevodilac. Ako iz ove perspektive pogledate evoluciju lrugi, prostiriji duie njihove nedoumice i.priteii u pomoi' Rad u parovima
programiranje postaie
programskih jezika, videiete da je napredak tehnologije uvek pratilo uvoden;'e odrZava tok i pravac potlu. MoZdu je jo5 vaZnije to Sto
stroTih tcstova. Asemblerski jezik je proveravao samo sintaksu, ali je c namet- humanije i zabavnije.
veZbi na nekim
nuo neka sernantidka ograniienja koja spredavaju odredene tipove gresaka. Poie'o sam da piimenjujem programiranje u parovima tokom
oot'] jezici donose dodatna semantiaka ogranidenja kola su vidovi testiranja. seminarima i iskuswa svih udesnika bila su znatno bolja'
,,1)a li je ovaj tip podataka pravilno upotrebljen? Da li je ispravan ovaj poziv
lunkcije?" jesu tcstovi koje obavlja prevodilac ili izwini sistem.videli smo rezul-
tate ugradivan,a ovih tesrova u jezik: ljudi prave slozenije sisteme i pustaju ih u Za5to C++ uspeva
rad, i za to im treba mnogo manl'e vremena i napora. pitao sam se sta je ;azlog, C++jetoliko..,p.Su.,delimidnozatostonijebiociljsamodaseCpreworiuooP
ali sam shvatio da se radi o testovima: udinite nesto pogresno i sigurnosni sistem jezik (iako ;e tako podelo), nego i da se rese mnogi drugi -nrolle1t -s
koiima se
ugradenih testova ukazuje na to da problem postoji i gde se nalazi. koji su mnogo uloZili u c. Tvorci ooP
d*u, ,,roduualu piogrameri, riarodito oni i krenu iz
Ali, tcstovi u sa.nom jeziku nisu svemoini. U nekom trenutku morate ,i jezika tradicio"a"o r"" nastojali da nateraju korisnike da zaborave sve
nastupiti i dopuniti skup testova (u saradnji s prevodiocem i izwsnim sistemom) por..tusnovimskupomkoncepatainovomsintaksom,uzobraz|oLenjedaje,
jezika' Na kaie
koji proverava ceo program. Posto shvatate koliko je korisno da vam prevodilac gt"aulrrel dugorodnoi bolje ostaviti stari prtljag proceduralnih
element moZda i nije
stalno gleda preko ramena, zar ne biste Zeleli da vam ovi testovi pomazu od staze, veiina tog pitlaga je imala wednbst' Najwedniji
prevesti),
samog pocetka2. zato ih i pisite na podetku i automatski izwsavajte pri svakom postojeia progrimsta o'rrt* (koja se, uz odgovarajuie alatke, moZe
sklapanju. VaSi testovi pro5iruju sigurnosni sistem programskog jezika. r1egoosnouaraamiiljanja.AkosteaktivniCprogramerimorate.napustitisveSto
otkrio sam cla me koriSienje sve moinijih programskih jezika ohrabruje da znateoC-udauisteusvolitinovejezike,smanjujevuunSeproduklirmosttokom
eksperimentiSem, posro znam da mi taj jezik neie dozvoliti da gubim weme vise narednih meseci, sve dok se vas nadin razmisljanja
ne uklopi u no\u para-
ga' b.iiete jednako
Ioveii gre5ke. XP Sema testiranja radi istu stvar za ceo vas projekat. posto znate da digmu. Oslonite Ii se na svoje poznavanje C-a i pro5irite
Posto svako
ie testovi pronaii sve greSke koje napravite (a vi redo,rno dodajete nove testove pr"oauttimi aok se selite u sveioblektno orijentisanog programiranja.
dok raz-mi5l.jate o njima), moZete po potrebi praviti velike promene, ne brinuii da mentalni model programiranja, ova promena je dovoljno.komplikovana i
ima svol
jezikom od osnova' Razlog
Cete izaz,val.i potpunu zbrku u projektu. Ovo je neverovatno moino. bez dodatnih troskova zbog z"apoiinjanja rada s novim
je Jkonomski: mora se platiti cena prelaska na OOB ali je
uspeha C++-a u su5tini
Programiranje u paru ,"iu ruC++ moZda niZa.t8
Programiranje u paru stoji nasuprot individualizmu kojim smo indoktrinirani
CitjC++-ajepovecanjeproduktirrrrosti.ProduktivnostSepostizenamnogo
nadina,alijejezikprolektovandavamStovi5epomogne'neometajuiivaspre-
od pocetka, kroz Skolovanje (uspeiemo samostalno ili pasti, a rad sa susedima skup moguinosti'
vise strogim pravitina iti zatrtevima da koristite neki odredeni
se smatrao ,,prevarom") i medije, narodito holir,rrdske filmove u kojima se desto odluke pri projektovanju C++-a su bile
C++ je projek,or* Ju bude praktidan:
jrrnak bori protiv bez,mnog poretka.l6 programeri se, takode, smairaju uzorima
zasnovane na pruZanju Sto viSe korisnih moguinosti
programerima (bar sa
inclividrralizrna - ,,usamljeni kauboji programeri", Sto bi rekao Larry constan-
stanoviSta C-a).
trne. XII koli sc bori protiv konvencionalnog nadina razmisljanja, nrdi da pro-
grarn treba da piSu dve osobe za.iednom radnom stanicom. osim toga, ovo treba
raditi u prostoriii s veiim brojem radnih stanica, bez paravana koje vole projek- Bolji C poSto je C++ popunto
tantr raeunarskih sala. Beck kaze da pri prelasku naXp prvo treba doneti klesta Napr"edovadete dak i ako nastavite da piSete k6d na C-u'
da bi se rasklopilo i bacilo sve sto se nalazi na putu.lT (ovo podrazumeva da proveru tipova i analizu pri prevodenju'
niog" praznine jezika C i uveo bolju njihovu upo-
rukovodilac moZe da vas zaStiti od gneva osoblja za odrZavanje.) funkcije, tako da prevodilac moZe da proveri
ftforu"e"t. deklariiati
Vrednost programiranja u paru je Sto jedna osoba pi5e program, a druga ne koristi za zamenu
trebu. Pretprocesor je postao skoro nepotreban, bar se viSe
razmi5lia o njemu. onaj koji razmiSlja ima u vidu globalnu sliku i uputswaXp-a, a wednosti je
i mut<roe,-pi uklonjen uirok niza greSaka koje se teiko otkrivaju'
pogod-
ne samo trenutni problem. Ako radi dvoje, manje je verovatno, na primer, da ie ciii.nu svojstvo pod nizi.rom irpr",,o(engl' reference) 5to omoguiava
upotreba imena
niju obradu adresa argumenata ipovratnih wednosti funkcija.
koia
Iako je ovo pretcino an)eriako sranoviSte, holirudski frlmovi stizu swda. je pobolisana uvodenl-em preklapanja funkciia (engl function ouerloadin$
Ukljueujuii (posebno) razglas. Jednom sam radio u kompaniji koja je preko rzglasa obavestavala o tele-
fonskim pozivima i ro je neprekidnoometalo rad (direkrori nisu mogli di zamisle-da se ukine tako znaCajan
sistom kao aro je razglas). Konaano, kada me niko nije gledao, poaeo sam da sedem kablove. ffinostc++-a,mozebitijeftinijepIecinaIaw.odlukaoizboru
pretpostavljam da ste izabrali C++'
i*if." i.u *nogo einilaca, a u ovoj kniizi
44
Misliti na jeziku C++ Poglavlje l: Uvod u objekte 45
I
dozvoliava upotrebu istog imena
za razli(ite funkcije- Imenski prostor (engl.
i::,::1t!"r:J
takode unapreduje upravljanje imenima.
tor,o;. i'tfi"."orJUir. Maksimalna dobit od biblioteka
ro;e poveiavaju bezbednost C_a. NajbrZe iete napisati program ako koristite vei napisan kOd - biblioteku'
znaiajni cilj c++-a jeste jednostavija upotreba biblioteka. ovo je reseno pret-
Vei ste na uzlaznoj Iiniji varanlem bitloteka'u nove tipove podataka (klase), tako da se uvodenjem bibli-
oteke jeziku dodaju novi dp;vi. Posto C++ prevodilac vodi raduna o upotrebi
ProtiLtktirnost jt' problem priueenj-u
novog jezika. Nijedno preduzeie
scbi prirrstiri da iz,enada izguui piodukrGo"; ne moze biblioieke, garantuje ispravnu inicijalizaciju i brisanje i obezbeduje ispratnost
inzenjera ,.i" si" ,ei poziva funkiija, moZete se usredsrediti na ono sto biblioteka treba da uradi a ne
,

C++ je prosirenie C-a, koie nema v jezik. i


porpuno nor.n] sintaksu t,";;i;-;u_iru.,;u.
"" na to kako biblioteka radi.
To vam omoguiava da nasta'rite pisanle
nove moguinosti dok ih udite i usvalate.
Lorisnog koau i primenjujete postepeno ;: Po5to imena funkcija mogu biti podeljena po delovima programa, pomoiu
imenskih prostora C++-a mo7ete ioristiti koliko god biblioteka hoiete, bez
[;.
ovo hoze uiti J.udrr uu Ila.,\
;eaai-'oJ-;"j;";;;ih
razloga uspeha C++-a. Fi
*. sukoba imena koji se de5avaju u C-u.
osim toga'^svi va5i postojeii c programi
, - usawsen, desio
i dalje su upotrebljivi u c++-u. posto &
cit" p'onrZi skrivene d.'sk;c-kolu"ili'J:
illffiii"$c++-a Ponovna upotreba izvornog koda uz Sablone
ffi postoji znadajna klasa tipova koji zahtevaju izmenu izvornog koda da bi se mogli
Efikasnost f;
eflkasno ponoro koristiti. Sablon (engl. template) C++-a automatski .menja
izvorni p-g.u- i moino je sredsWo zi pono\.nu upotrebu biblioteka. Sablon
Ponekad rreha smanjiri brzinu izwsavanja
mera Na primer. rinansijski model moze
zarad veie produktivnosti p.oe,u_ koji radi s'iednim tipom radiie bez problema s mnogim drugim tipovima'
titi upotreotyiv samo , t .zT.'.frfi $,i
ffi saLtoni su posebno mocni posto od programera klijenta skivaju slozenost ovog
"*"#""t"ti-
[1x!:til:
daje
[
*i :xlii:].,?l;;ffi1 ff.1:n
prednosr efikainosri u
:h*:;l*:tt1X H
nadina ponovne upotrebe koda.

odnosu ;"r.k;;;;;gramiranja. po.to c prosr"n,.ri


&' Obrada gre5aka
Obrada gre5ika u C-u je ozlogla5ena i testo se ignori5e, pa se programeri
desto
l'ffi ii-il,:H:,'","**#:**1tf*i#.Hl*ff*ii#ffi oslanjajri na sreCu. Ako pravite velik, sloZen program, nema nideg neugodnijeg
oO grlite koja je negde skrivena, a nema nikakvog pokazatelja_odakle potide.
."i:::,1,1:':1*11::i:lLii'ff rurun,x;i*:ltr:,:,.;:*"*,:r:ffi Obiada izuzitakaC++-a (opisana u ovom tomu, a detaljno obradena u tomu 2)

#ffi ;?.'#1,"#'l.iJI:l::.il,1*;H;: j}*ni:;ff tr'.T;:?:E garantuje da ie se gre5ka otkriti i da Ce biti obradena'

za ooP prosram .oz-Joiti mnoso enkasniji n"*o,u


,.u:l?:i;:.HlT;']:, ffi Programiranje sloZenih sistema
Upotr-ebllivost mnogih tradicionalnih jezika ogranidava velidina i sloZenost pro-
grama. Na primer, BasIC moZe biti sjajan zabrzo resavanje odredenih kategorija
S,isteme je lakSe opisati i razumeti H [roblema, ali ako program preraste nekoliko strana ili izade
iz domena problema
jezik
uobidajenih za taj jezif, daljl rad lidi na pokuSaj plivanja kroz gustu tednost. I
C ima ovakva ogianidenja. Na primer, kada program premaSi otprilike 50000
redova koda, nuilazi se na problem kolizije imena koji potide od prekoradenja
broja imena funkcija i promenljMh. Posebno tezak problem su sitne pukotine

ff;gffr*****,.*"*x***,;*;l. I C-a: gre5ke skrivene u velikom programu se jako teiko pronalaze'


Ni postoji jasna granica koJa bi ukazala da je programski jezik ispod va6ih
odekivinja, i i-Ou poJtoyi, vi biste je ignorisali. Ne kaZete: ,,Moj BASIC program
postao pievelik i moram ga ponovo napisati na C-ul " Umesto toga,
je
pokusavate

ffit:$Ii ih:l n,:,,11i#,f#ix*Jxi::"ri:ffi [#: E


iu ,ra sii, u-etnete jos .rekoliko redova kako biste dodali nor,r.r moguinost. Tako
vam se neosetno pribliZavaju dodatni tro5kovi'

mmansiC++bibliotekemoZetenaiiudasopisuC/C++,,,.,,,.}
Misliti na jeziku C+$ vlje l: Uvod u oblllte
c++ je projektovan da podrzi ue.rike projekrq
izmedu malog ivelikoc p^.:qTTl pri posieplnom
sto znadi da izbrise granice 3. Modelirajte na osnovu uspelih reSenja pre nego sto podnete
povedavanju sloZenosti. Sva- potiJit" p.ir"Jre dobrih objektno orijentisanih projekata
kako ne morare koristiti ooB sautone,^i*".rrk" resio vas pro-
piSete mali usluZni program u stilu
prostore i obradu izuzetaka kada
; ;;;";g lista hartije. Posioji velikaverovatnoda da je neko vec
,zdravo, svete,,, ai or" *o[o,:.ror,i-"r.r ar, ruau
vam budu zatrebale. Osim toga, prevodilac blem,alakiakonijere5enba5taj,verovatnomoZeteapstrahovatiiizmeniti
je op5ti koncept
detaljno traZi gre.ke, kako u malim, projekat tato da odgovara va5im potrebama' Ovo
tako i u velikim programima. p"ri";"ei
-obraia.caproiektouania,
opisanih u tomu 2"

Strateg Ue u napredivanja 4. Koristite postoieie biblioteke klasajeste jednostavnost.


Ako vam se dopadne ooB verovitno je va.e *oii, ,u prelazak na OOP upotrebe
sledece pitanje: ,,Kako da prido-' Osnovni ekonomski
(konkrerno, standardnih c++ biblioteka
bijem Sefa/koregei odeljenje/susede da poenu
du korir; ;lj-,"kteg ,, pomisrite na p"Gle"g t"aa u viau Liu[oteka klasa
to kako biste vi, jedan nezavisni programer, "k;i;;" aeialno opirarre u tomu 2 ove knjige). Najkraciciklus razvojaaplikacije
udili da koristite novi jezik i novu
osim funtcii;e mainQ, inicijalizuju6i i koriste6i
programsku paradigmu. vi sre ro vec
primeri, a zarim se radi probni projekat
uradili. Na p*o*..r"il; ;ffi;;j;i' ;;,,d"1"'"6 ne napiSele ni5ta
obiekte iz eotovih biblioteka. Neki podetnici ovo ne shvataju,
nisu svesni posto-
da biste naudili o;n;;;;ez zbunjujucid koje vec moZda
detalja. Zatim stiZe prolekat ii,,srvarnog
sveta. koji zaista radi nesto korisno. ir#rt|"m kil
iii, ;ilsevljeni jezikom, Zele da pisu klase

3*:Lly5::?1,".11:::Tlljare lld:liidi,"r"ci, pl,,",rlffi pitu.,;u strudnja_ ffid;. ilj;;;ila;oop


'"i,i i L**'postiii
koristite k6d
cete ako
drugih
se potrudite
autora'
da napodetku
cima i razmenjujuii saznanja s prijatetjima. 6r;i;ilil;l;i;."k ,,;_:ltrt;;, itetazt og p"rio.al3rorldete i

lff i.:T[1T"ff
sigurno ::i,,'*#::i::1':*::l,.rl:r;$i;r:.,gry."J*";H;;l
je dinamidniji, ali je korisrio prisetiti se tato bi ,;i#;;;;;:
;:H:i 5. Nemoite na C++-u ponovo pisati postojeii k69 .
i^k;;;;;;'d"i;, C piogru*u C** pr"rbdiocem desto daje (nekada ogromne)
koristi ier se prondaz! p*Uf"*i kodu' pono'urro pisanje. ispravnih
tt*ott'
Uputstva " iskoristi vreme'
desto nije najbolji
Pri prelasku na OOp i C++ treba uzeti u
obzir naredna uputstva: ;GJifi;;;;e ""t++-u
(Ako sa morate preworiti
"19T.q1'"
u objekte, mozete ,,omoiati" C kod C++ klasama')
Neka
Mozda
iiliil,;,;-6;; i ;;eito ako e k6d namenjen p onormoj up otrebi'
l. Obuka oe"nri*o r"tiko poveCanle
;
produktivnosti, osim ako projekat nije
P.ri korak je obrazovanje. prisetite sekoriko je preduzece ".e"ir"ofi[ C++ i oOp ie plUzu;u u punom sjaju kada
projekat radite od
poku5ajte da spredite haos tokom uroZilo u c programe i poipr"o nov.
sledeiih Sest do devet meseci, dok su svi ideje do realizacije.
zaokupljeni odgonetanjem kako radi visestruko
grupu za indoktrinaciju, po mogucnosti
r"rr"di;;;j;."ir-atJrit" mau
sastavrjenu od ."d;;ilil ;oba koje
dobro rade timski i mogu delovali uo
-."zu ru podrsku toto* ue"rrfi c++-a. Te5koie uPravljanja nabavite resurse za tim, da
A l ternativni pristup"koj i. s"
6"-"il;r;;ruduj e j este istowemeno o buda- Ako ste na rukovode6oj"pozi-ci1i, va5a zaduZenja su da
vanje na svim nivoima pre.duzeia,-ut<ryueu;uCi
informativne kurseve za rukovo- prlt-iO.t" prepreke i; p"t i do uspeha i, uop5te' da pokuSate da obezbedite
sva ona
dioce koji definisu strategilu, kao i kurieve pro;"tto.rurqa irip-J"f.tii^iie i na;ugodnije olaulinje, tako da va5 tim moZe da stvori
i programiranj a za o\e prelazak na C++ spada u sve tri navedene kate-
koji se bave razvojem proje.kata..Ovo
;" poi"U'"o pogodno za manja preduze.a Jri-" t"i" ," .r*t trazi-oa vas.
da platite. Iako_prelazak na c++
koia sustinski menjaju nadin rada ili za'orga-ruzaiio"ne
celine u"Zm J."a.,r"cu. ;;;ij" i;i1; bi:r;u;"o kada ne biste morali nista nego druge OOP moguCnosti za
Posto je cena visa, neki mogu odrrrditi moZe biti ieftiniii, Sto zavisi od ogranidenja,2o
au rufroe"r, obudavanje na nivou projekta, proceduralnim
naprave pilot projekat,(evenrualno uz pomod
spof;nog s-a,ve*if.li,"iorf" e"gu ffi;;G.[,j;.u-ii-u.touutno"za prograrnere na drugim svesni pre
projektni tim moZe podudavati ostale u
i."d,rr"cr. j";i.ird, o:vaj jezik nije besplatan i poitoji te5ko6e kojih moratesebitiu troskove'
nego Sto zapodrr.t" prllazatcna C**-t""'tut pteduze1ai upustite
2. Projekat niskoq rizika
Poe nite od projekta nislkog rizika i slobodno gresite.
Kada steknete izvesno isku_ Poietni troikovi (GNU C++
stvo' dlanovi prvog tima mo.gu. zapodeti
drugl projekte ,i postau t"t.riltu poar- toStovi prelaska na C++ prevdzilaze cenu nabavke C++ prevodioca tro5kovi ie
Srednjorodni i dugorodni
5ka. Prvi projekat ne bi tredaro da bude
,ii{"iui ,u p;;i;;;;";ffi; moZda ii""oa1u'", ;"aan oa naluoilih, besplatanje).
je angaZujte i savetnika za prvi
nece od podetka raditi sasvim korektno. ie smanjiti'ako investirate u oUutu (ako mogu6e,
Trebalo bi da bude jednostavan, neza_ kako te
problem,
visan i poudan, sto znadita obuhvata stvaranje
krasa koje ce biti znadajne dru- prri"t",ii izaberete i narudite biblioieke klisa koje re.avaju
gim programerima u preduzedu kada "f."
dode,"d ru njih da ude C++.
20 i jezik Java'
S obzirom na pobolj5anja produktivnosti, trebalo bi razmotriti
48
Misliti na jeziku C++ Poglavlje l: Uvod u objekte 49

biblioteke ne biste nravili sami.


ovo su veliki troskovi, i moraju
planira..;.. posroje iskriveni u obzir prise uzeti druge strane, dinjenica da je lako napraviti ove greSke u projektovanju uka-
,i"r;, nouog;"rik],
rro.=k"Jrr, Sa
programskog okruZenja.
oni se svakato sman;u;u ni2 ";irufro i novog zuje na osno'rni nedostatak C++-a: powatnu kompatibilnost sa C-om (to je,
ilanovi tima moraju uroziti i.sops;;;i;;p* irui"toru.,;", utr naravno, i njegova osnovna moi). Da bi se izveo podvig prevodenja c programa,
"urt,
pri.usvajanju ."r" ,"i-r""r" gije. za
to weme tim ie vi.e gre.iti (ovo
pri.oa'no, jezik je morao da napravi neke kompromise, Sto je dovelo do nastanka ,,tamnih
;" po.to ,e u.vidanje gre.aka najbrZi
naiin trienja) i bife manje produkrivan."crt itrana'. Takvi problemi postoje i desto se javljaju tokom udenja C++-a. U ovoj
i ,uau, s nekim probremima u pro-
gramirarrjrr' prave klasc i u oogouuruj;m knjizi i narednom tomu (i u drugim knjigama - videti dodatak C) pokuiavam da
'z
vecu produkrivnosr (uzima;rCt okruzenju, moguie je os*ariti
razotkrijem najveii broj zamki na koje iete naiii radeii u C++-u. Ilvek morate
u o8ii, iri"liir"i greSaka i manji
skih redova na dan) n.gn u[o broj program- imati na umu da u bezbednosnom sistemu postoje pukotine.
se zadrZite nu C ,.
Pitanja performansi
uobiiajeno piranje ie: oop mnogo ne uveiava^i_ne usporava
SaZetak
grame?"' odgovor ie: .,Z.visi". moje pro- Namena ovog poglavlja je da vas uvede u Siroki skup osobina objektno orijenti-
Veiina iirai.Lrurnih ogp jezika
"'7'ar
tako da orrrogrrii e[socrimentiranl. napravrjena je sanog programiranja i c++-a, ukljudujuci razliditosti ooP-a i posebno c++-a,
i urru J."ao, protoripova, a ne ideje OOP metodologija i wste zahteva na koje iete u preduzeiu nailaziti pri
snih sistcma zaro je derovaro iiradu efika-
;;:; biti veii i sporiji. c++ je prelasku na OOP i C++.
namenjen produktii'nom programiranju. ";;;;i'p.og.u-i
pove' moZete ubacivati komponente Kada se usredsredite nu'air"prototi- OOP i C++ moZda nisu dobri za sve situacije. VaZno je proceniti sopstvene
stite gotove bibrioteke, one
ru""-u.u;rci
pitanja efikasnosti. Ako kori_ potrebe i da li ih C++ optimalno ispunjava ili bi bilo boije nastaviti sa nekim
su obiino vei optimizovane, pa
dok razvijate protoriDJ<ad',a"J.i. vi to ne morate
raditi drugim programskim sistemom (ukljudujuii i onaj koji trenutno koristite). Ako
i" znate da ie vase potrebe biti sasvim posebne u doglednoj buduinosti i imate
"i[o*.u;r*g sis.rema koji je dovoljno
mali i brz' posao ie zawsen. u suprotnom;"po.,nl","
pode.avanje parametara, jasna ogranidenja koja C++ moZda neie ispuniti, tada bi trebalo da proudite i
otkrivajuii sra se sve moze uhrziti
C++-a. Ako ro ne Domogne, i"anoriJilg- primenom ugradenih opcija druga re5enja.2l eak i ako izaberete C++, razumeiete kakav izbor ste imali i
ispitu,te luto r..roZ"promeniti program,
ne menja_ imaiete jasnu sliku za5to ste izabrali taj put.
i:ti I' E l?:i:i :l: Tl;iliil'tr *lit:"'H.lJ u.da n is,a, ; ;;;? ;
;" jaj,e p io. Znate kako izgledaju proceduralni programi: definicije podataka i pozivi
funkcija. Da biste otkrili znadenje takvog programa i stekli sliku modela, morate
pokazateli a.
"," .","ju biti deo
otkrijcre primen jrrjuii brz.i razvo).
p".;;;l;1;ffi;::i.:T.ff1::1"-::;; pratiti pozive funkcija i shvatiti osnovne ideje. Zato su nam potrebni pomoini
Ranije je reeeno da se razlika nadini predstavljanja resenja proceduralnog programa - sami po sebi, ovi pro-
u brzini izmedu c-a i c++-a
inrervaiu !1,vo, a iesro je sasvim najdesie grami zbunjuju poSto 1e izraiavanje re5enja vi5e orijentisano ka radunaru nego
,"rr. v"riio'rtraiivanje izvornog koda narazi u
i ubrza_ ka problemu.
primenom c++-a moZe p"il.",t
I?#Xfi:Ta od raztike u proyeltima pravlje_ Posto C++ dodaje mnostvo novih svojstava jeziku C, prirodna pretpostavka je
Podaci o poredeniima^c-a.i da ie funkcija maino u C++ programu biti mnogo komplikovanija nego u ekvi-
Iako neki preporufuju ci,a. se 'rJlule i verovatno
c++-a su anegdotski
ie tako iostati. va.lentnom C programu. Ovo je prijatno iznenadenje: dobro napisan C++ pro-
isti proyekat i na c-u
mogu priu.titi samo velika predu."cu, i na c++-u, to sebi gram, u op5tem sludaju, mnogo je jednostarmiji i razumljiviji od ekvivalentnog C
projekte. Cak i tada ,r*,..L-l .ii"t"resovana za ovakve istraZivadke p.og.amu. Videiete definicije objekata koji predstavljaju problem (a ne speci-
t;""* ,rd;
argumenr jc da str skoro srri *programeri
-ol,:0"i1:.
koii su_sa.C.a
ulozen. Najubedljiviji
(ili nekog
henosti radunara) i poruke poslate objektima koje predstavljaju aktivnosti. Iedna
drugog proce_ od pogodnosti objektno orijentisanog programiranja jeste lakoia razumevanja
pre(ri na c** r,fi ,.ti i,,Ji obp i",t; znarno pouol;sau svolu dobro projektovanog programa. obidno ima i mnogo manje koda, posto ie
3lJ:iili,iTlka)
veiina problema biti resena ponovnom upotrebom postojeiih biblioteka.
Uobica1ene greike pri pro1ektovan
[)ri uvodenju tima u oop i iu
eajenih greSaka. Cesro jc razlog
c-- pG*,n"r r'" nu;,",re prolaziti kroz niz uobi-
nedostu,ut'r,ru
" .fJ;,:
:,.: : I,, " l"
; *,,i o,. ; I o.,.. p"" s, pl;A; ill:t
moze postojati otpor" prerna angaZovanju ", :?.,.#j : lH:, :.TT
,ur"rnii.u. M;;;;"";."*lTl,"cir,i.ur.
da razumere oop i krenuti
oiigledno' moze biti izvor velikih
pog;sni;i;,;'o"" sro je iskusnom programeru
n"af,,-i.u)a.podernika. Mnoge nevorje
mogu izbeii ako se za ohukrr i se
.ur.,nuon;"-oiiazule spolini saraclnik 2l Posebno prcporuaujem da pogledate Web lokacije iezika Iava (http://iava.slrn'conr) i P\tiron (http://
r' rr rr' l)r'tlrrrrr rrrr,l
kffi
ffi
. :-:-* . :-;
ffi
S.I'

ffi
h
tu_

h
r'
t
&r
F

E j

E
ffi

F
n
E
s

E,
[
H.
I
r
I
E
t
E
p
T
2=
t
Ii
E
h
$
v,
$

I
r
52
Misliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata 53

lil:: il ::51i:H,:' :'j"'-"j :j.;:.':,:a l"^ 1 I menr objekara iz c++. a u pro.


i najbrZi interpretator moLe izazvati neprihvatljivo usporavanje programa.
I Lil,
tla ii'lldovoljno
btidc ::'l:
ll ; l, il.I da vir:I L'"i:" :li!i: z 1i
lrupurdroost
1 i; i,i i;,r
kroz :poglavlje
# ffi i;1# ;ffi
[ 3:i; [:
ovog jezika. To bil, trebalo
Veiina interpretatora zahteva unoSenje kompletnog izvornog koda. To poveiava
s;rtirzi vcciinLr detalja
sacirZi (icrirlia jezika i.r,il?Y"n"
O.
3, koje ."i"
uiiir"p""r;; ,"iiJ ft potrebni prostor, a moZe izazvati i ozbiljne greSke ako jezik ne omoguiava loka-
't,r,irru
lizaciju efekata razliditih delova koda.
:!,iil|i::\i::li.l::lJ::^-::l'11:
tzttrctltr ( ''+-ir i rrariiciorralnih ilIukratko
n'"t''
tiasa, predstavrja
preostavlja glavnu
gravnu razriku
razliku
prn."o,,rutni;;"
,.';,; je nov tip podataka
P,tttirlt' pri- .-.
I..i,,uon;u
i,,r,.(,,,r,, n.lr.d.,,"
n.l,.;
uo n I u ,,L,rtrutjuL nrnhr-,-^
wsrc; ;;;0,
; ;, wste 'li_[it:l
probrema..Napravljenu koji
fl,, :,:y,: I li,..
speci fi dnosti njenog .la",i
[.111' klasu i.o.irtrc"l o,li Prevodioci
I:] I-:.r.iu da r"ti" n iene izra.ro
.,r-;;r;e;;li tip podatakan,njene
bavi : ",:,
klasama'kao izrade. r.r,.^ - ^ -r
Ovo poglavlje Prevodilac neposredno prevodi izvorni kod na asemblerski jezik ili u masinske
se
grarnima ro;i se .n"g" rtl[jff;;".;: instrukcije. Konadni proizvod je jedna ili viSe datoteka maSinskog koda. To je
Klase drugih autora ue sloZen proces i obidno se sastoji od nekoliko koraka. Put od pisanja do izwsa-
is t i n e ko i ko o, o,,o,"ou'ilu..i";;, j::y:y:T:_l
bibrioteku. ovo po gravrje vanja koda uz kori5ienje prevodioca znadajno je duZi.
ffi
e ito znatajna
r

il]..j,Hiil;1i::::"*,tj1-,:?]^"!1'1;";H,,""';i,:ffi
standardna uiurlot.ia reauzacuama c++-a. Naro-
;"e"i;:";;"""' izmeduostarog, omogu-
:H,J:.T1lil:: U zavisnosti od veStine autora prevodioca, prevedeni programi obidno staju
iava uiitavanje
uiitavanr"l,iz ala,"to na manje prostora i mnogo su brZi. Iako su velidina i brzina verovatno najde5ie
vr.r. c. i. i,ffi datoteka iis rasr:tr,..,,.^,-l.l:]a,
il"J:x'
o:
jlj':::,T"',
i- 3:':y:::.i.*.,:*k"
l' iontejner
i nu' m o.,i to,, navodeni razlozi za kori5ienje prevodioca, u mnogim situacijama nisu i

l:?l;J'ffi
gotove biblioteke
,, 3,: * I ?,';.
klasa
j; ;; i' Il1::,,1",iq
"
*'
"'';
vectorutunaura.,"
"'
; ;:'iJ,ff; ::H # illXf T".tJ: cll najvaZniji. Neki jezici (kao Sto je C) projektovani su tako da dozvoljavaju neza-
visno prevodenje delova programa" Ovi delovi se kasnije povezuju u konadni
ncso iro napiicrc izurini (engl executable) prograrn pomoiu alatke koja se zove poueziuai (engl.
f 1e
za sklapanje prograrna.
- t-"r
llrvi program,"1i5'
Hrv6rorrr' trrurate
morate poznavati alatke koje linker). Ovaj proces se naziva oduojeno preuodenje (engl. separate compilation).
se koriste
Odvojeno prevodenje ima mnoge prednosti. Program koji je suvi5e velik i ne bi
mogao odjednom da se prevede zbog ogranidenja prevodioca ili okruZenja za
Postupak prevodenja jezika prevodenje, moZe se prevoditi u delovima. Jedan po jedan deo programa se moZe
___.. .-, Jr
izgradivati i ispitivati. Ispravan deo se moZe sadur,ati i koristiti kao gradivni blok.
i;;:':;UI|;
Ao4, cngl. source
,L'_rLr
),?:',:;;;r:i,*i,^*ls!it
code) u neSto Stc
I ,judi mogu rako razumer i (izuorni Skupovi testiranih radnih delova se mogu organizovati u biblioteke i staviti na
i: j:"tJffj-'
""
1T
i a.u a
!
m.as i n
l
t r i r' r, i ii i i ci.
raspolaganje drugim programerima. Prilikom pravljenja jednog dela, skrivena je
J',:ij::','::,;;',:;::::,";:,":,:,1;r:":lh:;;#;:H.\;?;:i::'ilix#J,':;L:1
gortle: interpr.rorore {engllinrerpreii,:liii'irriir;;;:;irr:;Tri;r:0, sloZenost drugih delova. Sve to omoguiuje pisanje veiikih programa.z
Moguinosti prevodioca da pronadu greike wemenom su znadajno pobolj-
Sane. Prvobitni prevodioci su samo generisaii maSinski k6d, a programer je
lnterpretatori dodavao naredbe koje ispisuju medurezultate kako bi uvideo sta se deSava. To
Inrerltrcraror Jrrt,vocli izvrlrni nije uvek eflkasno. sawemeni prevodioci mogu umetati informacije o rzvornom
kod rr akcije (ko;e:nogu obuhvatati
skih i,strrrkcija) i ,epo,sredno
ih ir*luri. ,io_r191.,.na primer, skup maSin_ kodu u izvrsni program. ove informacije koriste moini programi za otkriuanje
KoJl sc rnrcrprctira. Tr.adicionarni popularnijezik greiaka u izuornom kodu (engl. source-leuel debuggers) koji prikazuju Sta se
BASIC in,..or"tutori prevode
jcdan red i zatim ,r,[311;.1, i iiwlJvaluledan
1to
morajrr pono\'o prevcsri i
;;;;;;;;iio p."u.a"n. Kil;;;,;" ponavlja
tadno de5ava tako Sto prate izvr5avanje kroz izvorni kdd.
to ih e ini rr".,rir. nra, ubrzavanja Neki prevodioci reSavaju problem brzine preuodenjem unutar memorije(engl.
vodioci za IiASlC. Savremerriji napravileni su i pre- in-memory compilation).Yeiina prevodilaca radi s datotekama, ditaju i upisuju u
ln,"rpr.,riori,"n*u
ceo I)rograrn u nrcdu jezik 0.,,n". ru jezik py,thon svakom koraku procesa prevodenja. Prilikom prevodenja unutar memorije, pre-
koji zarim rrrrir"" n-,nogo
Interpretatori irnaju mnoge prednosti. prelaz brzi interpretu,o.'ior"uoo. vodilac je u MM-u. U malim programima, ovo moZe biti efikasno kao Sto bi bio i
od, pisanja ao izwsavanla
koda interpretator.
a" i.i"rp*il; il;"
ili:l'ir[:]:ii;, t_t:i::z:* t-q
tora jcd.osta*".'i i-n,.ii;ili';,')::i:.::):^"',1dobiti
;:*jfsi mnoso
od korisienja interpreta-
f,.og.u.nu. Postupak prevodenja
,r,rrrcrprcrirar,,i"),.i,.,il!,J,..:t#ffi:lllil!:::1"",iizwsavanjir
projckara iizgreda ,r. kada se korisre zaizgradniu Da biste programirali na C-u ili C++-u, treba da razumete korake i sredstva po-
nii:ena verzi,a) nrora'.rek i.
:::li!'l ov.i""';;;:i:?'"', stupka prevodenja. Neki jezici (konkretno, C i C++) zapodinju prevodenje propu-
rri,i,, il.."r;;;:;:i:::r*$X,;;,llJJ:rt:,;:T*; Stanjem izvornog koda kroz pretprocesor (engl. preprocessor). pretprocesor je
t,r.utrtl izrnedtr prcroriil.rc,r jednostavan program koji zamenjuje Sablone izvornog programa drugim Sablo-
i int erpretillora
i,'/rL, rrrirj. ,,,,,.,A., .r,;;,;;,; ' " ,f prer l'()'lala je neiasna, n;
y-':1'u' pvrhon. prosrami nima koje je programer definisao (upotrebom pretprocesorskih komandi, engl.
crrt.nih n,d;,;;l;i;', ;;;1':::1:
r oozrv rnterpretiranih.
na rom
preprocessor directiues). Pretprocesorske komande se koriste da bi se manje

'I I'r.tiron jt ltonoYo izrrzetak. l)oito takodc llodr2ava orlrrrjeno ltre!orlt,rrje


54
Misliti na jeziku C++
Poglavlje 2: Pravljenje i upotreba objekata 55

i:.'; :;fi
I ll.".:l jtr
prsan ;1, c++ programu
H: 1;
n" o.".,nr, ;'.;m:*S KnJlSe
i ^fy ::,,::\lltn
j i ge cete
ie re nauditi
naudi ti da se pri
U C++-u moZete zaobiii statidku proveru tipova. MoZete i sami dinamidki
zvari tesko uoitiive ,*uoi yii.?ljj^.ll,l"ii:i:nje
^;;;X::l"vKu p,retproceso.a, posto
L oze iza,_
'"i:i:i::: j::' jffi 'H"X1'"';'.1iffi proveravati tipove, samo treba da napi5ete odgovarajuii k6d.
S:.:5;:":,-::ili::ffi
'.i:,:'fl
#iT:;;;:.Hi;-xx'?";;l
ii#i
Hi3ffi ?:T:J:i'-:;;igr:iiy;_fi
f ,*fi'.':l:#ff :Jil?y j1ft
u', ;i, i i,;i*illrtii,jl'_*qx!'::t^;:::;!::,'::;:
ru k r u r
;;;;; ;:, :;#1T?il?9,Y#3l1i.1li[,l l Hi. Alatke za odvojeno prevodenje
}:? :,'I
snog [ :'
stabla. "
odvojeno prevodenje je narodito znaiajno pri izgradnji velikih projekara. pro-
r, gram na jezicima c i c++ se moZe napraviti od malih i preglednih delova koji se
b i s e n;, il;"f
gto ba t r (engt
p t i m i zato
o p r i m i zer), d a

[I drugont prolaz ;;;ff :# di ",


o
nezavisno testiraju. osnormo sredstvo za podelu p.og.ami ra delove je mo[ui-
^y::
(eng'l' c-ocle gineratoi nost pravljenja imenovanih potprograma. potprogram se u c-u i C++-u naziva
\.o srablo i ,,n ,,.,,n1'-,8I','.:::'o'koda prolazikroz sintak-
Ak o gc n e r s e
bterom u maSinski too u
;;;il1#:{il1 ;":x? fl ff ff l:i}
:: "fi '[:,#
jt
tli:Tj:Jtr
funkciia, a funkcije su delovi koda koji se mogu smestiti u razlidite datoteke, Sto
omoguiava odvojeno prevodenje. Drugim redima, funkcija je nedeljiva jedinica
oballua"ill" il"r;,.rezulrat objektni koda, posto se ne moZe iedan deo funkcije nalaziti u yednoj, a drugi u nekoj dru-
tipa .o iri .obi) u u.X?: modul (datoteka
peephole optimizer)koji_traZi g..?,; ;;;;;;i.ij.,l:::,i toia.tyi opiirzator (enet,
goj datoteci - potpuna funkcija mora biti u jednoj datoteti (datoteka moZe da
delove koia sa surriSnim sadrZi vi5e od jedne funkcije).
Pogresno je reiju asemblerskim naredbama.
"objektni" ;r,;i;;;"r"ve.masinskog koda. Red je Prilikom poziva- funkcije, obidno joj se prosle duju argumenti (engr. argu-
:i Hil"li: :'Ji i i"::l;: r j,
n'iiu. *n r(";;' ;;-,,)-u,,uusra u
p,"-
ments), a to su wednosti s kojima funkcija radi tokom izwsavanja. po zawsetku
d,lff
predstavlia ,,riuur ru'd"nn,rrr1- ffi orijentisanom programirinju funkcije, obidno dobijate rezultat ili pouratnu urednost (eng)-. return ualue).
povezivac (ens,r. s."",.#,":it'" Moguie je pisati i funkcije kojima se ne prosreduju argumentii funkcije koje ne
rinker) tp"j; iiri;';lj"tin,r,_,n"aura u izw.ni waiaju rezultat.
u n'"'ffi iizwsiti. r"a,
program koji
::il'ffi.:l'iil#T', "'luti '"
,li" r#r.i;u ,;"a- Da bi se napravio program koji se sastoji od vise daroteka, funkcije iz jedne
moduru,o;i,;;;#,'*i"'ix.*:*?L:,j.tll"T,,x#ii":".#rT#jH:[ datoteke moraju pristupati funkcijama i podacima u drugim datotekama. pri-
likom prevodenja datoteke, c ili c++ prevodilac moraju znati koje se funkcije i
:,,",st,!iil: :l? :, ;ff : : ll [:, jt#:
5*: t' ;';#J: J I i p ni
". podaci nalaze u drugim datotekama, konkretno njihovi imena i nadin upotrete.
ruvezrvac mo2e oretraiivati
i,

posebne cratoteke, pod


""i:j :j "
o s u
ovaj postupak,,saopstavanja' prevodiocu imena spoljnih funkcija i podataka i
nazivom bibrioteke nadina njihovog koriSienja naziva se deklarisanje. Kada deklari5ete iunkciju ili
-,',-. (eng).
o.;il ; ;r promenljivu, prevodilac zna kako da proveri da li se ona pravilno koristi.
[,niil.i i:i : : :x::: ;;;} }"? ;* #l:, "or i; o' u; r.,
pravi i odriavu "?uilito],.tu ' znje bibliotekama (engl. lib:rarian)
" " ",r,

Deklaracije ili definicije


Staticka provera tipova VaZno je razumeti razliku izmedu deklaracija (engl. declaration) i definicija
Prevodilac proverava t. (engl. definitions), zato sto ie se ovi termini koristiti u celoj knjizi.
Bitnole da u
pravirno ro,isie;,;;;:i?,':;,:ifi,n:Tl;lJ;.?llJ"J""fi;r_:t;,,1;X;.:ll,"T svim programima na jezicima C i C++ morate deklarisati piombnljive i ftrnkcije.
gre.aka poito se tipovi pr-overarulu Da biste mogli da napiSete prvi program, treba da znate kako se pide deklaracija.
var)jir
,otorip-."vodenja
'nur.iuu u-"rto,u *"-"
prr)grarna, prov(,ra r.ipova izwSa_ Deklaracija prevodiocu saop5tava ime (identifikator). Ona kaZe prevodiocu:
)'Jt,ki ,hjckrrrrr
se ,toii'iio(engl. slarrc type checkingl. ,,ova funkcija ili ova promenljiva negde postoji i ovako treba da izgleda,,.
rzr riavanjii prograrna.
j"ri.; ip;;;no lu*l proveravaju
,riit,nrisani
ripove Definicijakaze: ,,Napravi ovde or,u promenljivu" ili ,,Napravi ovde or,u funkciju,,.
to-ic cti,tantitk:;'
;;;;;;; ripoua (engt. dynamii type rokom
irig) Slaticka l)rovcrir tip,ova jc.nogo'.oini;a check_ ona rezervi5e prostor za to ime. ovo vaZi, bilo da se radi o promenljivoj ili
Konr proverom, ali takva kada se kombinuje funkciji' U svakom sludaju, prevodilac rezervi5e prostor kada naide na aefiniiiyu.
Pre,odioci jezika c++ statidki
komtinaciiJ;;";;
rzwsavanje programa.
s dinamid_
Prevodilac odreduje.velidinu promenljive i obezbeduje memorijski prostor u koji
prtr"-J"qir'ripov_e,.posto jezit
nikaki''u podr.ku za dinamiiku ne omoguiava ie biti smeStena njena wednost. Za funkciju, prevodilac pravi kod ai-e s.
gresata tokom izwsavanja.
"'i""arr"lirr
s taua p'o g'a
;;;;' p o gresn im upo tre b ama tip sta_
; zawSava zauzimanje memorijskog prostora.
-i.ru;X1 : X,""'i :j "* maksimalno Promenljiva ili funkcija se mogu deklarisati na viSe razliiitih mesta, ali mora
i"
c**, ui,i-.c.i" o" J"r,ril"" ubrzava'i:lnsu"u"J". Uot*iiliete ova postojati samo jedna definicija koja odgovara tim deklaracijama u programima
j::'0" po ueli
p rogran, i ran j u o ron,
d rZava i"' *'iu [.rlJlo ffi m*oe na jezicima C-u i C++-u, Sto se ponekad naziva prauilo
o ]J?::XT, ledne definicije (engl.
" one-definition rule, oDR). povezivad obieno prijavljujl greSku ako rokom
objedinjavanja svih objektnih modula pronade vise-od je"dne definicije iste
funkcije ili promenljive.
I

56 i upotreba objekata 57
Misliti na jeziku C++ Poglavlje 2: Pravljenje

ffi
Definicija moie biti i deklaracija. Ako prevodilac nije prethodno
naisao na ffi Sintaksa deklaracije promenljive
im. x, a definiiete inr x; tada prevodirac ime vidi tao aeuaraciyu iistowemeno
Znadenje fraze ,deklaraiila promenljive" dugo je zbuniivalo zbog kontradiktor-
rczervi5e prostor za promenljiwr.
nosti, a'bitno je razumeti pravu deflniciju da bi se k6d pravilno ditao. Deklaracija
promenljive saopstava prevodiocu kako ta promenljiva izgleda. ona twdi: ,,ovo
Sintaksa deklaracije funkcije ime se prvi put fojavljuje, ali garantujem da negde postoji i da je to promenljiva
funkcijc, C.l.i.++_u dodeljuje funkciji ime, tipove
De.klaracija
argumenara tipa X".
koji se prosleduju funkciji i tip rezultata funkcije. Naprimer,
Lro je aeua.acila U deklaraciji funkcije, navode se tip rezultata, ime funkcije, Iista argumenata
fu,kcije nazvane funcl0 koja ima dva celobrojnu u.gu-"ntu (releMsana i znak tadka izarez. Prevodiocu je ovo dovoljno da otkrije da se radi o deklaraciji
red
int oznadava cele brojeve) i waia ceo broj: i kako funkcija treba da izgleda. MoZe se zakljuditi da je deklaracija promenljive
int funcl(int,int); tip iza koga se navodi ime. Na primer, po toj logici
Prva rezervisana red koju vidite je tip rezultata: int. int a;
Argumenti se naraze
izmedu zagrada iza imena funkcije i poredani su po redoslea"u
tolim se koriste. moZe biti deklaracija celobrojne promenljive a. Problem je sledeii: gornji kdd
Znak tadka i zarezukaztje na kraj naredbe, a, ouo-
sludaju ,uopstuuu prevodi- sadrZi dovoljno informacija potrebnih prevodiocu da obezbedi prostor za ceo
ocu: ,,To je sve, ovde nema definicije funkcijel,, broj sa imenom a i to se i desava. Da bi se ovaj problem resio, C-u i C++-u je bila
Deklaracije , c-u i c++-r-r opona.aju nidin korisienja neophodna rezervisana red koja znadi: ,,ovo je samo deklaracija, a definicija se
elementa. Na primer,
ako je a ceo broj, tada se gornja funkcija moze koristiti
na sledeii nadin: nalazi na drugom mestu". Ta rezervisana red je extern (spoljni) i znadi da se
a= func 1 (2,3) ;
deflnicija nalazi izvan datoteke ili iza tog mesta u istoj datoteci'
Promenljiva se deklari5e bez definisanja pomoiu rezervisane redi extern koja
Posto je rezultat funcl0 ceo broj, prevodilac ie proveriti
kako se koristi funcl0 se navodi ispred opisa promenljive:
da bi se uverio da a moze prihvatiti rezurtat i da
su argumenti odgovarajuii.
Argume.ti u dekraraciji funkcije mogu imati imena. prevod]rac extern int a;
zaneqrarule
ime,.a, ali ona mogu objasniti namenu argumenata korisniku.
Na primer, extern se moZe primeniti i na deklaracije funkcija. Za funct0 bismo pisali:
moZemo deklarisati funcl0 na drugi nadin, a ia znadenje ostane isto: extern int funcl(int duzina, int sirina);
'int funcl(int duzina, int sirina);
ova naredba je ekvivalentna prethodnim deklaracijama funcl0. Posto ne
postoji telo funkcije, prevodilac prepoznaje naredbu kao deklaraciju, a ne kao
Zamka definiciju funkcije. Rezervisana red extern je suvisna u deklaracijama funkcija.
Funkcije s praznim listama argumenata nisu iste
u c_u i c++_u. u c_u, dekla_ Projektanti C-a, naZalost, nisu zahtevali da se koristi extern u deklaracijama
racija: funicija, posto bi se poboljSala konsistentnost i uklonile nedoumice (to Sto bi se
nt func2 0 ;
i viSekucalo verovatno obja5njava ovu odluku).
Ovo su ioS neki primeri deklaracija:
znaii ,,funkcija s proizvoljnim brojem i tipovima argumenara,.
ovo spredava
proveru tipova, tako da u C++-u to znadi ,,ftrnkcija bez"argumenutui. /l: COltDeclare.cPP
/l Primeri deklaracija i definiciia
extern i nl i1 I I Deklaraciia bez definicije
Definicija funkcije extern float f(float); // Deklaraciia funkciie
De.finicija funkcije ridi na deklaraciju funkcije, ari
sadrZi i telo. Tero je skup nare_ float b; // Deklaracija i definiciia
daba izmedu vitidastih .-u\ru!.u: Vitidaste'zagrade oznadavaju float f(float a) { // Definicija
podetak i kraj
bloka koda. Da bismo definisali funkciju runci0 koja return a + 1.0;
ima prulno',"r. irero koje
ne sadrZi kOd), piSemo: )
jnt funcl(int duzina, int sjrina) { }
zapazite da vitiiaste zagrade u definiciji funkcije zamenjuju
int i; // Definiciia
Posto vitidaste zagrade okruZuju jednu ili viSe
tadku i zarez. int h(1nt x) { // Deklaracija i definiciia
naiedaba, .,iy" pot."uun znak return x + 1;
tadka i zarez' o.bratite paznju i na to da argumenti
u definiciji funkcije moraju )
imati imena ako ih koristimo u telu funk"cije (ovde
su op.ioru, ffio ," .r.
koriste).
58
[/isliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata 59

rnt main0 {
b = 1.0; imena datoteka. Ovi zahtevi su doveli do problema pri preno5enju izvornog
| - 1',
koda. Da bi se problem ublaZio, propisan je standardni format koji dozvoljava da
f (b);
ime datoteke bude duZe od duvenih osam znakova i eliminiSe nastavak imena.
h(j);
Na primer, umesto starog nadina da se zaglavlje uHjudi iostream.h:
| /l/,-
#i ncl ude <i ostream. h>
Identifikatori argumenara
nisu obavezni u dekJaraciji
Jama s. neophocini samo u C_u, funkcije. U definici- sada se moZe pisati:
a u C_;;;j;
#include <iostream>
U kl.1 u c iva nJe zag lavlja Prevodilac moZe realizovati naredbe ukljudivanja na nadin koji odgovara
vecrna biblioreka sadr2iziatajan
broi funk, .. njemu i operatir.nom sistemu, po potrebi skraiujuii ime i dodajuii nastavak.
k;;;;;;;;;i[il?,,'-'",lT;:,{il?.T.'"'.:,""'#:],; Nara'rno, proizvodadeve datoteke zaglavlia moZete kopirati u datoteke bez
L";;;:XX,T:liJo??,l,t.i'," nastavka imena, ukoliko hoiete da koristite ovu tehniku pre nego Sto je
sadrzisporjne ;;;:J|,i:::',#i:zf!;,i!;{:"s1. h,";;;i;;;."rl,i'*t" z.aglavtja proizvodad va5eg prevodioca bude podrZao.

.ll;Ji,iJ[i:u1",?S*t,".hd;;i.H''".:l jilT:UXI*1il:-;T#,:lli:li j
Biblioteke nasledene iz C-a jo5 uvek su dostupne s tradicionalnim nastavkom
imena - '.h'. Medutim, moZete ih koristiti na savremeniji nadin dodajuii ,,c"
;, il H t, 5;.,#ffi1'i;.:i::iJ; itil li -i',i;
ispred imena. Tako
;:"$: ;i : -, zagt avtja
i;ilffi #include <stdio.h>
, o a *i n u a e ; - j;;;., : i
:i,:ll : : ffiffi +,,H ll:
c r

navedenu datoreku ,:.?:*_l*


i

f.yr_.i".'ir;.n,.u..ru;H[f
;*H*
:H: :*"fil; #i ncl ude <stdl i b. h>
ramo gde ," .,uiuri naredba postaje
X;:iiii". i : :, i,X,."fi il:XTj",i
;i" #J; o 2., J,ii,iu. a",,,tn
", ", izm edu #include <cstdio>
Ako je ime datotek ", #i ncl ude <cstdl i b>
znakova < i >' kao u siudaju:
#i ncl ude'rur.,.r,rl]'*edu To vaZi za sve standardne datoteke zaglavlja C-a. Na ovaj nadin, ditalac moZe
da prepozna kada se koriste C a kada C++ biblioteke.
3;;::'fi::T,i'lJt,XX!?'ij Efekat novog formata ukljudivanja nije identidan sa starim: kada se koristi .h
jTi":ijt,'ffi?,f dobija se starija verzija, a kada se izostavi.h dobija se nova, Sablonska verzija.
:l?!iiu:lHTiH:?*?.X,#
; ;;;;,;;;;'
Iil?ifrd
rorrnacije p"ir.r, i. .",-';
: :t ; :ili, I x.' j;#,tifl"i 1i;1i,,r", zac.i.ie c++-a',pi
p u, a n j e je
Ako kombinujete ova dva oblika u istom programu, imaiete probleme.
in
" u r f - d' p i o"turjnij.
r nr c .r a i o i e re l; ;;;i,HlJjf,?:: ;;;;; ;
""J"'#:'.T,:;'"?t::j.l:ii ;1
Povezivanje
fl :.,"1,1?:il
#include ,,local.h,, Povezivad (engl. Linker) objedinjuje objektne module (diji nastavak imena je
nala2e pretprocesoru iesto .o ili.obj), koje je napravio prevodilac, u jedan izwSni program koji opera-
da trazi datoteku na
,,r1ii: definisan rearizacijom prevo- tirmi sistem moZe uditati i izwsiti. To je poslednja faza procesa prevodenja.
:;.:.;;,,,X,.",?;r:?::ff".,iir r" ,"rc"sc"'r".,, da se datoteka t.ax.,.erattuno u Karakteristike povezivada razlikuju se od sistema do sistema. U opStem
tuo ,t,, .,, ,,p,,i"1,,;.iit"t';'m' Ako se ne pronadel";;;;'eoil'"'o
- vv P v. u u ooruur;. v
sludaju, povezivadu se navode imena objektnih moduia i biblioteka koje treba
i ime izvr5nog programa. Neki sistemi zahtevaju da sami aktivirate
, t,'. i, i ;, ;H :i :il X?.';;ilj.j
" "'
#include <iostream>
r
iff.#i ffi,".f
povezati
povezivad. Veiina C++ prevodilaca automatski aktivira povezivad, pa u mnogim
situacij ama nij e uodljivo pozivanje povezivada.
Pretpoccsor cc nrona.i daratot,,, _^_t- t. Neki stariji povezivadi ie samo jednom traZiti objektne datoteke i biblioteke,
zagtavlia iostream (desto
1r,,,,, rJ.luo.i ;;!fr.ll.,:.datoteku u poddirektori- alista se pretraZuje sleva udesno, pa redosled navodenja objektnih datoteka i
biblioteka moZe biti znadajan. Ako se tek u trenutku povezivanja pojavio neki
Standardn i C++ format. dudan problem, jedan od uzroka moZe biti redosled kojim su datoteke prosledene
naredbe ukljucivanja
lbkonr rat'voja ( ++-a. nr.izvodaii povezivadu.
datoreka osim toga' u p.*"iir#";, birari razriiite nasravke
nekim imena
'p;;;i;ff'sistemima ogranidena je duZina
60
Misliri na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata 6t

Upotreba biblioteka
PoitO ste ovladali osr standardnoj C++ biblioteci. Da biste ih koristili, dovoljno je da ukljudite
razumere kako treba koristiti bi. d ato teku zaglavlja < iostream>.
briotckrr r)a r,isre,,;:;t?,ff;iili:;j:[?iT, Ako koristite dodatnu biblioteku, povezivadu morare izridito navesti njeno
I . tJkljue iri clarorcku zaglavlja ime.
biblioteke.
2. Koristite lunkcije i promenljive sadrZane
u biblioteci.
3. PoveZere biblioteku i obj ektni k6d u izwsni Koriiienje uobidajenih C biblioteka
program.
ovi koraci se primenjuju.i ako objektni moduli To Sto pi5ete program na C++-u ne spredava vas da koristite lunkcije C biblio-
nisu smesteni u bibrioteku. teka. U stvari, podrazumeva se da je kompletna C biblioteka ukljudena u stan-
Ukljudivanje datoteke zagl2vrjli p_ou"iiuu.,j"
otjett.,rt modula osnovni su koraci dardni C++. Ove funkcije su veoma korisne i mogu vam u5tedeti dosta wemena.
odvojenog prevodenja i u C_u i u C++_u.
U ovoj knjizi ie se koristiti funkcije standardnih C++ (takode i standardnih C)
Kako povezivat pretra2uje biblioteku biblioteka, i to iskljudivo standardne funkcije, da bi se obezbedila prenosivosr
Kada povezivad naicle na spoljnu-referencu
programa. U malobrojnim primenama funkcija biblioteka koje nisu po C++
funkcije ili promenljive moZe uraditi standardu, koristiie se funkcije usaglaSene sa srandardom POSX. POSIX je stan-
dve stvari Ako rrije pr.thodno nasao a"nniciju te funkcije
dodaie identifikator svojoj Iisti ,,n..ur."5"nlh ili promenljive, dard Unixa, i obuhvata funkcije izvan C++ biblioteka. Uglavnom moZete
referenci,,. ukoliko je povezivad odekivati da nadete POSX funkcije na Unix (posebno Linux) platformama, a
ranije naSao definicijr-r, referenca se rarre5ava.
desto i pod DOS/Windows sistemima. Na primer, ako pravite uiSenitne pro-
Ako povezivad ne moZe da pronade
deflnrcilu u objektnim modurima iz liste, grame, imadete koristi od POSX biblioteke, po5to ie va5 k6d biti razumljiviji i
tada pretraz. je biblioteke. Biblioteke
ouieno ima;u i indeks sadrzaja, pa povezivad lak5e ie se prenositi i odrZavati (POSIX biblioteka za vi5enitno programiranje
ne mora da pretrazuje sve objektne
module bibiioteke, n"go najde5ie ie samo koristiti odgovarajuie funkcije operatirmog sistema).
po'ezivai pronade definiciju u biblioteci, Kada
u izwsni program"#o'i'rteks.
se povezuje cero_
kupni objektni rnodur, a .e samo definicija
tunkcije. Lup"uri;t";; ;" ; povezuje
kompletna biblioteka, nego samo objektni
(inade bi programi bili nepotrebno
modul i";i tia.zip"oJ.,, o"n.i.iy, Vai prvi C++ program
veliki). Ako hoiete da smanjite izwsni pro- Stekli ste dovoljno osnovnog znanja, pa moZete da napi5ete i prevedete pro-
gram' razmotrite moguinost da jedna
datoteka izvornog koda u biblioteci sadrZi gram. Program ie koristiti standardne C++ klase ulazno-izlaznih tokova. One
samo jednu ftrnkciju. ovo zahteva
viie izmena,j ditaju i upisuju u datoteke i ,,standardne" ulazne i izlazne uredaje (obidno je to
Posto povezivad rraZi datoreke redosteaoL "ti;;;"";;;i,i".or,or.
r.o;i .,auea"i", ,p'."ric"," to.r_ konzola, ali se moZe preusmeriti na datoteke ili druge uredaje). I-l ovom jedno-
Sienje biblioteike funkcije ako cratotek,
istormenom rr'rrt.1;o.., ,ru.r._ stavnom programu, objekat toka ie se koristiti za ispisivanje poruke na ekranu.
dete pre imena biblioteke- posto C. porr"rrrre " "uso.n
reference korisienjem vaSe funkcije
razre5itt sve odgovara;.uie
p." ,i"gos,o pretraZi biblioteku, vasa funk_
cija se koristi umesro one iz bibrioieft.
obr;;r; paZnju na to da ovaj nadin moZe U potreba klasa ulazno-izlaznih tokova
izaz'vati i gre.kr-r koja se spredava upotrebom
imenskih prostora c++-a. i spoljni podaci klase ulazno-izlaznih
Da bi se deklarisale funkcije tokova,
datoteka zaglavlja se ukljuduje naredbom:
Skriveni dodaci #i ncl ude <i ostream>
Toko'-r pravljenja izw5nog.programa, povezuju
se i neki skriveni erementi. Prvi program koristi standardni izlazni tok, Sto znadi ,,mesto opSte namene za
,d n.iih je prier.i modrrr i[odJ. ru ini.i;ui,,u.iiu, Iedan
na podctk, rada c iri (.++ programa.
koji se mora svaki put izwsiti slanje izlaznih podataka'. Videdete i druge primere koji na razlieite nadine
ovaj k6d definise.r"kil;i.i;;riruje neke koriste standardni izlazni tok, ali iete u ovom sludaju koristiti konzolu. Paket
prograrnske prornenl jivc.
Povezivai u standardnoj biblioteci iostream automatski defini5e promenljivu (objekat) pod nazivom cout. Ona
uvek traZi prevedene verzije,,standardnih,, prima sve podatke koje treba poslati na standardni izlazni tok.
funkcija koje se pozivaju u programu' posto
se standardna bib[o;;k;-;rek pre- Za slanje podataka na standardni izlazoi tok koristi se operator <<. Pro-
trazuje, mozere koristiti uito stirz te
uiutioteke tako Sto iete program
u uktjuditi grameri na jeziku C znaju da ovaj operator oznadava pomeranje bitova ulevo
odgovarajuiu datoteku zagravrja n.
- -o.ui"
standardne bibrioteke' Ni piimer, f"nk;ii;
posebno zahtevati povezivanje (biie opisan u sledeiem poglavlju). Dovoljno je reii da pomeranje bitova ulevo
urazno-izraznih tokova su u nema nikakve veze sa izlazom. Medutim, C++ omogu(ava preklapanje
' l',,,1,o,r,, ro lrilt dir Ioristirc I)crl ili pr,nlr0rr
za arrtomatizaciiu ovog zadatka koji
biiriiorek. ,'ia",i rrg ir, ,*.euii,",.;;;;l'""^' .ie deo procesa pakovan.ia
"-r',ia,,.i '"
62
Misliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata 63

or)erarora prekroprjeni operaror dobija novo


znadenje pri kori.ienju sa objek-
tor.n.ociredenog tipa. Sa objektima ttiazno_iztaznih lzlaganje svih elemenata jednog imenskog prostora, po5to je neko uloZio
,,poslati". Na primer:
i;[";;,;;;;t,o... r.,uet veliki napor da ih sakrije, moZe delovati kontraproduktivno, i potreban je oprez,
kao Sto iete videti u nastavku ove knjige. Kako, naredba using stavlja na raspola-
cout << "zdravo I
,,
; ganje imena samo u datoteci u kojoj je napisana, opasnost nije velika kao 5ro na
Salfe niz znak<tva ,,zclra,",ol,, objektu pod prvi pogled izgleda. (Ipak, razmislite dvaput pre nego Sto iskoristite tu naredbu u
nazivom cout (to je skraienica od
sole output", Sto znaci,,iz.laz nakonzoIu,,).
,,con_ datoteci zaglavlja- to nije dobar polez.)
dovoljno reieno o preklapanju operatora. pogtavlje Postoji veza izmedu imenskih prostora i nadina ukljudivanja datoteka za-
aJiJ;,,".,i:p l2 se deratjno glavlja. Pre nego Sto je standardizovan sawemeni naiin ukljudivanja datoteka
zaglavlja (bez prateieg.h, kao u <iostream>), obidno su se ukljudivale datoteke s
nastavkom imena.h, kao u <iostream.h>. U to weme nisu postojali ni imenski
lmenski prostori prostori. Da bi se obezbedila kompatibilnost sa starijim verzijama postojeiih
Kao 5to je napomenuto u poglavrju programa, ako napi5ete
l, u jeziku c se nailazi na probrem ,,iskorisia-
vanja svih imena" funkcija i promenrjivih
kaJa program dostigne odredenu veli- #i ncl ude <i ostream. h>
dinu. Narayno da nisu srvarno iskori.iena
,u;, i,,"1u, ndo pJ; izvesnog to znadi
wemena postaje sve reze smisljati nova
imena.
Sto.,e los vazi,r":O;; program
dostigne odredenu velidinu, #i ncl ude <i ostream>
vijaju i odrZavaju razlidite osobe "obieul".ro i" aa se poaeri na manje celine koje raz-
ili rimo;i. posto ," ,., c p.og.J,,ii-ru'ruu i_..,u using namespace std;
nalazc u istom prostoru, programeri
moraju paziti da sludajno ne upotrebe U ovoj knjizi ie biti kori5ien standardni format ukljudivanja (bez.h), tako da
i'rena tr sitrracijanra tacra ili to moglo 6iti ista
arnr,,,irr"no. uJo.o'ao po.,uj. se naredba using mora izridito navesti.
,/Atr-lorno, troii se
llrcviie vrcntr,na, a i ttovca. Zasad je to sve Sto je neophodno znati o imenskim prostorima, a u poglavlju
Standarclni a++ ir,a nrehanizam koji
spredava ove probleme: rezervisanu 10 ie ova tema biti detaljnije obradena.
namespace (imcnski prosror). svaki red
skup c++ deflnicij" , uiuirti".i, odnosno
programr-r,
"upakovan" je u imenski prostor i neie
dcfinicija ima isto ime u drugom i-".,rto.rri.ostoru. biti nedoumice ako neka Osnovna struktura programa
Imenski prosrori su pogodni i korisni, Program na jeziku C ili C++ je skup promenljivih, definicija funkcija i poziva
ali'morate biti svesni njihovog posto-
janja pre.nego sto zapodnete pisanje funkcija. Program prvo izvrSava kOd za inicijalizaciju i poziva posebnu funkciju,
pirg.u*u. Ako samo ukrjudite datoteku
zagla'rja i koristire neke njene funt.ile mainQ. Tu se sme5ta osno'rni k6d programa.
irioB;"t,", ,.rovatno iete pri prevodenju
programa dobiti neobicne poruke o gre.kama, Kao Sto je spomenuto ranije, definicija funkcije se sastoji od tipa rezultata
iak i to au p."uoriu. Ie moze aa
p ro nade dekraraci je (mora biti definisan u C++-u), imena funkcije, Iiste argumenata izmedu zagrada
eremenara koje'ste upravo ukrjud,i
lavljal Kada nekoliko puta vidite o'"'ll po.r[r, ;"-;r;;;i;teke zag- i tela funkcije unutar vitidastih zagrada. Ovo je primer definicije funkcije:
por,ai.e vam jasno njeno znadenje
(moZe se tumaditi kao:
,,tJkljuditi .te artot.li, zaglavlja, uti ,, ,ir. int funkcija0 {
J"klaracije
'n'tar nekog
korisrire
imenskog prostora, a niste saop.tiri prevodiocu
deklaracije iz tog da hoiete da // 1vo ie telo funkcije (ovo je komentar)
imenskog p.or,o,u ). )
Postoii rezervisana red koja omo'guiava
da'kaZete: ,,Hoiu da koristim dek_la_ Navedena funkcija ima praznu listu argumenata i telo koje sadrZi samo komen-
raciie i/ili definicije iz ovog imensko"g p.or,oru'l
ova rezervisana red ima sasvim tar.
odgovarajuii naziv using ikoristeCil."S'v"
,iunau.a.,. C+* UiUiiot"f."^riut o.ru.,. U definiciji funkcije moZe postojati vi5e parova vitidastih zagrada, ali mora
su u jcdan imcnski prostor, a to je std (od
redi,,standard,,). po.to se ut'voj knjizi postojati najmanje jedan oko tela funkcije. Po5to je main$ funkcija, ta pravila
koriste skoro iskrjue ivo standar.n"
uiuii"t"t", ,ideiete sledeiu iirriiurirg , vaie i za nju. Tip rezultata funkcije mainQ u C++-u je uvek int.
skoro svakom programu:
C i C++ su jezici slobodne forme. Osim malog broja izuzetaka, prevodilac
usi ng namespace std;
ignori5e prelom redova i razmake, tako da mora postojati nadin da se prepozna
ovo znadi da hofete da budu dostupni svi kraj naredbe. Naredba se zawSava znakom ta(kaizarez.
elementi imenskog prostora std.
Posle ove naredbe ne morare razmisljati
da ri je konkretna'[oiipo.,"n,u Komentari u C-u podinju sa /* i zaw5avaju se sa */ i mogu se pisati u viSe
biblioreke r.Lrrar inrenskog prostora, pi,si" redova. C++ koristi isti stil komentara, ali postoji joS jedan tip komentara: //.
i menskog p ""*aira
rostora raspoloz_ivi m u ceto;'aatoteci
using ei.,i i-".,u i, tog Oznaka I I zapotinje komentar koji se zaw5ava znakom za novi red. To je pogod-
nije nego l* * I za komentare u jednom redu i iesto se koristi u ovoj knjizi.
64
Misliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata 65
,,Zdravo, svete!,,
A sada, konaino, prvi program: Prevodenje
/ : C)Z: He1 ) o. cpp Posle preno.enja i^rlsRlkivanja izvornog koda
/ iz knjige, pronadire program u
// Pozdrav u C++-u poddirektorijumu co2. pozovire prevodi'iac navodeii
H"rrlr."pp kao argumenr.
rinclude <jostream>
I I Oep,laracr.je tokova
u jednostarrnim programima sme.tenim u jednu datoteku, iao sto je ovaj,
us I ng namespdce std; veiina prevodilaca de obaviti ceo proces. Na primer, ako
koristite GNU c++ pre_
vodilac (besplatno je dostupan na Internetu), napiSite:
int main0 { g++ Hello.cpp
cout <<,,Zdravo, svete! Danas jmam,,
<. B << ,'godinal,, .. endl; Za ostale prevodioce koristi se sridna sintaksa,
a detalje potrazite u odgovara_
t\ //t,,/:- juioj dokumenraciji.

::l: :'* ::lJ


rsprsuJe ove
prelaz-ak
;:;l:Y:l:"
arg.menre "il:^tfl
redom, ,t.ru :."i"
ri"rno.
purem operatora << uDiekat
pl.J.l, Ji':;:::::<<. objekat
p";;i;k ;; os rerta pnmnr,, ,.,---]t""_?lu oznaka endl prouzrokuje
ViSe o ulazn o-izlaznim tokovima
::"ff :*TnT:I.::Hs#i",::::,:::{r;ir-',;('i;ffi
""
ata, 5to p.;.a.".i"'rffi '#:ilff:fi
Dosad ste videli samo najosnovnije moguinosti klasa
"':',"..P::::"l.:'j.::tll;",
,l i;: r c++
"?fi:',:1:xT:}l;
rlrrruuu arrd^uva navooa. posto
I: Formatiranje izraza pomo(u ulazno-izlarlrih tokouu
ulazno -izraznih tokova.
obuhvata i moguinosti kao
Sto su dekadno, oktarno i heksadecimalno formatiru";.
standardna ;::'L{,, : :^?::t:"r
biblioteka "u" "',.,;H';;H;::il#T:,oda
obuhvata ,.nri;;'i,r utY p99 prikazuj e up o trebu ulazno - izlaznih tokova:
uro;"*. Sredeii primer
tekstom,za ,.tr, rr-..r,, nrrrnrrnir.^ 1-^-:^.: 2 nazivom string za rad s
"o;::*,il,i:*,:i::,:i:*dtif 1k"il;;ilLilI,:ffi1'f :":';::i,,7;' l/: C02:Stream2.cpp
::"":'l[i,Y;::i:T',T::r:{i;;:..i;;;?"#'#;:::::x:rl!'ir*
ul piort o.. *"'r."r ;;*;;"": II Dodatne mogucnosti tokova
",.4 ""
doda.je ;,bajtii|I"nl ::li:.,,
vred-nosti 0. ;?,:Z:ffinii::i #include <iostream>
using namespace std;
lJ znakor,ni niz sr
sekuencr.teigt,;;;o;:,;nf, :J?J::"::::J,*::?i::,:,T::.J"?,i:,rf
nog znaka' Na primer, \n znaii JK{. int main0 {
no.l
priruinikrr z'a iez.ik (l oorrazite potpun ."a.-ulrekom uputstuu za prevodilac ,i // Def.i ni sanje formatapomocu mani pul atora:
\t (labularor), \ \ (ohrntrta kosa crra) skirp'irr.rr*r'r"iJ";:t _;:iJ-"d njih su: cout << ,'broj u dekadnom zapisu: ,,
, ,U if*"" znak unazad). << dec << 15 << endl;
," 1-,iil?J:.tXse
naredba moze pisati J iil ."a"*, u a"l"iueu i zarezoznaka cout <<,,u oktalnom: ,,<< oct << 15 << endl;
cout << ,,u heksadecimal nom: ,, << hex << 15 <<
t.l .arcdbi se, p.red.objekta end.i ;
cou.t, po.iavljuju i znakovni
nizovi i konstantni cout << ,,u formatu pokretnog zareza: ,,
hrrojevi t)osro je operaror prektopll;n ;;" puta kada << 3.14159 << endl;
.<'
proslediii ,orni ,ipori ursumenara
se koristi uz cout,
c0ut <<,,znak koji se ne prikazuje (escape):
::i:i,..,,..,|Xl:l;:"*, i on ie ,,otkriti sta da
,,

<< char(27) << endl ;


,KomI)ok cirare ovr: kn jigrr, primeriiere
kornenrara (ohicno
da prvi red sv_ake datoteke zapoiinje
ozna_
l /// ,-
r r), iz.a kojeg srede dve tadke, a posrednji Ovaj primer pokazrrje ispisivanje brojeva pomoiu klase
sadrTi oznaku komenrara.posie
kojEg rr"aiir-, or.u tehniku
red programa .
kova u dekadnom, oktalnom i hekiadecimarnom
ulazno-izlaznih to-
omogrriio ieclnosravno izclva.janje
iri"....ii" iz. koristim da bih formatu, p.i.*.ro- manipu_
latora koji ne ispisuju nista, ali menjaju sranje izlazn;g];k". prevodilac
koji ovo radi naii iere u datoteka , toJ"rn,ip.og."*
.rr..il"- ;;;;';;"'i"jige). prvi red sadrZi i naziv i automatski odreduje f9r1a1r1gje brojeva u pokretnom
iokaciju datoteke, sro korisrim't"0" .urJru.Osim toga, bilo
f taj program ,, i.k;;;, koji znak se moZe poslati objektu toka ako se konvertuje
datotekama Na osnovrr ,in "-iffi
oar"a,rJo];;;;;;
r -"o'qr se Iako moze pronaii
drugim
podatakakoji sadrZijedan znak. ovde se konuerzijaouavtlat""gf.
,^O u char, tip
nom kodu pridruZenont ovoj knjizi. u izvor- pJzrvan-]em funkcije
char0, uz ASCII wednost znaka. u navedenom programu,
char(27) Salje znak
tastera,,escape" objektu cout.

Spajanje n za znakova
vaZna osobina pretprocesora jezika c jeste spajanje
nizoua znakoua {engr. cha-
racter atay concatenation). Ova moguinost ie koristi u nekim primerima u
Iir.
f
56 *'
Misliti na jeziku C++ ts
Si Poglavlje 2: Pravljenje i upotreba objekata 67
k,
r"
t'!
knjizi. Ako znakovna niza, uokvirena navodnicima, jedan pored drugog, i,,,
srr dva j..

bez z.akor.'a intcrpunkcijc izmedu njih, prevodilac ie ih spojiti urjedan. ovo Li Pozivanje drugih programa
fe i' Bilo koji program se moZe pozvati i iz C ili C++ programa primenom standardne
posctrno korisno ako je ogranidena Sirina programskog koda:- [.
i" C funkcije system0, deklarisane u datoteci zaglavlja <cstdlib>:
II : C02: Concat. cpp
tiJ

[,
// Spajan.le znakovni h ni zova E,I
ll: C02:Ca11He1lo.cpp
#include <iostream> h,
F.
/i Pozivanje drugog programa
rs i ng narrg5p6ce std; vi #j ncl ude <cstdl i b> // Dekl ari 5e "system0 "
w using namespace stdl
int main0 {
H. jnt main0 {
cout << "Tekst je presir-ok da bi stao,, F,
E
"u jedan red, al i se moze podel iti ,, tr system("zdravo" ) ;
"bez posl edi ca\nsamo ako nema ,, H
H
l //1,-
"znakova'interpunkcije .izmedu n.
susednih znakovnih,' rri Funkciji system0 treba proslediti znakovni niz koji biste uobidajeno otkucali
"ni zova. \n"; ,.',
M nakomandnoj liniji operatirnog sistema. Mogu se dodati i argumenti komandne
I l/l ,- B.
F.,i
lr.
linije, a znakomi niz moZe biti napravljen i tokom izw5avanja programa (umesto
Na prvi pogled, ovaj k6d deluje pogresno, posto nema tadke izarezana
kraju E statidkog niza znakova kakav je upotrebljen u primeru). Komanda se izwSava, a
svakog reda. Prisetimo se da su c i c++ jezici slobodne forme. Iako iete H posle toga se izvrSavanje programa nastavlja od mesta s koga je pozvana.
rrglavnorn videti taikr.r i zarez na kraju svakog reda, znak tadka i zarez mora sta- B
& Ovaj program pokazuje koliko se jednostarmo koriste uobidajene funkcije C
jati sanro na kraju svake naredbe, a jedna naredba se moZe pisati n biblioteka u C++-u: ukljudi se datoteka zaglavlja i pozove funkcija. Kompatibil-
u vise redova. 6
E- nost C-a s novijim verzijama C++-a je velika prednost ako podinjete udenje C++-a
veC znale C.
Citanie sa ulaznog toka F:

tr.,,
Klase ulazno-iz.laznih tokova omoguiavaju ditanje podataka. Za standardni
E
ulazni.tok se koristi objekat cin (skraienica od ,,coniol* i.,prt,,, sto znadi
,,ulaz sa $:
F, Klasa string
konzole"). objekat cin podrazumevano odekuje ulaz sa konzole, ari se moze [.:
E.
r Iako niz znakova moZe biti veoma koristan, sasvim je ograniden. To je samo
preusmeriti na druge izvore. primer preusmeravanja ie biti naveden u nastavku &,

h grupa znakova u memoriji. Ako hoiete s njim da udinite bilo sta, morate se baviti
poglavlja. I
x.. mnoStvom sitnih detalja. Na primer, velidina nizaznakova izmedu navodnika je
Uz objekat cin koristi se operator ulazno-izlaznih tokova, >>. on odekuje
ti f,ksirana u weme prevodenja. Ako postojeiem nizu znakova hoiete da dodate
ulazne podatke koji po tipu odgovaraju njegovim argumentima. Na primer,
ako E nove znakove, treba da znate mnogo swari (ukljudujuii dinamidko upravljanje
mu prosledite celobrojni argument, on odekuje ceo broj sa konzole. Sledi sE memorijom, kopiranje niza znakova i spajanje). Upravo zato je potreban objekat
primer: B'
rr koji ie obaviti taj posao.
I/: C02: Numconv. cpp [' Standardna C++ klasa string napravljena je da bi se pobrinula (skriveno) o
l''
// Konverzija dekadnog u oktalni i heksadecimalni broj iiq. rukovanju nizovima znakova na niskom nivou, Sto je prethodno morao da radi C
#include <iostream> programer. Programeri na jeziku C su stalno gubili vreme na pisanje ovih ope-
i
us'tng namespace std; racija, a desto su baS tu pravili i greSke. Iako je u tomu 2 ove knjige celo poglavlje
l:
posveieno klasi string, klasa je tako vaZna i toliko olak5ava Zivot, da iu je sada
int maln0 { t.

opisati i koristiti od samog podetka.


int number; i'
t: Da biste koristili klasu string, treba da ukljudite datoteku zaglavlja <string>.
cout << "Unesj te dekadnj broj: ,,;
ICasa string se nalazi u imenskom prostoru std, tako da je neophodno koristiti
cin >> number;
naredbu using. Usled preklapanja operatora, sintaksa koriSienja klase string je
cout << "oktalna vrednost = 0,,
<< oct << number << endl; i veoma intuitivna:
cout << "heksadecimal na vrednost = 0x', ;
/ / : C02z[e11 oStri ngs. cpp
<< hex << number << endl; // }snove standardne [++ klase string
\ lll'- i
#i ncl ude <stri ng>
#i ncl ude <i ostream>
ovaj program dita brof s tastature i konvert,je ga u oktalni i heksadecimalni i
usi ng namespace std;
za p is.
58
Misliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata
69
int main0 {
stnlng s1, sZ; ll prazni znakovni nizovi Sledi jednostavan primer kopiranja sadrZaja jedne datoteke
u drugu:
string s3 = ,,Zdravo, svete.,,; // Inicijalizovano //: C02:Scopy.cpp
string s4(,,Ja imam,,); /l Takodje inicijalizovano // Kopiranje datoteke u drugu datoteku, red po red
t2 = "godi na danas " ; I / Doder jivanje vrednosti znakovnom #i ncl ude <stri ng>
ni zu
sl = s3 +,' ', + s4; /l Konbtnovanje znakovnih nizova #i ncl ude <fstream>
s1 += " A "; I / Dodavanje znakovnom nizu using namespace std:
cout << sl + s2 1 ,,r,, <. end1.
) ll,- int main0 {
Prva dva objekta tipa string, sl i s2, na podetku ifstream in(,,Scopy.cpp',); // 0tvaranje za ud i tavanj
su prazna, dok s3 i s4 prika- e
zr ju dva ekvivarentna nadina inicijalizacije ofstream out("Scopy2.cpp,') ; / / 0tvaranje za upisivanje
objekata tipu ,tiirrg nizovima zna-
kova (isto tako jednosravno mozeie inicijalizovaii"u;Jt," stri ng s;
drugih objekata tipa string).
,lp"tstring pomoiu while(getline(in, s)) ff Zanemaruje znak za novi red
Bilo kom objektu tipa string moZe se doderiti wednost out << s .< ,,\n,,; // ... mora ga dodati
operarora kori.ienjem
=. Tako se vrednost objekta zamenjuje sadrZajem ,u-J"rn"
l / // ,-
strane i ne
morate voditi raduna o tome Sta se desava-si prethodnim Da bi se datoteke otvorile, imena datoteka se prosleduju objektima
saarzalem _ to se tipa
re.ava automatski. Za nadovezivanje objekata ifstream i ofstream, kao Sto se vidi iz primera.
trpu,t.i"g-ko.irii ," operator +,
koji omoguiava i nadovezivanje nizova znakova
nadovezali ili objekat tipa string ili niz znakouu
s ou;ettiria iipa string. Da biste . u prethodnom primeru je uveden nov pojam - petlja while. Iako ie biti
detaljno objasnjena u narednom poglavrju, sada iemo je ukratko
rnozete koristiti operaror +=' Naiz.ad, obratite paZnju
a."giffikar tipa string,
"una to"da uiazno-izrazni Zamisao je da izraz u zagradama posie .eti while upravrya izwsavanjem
opisati.
tok- sledeie
ovi vei znaju sta treba da racre s objektima naredbe (to moZe biti i veii broj naredaba, unutaivitidastih zagraial.
tipa string. zuto ouy"tat tipa string sve dok
(ili izraz tog tipa, kao r,r sludaju sI + izraz u zagradama, u ovom sludaju to je getrine(in, s), ima"vrednost
s2 + !) moZete poslati direktno objektu cout true,
da bi ga ispisao. izw5avaie se naredba kojom upravlja while. To znadi da ie getlineO
watiti wed_
nost koja se tumadi kao true ako je red uspesno uditan, a false
kada se dode do
kaja ulazne datoteke. Na taj nadin petla while uditava svaki red ulazne
UtitavanJe iz datoteka i upisivanje u njih i Salje red u izlaznu datoteku.
datoteke
Proces orvaranja i rukovanja datotekama u c-u zalitevu dostl predznanja Funkcija getline0 uditava znakove sve dok ne naide na znak
da bi za novi red
se mogle obaviti slozene operacije. Medutim, bibrioteka iostieam (zawsni znak se moZe promeniti, ali se time neiemo
omoguiava baviti do poglavrja o
jednostavno rukovanje datorekama, ulazno-izlaznim tokovima u tomu 2). Medutim, funkcija ,u""*u.,i;"
tako da r. ou" 2"t.i;;;;;; uvesti mnogo znak za
ranije nego na jeziku C. novi red i ne upisuje ga u rezultujuci objekat tipa string. Ako
hoiemo da kopi-
Da bi se datoteka otvorila za uditavanje i rana datoteka izgleda upravo kao izvorna, moramo doaiti
upisivanje, mora se uktjuiiti zagravrje znakzanovi red, kao
<fstream>. lako se time a.,tomatsti uttJueu]e Sto jei pokazano.
z.agla.rje.io.t."-u-r, dobar je
potez da se <iostream> izridito ukljudi ako planiratJda (oristite sledi zanimljiv primer uditavanje cere datoteke u jedan objekat tipa
cin, cout itd" string:
Da bi se datoteka otvorila.za uditavanje, pravite : C02:Fi lstring.cpp
objekat tipa ifstream, koji se I I 1
ponasa slidno objektu cin. Ako datoteku
otvarate zaupisivanje, pravite objekat
tipa ofstream, kofi se ponaSa slieno objektu cout. 'posto
// Uditavanje cele datoteke u jedan znakovni niz
Jiri.ite datoteku, #j ncl ude <stri ng>
mozere udiravati iz.nje i upisivati u nju kao #include <iostream>
sto biste din,i s bilo kojim drugim
objektom toka. Eto kako je jednostarmo (u tome je #include <fstream>
i poenta).
Iedna od najkorisnijih funkcija bibrioteke io.t."i-;"rie using namespace std;
gettine0, koja udi_
tava jedan red (zavrSen znakom za novi red)
u objekai,ip"'.,ri"S;.';;l,!;
menr je ohjekat tipa ifstream iz koga se uditava,
a ai"gi urg'r,,;ni-ie objekat tipa
int main0 {
string. Po zavr5erkLr funkcije, pro.sledeni objekat i fstream i n (,,Fi 1 I Stri ng. cpp,')
,fp:" .i?*g .,uarZue" uditani ;
red. stri ng s, 1 i ne;
whi1e(get1 ine(in, 1ine))
s += line + ,,\n";
ltrttlttr. BetlineO. l)cralj.o se razrnarraju u pog]avlju o utazno-izlaznim
l;:;l;li;;:;ilrlrl'r tokovima, u cout << s;
70
Misliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata
7t
S obzirom na
,dinamicktr prirod. krase string, ne morate voditi raduna o
0"" (da ponovimo, to je vaZan cilj oop-a). posto
;:Hii:Hl;i: "'r'u 'J"''lati'za ot vetai ,i& ,ui;; - samo dodajte iete o ovom i drugim kontejnerima

,
rzrne*
^, "*
u. n
datoteke
.,., i J,,J,iili;,,i.l
i?JJ
znikovno g nu..a,'u',u
ciatoteke tr obiekat tipa string.
ka.o
1" ;"aru
: I
x,":
j

ii.l:
oa f."-alosir topiranla cete
pos,tojei ogranidenja.
r* ,;?# rl*;; nauditi vi.e u romu 2, u pogravijima posveienim
je u redu da se krasa u:"Ig. u podernim
Sto bi to radio iskusni c++ progra-".. oit.iclt"
vatna u najveiem broju sludajeva.
standardno; "uiutio1..i, sasvim
poglavrjima t";ig" toli*"Jrirgaerle nego
au i."ouut ra upJ.eua ua.t-
laksi. obradu ju ^ieil;;, vetiti ietstirat;;;;;;d cesto se datoteke
hoiete da numeri.e* iran'.,
,".,i"r"]'""
kao- siupovi
Na primer, ako
Klasavector je lablon-(engl. template),Sto znadi
da se moZe efikasno prime_
i"Jnor,rrr,;. ;. J" ,""ii ."iiro" predstavrjen niti na razlidite tipove. moZe napraviti vektor ngura, vettoimadaka, vek_
posebnim oLrjektom string. la\o_se
o. rri ," p."u,". i** o""."Our";Jlu*rdji pristup.
tor objekata tipa string itd. pomoiu sabrona, moZe
Da.bj s9 saop5tilo prevodiocu sa dim ie klasa
se riapraviti ,,Husu uito e .ga,,.
raditi (, ouo-.f.i"lrlSi" ie vector
sadrZati), ime tipa se smesta izmedu znakova < i >.
Klasa vector Tako ie ue"toi ru krasu string
biti oznaden sa vector<string>' Kada ovo napisete, aoti;ate jr,"goi""i
ob;ekat tipa string moZemo popuniti koji ie sadrZati samo objektJ.krase srring i pievodilac vektor
prosrora' problem pri uditavanju ne zna.iuii unapred koliko nam
treba e" p.ii*iffisku ako u
iedova iz.datoieke , pJ;"a,ir"e vektor poku5ate da smestite objekat neko"g drugog
string iini ro sro na poietku objekte tipa tlpa.
ne znare koriko ie ,;;;;;;;ih''niroru Po5to je vector skladi5te za objekte, tji". to.,t"Jn".,
nego saznajete tek poSto trebati, mora postojati nadin da
udirate ceru daroteku. o" ne5to stavite u kontejner.i uzmete ii n1ega. oa
ui." p."[i"- ..rro, potrebno bi se na kraik"*"1."'." a"aao nov
ui
[ff]ilf#l'j;:'i" " "'to'nuiii.].,ro
da
r p.*,,",,i"
u njega smestimo.
ou;"tut, tipu
",ii*o
element, koristi se funkcija dlanica push"-backg. (prisetimo
bismo pozvaii funkciju dlanicu-nekog Jj"ku.l Ime
,.,
se da koristimo
ove funkcije dl.anice moze
da
Zasto bismo seeravamo delovati.preop5irno - push_tack0 ,,,ri"sto
tipa string? rspostavrja se da l"anostar,nijeg naziva,put,, _ zaro Sto
.esro rokom ;i';;;-J::';::HJ;J#ffi?:,?itl" p:ttor." i drugi kontejneri.i drugefunkcije dianice za smes"tanle .,ofi[.r...,.r,u,u.
ko ri s ni n o,'u i o,,rr u a is,.,"
j e u Na primer, postoji funkcija dlinica inslrt0 za
i

zove konte;'ner) koie bi


r

";l;ilJ?fiffi
moglo aii"aii-ain
;ffi :il",lTjlliT;I*??i vouno mesto u kontejneru. I(asa vector ovo podrZava,
sme5tanje elemenata na proiz-
dardna c++ bibrioteka]T" koju urstu objektisre(om, t"risc""iJ slozenije i
sran-
tejnerske klase su zaista moZnaq"i; ;#;;", standardne kontejnerske k.rase. Kon-
nije potrebno da ga proudavamo do toma i ove
(nema je u krasi vector) smesta elemente
"ri;"
knjige.'r""t.ii" p"rh_front0
ulutto sianaarnog C++-a. na poreiaf. nostole i ,irlg" a.,rg"
I.irdi cesro meiaju tonr.;n"r. i funkcije dlanice krase vector i mnogi drugi kontejneri
u'r!ori,-"-rtunau.an" c++ bibrioteke
biblioteku s,L lzraz'i,unonrJi.-"p,u,JTtu*.y standardne c*i Liutiotet.,
(standardna bibro."tu
i ali iete se iznenaditi koriko se.no-2.,ei"riti iako
koristio je AIex Srepanov (tada je sablona) se zna samo o,uti tin; jeclno_
raOio u Uewtett_packardu) stavnih osobina.
svoju billliorektr Kom itetu kada je predstavio
za C++r;r;;";; Ako nove elemente dodajete u vector funkcijom push_back0,
u p ro r e i c
preuzimanje s Inter.nera.
rss
n.*, +. rvu, i u 1.
u.l?'iii'"JoX,fru;uuc",,'n jiil?,llTll#if*: mate odatie?.Resenje je jednostavno i veoma kako ih uzi_
eregantno - k"ilil; ;;;Kapanje
U meduvrem"r, ;" komitet integrisao operatora da bi vector izgledao kao niz (eng). arriy).Niz (biie
detarjnile opisan u
srandardnu c++ bihriotek" biblioteku u
Silicon Craphics (S(it; videti
i.ir."ri"l.li!::1,:.1 j" u kompaniji ;;;i;;,; sledeiem poglavlju) jeste tip podataka koj"i portoli
u skoro ,rri- fiJg.u.rrrti-
t,,rpt),r*'*..r)i.rom/Technology/SiZt.
" jezicima, tako da bi trebalo au.uum vei
budl por.,ut. Nizovi su ogrrgoti,sto
Iikuje od srandardnc.c- * uiurioi.r.. SCI STL se raz_ da se sastoje od izvesnog broja grupisanih eiemenata. posebnio.Iouinu znadi
ttir C++ srantrarcr ,,ukrjucuie.:'il; ,'J."r"g,r-, aetatlimiinopiri"-*r;" zabluda niza je
aigorirrni srantlarcirre (.++ bibliorek"
i"";;;;'^ut" J"lrrril,;;H; kontejneri
Sto su ovi elementi iste velidinJ i uredeni
su tako da slede jedan za drugim.
,",.i,, isri.koren i NajvaZnije je da se ovi elementi mogu izabrati
st L knjizi r'r:.,k,risriri feestb iisia imenat kao SGI ,,indeksiranj"ill Sto-rrruel au
moZete reii' ,,Treba mi erement b.9., ,' i uglavnom
' 'v'j
ko n rej n eri h ibl i o r cke,,
o";r,;;,.;;;;;ardna
.['";,
c++ bibrioteka,, iri,,srandardni
Mada postoje izuzeci.,, p.og.*rkim yeziiima,
iete brzo dobi r ,uy
Iako rearizaciia srandardnin
.n ;;*uru.u izraz,,ST L,,.
iIi eSr ; indeksiranje se obidno"t.*..,r.
postize
t".,iq:r"rlti.ulgo.i,u,,,a c++ bibrioteke k9$-ee1i9m uglastih zagradi. Ako imatl niz a i treba
napredne pojmove i zanzima uu,,-, p.ti navodite
a* korisri a[4] (indeksiranje podinje od nule). "r"-"ni,
biblioteka moze da .. tnri.ti ""rii'""r"gta;ja o*g"g1"-llve tnytge, ova
iuJr'i.ri'""* ova kompaktna i mocna notacija indeksiranja ukljudena je
naiosnovniji poznavanja. zato seklasa u vector prekla-
.,o::11,*,n r*,.r**l ,;;,, , vector, panjem operatora, na isti nadin kio sto su ..
"o kn jigu.
koristi kroz celrr *;;;;;;no,m pogiavlju
otkricere an .io!o.oga..mois1g i
i ,, ,rujre".,i , ,turno_irturn"
tokove' Ni sada ne treba da znate kako je realizovano
osn()vr)c rrr,gucrrosri k.rrtejncra
vector i n3 vooeci raiuna o
uradiri primenjujuii ostavljeno za neko kasnije.pogravlje ;."udr* - to je
njegovoj rearizaciji - ari ie korisno rurnu.,p-Ii
tajanstveni mehanizam koji omogudava da vector fJstoli net<r
koristi opeiator I i.--
7Z
Misliti na jeziku C++ Poglavlje 2: Pravljenje i upotreba objekata 73
Ima.luii sve ovo
r, n'"i,,ri u".io; ;U.,?]i :
:
Ii #,-J;:iX;,Xfi5H.1;ll I".isti
vector Da bi
//: C02:GetUords.cpp
/ / C\Z :Fi I lvector.cpp // Podela datoteke na redi razdvojene razmacima
#i ncl ude <stri ng>
datoteke u vektor objekata
/{.:ilJ:'::;.|il:'"" tipa s*ins #i ncl ude <i ostream>
#include <iostneam> #i ncl ude <fstream>
#include <fstream> #i ncl ude <vector>
#i ncl ude <vector> using namespace std;
usi ng namespace std;
int mainfl {
jnt main0 i vector<strj ng> words;
vector <strjng> v; i fstream in(,,Getl^lords.cpp',) ;
i fstream jn (,,Fi I i vector. string word;
cpp,,)
stning line; ; whi)e(in > word)
while(get).ine(in, I ine))
words, pusir_back (word) ;
v.push_back(1 )ne); for(int i = 0; i < words.size0; i++)
// Dodavanje reda na kraj cout << words[i] .. endl;
// Dodavanie brojeva redova:
for(int i = 0; i < v.size0; i++) ) l//:-
cout << i << ,,. ,, .. v[i] ...-srrur lzraz
| ///:-
'L'r andl, .
. while(in >> word)
slidan je prethodnom:. daroteka
j..Xi:T:.t::,[l"j:'T1 se orvara i jedan po uzima sa ulaznog toka jednu po jednu red (engl. wors i kad,a izraz dobije wed-
ffi j"',.-;:;;1T:X;:.1ii;.lfr nost false znadi da je dostignut kraj datoteke-. Razdvajanje redi razmacima je
:;Iil":ff ::,,:ll,#ilH#ft.J*#I svakako grub primer, ali je zato jednostavan. u nastavku t"jig" videiete
bolje
primere koji omoguiavaju podelu ulaznog toka na bilo koji nidln.
Sledeia naredba nrograma
pettf om drugadije ie petrja for. ona je slidna petlji while, Da bi se pokazala jednostarmost korisienja klase vector s bilo kojim tipom,
uprurr,u ,r;
rao kod petrje whire. raj
|;I;;,;
;;,Iro1ni izraz,, izmeduzagrada, ali se tom
u sledeiem primeru se defini5e vector<int>:
kontrorniJ'- i","'i.,t"r.,slidno
i"i.i;"iilffi;i::", //: C02:Intvector.cpp
l'.'-T:[J:ffiXXiXi:i:l r:;n i ffi'il;i;:sto menjaikako bi se irosro kroz
deo koji
// Definisanje vektora koji sadrZi cele brojeve
korisri: ;;;i;;j;;;;;T:5::f
il;HflH,,,, r*, ,iui*, u k;;:" najdesie #i ncl ude <i ostream>
ooJeryu;e mu poiernu b:"; i kako bi ga koristio kao #include <vector>
I:ll. un,i:
ostaie petrjii sve i;i
wednosr Xl? using namespace std;
1-; 1,;1,i..i;
upotrebom funkciie ilanice
size,, koju,sam neprimetno ffii,"l,i;
"r;:lJif,ff";ii:?X,J"A: int main0
priznati da ie nieno ,nue"n,uleigi;;;; ubacio, ali morate {
C++-a, op.rutoi ra ,,ruromui.f oliliori, deo koristi st acenicu c_a vector<int> v;
o r.rir"Cuuun;.lio;i *"a.,osr i for(inti=0;i<10;i++)
i uveiava za ledan. U
uveiati i za. jedan i rezultat doderiti v.push_back(i);
l\liiiil;,i,1,1, i"2ij^!,^otreba ",.1"",,
petljefor da prom""ii,'lj'iooo",;ui. for(int i = 0; i < v.slze0; i++)
redom vretinosriorr"ri'j.,'l}:1r1|in,at
cout << v[i] .< ', ".
w e d n o s r,
"
0,,, ,. l.' * X :. i : H L,i,
se u niz znakova),
flff
dve tadke i .ur-ut,^."a'i,"T,",",,;f ,l..1",,"j flT f":,,:.t"1ili#: cout << endl;
for(int i = 0; i < v.sizefl; i++)
au,o,"t" i ;k;; ;;;.|o aou,;".,
i izvrsite";';;;-, v[i] = v[i] * tO: /l Dode)jivanje
ffff;[::llffili"?::*aete videiete da je rezurtar nume-
for(int j = 0; i < v.size0; i++)
S obzirom na naiin rada operatora >> sa cout << v[i] .< ", ''
ul,azno_izlaznim tokovima,
pret- . cout << endl
[",1?:i#5 ::]# fi :'#1x tr f I"X;;J"'11,'"I " a ",.,1 - u n a re di;;;ti, ] / //:-
;

Da bi se napravio vektor koji sadrZi neki drugi tip, navedite taj tip kao argu-
ment Sablona (argument se navodi izmedu znakova < i >).. Sattoni i dobro
definisane biblioteke Sablona upravo su namenjeni tako jednostavnoi trporrebi.
74
Misliti na jeziku C++ Poglavlje 2: Pravljenje i uporreba objekata
75
( )r'aj prinrer prikazuje jos jecrrrr-r z.raiajnu
osobinu krase vector. IJ izrazu
v[]l = v[,] * tO; / 5 . Izmenite Fillvector.cpp tako da ispisuje redove unazad, od poslednjeg
do
prvog.
viditc da vector nije ograniien na smestaj
i uzimanje elemenata. Moi.ete i da 1/ 6. Izmenite Fillvector.cpp tako da spaja sve eremente vektora u jedan zna-
dodelirevrednost bilo kom elementu vekro;a (.r-i-
iere uporrebiti rrgraste z,agrade koje predstavljaju ii;;;ilzmenitel, tako Sto
kolmi niz pre ispisivanja, ali nemojte numerisati redove.
z,adi da je vector ,,privrcmeni smeStajni p.nrto." oper?or-inoeksrranya. to 7. Prikazite datoteku red po red, dekajuii da korisnik pritisne
raster ,,L,nter,,
zbirkama objekata i mi iemo ga svakako
opst" .,u,n"ne za rad sa posle svakog reda.
ioristiti u
"".;;;i," ;glavljima. ,' 8. Defini5ite vector<fl_oab i u njega smestite 25 brojeva u formatu pokretnog
zarezakoristeii petljufor. prikaZite sadrZaj vektora.
SaZetak .
rr,/g. oennlsite tri objekta.tipa vector<float> i popunite prva dva kao u prethod-
Namera je da se u ovom poglavlju pokaZe nom zadatku. Napisite petlju for koja sabira odgovarajuie eremente
koriko jednostavno moze biti objektno pr,ra
orijentisano programiranj e atco'neko drugi prione dva objekta tipa vector i smesta rezultat u odg:ovarajuii element
,u poruo i J"n.ris" objekte. u treieg
tom sludaju rreba samo da ukrjudite altot"r., objekta. PrikaZite sva tri objekta tipa vector.
Saljete im poruke.Ako.su tipovi koje
,ul[;rj;, ;;;."vite objekte i vl 0. Defini5ite objekat tipa
koristite dovoljrio zuirr..i"tr.i i dobro pro- vector<float> i smestite u njega 25 brojeva kao u
jektovani, necere imati puno posla prethodnim zadacima. zatim izratunajte kvadrat r"uiog uro;a
i program ie biti funkcionalan. i rezurrat
Prilikom upotrebe bibriotedkih Lruru, u ovom dodelite istom erementu vekrora. prikaZite sadrZaj vekio.a
poglavlju su uvedeni neki od tre r posre
osnov'nih i korisnih tipova standardne mnoZenja.
c++ bibrioteke": po',oar.u urazno_izraznih
tokova (konkretno, onih z_a eitanje i upis
na konzolu i u aatotel-e), kiasa string i
Sablon vector. Vicrcli ste da sc jednostavno
primenjuju i sada verovatno mozete
zamisliti Sra sve pomoiu njih moZete
uraditi, ali one ,_u;r'i mnoge druge
mogui,osri.i' Iakl i1rno.,u p.od.tni- pogravljima
podskup moguinosti,ovih alatki, to je
t";ig" to.iriii ,u*o ograniden
ip"ak r"riu toiui-n;;.!j'; odnosu
menrarno udenje jezika niskog nivoa kakav je na ele_
c. Mada je ,?"";" niskog
nivoa jezika C korisno,.ono iziikuje puno ".p"tata
wemena. Na kraju, glawra surhaoop_a
je da prikrije detalje, rako da r.
.oz.t. baviti vaZnijim p.o6r"fii_u.
I)ez' o.tzira na apstraktnost oop-a, postoje
nezaobiLzni pojmovi c_a,
a njih iu obraditi u narednom poglavlju. "r""*i

VeZbe
Resenja izatrranih zadataka.tlalaze se
u elektronsk.m dokumentu Tlte Tltinking
()ttirlektli se' uz,alu nadoknadu, irt c++ Atlnotated. soLution
-"z"pi"i,r"ii'.i"kr.q" *.u.r."Ecker.com
r ' Izmenite Hello.cpp. tako da. ispisu;'e vaSe imei broj godina (,i broj cipela ili
srarosr vaieg psa, ako vam je to lak5e). prevedite
i ii"lii" p..og.u_.
2 Koristeii ideje programa Stream2.cpp_i Numconv.cpp
koji ueitava poruprednik kruga i izriaunava napi.ite program
MoZere upotrebiti operator * ia izracunaru";"
i ispis-'u]e fow.inu kruga.
tuui."i'u pltupr"e.rika. Ne
ispisujte wednost okrarno ili heksadecimatno
(ovi f;;;;;" koriste samo
z.a cele bro;'eve).
, koji orvara daroreku i u njoj prebrojava redi
IXil:f;jogram razdvojene
4 Napisite program koji
(koristite operaror .prebrojava pojavljivanja odredene redi
' u datoteci
== klase string da uiste p.epozn-ati;;;j.

Ako jedva tekate.a odmah vidire sve slo sc moze uciniri pomoiu
ovih i drugih komponenata bibrioteke,
tnttt'rtclttiiAr'krrirrrrrTt'rcr,;.,;,;,,; .;,i,;:..:iuuRrrrceEcker
l';illlli;1i",:]'-' com.(,(rno,r)(,mrurrirr
rl

:i:,
78 Misliti na jeziku C++ Poglavlje3: CuC++-u 79

Ako nikada niste videli C, ovo poglavlje ie vas upoznati sa osnovom C-a koja se Po5to prevodilac proverava iskijudivo tipove, imena nisu navedena zbog pre-
koristi u C++-r.r. t-l sludaju da znate jezik C koji su u prvom izdanju svoje knjige glednosti koda.
opisali Kernighan i Ritchie (desto se naziva K&R C), otkriiete neke nove i drugadije Imena su neophodna u definiciji funkcije po5to se argumenti koriste unutar
moguinosti C++-a, kao i standardnog C-a. Poznavaoci standardnog C-a, neka tunkcije:
letimice proeitaju ovo poglavlje i pronaii ie specifiine osobine C++-a. Ovde su int translate(float x, float y, float z) {
predstavljene neke osnovne osobine C++-a, koje su srodne sa osobinama C-a ili x=y=zi
se od njih malo razlikuju. Naprednije osobine C++-a naii iete tek u kasnijim
poglavljima. )
Ovo poglavljc omoguiava brz-i pregled struktura C-a i uvodi u neke osnovne
Izgleda da se ovo pravilo primenjuje samo u C-u. U C++-u argument ne mora
strukture C++-a. Pretpostavl,a se da ditaoci imaju izvesno iskustvo u radu s
biti imenovan u listi argumenata definicije funkcije. Po5ro nije imenovan, ne
nekim programskim jezikom. Postupniji uvod u C nudi multimedijski seminar
moZete ga koristiti u telu funkcije. Neimenovani argumenti omoguiuju pro-
na prateiem CD-u. Seminar ie vam pruZiti osno\,1r za udenje C++-a ili Jave i ne
grameru da ,,rezervi5e mesto u listi argumenata'. Osoba koja koristi funkciju,
pokuSava da od vas napravi strudnjaka zaC (jezici visokog nivoa kao Sto su C++
mora je pozvati sa ispra'rnim argumentima. Onaj ko piSe funkciju, ubuduie
ili Java koriste se upravo zato da bi se izbegle zadkoljice jezika C). Kompakt disk
moZe koristiti taj argument", bez izmene koda koji poziva funkciju. Argument u
sadrZi i veZbe i postupak reSavanja. Imajte na umu da ovo poglavlje prevazilaa
listi moZete ignorisati i ako ostavite njegovo ime, ali iete pri svakom prevodenju
sadrZaj CD-a, pa CD nije zamena nego priprema za ditanje ovog poglavlja i
jige.
funkcije dobijati upozoravajuiu poruku o wednosti koja se ne koristi. Upozo-
kn
renje se ne javlja kad uklonite ime.
C i C++ podrZavaju jo5 dva nadina deklarisanja liste argumenata. Ako je lista
Pravljenje funkcija argumenata prazna, u C++-u moZete deklarisati func$, Sto saop5tava prevodiocu
da argumenti ne postoje. Morate imati na umu da ovo oznadava praznu listu argu-
Ll starom C-u (pre standardiz.acije) mogli ste pozvati funkciju s bilo kojim
menata samo u C++-u. U C-u to znadi ,,neodredeni broj argumenata" (to je trik
brojem i tipom argumenata i prevodilac se ne bi Zalio. Sve je izgledalo ispravno
kojim se onemoguiava provera tipova u C-u). I u C-u i u C++-u deklaracija
do trenutka izvr5avanja programa. Dobijali ste dudne rezultate (ili, Sto je gore,
func(void); oznadava praznu listu argumenata. Rezervisana red void znadi ,,niSta"
program je otkazivao) bez ikakvih naznaka o razlogu. Nedostatak pomoii pri
(k6d pokazivada moZe znaditi i ,,nedefinisani tip", kao Sto iete videti kasnije u
prosledivanju argumenata i zagonetne gre5ke koje su se pojavljivale verovatno
ovom poglavlju).
su jedan od razloga Sto je C dobio nadimak ,,asemblerski jezik visokog nivoa'.
Postoji i drugi sludaj, kada ne znate unapred broj i tip argumenata. Takva lista
Programeri na nestandardnom C-u su se navikli na to.
se naziva promenljiua lista argumenata (engl. uariable argument list). Ova ,,neiz-
Standardni C i C++ podrZavaju pisanje prototipafunkcija(engl. function pro-
vesna lista argumenata" se oznadava pomoiu tri tadke (...). Definisanje funkcije
totyping). Prototipom funkcije morate opisati tipove argumenata pri dekla-
s promenljivom Iistom argumenata mnogo je komplikovanije od definisanja
risanju i definisanju funkcije. Ovaj opis je ,,prototip". Prilikom pozivanja obidne funkcije. Promenljivu listu argumenata moZete koristiti i kada (iz nekog
funkcije, prevodilac koristi prototip da bi proverio jesu Ii prosledeni argumenti
razloga) hoiete da spredite proveru tipova u prototipu funkcije. S obzirom na
ispravni i da li se pravilno upotrebljavaju rezultati. Ako programer pogre5i pri
ovo, trebalo bi da upotrebljavate promenljive liste argumenata samo u C-u i da
pozir,u fr.r nkci je, prevodilac uodava gre5ku.
ih izbegavate u C++-u (u kome, kao Sto iete videti, postoje mnogo bolja reSenja).
[)rototip fr.rnkcije (ali ne pod tim imenom) upoznali ste u prethodnom
Uputstvo za koriSienje promenljivih lista argumenata pronaii iete u odeljku o
poglavlju, poSto deklaracija funkcije u C++-u zahteva pisanje isprarmog pro-
bibliotekama bilo kog prirudnika za C.
totipa. Lista argumenata u prototipu funkcije sadrZi tipove argumenata koji se
moraju proslediti funkciji i (opciono pri deklarisanju) nazive argumenata,
Redosled i tip argumenata moraju se slagati u deklaraciji, definiciji i pozivu Rezultati funkcija
funkcije. Ovo je primer prototipa funkcije u deklaraciji: Prototip funkcije u C++-u mora definisati tip rezultata funkcije (ako u C-u
int translate(f1oat x, float y, float z); izostavite tip rezultata, podrazumeva se int). Definicija tipa rezultata nalazi se
ispred imena funkcije. Da biste definisali da nema rezultata, koristite rezervisanu
Promenljive u prototipima funkcija ne mogu se definisati na uobidajen
red void. Ako iz takve funkcije poku5ate da watite wednost, nastaje gre5ka.
naiin. Znadi, ne moZete napisati: float x, y, z. Morate definisati tip suakog argt-
Navedeno je nekoliko potpunih prototipova funkcija:
menta. Sledeii oblik je takode prihvatljiv kao deklaracija funkcije:
int translate(float, float, float) ;
80
Misliti na jeziku C++ Poglavlje3:CuC++-u
8r
tnt f1(void); // yraea ceo broj, nema
argumenata
,.:r tr(-)_;. // rao f10 ;n C++-u, ati standardne biblioteke. Ako morate
float f3(fioat, int, char, double); n.-t'r'rturdardnom C_u! da uradite ne.to Sto je specifiino
kome radite, ni!{ar3e da izorujete za sistem na
voi d f4 (voi d) ; 11 Vraea broj tipa float tay toa na yea,o ,,,".io,"r'uto
// Nema argumenata, nema rezul tata promeniti pri preno.enju na drugi da ga rako moZete

jl:,lJJi:"1:l;;lj,],iJ":.*sr, odredeni sistem, desto kapsuliranJ


sistem. Li c**-u ,, utti*orti, speci'dne za
korisrire naredbu return. ra naredba u klasu, Sto je idealno re5enie.

: :j : ffi y'
q ".",,i;. ; ;' il'
zawsava
#iff :i.TrH;
Formura za upotrebu bibliotedke
fr"k.,l.l; ri;;;;;il
ffi ;u;;;' "il#;:".l,ff;
:1i,'.i,,1 :l l.]l} ;,":. I'51....: : :, " : ?: u referentnom prirudniku (mnogi ;."nadite [unkciju
priruinici imajuindeks funkcija po
referentni
i::;i X: :o j. o,:i "::s':
p
;::::i,,:: i r s a n o g, i p" ".,i.
:I I .", ii,
;,;:,ili:,,,:i,:.:ll1?"
vrSe nareclaba return: "
i

"i"
; ;.il # ;; :,,:; : ";#tiil kategorijama, kao i po abecedi).ireb;r,r;i;;;;;,ii;i*Illirzi
zuje sintaksu koda. Na podetku aeo koji prika_
naredbom #incrude,koji pokazuje
ouo* d"ru ,"'obid;;";Jiu". jedan red sa
/ / : C03: Return. cpp u t'olo,.leaato;;;;;i;;f; prototip
Kopirajte red s naredb-om *inctuie, tunkcije.
// Upotreba naredbe neturn t"tb i'" tu"k.ij;'br;" iriiu*o dekrarisana.
nclude <i ostream>
#'i sada moZete pozvati funkciju .ru .ruri., ,

opisan u delu o ,rrra'u-tri. Ako pogresite,


using namespace std; prevodilac ie to otkiti ie uporLditi ous porir-n,.,t .ije s prototipom
tako sto
funkcije u datoteci zag.lavlia i p.l;uJi"
gresku. poa.ur,r-"uu se da povezivad
char cfunc (j nt i ) { biblioteku,'pa samo ukrjudite a",",.r,
jf(i == 0) fl1"Ji::?;,j:"ndardnu zaglaviiai poro_
return 'a ,
;
jf(i =_ t)
netu rn ,g , pomoiu prosram a za upravljanje
if(r == 5)
return 'z'
;
f ffiffijibtioteka
.
Svoje funkcije moZete smestiti
return ,c , ; u bibiioteku. uz veiinu paketa za programiranje
isporuduje se program za rad s bibriotekama,.koyi
i modula' svaki program za.upravrjanje upravla ,triorr-u objektnih
bibriotekarir" il;;;il#i skup komandi,
ali je postupak izrade bibriotet"'.rgiu*orn
int majn0 { koja sadrZi prototipe svih tunkcija
sledeii: zagravlja
cout << ,,unesj te ceo broj : ,,;
""pi"ii.'a",oteku
biblioi"t.. snimiteJitot"tu )ug"rr;u u puranji
koju pretprocesor pretraZuje, iliu
int val; pomoiu #include,d.atotekazaglavlja,,)
tekueem direktorijumu (tako da se
moZe naii
cin >> val; ili u direktorijumu include (tako da se
moZe naii pomoiu #include.iatoiekuzaglavljo).
cout << cfunc (vai ) .< endl Z"ii_ r*
l. l//'- ; prosledite programu za rad
s bibliotekama , zajednoru r-".ro* "U;ektne
programa za rad s bibliotekama
module
uiblioteke (veiina
zahtevaju isto ime ,tp;,
Prva naredba if diii usrov ima
vrednost novu bibrioteku zajedno ;"p* ;ib ili .a). Snimite
sa ostalim bib-liotekama, u ';"j;'pou.riure
cfunc, narecibom return. obrarite paznp true dovodi do izlaska iz funkcije pronaii. Kada koristite svoju biblioteku, mogao
na to da nije neophodna dekraracija na komandnoj riniji povezivada
iunkcije, posro se o.n:l:,1i
main0. prevodilac, na osnovu deliniciye p," flJi;j;;;F,i;"
lrr_,fiJ;", zna daona postoji.
tunkciji n;"n.;;;;;", da zadate da i u_ toj biblioteci t."tul"
priruiniku prevodioca, posto se razliku;u
moraiete
tazi funkcije. sve detalye potraiite u
oa;.ar"S a; ;*g;g;;;"_".
Kori5ienje biblioteke C funkciia Up ravlja nje izv rSava nj e m
S'e frrrkt ijc i'iric r'karnc^bibriorekc c r,,"t.ii]",
gramirare u c++-u. Dobro pregledajte uur rasporaganju dok pro- ovaj odeljak obraduje upravljadie iskaze
bibrioku ru da b_iste mogli da ditate ipi5eie p.";;;;;
u c++-u. ove iskaze morare poznavari
svoju hrnkciju, zaro Sto je nekJ pre nego sto definisete
'unkcija
rnnZau ,J'i".'rlo vas na jezicima C i C++.
Ipak rnoramo rra vas.trpozorimo: problem. U jeziku C++ koliste,se s"i C-
o"i"up.avryafU lrturi. fo ,._,, if_else,
mnogi prevodioci obuhvaraju vetiki -while, for i iskaz zaizbor switch. while, do_
dodat.ih l-rr,kcija krrjc olaksavaj,, c'** aoruor;auu i;;p;.,r"'..i iskaz goro,
standardne (' bibrioteke. nko
il"o; ;';".;50" o, ih upotrebire, ali nisu broj koji iemo izbegavati u ovoj knjizi.
ste sigurni a" deo
drugi sisrem (a ko rnoze biri sigu;;.?),';;;^;"p.ed ne-iete prenositi program na
"it"a" _ koristite oul tuntcile
olakiajtc sebi posao. Kad pravite i
[."noriu prog".am, trebaro bi da se Jrzite runtcila

I
82
Misliti na jeziku C++ Poglavlje3: CuC++-u
83
Tadno i netacno
t,slovni iskazi odrecrrrju ita COut << "5 < i < 10', << endl
ie biti izvrseno
na osnovu tadnosti ili netainosti el se
;
uslor.nih izraza, primer Lrslor.,nog
irrur.u'j"""i'l=8,. Izraz koristi uslormi cout << "i <= 5u << endl;
rla bi cia Ii je promenrjiva a operator __
'rr"'rcrio ;"inuta p.omenrjivoj B. Izrazdaje logidko else // (i < tO)
:lT :i}::l i,u *o CoUt <<
>< >= it
JX"ll"';' ffi f T.?,
cr irs r ovn i ka z i u
I :U::lf:an e ree u c** -,,"' pos to i",
*
"i >= 19" << endl;
i s s .r
","u.ii"."r,."l;:,Hi: ;.'f#*"ruiliT,o.i _.
Po konvenciji, telo iskaza zakontrolu toka r pise se uvudeno, da bi
lskaz if-else
ditarac rako
"a.i,ai" ea"
p".i"j; i;;;;;;*:prorsrama
Postoie dva oblika iskaza if_else:
sa i bez else. Ova dva oblika
if(izraz)
su: lskaz while
Iskazi while, do-while i for upravljaju
i skaz petliama. U petljama se neki
ponavlja sve dok je kontrotni urtou iskaz
i
rui6uoi""l'ouril petlje while je
while(izraz)
if(tzraz) i skaz
iskaz
el se Izraz se izradunava jednom na podetku
ponavljanja iskaza.
petlje i ponovo pre svakog sledeieg
i skaz
vrednost izrazamoie bititrue (tadno) petrjewhile sve dok ne pogodite
van' s radkom i zarezom na
ili false (netaeno).Iskaz je ili jednosta_ t,t flixHl,',li1?:'.T11.:i":: tajansfveni broj
kraju ,i slozen - r;"p jednostavnih
vitiiastih zagrada. Svaki pur kada iskaza izmedu //: C03:Guess.cpp
se k;;ir;;t"l,,,in ,,iskaz,,,podrazumeva
iri'roz"n'i"i"'*'''.i- takode se da // Pogadjanje broja (prikazuje petlju while)
:,'I:: ffi::;1';:,L:';T;l# -tz" u-i,in"rse, tako #include <iostream>
usjng namespace std;
l/: C03:tfthen.cpp
// Prikaz uslovnih iskaza if i if_else int main0 {
#inc'lude <iostream> int secret = 15;
using namespace std; int guess = Q;
jnt main0 // ,'l=,, je usl ovni operator ,,razl i di to od,,:
whi)e(guess != secret)
1nt i;
{
{ 7/ SfoZeni ist<az
cout << ,,pogadjajte broj: ,,;
cout << "unesite broj i pritisnite ,Enter,,, cin >> guess;
<< endl;
cin >> j; )
jf (j > 5)
cout << ,'Broj je vecj od 5,, .. . !9rt .. ',pogodi I i stel,, << endl ;
- end,]; l I //,-
else
if(i < 5) Uslowri izraz petrie while ne mora
da bude jednostavno poredenje kao
navedenom primeru' nego moze
_cout
<< "Broj je manji od ,,<<
5 biti proizvotlno sroZen, ari njegova wednostu
else
endl.
#ii
iri fatse. susresiete ,.
#.:;Te
i;;;lj;u
ro;" .,emalui"io] ,i"go ,u_o
cout << "Broj je jednak 5 ,, <<
endl;
while(/* sloZeni tzraz *f)
cout << "unesite broj i pritjsnite,Enter,,,.. ;
cin >> i; endl;
jf(j < 10) programer pi5e usto,.rni izraz
koji poredi wednosti,
if(i > 5) // "if" je
."oy,"r""XYili'rXtu]"'i*,, a.li
samo drugi iskaz

Obrarite pazniu na ro da se sve konvenciie


srirovimarormatir""i"l;;,,;;; lr dori,k, slaZu da je potrebno u n r.rzrir.rrir,
a ic op,\a,) .rir ,,,.,,, ill?l:ll:::,1?:,ii,1,1,:1,.,1,..,,
84
Misiiti na jeziku C++
Poglavlje3:CuC++-u
85
I
lskaz do-while
Oblik perlje do-while je int main0 {
for(int i = O; i < 128; i = i + t)
do 'if (i != 26)
i skaz // ,erisanje saOrZaja ekrana ANSI Terminala
cOut << " vrednost: ,, <<
while(izraz); i
<< ', znak. ,,

Petlja do-wh,e se razrikuje od iskaza wh,e <. char(i) //


po tome sro se uvek izvrsava naj- Konverz.ija tipa
manje jednom, eak i ako je vrednost izraza << endl.
netidna kada ,. t; ;;;;rraduna. u
petlji while, iskaz se nikada ne izwsava
ako je irr", il"i"J", pri p.uom l ///,-
izratunavanju.
Ako se petlja do-whire koristi u programu
Guess.cpp, promenljivoi guess se
, Obratrte paZnju ,1 l? d1..9 promenljiva i definiSe na mesru na kome se
Ko'srr' umesto na oodetku
ne mora dodeljivati besmisrena poe"t* vrednosr, btota oznaeenof orvorenom vitiiastom
posio se dita iz toka cin pre ovo je drugadiie ;-i;;i;ii;ffi;:leduralnim lagradom.
ispitivanja. c)' koji zahtevaiu ";*"
daire promenlive buai aJnrsane
jezicima (ukrjuiuluii i
//: C03:Guess2.cpp ie biti redi kasni.le u ovom poglavlju. na podetku bloka. o tome
// Progran za pogadanje broja, koji korist.i petlju do_whi1e
#i nc l ude <i ostream>
usi ng namespace std; Rezervisane reai break i continue
IzwSavanjem perlji while,
ao-*t it" i ir;;; se upravtjari i
int main0 { sanih redi break i continue. pomoiu rezervi_
Ird;.""k';;;,
int secret = l5;
int guess; // Ovde nije potrebna inlcijalizacija ;'};affi?,i;,,:l,J:ilr*i],ff:1;ffi f.H:tlTxt?";".iilT:::il:::::x,:
do { break i continue je jednostavan
cout << ,,pogadja;te sistem menija prikazan u
broj: ,,; ,.offi,'u sredeiem
cin >> guess; // Ovo je inicijalizacija
.) while(guess //: C03:Menu.cpp
!= secret);
cout << "Uspel i stel,, << endl; // Jednostavan program za rad s menijima
) //l ,- // koii prikazuje upotrebu redi break i continue
#i ncl ude <i ostream>

il nr-kgs razroga, veiina programera izbegava petrje do-wh,e i koristi samo


petlje while.
using namespace std;

int mainfl (
char c; // Sadrii
lskaz for while(true) {
odgovor
r"t inicijaliz,je promenrjivu pre prvog ciklusa. Zatim cout << "GLAVNI MENI: " << endl.
,ft.lit
krajr.r svakog ciklusa,
ispituje uslove i, na
izvriava .eki obtik ,,tniot OUfit petf;eior;l: cout << ',,l: levi, d: desni,
o,,.
cin >>
k: kraj _> ,,.
for(inicijal izacija; uslov; korak) 6;
iskaz if(c == ,9,,;
,,while(true),,
svaki izraz: itticijarizrtcija., usrou i korakmoZe . -break; // Izlaz iz
biti prazan. K6d za inicijaliza_ if(c == 'l') {
cr7, se izw.ava jednom, ra samom podetku.
urlor r"irfrtu;";;;;k;g cikrusa CoUt <<'LEVI MENI:,,<< endl.
f).:1.;::Tn
na poderku, iskaz se nikaau ne irwsarat.
I,r, i.i,,"Jrscikrusa, cout << ,,i
zaberi te a .i .l i b : i
;
cin >> c;
Petlje for se iesto koriste za nabrajanje: if(c == 'u'; 1

//: C03: Charl j st. cpp COut << "jzabral i Ste ,a,, <<
endl
// Prikazuje sve ASCII continue; // Povratak ,a glarni ;
znakove , ,eni
I / Priner za
,,f I
or,,
#i ncl ude <i ostream> if(c == '5'; 1

usi ng namespace std; cout << " i zabral i ste ,b, ,, <<
endl ;
continue; // Povratak na gtavni
,l meni
Misliti na jeziku C++ Poglavlje3: CuC++-u
87

Sele_ktor je izrazkoji ima integralnu wednost (ceo broj,


else { znak ili iogidku wed_
cout << "ni ste i zabral i ni a ni bl" nost). Iskaz switch uporeduje rezultat selektora i svake integralne
uridnosti. Ako
.. endl ;
pronade istu wednost, tada se izwsava odgovarajuii isiaz (jednostavan
ili
Povratak na gl avni i sloZen). Ako ni jedna wednost ne odgovara seiektoru, izwsava
cont i nue; // men
,. irku, oznaden
)
kao default.
Tapaziaete da se u gornjoj definiciji svaka oznaka case zawsava
) iskazom
if (c == 'd ) { break, kojiizaziva skok na kraj tela iskaza switch (zatvorenu vitiiastu
zagradu
cout << "DESNI t'4ENI : " << endl ; koja zaw5ava switch). ovo je uobidajeni nadin pisanja iskaza switch,
ali break
cout << "izaberite e i1i f: "; nije obavezan. Ako se izostavi, posle izwsavanja
leanog bloka izwsava se i
cin >> c; naredni. To znadi da se k6d koji sledi iza iskaza case izwsava sve dok
se naide na
if(c == e') { break. Iako je izvrsavanje narednih blokova najdelie nepozeljno, moze
cout << " i zabral i ste 'e' " << endl ; biti
korisno iskusnom programeru.
continue; // Povratak na glavni meni
) vi5e izwsnih putanja), ali se zahteva da selektor ima integralnu
if (c == f ) wednost u weme
{ prevodenja. objekte tipa string ne mozete koristiti lao seiektore u iskazu
cout << " i zabral i ste 'f "' << endl ; switch. Da biste napravili visestruki izbor sa objektima tipa string, morare
conti nue; // Povratak na g1 avni meni stiti niz iskaza if i porediti znako,rne nizove u uslormom iirazu.
kori_
)
Primer menija je veoma dobar za prikaz iskaza switch:
else (

cout << "ni ste i zabra'l i ni e ni f !" //: C03:Menu2.cpp


'< endl ; /l Meni koristi iskaz switch
continue; // Povratak na glavni meni #include <iostream>
)
using namespace std;

I jli d ili kl"


)
<< endl; int main0
cout << "morate uneti {

)
bool quit = false; // Indikator za kraj
cout << "izlazak iz menija'''" << endl; whi 1 e(qui t == fal se) {

\ I I l,- cout << "Izaberite a, b, c ili k za kraj: ,,;


char response;
Akokorisnikizabere.k,izglavnogmeni|a,zbogrezervisaneredibreakizlazi
koristi cin >>
od podmenija' response;
se iz petlie, inaie se petfia poriavlja Fosle izbora iisvakog tch (response)
continul za skok na po'etak petlie while' sw1 {
.. ,.r.r.riruna red
zauvek ovu petliu"' Iskaz case 'a' : cout << i'izabrali ste 'a"' << endl;
Iskaz while(true) ie lkri,alentat' t'ulog' "izwsavaj
izw.avanje petlje kada korisnik break;
break omoguiava da ;;;d"i; b"sto.,Jeno case 'b' : cout << ,,izabrali ste ,b,,, << endl;
unese'k'. break;
case 'c ' : cout << ,,i
zabral i ste ,c , ,, << end.l ;
break;
lskaz switch case 'k' : cout << ,,kraj rada,, << endl;
na osnovu wednosti integralnog
Iskaz switch bira deo koda koji se izwSava quit = true;
izraza. N jegov oblik je:
break;
swi tch (sel ektor) { default : cout << ,,Unesite a,b,c iI i kl,,
case i ntegral na-vrednostl : i skaz; break; << endl ;
case i ntegral na-vrednost2 : i skaz; break; ]
case integralna-vrednost3 : i skaz; break; )
case integralna-vrednost4 : i skaz; break; | / //,-
case i ntegral na-vrednost5 : i skaz; break;
Indikator quit je tipa bool (skraienica od Boolean, logidki), a ovaj
(...) tip je uveden
u c++-u. MoZe imati iskljudivo vrednosti true ili false. KIda
default: iskaz; se izabe.e^,(, , indika_
toru quit se dodeljuje wednost true. pri sledeiem izradunavan;'tr wednosti
) selek-
lora, izrarz. quit =- false ima rrerJrost farse i tr'rrr rr.trj. *.rrire s, rrr. irr,.(,,, .,
88 Misliti na jeziku C++ Poglavlje3: CuC++-u
89

Upotreba i zloupotreba rezervisane reci goto ,} else


Rezervisana red goto je podrzana u c++-u, poSto postoji i u c-u. Upotreba te redi cout << ''v00Ml ! ! ,, << endl ;
se desto odbacuje kao znak loSeg stila programiranja, Sto najdesie i jeste. Svaki )
put kada upotrebite iskaz goto, pogledajte k6d i proverite da li postoji drugi
nadin da ga napi5ete. U retkim prilikama mozete otkriti da samo goto resava int main0 {
problem, ali ga ipak paZljivo razmotrite. Evo jednog primera: removeHat(,A,);

//: C03: gotoKeyword. cpp | ///,-


// Nepopularni goto je podrian u C++-u sve dok je cat manje gd'2" funkcija removeHat0 poziva samu sebe,Sto pred-
#i ncl ude <i ostream> stavlja rekurziju. pri svakom pozivu iunkcije removeHatg,
nyen argument je za
us i ng namespace std; jedan veii od tekuie wednosti cat, tako
da argument raste.
Rekurzija se desto koristi prilikom resavanl-a nekih
wsta probrema nepoznate
int main0 { sloZenosri, posro niste ogranideni na odredenu
,,veridinJl i"s;;j; - rekurzija se
'I
ong va1 = 0; nastavlja sve dok se ne dode do re5enja.
for(int i = 1; i < 1000; i++) i
for(int i = 1; j.100; j += 10) {
val = j " i; Uvod u operatore
i f(val > 47000) operatore mozete smatrati posebnim tipom funkcije (videiete
goto bottom; da se operatori
preklapaju u c++-u upllyo tako). operator ima jedan
I I Break bj i zaSao u spol j ni ,for, zvodi novu wednost. o.blik
iii uis" urgr-enata i proi_
argumenata razlikute se od uobida-
) ^prosredivanja
jenih poziva funkcija, ali je efekat isti.
)
Trebaro bi da se, na osnovu prethodnog programerskog
bottom: ll 1znaka iskuswa, sasvim
dobro snalazite s dosad kori5denim operatJrimalsabiranje'1+),
cout << val <. endl; oduzimanje i
unarni minus (-), mnoZenje (-), deljenje (/) i-dodeljivanye
\ Iil,- u svim programskim jezicima. Kompretan skup oieratlra
1=j lmalu isto znadenje
Alternativa bi bila definisanje logidke promenljive koja bi se ispitivala biie naveden kasnije
u u ovom poglavlju.
spoljnoj petlji for, a iskaz break bi se izvrsavao u unutrasnjoj petlji for. Medutim,
moZe biti nezgodno ako imate nekoliko nivoa ugnezdenih petlji for ili while.
Prioritet
Prioritet operatora definise redosred izratunavanj a izraza kada postoji vise
Reku rziJa razliditih operatora. c i c++ imaju specifidna praviia
Rekurzija je zanimljiva i ponekad korisna tehnika programiranja kojom funkcija ,u od."Jiuunje redosleda
izradunavanja- Najjednosravnjie
poziva samu sebe. Naravno, ako je to sve sto radite, funkcija ie pozivati samu ie zapamriti ai t" *"o2"";" i a"rl"";" obavrjaju
pre,sabiranja i oduzimanja. Ako izraz nije vama jasan,
sebe sve dok se ne zauzme sva raspoloZiva memorija, tako da mora postojati tada verovatno neie biti
ni drugima koji budu ditali k6d, pu po*biu zagiadaizridito
nadin okondavanja rekurzivnih poziva. u sledeiem primeru, rekurzirma funkcija naznadite redosled
izradunavanja. Na primer:
se izw5ava sve dok cat ne postan e ve(e ad'Z'.2
A=X+Y-2/Z+Zi
I / : C03:CatslnHats.cpp
ima potpuno razlidito znadenje odizrazau kome je
// Jednostavni prjmer rekurzije
zagrada:
izwseno grupisanje pomoiu
# ude <i ost ream>
i nc'l
usi ng namespace std; A=X + (y _ z)/(z + 7);
(Poku5ajte da izraeunate rezultat za X
= l, y 2 i Z = 3.)
_
voi d removeHat (char cat ) {
for(char c = 'A'; c < cat; c++)
cout << " "; Uveianje i umanjenje
if(cat <= 'Z') { c' pa samim tim i C++, pun je skracenica. skraienice mogu
cout << "cat " << cat << endl; oraksati pisanje pro-
a ponekad ga eine neditljivim. MoZda su aurori
removeHat(cat + 1); // Rekurzivni poziv Fr.ama, ;."riu E -irrili da ie biti
lakie razumeti zamrSeni deo koda ako zauzima manii piostor.
Misliti na jeziku C++ Poglavlje3: CuC++-u 9t
10
-ret"*----
Oni Medutim, ako radunar, na primer, koristi binarno kodiran decimalni sistem
su operatori za uveianie i umanjenje'
Medu najkorisnijim skraienicama (BCD) za predstavljanje brojeva, tada ie za smestaj najveiih wednosri
wednosti broiadkih-promenljivih' tipova
se desto koriste, p.tr1u*u-'"u ;;;;""Y podataka biti neophodna razlidita velidina prostora. Najmanje i najveie wed-
zaiedan"' operator za'uveianie
operatoruu u-unitnlJ lt'I-1-i 'nuei "umanli nosti koje se mogu smestiti u razlidite tipove podataka def,niiane su u sistem-
Nu p'i*"t ato.ie Atipa int'izraz ++A ie ekviva-
ie'++' i znaii ,,uvciai '";;i;t' za uveianie i umanjenie
je vrednost skim- datotekama zaglavlja limits.h i float.h (u c++-u iete umesto toga pisati
lentan izraz-u (A = A + I ) Rezultat operatora prvo se
(ti' ++A)' #include <climits> i <cfloab).
re promenliive. Ako oi"iuto' nalazi ispred promenljive
" promenrjivoi. Kada je operator c i c++ imaju detiri osnovna ugradena tipa podataka, a ovde se navodi njihov
izwsava operacija, o ,u,iilr. Jnderjuje *"dnort
opera- opis za radunare zasnovane na binarnom sistemu. Tip char sluzi za smestaj zna-
iza promenliiue tti' an*l' pt'" tt aoa"liuie vrednost' a zatim se izw5ava
kova i koristi najmanje B bitova (jedan bajt), mada moZe biti i Siri. Tip int sadrZi
cija. Na Primer: ceo broj i koristi najmanje dva bajta. Tipovi float i double sadrze bro.ieve u for-
matu pokretnogzareza, najdesie u IEEE zapisu. Tip float sluZi za brojeve jedno-
//: C03:Autolncrement'cPP
operatora struke preciznosti, a double za brojeve dvostuke preciznosti.
// Prikazuje uPotrebu
i
// za uveeanje umanienie' Kao Sto je ranije napomenuto, promenljive moZete definisati bilo gde u pro-
<i
#i ncl ude ostream> gramu i mozete ih istowemeno definisati i inicijalizovati. Sledi prinier defini-
using namesPace std; sanja promenljivih kori5ienjem detiri osnovna tipa podataka:

int main0 { //: C03:Basic.cpp


/ I Upotreba deti ri osnovna
int i = 0; // tipa podataka u C-u i C++-u
int i = 0;
Cout << ++i " endl; // Prefi ksno uvecanje
Sufi ksno uvecanje int main0
cout << .1++ << endl'// {

cout << --i .. endl; // Prefi ksno umanjenie // Definjcija bez inicijal izacije:
char protein;
cout << j-- " endl; // Sufi ksno umanienje
int carbohydrates;
korak float fiber;
", sada ga razumete. Ono znadi "jedan
Ako vam niie bilo jasno ime "C++ double fat;
yiSe od (l-a". // Istovremeno definisanje i inicijal izovanje:
char pizza = 'A', pop = 'Z';
int dongdings = 100, tw.inkles = 150,
u tiPove Podataka
Uvod'lilxtt'i koristi smestajni pro-
heehos = 200;
Ttrtdat0l-a
tla koii se r'r programima
tlt'finiirr traiitl float chocolate = 3.14159;
prevodiocu kako da
sl()r (lll('lll()l-iiar' I)ctirrisartiettl ti1'ra 1''odataka saopstartate // Eksponencijal na notacija:
da uprarlja n)inte.
tt.l1lt..tri \()IlIn.II]i (l(\(l }.rr(]sJ(]r.l i kako double fudge_ripple = 6e-4;
rip podaraka je
I.ipor.i ptrrlrrrr,i., ,rr.ig., lriri rrgr-irtlc,ni ili apstraktni. Ugradeni ) / l/ ,-
podataka-su skoro identi-
neposreclno po\/ezan s prevodioLem. Ugradeni tipovi Prvi deo programa defini5e promenljive detiri osnorma tipa, bez inicijaliza-
je tip podataka koji deflnisete ili neki
dni u (.-tr i (.++-tr' Nur,ip.n, ovome, klasa cije. Ako ne inicijalizujete promenljiru, njen sadrzaj je, prema srandardu,
podataka poznati kao apstraktni. eim aktivirate
drugi programer. ovi tipovi su
nedefinisan (ovo uglarmom znadi da sadrZi smeie). Drugi deoprograma istowe-
prevodilac, on zna tato aa iukuje ugradenim tipovima, a iz datotekazaglavlja meno defini5e i inicijalizuje promenljive (najbolje je, ako je-mo uie, dodeliti
i<oje sadrTe deklaraciie klasa ,,uai,, kako da rukuje apstraktnim
tipovima (to
podetnu wednost u trenu&u definisanja). zapazite upotre6u ek$onencijalne
opistrienro tt tlarednim poglavljima)' notacije u konstanti 6e-4, Sto zna(i,,6 puta l0 na -4,,.

Osnovni ugradeni tiPovi Tip bool, vrednosti true i false


StandardnaspecifikaciiaugradenihtipovajezikaC'tgiunasledujeC++'nepre- Pre nego Sto je tip bool postao deo standarnog c++-a, koristile su se razliiite
toga, odredene su
cizira koliko bito'a mora sldr2ati svaki ugradeni tip. Umesto nike rada s logidkim wednostima. To je izazvio problem prenosivosri i greske.
teh-
da podrZi. Ako
najmanje i najr,eie r.rednosti koje ugradeni tip mora biti ustanju
jera-unarzasno\,annabinarnomsistemu,najveCawednostsemoZenepo-
srecinoprer,estiLlnlininla]nibrojbitol'aneophodanzasmeStajtewednosti'
92
f
Misliti na jeziku C++ Poglavlje3:CuC++-u
93
l'ip bool srandardnog O++_a moZe imati dva stanja izraZena
ugradenim kon-
stantama true (konverluje se u celobrojnu nulu) i
false (konveriuje se u celo_ //: C03:Specify.cpp
brojnu jedinicrr). Sva rri imena su rezervisane redi. Osim
tog1a, usvojeni su jo5
// Prikazuje upotrebu specifikatora
neki elemenri jezika: #include <iostream>
using namespace std;
Element Upotreba s tipom boot int main0 {
&&llt Argumenti i rezultati su tipa bool char c;
\-
--
l-
Rezultati su tipa bool. unsigned char cu;
in, for, while, do Uslovni izrazi se konvertuju u vrednosti tipa bool.
int i;
unsigned int iu;
Prvi operand se konvertuje u vrednost tip" b"ol. short .i nt i s;
short iis; // tsto kao short int
Posto veliki broj posrojeiih programa koristi indikatore unsi gned short i nt i su;
tipa int, prevodilac
posredno konvertuje wednosri tipa int u tip bool (wednosti unsigned short iisu;
razlidiie od nule
daju true, a nula daje false). prevodilac ie vas u idealnom long int i1;
sludaju ufozoriti na tu
konverziju i predloZiti da sami izmenite uslov. long ii1; // tsto kao long int
Iedna od losih tehnika programiranja jeste upotreba ++ da bi
se indikatoru
unsigned long int i1u;
dodelila wednosr true. ovo je dozvorjeno, ari se ne podriaua,
sto znadi da ie u
unsigned long iilu;
nekoj buduioj verziji biti onemogrJeno. problem je float f;
u tome sto se wednost double d;
posredno konvertuje iz boor u int, uveiava
se wednost (mozda i izvan 1 ong doubl e d;
dozvoljenog skupa nule i jedinice za tip bool), a zatim 1
se posredno konvertuje u cout
suprotnom smeru.
<< "\n char=,,.< sizeof(c)
Pokazivadi (biie uvedeni kasnije u ovom poglavlju)
takode se automatski << "\n unsigned char = ,, <<
pretvaraju u tip bool, po potrebi. sizeof(cu)
<< "\n int =,,<< sizeof(i)
<< "\n unsigned int = ,, <<
sizeof(iu)
Specifikatori <<,,\n short =,,<< sizeof(is)
<< "\n unsigned short ,, <<
specifikatori menjaju znadenja osnormih ugradenih tipova = sizeof(isu)
njihov skup wednosti. posroje detiri specifikatora: Iong,'short,
i zna(ajno prosirujul << "\n long = " << sizeof(il)
signei i unsigned. << "\n unsigned )ong =,'<<
Specifikatori long i sho,rt-menjaju opseg najveie i najmanje sizeof(ilu)
riednosri koje tip << ',\n f I oat = ,, << si zeof (f
podatka moZe sadrzari. obiini tlp int mor*a biii )
velidine bar kao short. Redosled
velitina za celobroine tipove je: short int, int, rong int.
Sve or" u"iiti.r"
'< "\n double = ' << sizeof(d)
<< "\n long double =,'<<
biti iste, samo ako ispunjavaiu uslove najmanje/najveie wednosti. -og, << endl;
sizeof(ld)
Na 6a-bit-
nom radunaru, svi tipovi podataka mogu biti 64_bitni.
) ///,-
Redosled veliiina za brojeve u formatu pokretnog
zarezaje: float, doubre i Imajte na umu da ie se. rezurtati koje
long double. Tip ,,long.floar" ne postoji. trii specifikator dobijate izw.avanjem ovog programa
short se ne koristi s razlikovati od jednog
brojevima u formatu pokretnog ,ui"ru.' .ueunuru, oierativnog sistema i prevodioca.
Specifikatori signed i unsigned ukazuju prevodiocu kako .to j" uec.redeno, jedino
lo,,9luro,
se mora dosredno sprovesti da svaki
da koristi bit za f19
naj-manje i najvede wednosti definisane rip obuhvata
znak sa celobrojnim i znakov,nim.tipom stanaa.Oom.
itrojevi u formatu poketnog zareza Kada izmenite tip int specifikatorom
uve.k sadrZe znak). Tip oznaden kao unsigned
ne sadrZi r.,ut, tuto da ima short ,i long, rezervisana red int nije
dodatni bit na raspolaganju i moze sadrzai dvostruko obavezna, kao Sto je pokazano u primeru.-----'
vece pozitivne brojeve
odgovarajuieg tipa sa specifikatorom signed. Specifikator
.igrr"J-se pod.a-
zumeva za sve ripove sem tipa char. Kada definisete
tip signed Ihar, namece se Uvod u pokazivade
upotreba bita za znak. Svaki put kada izvrSavate
sledeii primer prikazuje velidinu tipova podataka u bajtovima. prlqrtn,on se najpre uditava (uglavnom sa diska)
Koristi memoriju radunara' To znadi da se svi u
operator sizeof, koji se uvodi kasnije u ovom poglavlju: se eteiienti p.og*ilu nurur"..n"go" u
organizovana u vidu niza uzastopnih
::T.:il Y"-?Iiju.;:bajtoui
nazrvamo osmobitni (engr. byte)- Srvarna veriiina
tokacija koje obidno
.""k" .;r;i,;le c,erine
Misliti na jeziku C++ Poglavlje3: CuC++-u
95

zavisi od arhitekture radunara i obiino se naziva ueliiina reii (engl. word size). Izraz (long) je konuerzija tipa (engl. casr). Na taj nadin se kaZe:
,,Sa elemen_
Svaka smejtajna celina razlikuje se od ostalih po svojoj adresi(engl. address). tom treba raditi kao da je tipa long". Konverzija nijeneophodna, ali bi se bez
nje
Zbog jednosta\mosti, pretpostavimo da svi radunari koriste bajtove sa uzasto- adrese ispisivale heksadecimalno, tako da ih konverzija L Iong dini
ditljivijima.
pnim adresama koje podinju od nule i rastu do vrednosti velidine memorije Rezultati ovog programa ce zavisiti od vaseg radunara, opJrativnog sistema
i
raeunara. raznih drugih dinilaca, ali ie vam uvek dati neke zanimijive podatke. posle
Posto se program nalazi u memoriji tokom izvrsavanja, svaki element pro- izwSavanja na mom radunaru, dobio sam sledeie rezultate:
grama ima adresu. Podnimo od jednostar,nog programa: f0: a198736
doq: 4323632
ll: C03:YourPetsl.cPP cat: 4323636
#i ncl ude <i ostream>
usi ng namespace std; bi rd: 4323640
fish:4323644
i nt dog, cat, bi rd, fi sh; i: 6684160
j: 6684156
void f(int pet) k:6684152
{
cout << "identifikacion'i broi ljubimca' "" pet << endl; vidite da su promenljive definisane unutar funkcije mainO i one deflnisane
) izvan te funkcije u razliditim oblastima, a razloge iete razumeti kada
budete
naudili.vi5e o ovom jeziku. Funkcija f0 se nalaziu sopstvenoj oblasti
- k6d je
int main0 ( najde5ie u memoriji razdvojen od podataka.
int i, j, k; Zapazite joS nesto zanimljivo. promenrjive su definisane jedna za drugom
i
\ ll l,- tako su sme5tene i u memoriji. Razdvojene su brojem bajtova koji je porreban
za
Tokom izvrsavanja programa, svaki element ima svoje mesto u memoriji. Cak njihove tipove podataka. ovde je korisien sumo tip int, tako aajL promentyiva
ifunkcija zauzima prostor. Kao Sto iete videti, oblast memorije koju neki ele- cat detiri bajta udaljena od.promenljive dog, promenljiva bird'je detiri bajta
ment zauzima odredena je vrstom elementa i nadinom kako je definisan. udaljena od promenljive cat itd. Ispostavlja sJdi je tip int velidine detiri
bajta na
U C-u i C++-u postoji operator koji ie vam reii adresu elementa. To je opera- ovom radunaru.
tor &. Stavite & ispred imena elementa i dobiiete adresu tog elementa. Your- cemu jos sluzi adresa? Najvaznije je sto je moZete smestiti u promenljivu
-kasnije i
Petsl.cpp se moZe izmeniti tako da ispisul'e adrese svih svojih elemenata: koristiti. c i c++ imaju specijarni tip promenljive koja sadrzi adresu. ova
: YourPets2.
promenljiva se zove pokaziuai (engl. poinieil.
/ l C03: cPP
#i ncl ude <i ostream> operator koji defini5e pokazivad je isti kao onaj koji se koristi za mnoienje: *.
usi ng namespace std; Kao
_Sto
iete videti, prevodilac po kontekstu primene zna da se ne radi o
mnoZenju.
j nt dog, cat, bi rd, fi sh; Kada definiSete pokazivad, morate zadati tip promenrjive na koju pokazuje.
Prvo navodite ime tipa, a zatim, umesto da odmah .,u*r"d"t" ime
iromenlive,
void f(int pet) { kaZete: ,,To je pokazivad" i umecete zvezdicu izmedu tipa i promenljive. poka-
cout << "identifikacioni broj ljubimca'" pet << endl; zivad na vrednost tipa int izgleda ovako:
"
) int* ip; // ip pokazuje na celobrojnu promenljivu

int main0 { Povezivanje operatora * i tipa izgleda logidno i lako se dita, ali su u primeni
int i, i, k; moguie gre5ke. MoZda nameravate da koristite,,pokazivad na ceo broj,,kao
da je
cout << "f0, ' .. (long)&f.< endl; poseban tip. Medutim, u sludaju int ili drugih osnormih tipova podataka,
cout << "dog: " << (long)&dog << endl; moguie je napisati:
cout << "cat: " << (long)&cat << endl; int a, b, c;
cout << "bird: " << (long)&bird << endl;
i tako biste hteli da napi5ete i za pokazivade:
cout << "fish: " << (1ong)&fish << endl;
cout << "i: " << (long)&i << endl; int* ipa, ipb, ipc;
cout << rri ' rr << (long)&: << endl;
cout << "k: " << (long)&k << endl;
\ I ll,-
)6 Misliti na jeziku C++ 97
Poglavlje3: CuC++-u

Sintaksa c-a, koju nasleduje i c++, ne dozvoljava ovakve izraze.lJ navedenim int majn0 {
definicijama, samo ipa je pokazivad, a ipb i ipc su tipa int (moZe se reii da se * 'i ntx=47;

dvrsie vezuje za ime promenljive). posledica je da najbolje rezulrate postizemo cout<<"x="<<x << endl;
ako piielno po jednu clefiniciju u redu.'Iako dobijamo logidnu sintaisu i nema f (x);
zabrrnc: cout << "x = " << x << endl ;

1nt* i pa;
rnt* rpb; U funkciji f0, a je lokalna promenljiua, tako da or-ra postoji samo tokom
int* 't pc;
izvr5avanja funkcije f0. Po5to je to argument funkcije, wednost a se inicijalizu.ie
Po5to je opSta preporuka za programiranje na c++-u da se promenljiva inici- prosledenim argumentom. U funkciji mainQ argument je x, dija je wednost 47,
lalizuje tamo gde je i definisana, ovaj oblik zaista boije funkcionise. Na primer, tako da se wednost kopira u a pri pozivanju funkcije f0.
navedene promenljive nisu inicijalizovane nekom vrednoiiu i sadrZe smeie. Kada aktivirate ovaj program, videiete:
Mnogo je bolje napisati neSto poput ovoga: x= 47

int a - 4/; a=47


int* ipa = &a; a=5
x=47
Sada su i a iipa inicijalizovane i ipa sadrZi adresu od a.
osnovna svrha inicijalizovanog pokazivada je menjanje wednosti na koju Na podetku, naravno, x ima wednost 47. Kada se pozove f0, napravi se priwe-
pokazu je. Da bi se pristupilo promenljivoj preko pokazivada, pokaziv meni prostor za auvanje promenljive a tokom izw5avanja funkcije i inicijalizuje
a( se dere- se kopiranjem wednosti x, Sto je potvrdeno rezultatima programa. Nara'rno,
ferencira (engl. dereference) tako sto se primeni isti operator tolim je i deflnisan,
na primer: rnoZete promeniti \Tednost a i prikazati da je promenjena. Po zawSetku f0,
*ipa = priwemeni prostor rezervisan za a se oslobada i vidimo da je iedina veza izmedu
100;
a i x postojala kada je x kopirano u a.
Sada a sadrZi wednost 100 umesto 47. Unutar funkcije f0, x je spoljni objekat (moj termin). Promena lokalne pro-
Tobi bile osnove pokazivada: moZete duvati adresu i koristiti je da biste menljive ne utide na spoljni objekat, Sto je prirodno, poSto se nalaze na razliditim
promenili originalnu prornenljiv'Lr. I dalje ostaje pitanje: zasto zelite ia menjate memorijskim lokacijama. Ali, Sta ako hoiete da promenite spoljni objekat? Tu se
promenljivu koristeii drr.rgu promenljivu kao posrednika? pokazuje pogodnost pokazivada. Pokazivad moZete da posmatrate i kao alijas za
Nudim sledeie odgovore: drugu promenljilu. Ako funkciji prosledimo pokaziuaiumesto obidne wednosti,
I . Da bi
se menjali ,,spolj.i" objekti u okviru funkcije.'fo je verovatno osnovna mi zapravo prosledujemo alternatirmo ime spoljnog objekta, Sto omoguiava
primena pokazivada i ovcie iemo je razmatrati. funkciji promenu tog objekta, kao u primeru:
2. I)a bi sc ostvitrile nrr)oge cl^rge napreclne tehnike programiranja, o kojima / :
/ C03: PassAddress. cpp
iete viie saznati rr nastavku knjige. #i ncl ude <i ostream>
using namespace std;

Promena spoljnog objekta void f(jnt* p) {


Uobidajcno je da se unurar funkcije pravi kopija prosledenog argumenta. ovo se cout << 'rp = rr
<< p << endl;
zove proslediuanje po urednosti (engl. pass-by-ualue). Efekte prosledivanja po cout << 'r*p = ' .. *p << endl ;
vrednosti moTete videti u sledeiem programu: *P = 5;
cout << rrp = rr
<< p << endl;
I / :
C03:PassByValue.cpp
)
#include <iostream>
usi ng namespace std;
int main0 {
void f(int a) { int x = 47;
cout << 't* = " << x << endl ;
cout << "a = " .< a .< endl; cout << rr&x = n << &x << endl;
a = 5; f (&x) ;
cout << rra = rr << a
cout << rrx = r' << x << endl;
<< endl;
I
Misliti na jeziku C++ Poglavlje3: CuC++-u
99

Sada je argument funkcije f0 pokazivad. pokazivad se dereferencira tokom


dodeljivanja vrednosri, Sto dovodi do promene spoljnog objekta x. Dobi;'a se f(x); l/ Izgleda kao prosledivanje po vrednosti,
// zapravo je prosletlivanje po referenci
rezultat:
cout << "x = ,, << x << endl ;
x=47 ) // / ,-
&x = 0065FE00
p= 0065Ft00
U listi argumenata funkcije f0, umesto prosledivanja pokazivada pomoiu
*P=47 ini*, pi5ete int& i prosledujete referencu. Ako unutar f0 napiSete samo r (Sto bi
da-lo adresu kad bi r bio pokazivad) dobijate urednost piominlliue
p= 0065FE00 kilu r referen-
x=5 cira. Ako dodelite wednost promenljivoj r, zapravo doderjujete wednost
promenljivoj koju r referencira. primena operatora & je jedini naein
zapazite da je wednost sadrZana u p ista kao adresa x, sto znadi da p zaista aa dobijete
adresu koja je sadrZana u r.
pokazuje na x. Ako ovo nije dovoljno uverljivo, pogledajte sta se desava kida se p
u funkciji main0 vidite-osnovni uticaj referenci
na sintaksu pozivafO, koji se
derefencira i promenljivoj se dodeli vrednost 5. vrednost x takode postaje 5. piS.ef(x). Iak-o ovo izgleda kao obidno prosledivanje po wednosti, zbog toga
Prosledivanje pokazivada funkciji omoguiava promenu spoljnog objekta. sto
se koriste reference, prosleduje se adresa umesto [opiranla wednosti.'Dobija
Kasnije iete videti mnosrvo drugih primena pokazivada, ali ova je osnor.na i se
rezultat:
verovatno najde5ia.
x=47
&x = 0065FE00
Uvod u C++ reference r=47
Pokazivadi rade skoro isto u c-u i c++-u, ali c++ ima jos jedan nadin pro- &r = 0065FE00
sledivanja adrese funkciji. ovo je proslediuanje po referenci (engl. pass-by-iefe- r=5
rence) i postoji i u nekolicini drugih programskih
)ezlka, rako da to nije novina
C++-a. po referenci omoguiava funkciji da menja spoljni
prosledivanje
Mozda iete pomisliti da su reference nepotrebne i da se svi programi mogu . .D.uH":
objekat, kao i prosledivanje pokazivada (vidite i da referenca zamagtjuye
einje-
napisati i bez njih. U opstem sluiaju to je tadno, ali posroje izuzeci koje iete nicu da se prosleduje adresa, sto ie biti razmatrano u nastavku). posle
ovog jed-
videti u nastavku. o referencama iete vise nauiiti kasnije. Swha je ista kao kod nostavnog uvoda, referencu moZete smatrati sintaksno razliditim naiinom
pokazivada: adresa argumenta se moZe proslediti primenom reference. Refe- (nekada se naziva ,,zasladivai sintakse,,) re5avanja iste
stvari koju rade
rence i pokazivaii imaju razliditu sintaksu: jasnije je poziuanjefunkcije diji argu- pokazivadi.
menti su reference nego funkcije diji argumenti su pokazivadi (upravo ova
razlika u sintaksi cini reference neophodnim u nekim situacijama). Ako se pas-
sAddress.cpp izmeni tako da koristi reference, mozete videti razliku pri Pokazivaii i reference kao modifikatori
pozivanju funkcije f0 iz funkcije main0: Dosad ste upoznali osno'rne tipove podataka char, int, float i doubre,
i specifika-
tore signed, unsigned, short i rong. ovi specifikatori se mogu koristiti uz
I / : C03: PassReference. cpp
osnovne tipove podataka u skoro svakoj kombinaciji. Dodali smo pokazivade
#i ncl ude <i ostream> i
reference koji se primenjuju na osno'r'ne tipove podataka i specifikato.", pu
usi ng namespace std; r"
broj moguiih kombinacija utrostrueio:
void f(int& r) { // : C03:AllDefinitions.cpp
cout<<"r="<<r <. endl; // Sve moguee kombinacije osnovnih tipova podataka,
cout << "&r = " .< &r << endl; // specifikatora, pokazivada i referenc.i
- - t. #i ncl ude <i ostream>
cout << "r = " << r << endl; usi ng namespace std;
)
void f1(char c, int i, float f, double d);
int main0 { void f2(short int sj, long int li, long double 1d);
int x = 47; void f3(unsigned char uc, unsigned int ui,
cout << "x = " << x << endl; unsigned short int usi, unsigned Iong int u1i);
cout << "&x = " << &x << endl ; void f4(char* cp, jnt* ip, float* fp, double* dp);
void f5(short int* sip, long int* lip,
1 ong doubi e* 1 dp) ;
Misliti na jeziku C++ Poglavlje3: CuC++-u lol
IOO

int* uip' jednog tipa kao nekog drugog. u navedenom primeru koristim tip int kao int
void f6(unsigned char* ucp, unsigned
unsigned short int* usiP,
ko.tu"itrj.rel vp u int;, ali me ni5ta ne spredava da konvertovanjem u char* ili
unsi gned 1 ong i nt* u1 i P) ;
double*. Za podatke tih tipova ne zauzima se ista kolidina memorije kao za int ,
voj d f7 (char& cr, j nt& i r, fl oat& fr, doubl e& dr) ; pa takva konverzija moLe izazvati greske i dovesti do otkazivanja programa.
^pokazivade
void fB(short int& sir, long int& lir' na tip void bi trebalo izbegavati i koristiti samo u posebnim sluda-
1 ong doubl e& I dr) ;
jevima (o tome Cete ditati kasnije).
void f9(unsigned char& ucr, unsigned int& uir' Ne moZete imati referencu na tip void. Razloge iu objasniti u poglavlju 11.
unsigned short jnt& usir'
unsi gned I ong i nt& ul i r) ;
Oblast vaZenja
int majnO \\ lll:- Pravila oblasti vazenja govore gde promenljiva vazi, gde je napravljena i gde se
pokazivaei i reference se koriste i za prosledivanje argumenata u funkcije i iz unistava (tj. nije vise vidljiva). oblast vazenja promenljive se prostire od mesta na
njih, o demu iete vi5e saznati u nekom od sledeiih poglavlja' kome je definisana do prve zaworene vitidaste zagrade koja odgovara najbliZoj
' ]oS jedan tip radi s pokazivadima, a to je void' Ako napiSete da je tip poka- otvorenoj vitidastoj zagradi pre definicije promenljive. Drugim redima, oblast
zivada void*, ro znadi da se tom pokazivaiu moZe dodeliti bilo
koji tip adrese' vaZenja promenljive definiSe par njoj najbliZih vitidastih zagrada. Pogledajte
mozete dodeliti samo adresu promenljive primer:
Ako koristite int*, ovom pokazividu
tipa int. Na primer: //: C03:ScoPe.cPP
//: C03: Voi dPoi nter ' cPP // Oblast vaZenja Promenliivih
int main0 {
int mainO {
voi d" vP; i nt scpl;
char c; // u oblasti vaZenja scPl
i nt i ;
{

f1 oat f; //t/ io5 uvek u oblasti vaZenja scPl


doubl e d; t1..,"
Adresa BIL0 tiPa moZe se i nt scp2;
// KOG

II dodel i ti Pokazi vaiu na voi d: // u oblasti vaienja scP2

vP = &c; il.....
vP = &i; {

vP = &f ; // jo5 uvek u oblasti vaZenja scpl i scp2

vP = &d; il..
\ ttl.- int scP3;
o tipu // u oblasti vaZenja scpl, scp2 i scp3
Kada dodelite vrednost pokazivadu tipa void*, gube se Sve informacije t/...
morate konvertovati u odgovarajuii tip pre
promenljive. To znaei da pokazivad I ll '-- scp3 je ovde uniStena
nego sto ga upotrebite: ll scP3 nije dostuPna
I : C03: CastFromVoi dPoi nter ' cPP // jo5 uvek u oblasti vaZenja scpl i scp2
I
int main0 { il...
int i = 99; I ll '-- scp2 je ovde uniStena
void* vP = 61 ' ll scp3 i scP2 nisu dostuPne
pokazivai na void se ne moie dereferencirati:
ll *vp // io5 uvek u oblasti vaZenja scPl
ll = 3; // Greika pri prevodenju il.-
II llora se konvertovati nazad u int pre dereferencirania: J l/ '-- scPl je ovde uniStena
*((int*)vp) = 3; / // ,-
\ I I t,- Navedeni primer pokazuje kada su promenljive dostupne, a kada su nedo-
(int*)vp traZi od prevodioca da pokazivad tipa void*
lz,raz z,a konverz-iju stupne (znadi, izuan oblasti vaienja). Promenljiva se moZe koristiti samo unutar
posmatra kao da ie iipa int*, tako da se mo7.e uspesno dereferencirati. MoZda svoje oblasti vaZenja. Oblasti mogu biti ugneZdene, na Sta ukazuje par unutar
ietezapazitirttZnrlt:ttrlvcsintakse,izbiljajertrZna.Io5jegoreStovoid*pravi drugog para vitidastih zagracla. Promenljivoj moZete pristupiti u oblasti koja ie
,,,,\r,,, (i(r|,,r,r 'irrot:r iIzik;t Io zrlaiirtrt riozl'rl1iava, iak ipotpornaZe' koriiienie
Misliti na jeziku C++ Poglavlje3: CuC++-u ro3
o2

u tekrrir.r oblast. LI navedenom primeru, promenljiva scpl ie dostu- int p = 1; l/ 1vo je druga promenljiva p
r.rgneT-clena
| // Kraj oblasti koia sadrZi q j spolinu promenliivu p
pna u sri,n drr,rgim oblastima vazenia, dok ie scp3 dostupna samo u najdubljoj
cout << "Unesite znakove:" << endl;
oblasti.
while(char c = cin.get0 t= 'q') {
cout << c << " zar ne" << endl;
jf(char x = c == 'a' ll c == 'b')
Usputno definisanje promenljivih
Kao Sto je napomenuto .unij" u ovom poglavlju, izmedu c-a i c++-a postoji cout << "Uneli ste a ili b" << endl;
zna(ajna razlika u definisanju promenljivih. oba jezika zahtevaju da promen-
el se

ljiYe biclu definisane pre korisienja, ali se u C-u (i mnogim drugim tradiciona-
cout << "Uneli ste " << x << endl;

lnint prograntskint jez,icinta) insistira da se definisu sve promenljive na podetku )


cout << "Unesite A, B ili C" << endl;
oblasii vi7enla, tako da prevodilac pri formiranju bloka moLe rezervisati prostor switch(int i = cin.get0) {
za njih. case 'A': cout << "Pucanj" << endl; break;
podetku oblasti va1enja u programu na jeziku C obidno najpre zapaLale
Nia case 'B': cout << "Pogodak" << endl; break;
blok dlfinicila promenljivih. Deklarisanje svih promenljivih na podetku bloka case'C': cout << "Prasak" << endl; break;
uslovljava programera da piSe na odredeni naiin zbog detalja realizacije prevo- default: cout << "Nije ni A, ni B, ni C!" << endl;
dioca. Mnogi ne znalu unapred koie ie sve promenljive koristiti, tako da se i
moraju vraiiti na podetak bloka i dodavati nove promenljive, Sto naporno i
je
promenljivih obidno beznadajne, a
\ //t,-
proLrirokuje grcske. Citaocu su ove definicije
od konteksta u kome se koriste' U najdubljoj oblasti, promenljiva p je definisana neposredno pre zawSetka
mogu zbunjivati posto str odvojene
oblasti, Sto je beskorisno, ali pokazuje da se promenljiva moZe bilo gde defini-
d*+ (ne i C) clozvoliava definisanje promenljivih bilo gde u oblasti vaZenja. sati. Isto je i s promenljivom p u spoljnoj oblasti.
Zbog toga promer.rljivr,r defini5ite neposredno pre upotrebe. Promenljil'u moZete
Definisanje i u kontrolnom izrazu petlje for pokazuje da je moguie defini-
inicr;aliiovati na mesru gde je definiSete, dime se spreiavaju neke deste greSke.
sanje promenljive taino na mestu gde ie biti potrebna (to se moZe udiniti samo
ovaj nadin definisanja promenljivih olaksava pisanje koda i smanjuje broj u C++-u). Oblast vrteoia i je petlja for, tako da moZete ponovo koristiti ime i u
greSaka izazvanih kretanjem napred-nazad unutar oblasti. Program je
je sledeioj petlji for. Ovo je pogodna i desto koriSiena tehnika u C++-u; i je kta-
iaz_umljiviji, po5to promenljir,u vidite u kontekstu u kome se koristi. Ovo
i inicijalizujete promenljilu, posto sidno ime brojada petlje i ne morate stalno izmiSljati nova.
posebno vaTno kada istovremeno definiSete
Iako primer pokazuje i promenljive definisane unutar iskaza while, if i
znaien je itricijalne Vreclnosti rnoZete razumeti prema nadinu koriSienja
switch, ove definicije nisu tako uobidajene kao u iskazima for, moZda zbog sin-
promenljive.
taksnih ogranidenja. Na primer, ne moZete koristiti zagrade. Znadi, ne moZete
Pronrenlji,,,a sc lt.to7-e cicfir-risati i ul'ttttar kontlolnog izraza, petljama for i
pisati:
while, unrrtar uslgva if isksza t unrttar selektora iskaza switch. Ovaj primer poka-
z-uje trsptrlno clefi rtisarlje promenljivih: while((char c = cin.get0) t= q')
//: C03:0nTheF1 Y. cPP Dodavanje zagrada bi izgledalo bezazleno i korisno, a poSto ih ne moZete
// Usputno definisanje promenljivih koristiti, rezultati vam se ne bi svideli. Problem nastaje po5to operator != ima vi5i
#include <iostream> prioritet od operatora -, tako da char c na kaju dobija wednost tipa bool konver-
JSrng na-espace srd; tovanu u tip char. Kada se ovo ispiSe, na mnogim ekranima iete videti nasmejano
lice.
int main0 { MoZete razmatrati definisanje promenljivih unutar iskaza while, if i switch da
biste upotpunili svoje znanje, ali je samo u petlji for poZeljno koristiti definiciju
{ // Pocetak nove obl asti vaZenj a promenljive i to iete desto i raditi.
int q = O; ll C zahteva da sve definicije budu ovde
il.
I I
for(i nt
Deftni sanje na mestu uPotrebe
i - 0; i ' 100; i++1
Definisanje raspodele memorijskog prostora
1
Pri definisanju promenljive, imate veii broj opcija za definisanje njenog Zivot-
q++; l l q poti ae i z 5i re obl asti
nog veka, nadina rezervisanja memorijskog prostora za nju i nadina kako je pre-
ll Definicija na kraju oblasti vodilac koristi.
1nt P = 12'
)
l04 Misliti na jeziku C++ Poglavlje3: CuC++-u tos

Clobalne promenljive Global2.cpp prvi red sadrzi cirugu posebnu oznaku komentara {o}, koja kaze
Globalne pronrenljive su definisane izvan tela funkcija i dostupne su svim delo- ,,Ne pokuSavajte da od ove datoteke napravite izwsni program, ona se prevod,
vima programa, tak i kodu u drugim datotekama. Na globalne promenljive se ne kako bi se povezala s nekom drugom datotekom". program Extractcode.cpp u
primenjuju pravila oblasti vaienja i uvek su dostupne (tj. globalne promenljive tomu 2 ove knjige (dostupan je na www.BruceEckel.com) pomoiu tih oznaka
postoie do kraja izvrSavanja programa). l)eklaracijom globalne promenljive uz formira odgovarajuiu datoteku makefile, tako da se sve ispravno prevodi (c
rezervisanu red extern, podaci se mogu koristiti i u drugoj datoteci. Ovo je datotekama makefile vi5e iete saznati na kraju ovog poglavlja).
primer upotrebe globalnih promenljivih:
I I : C03: G1 obal . cpp Lokalne promenljive
//{ Li Gl obal 2 Lokalne promenljive se nalaze u jednoj oblasti i one su ,,lokalne" za nekr.
ll Priner globa)nih promenljivih funkciju. Cesto se nazivaju automatskezato sto automatski nastaju pri ulasku u
#i ncl ude <i ostream> odredenu oblast i automatski nestaju pri zatvaraniu oblasti. Rezervisana red auto
using namespace std; koristi se zaizrl(ito pravljenje automatskih promenljivih. Za lokalne promenljive
to se podrazumeva, pa ih nikada nije neophodno deklarisati kao auto^
int globe;
void func0;
jnt main0 {
Reg i stars ke promen lj ive
qlobe = 12; Registarska promenljiva je jedan tip lokalne promenljive. Rezervisana red regi-
cout << globe << endl; ster nalaZe prevodiocu: ,,Neka se ovoj promenljivoj pristupa sto brZe". poveianje
runc 0 ; // Menj a gl obe tlrzine pristupa zavisi od prevodioca. PostiZe se, kao ito i samo ime sugeriSe,
cout << globe <. endl; smestanjem promenljive u registar. Ne postoji garancija da ie promenljiva bitr
| /l/'- smestena u registar, niti da ie se poveiati brzina pristupa. To je samo napomena
Ovaj primer pokazuje pristup globalnoj promenljivoj globe iz druge prevodiocu.
datoteke: upotreba registarskih promenljivih je ogranidena. Ne moZete proditati niti
izradunati adresu takve promenljive. Registarska promenijiva se moZe deklari-
ll : C03:Global2.cpp {0} sati samo unutar bloka (ne postoje globatne ni statidke registarske promenljive).
// Pristupanje spol jnim globalnim promenljivama
MoZete, medutim, koristiti registarsku promenljivu kao fbrmalni argumenr
extern j nt g1 obe;
funkcije (tj. u listi argumenata).
I I (Pouezivae razreSava referencu)
U opstem sludaju, ne bi trebalo da nameiete resenja optimizatoru prevo-
void func0 (
globe = 47; dioca, posto ie on verovatno bolje od vas obaviti posao. zato je najbolje izbega-
vati rezerrisanu red register.
\ lll,-
Memorijski prostor za promenljivu globe rezervi5e se definicijom u datoteci
Global.cpp, a istoj promenljivoj se pristupa iz programa Global2.cpp. PoSto se Rezervisana rea static
datoteka Global2.cpp prevodi odvojeno od datoteke Global.cpp, prevodilac Rezervisana red static ima nekoliko razliiltih znadenja. Lokalno definisanc
nrora biti obaveSten da pron'renljiva negde postoji, i to sledeiom deklaracijom: promenljive funkcije nestaju na kraju oblasti funkcije. Kada ponovo pozovete
extern j nt g1 obe; funkciju, rezervi5e se novi prostor za promenljive i one se ponovo inicijalizuju.
Ako hoiete da neka vrednost opstane tokom celog izwsavanja programa, lokatnu
Pri izvrSavanju programa, videiete da pozivanje func0 utide na jedan glo- promenljivu funkcije mozete definisati kao statiaki i dodeiiti joj podetnu wednost.
balni primerak promenljive globe. Statidke promenljive se inicijalizuju samo po prvom pozivanju funkcije, a pro-
ll Global.cpp nroT-ete zapaziti posebnu oznaku komentara (to je moja ideja): menljiva zadrLava wednost izmedu poziva funkcije. Na ovaj nadin funkcij a moze
//{Li Global2 ,Zapamtiti" neke informacije izmedu poziva.
Oznaka kazujc da objektna datoteka pod nazivom Global2 mora biti povezana MoZda se pitate zasto se ne koristi globalna promenljiva umesto statidke.
pri pravljenju konadnog programa (nema nastavka imena, po5to su nastavci Prednost statidke promenljive jeste sto je nedostupna izvan oblasti funkcije,
imena objektnih datoteka drugadiji na razliditim sistemima). U datoteci tako da ne moZe biti nehotidno promenjena. Time se lokalizuju eventualni
uzroci gre5aka.
r06 Misliti na jeziku C++ Poglavlje3:CuC++-u t07

Ovo je prirner koriSienja statidkih promenljivih:


Rezervisana ret extern
ll: C03:Static.cpp Rezervisana red extern vei je ukratko objasnjena i prikazana. ona saopstava
// Primena staticke promenijive u funkciji prevodiocu da promenljiva, odnosno funkcija, postoji, iako je prevodilac nije
#i nci ude <i ostneam>
video u tekuioj datoteci. Ova promenljiva, odnosno funkcija, moZe biti
usl ng namespace std; definisana u drugoj datoteci ili u nastavku tekufe datoteke. ovo je primer za
drugi sludaj:
void func0 {

static int i = 0; Il: C03: Forward.cpp


ll Deklaracije funkcija i podataka pre definicija
) #i ncl ude <i ostream>
using namespace std;
int main0 {
for(intx=0;x<i0;x++) // Ovo nije stvarno spoljna promenljiva, a1i se
func0; // prevodiocu mora saopStiti da ona negde postoji:
I //1,- extern int i;
extern void func0;
Pri svakom poz-ivanju func0 u petlji for, ispisuje se drugadija wednost. Da
nije koriSiena rezervisana red static, prikazana wednost bi uvek bila , 1,.
int main0 {

Dnrgo znadenje rezervisane redi static je povezano sa prvim u smislu ,,nedo-


i=0;
func 0 ;
stupnosti izvan odredene oblasti". Kada se static primeni na ime funkcije ili na
)
promenljiru izvan svih funkcija, to znadi da je ,,ime nedostupno izvan ove int i; ll Definicija podataka
datoteke". Ime funkcije ili promenljive je lokalno za datoteku i kaZemo da je void funcfl {
njihova oblast uaienja datoteka. Na primer, ako prevedete i pokuSate da pove- j ++;
Zete ove dve datoteke, doii ie do greSke pri povezivanju: cout << i;
I / : C03:Fi leStatic.cpp I ///,-
l/ Prikaz oblasti vaZenja u datoteci. prevodenje i Ako prevodilac naide na deklaraciju 'extern int i', on zna d,a je i negde
II povezi vanje ove datoteke sa Fi 1 eStati c2. cpp definisana kao globalna promenljiva. Kada prevodilac stigne do definicije
/I dovodi do greike pri povezi vanj u promenljive i, nije vidljiva nijedna druga deklaracija, rako da zna da je prona5ao
ono i koje je prethodno deklarisano u toj datoteci. Da ste definisali i kao static,
// 0b1ast vaZenja fs je datoteka saopsti-li biste prevodiocu da je i globalno deflnisano (red extern), ali je oblast
static 1nt fs; vaZenja u datoteci (red static), tako da bi prevodilac prijavio gre5ku.
int main0 {
fs = 1; Nadin povezivanja
I lll:- Da bi se razumelo ponasanje programa pisanih na jezicima c i c++, treba raz-
Iako se za pronrenljir,u fs u sledeioj datoteci twdi da postoji kao spoljna, motriti na(in poueziuanja(engl. linkage). Pri izwsavanju programa, svaki identi-
povezivad je neie pronaii po5to je deklarisana kao statidka u Filestatic.cpp. fikator se predstavlja prostorom u memoriji radunara, koji sadrZi promenljivu ili
prevedeno telo funkcije. Narin povezivanja opisuje ovaj prostor sa stanoviSta
I I : C03:Fi leStatic2.cpp {0} povezivada. Postoje dva nadina povezivanja: unutrainje (engl. internal linkage) i
// PokuSaj upotrebe promenljive fs spoljainj e (engl. external linkage).
extern int fs; Unutra5nje povezivanje znati da napravljeni prostor predstavl;'a ime koje
void func0 {
vaZi samo u odredenoj prevedenoj datoteci. Druge datoteke mogu koristiti isto
fs = 100; ime za promenljilu sa unutra5njim povezivanjem ili za globalnu promenljir,u -
\ ilt,- za svako ime se pravi odvojeni prostor. UnutraSnje povezivan je se u C-u i C++-u
Specifikator static se moze koristiti i unutar klase. objaSnjenje iete pronaii u definiSe rezervisanom redju static.
nastavku knjige, kada budete udili kako se prave klase.
Misliti na jeziku C++ Poglavlje3:CuC++-u t09
l08

SpoljaSnle povez-ivanje pravi smeStaini prostor za ime


koie vaZi u svim Konstantne vrednosti
s niim poveZe U C++-u konstanta uvek mora imati podetnu wednost (to ne vaZi u C-u). Kon-
prevedenini clatotekanta. p()stor se napiavi lednom, a povezivad
i imena funkcija primenjuje se stantne vrednosri ugradenih tipova se predstavljaju kao dekadni, oktalni, heksa-
ire druge reference. Na globalne promenljive decimalni ili brojevi u formatu pokretnog zareza (naialost, binarnim brojevima
spoljaSnje povezivanje iz. drugih datoteka im se pristupa .deklarisanjem
funkcija nije dat znadaj) ili kao znakovi.
pomoiu rez-ervisane redi extern. Za promenljive definisane izvan
'(izuzev u c++-u) i za definicije funkciia podrazumeva se spoljasnje Ako nije definisano drugadije, prevodilac podrazumeva da je konstantna
konstantni
pomoiu rezervisane redi static zahteva se unutra5nje povezivanje' wednost dekadni broj. Brojevi 47, 0 i t 10I smatraju se dekadnim brojevima.
for.riuanle. Konstantna wednost s preflksom 0 smatra se oktalnim brojem (osnova 8).
primenom rez-ervisane redi extern mozete izridito twditi da se ime spoljasnie
redi extern niie Brojevi u sistemu sa osnovom 8 mogu sadrZati samo cifre 0-7, a prevodilac
povezule. I)efinisanie promenljive, odnosno funkcije' pomoiu
C++-u' oznadava kao gre5ku sve druge cifre. Ispravan oktalni broj je 017 (15 u sistemu sa
ireophodno ,.r C-u, aii jL ponekad neophodno za konstante u
na steku' tokom osnovom 10).
Automatske (lokalne) promenljive postoje samo priwemeno'
vodi raeuna o automatskim promenliivama' Konstantna wednost s prefiksom 0x smatra se heksadecimalnim brojem
izvrsavanja funkcile. Povez-ivai ne
(osnova 16). Brojevi u sistemu sa osnovom 16 sadrZe cifre G-9 i slova a-f ili A-F.
Ispravan heksadecimalni broj je Oxlfe (510 u sistemu sa osnovom l0).
Konstante Brojevi u pokretnom zatezu mogu da sadrZe decimalnu taeku i eksponent
Ako ste Ll starom c-u (pre standardizaciie) hteli da
napravite konstantu, morali (oznaka je e, Sto znadi ,,10 na stepen'). I decimalna tadka i e su neobavezni' Ako
ste koristiti PretProcesor: neku konstantu dodelite promenljivoj u pokretnom zatezu, prevodilac konver-
tuje konstantnu \Tednost u format pokretnog zareza (ovaj postupak je jedan
#defi ne P1 3.14159
oblikposredne konuerzije tipoua). PoZeljno je pisati ili decimalnu tadku ili e da bi
Pretprocesorjenasvimmestimaz-amenjivaoPIwednoSiu3,14l59(ovu se iitalac podsetio da koristite broj u pokretnom zarezu, a nekim starijim prevo-
metodu i dalje moZete koristiti u C-u i C++-u)' diocima to treba i naznaditi.
izlazi iz
Upravlianje konstantama napravljenim pomoiu pretprocesora Ispravne konstante u pokretnom zatezu su: 1e4, 1.000I, 47.0, 0'0 i -1.159e-77.
pI dobiti adresu PI
domlna prevodioca. Ni tip imena se ne proverava, niti mozete Sufiksima moZete odrediti format pokretnog zareza'. f ili F se koriste za float, L ili
(zato ne moZete proslediti ni pokazivad, niti referencu na PI)' PI ne moZe biti
^et I za long double, inade ie broj biti tipa double.
vaZi od.mesta na kome je definisana do kraja te
promenliiva proizvolinog tipa. Znakovne konstante su znakovi izmedu apostrofa, kao: A, '0', ' '. Obratite
clatoteke - pretprocesor ne prepoznaje oblasti vaZenja' paZnju na to da postoji velika razlika izmedu znaka'0' (ASCII 48) i wednosti 0.
konitante koja Ie sliina promenljivoi' samo Sto
C++ trvodi pojam imenovane Specijalni znakovi se predstavljaju pomoiu ,,kontrolne obrnute kose crte": '\n'
se ne mo7.e piomeniti niena vrednost. Modifikator
const saopstava prevodiocu
(novi red),'\t' (tabulator),'\\' (obrnuta kosa crta),'\r' (podetak reda),'\"' (znak
du i*" predstavlja konitantu. Promenljiva svakog tipa' ugradenog ili namen-
navoda),' \" (apostrof) itd. Znakor,rre konstante moZete izraziti oktalno:' \ 1 7' ili
skog,moTesedefinisatikaoconst.Akone5todefini5etekaoconstizatim heksadecimalno:' \xlf '.
pnkuSate to da promenite, prevodilac ie priiaviti greSku'
prornenljiva tipa const se mora definisati prilikom deklarisanja, na primer:
constintx=10; Oznaka volatile
Dok oznaka const saop5tava prevodiocu: ,,Ovo se nikada ne menja' (Sto omo-
U standardnonr c-u i c++-u moZete koristiti imenovanu konstantu u listi guiava dodatne optimizacije pri prevodenju), oznaka volatile kaZe: ,,Nikad se ne
argumenata,dakiakojeodgovarajuiiargumentpokazivad.ilireferenca(tj. zna kada ie se ovo promeniti" i tako spredava optimizacije prevodioca, zasno-
n-.,'o2.,. proditati adresu konitantne vrednosti). Takva
wednost ima oblast
unutar funkcije i vane na stabilnosti te promenljive. Ova rezervisana red se koristi za pristup wed-
vaZenia, kao i obidna promenliiva, tako da
je mozete
"sakriti" nostima izvan vaSe kontrole, na primer registru komunikacionog hardvera.
biti sigurni da to ime neie uticati na ostatak programa' Vrednost oznadena kao volatile uditava se svaki put kada se koristi, dak i ako je
Redconstjepreuzetaiz-C++-aiukljudenaustandardniC,madanasasvim bila uditana u prethodnom redu.
zapromenljive,
razlieit nadin. c prevodilac tumadi const kao posebnu oznaku Poseban sludaj promenljive koja je ,,izvan kontrole koda' javlja se u viSenitnim
kolataze',,Nemenjajme...Kadadefini5etekonstantnuwednostuC.u,prevodi-
jos programima. Ako posmatrate odredeni indikator koji se menja u drugoj niti ili
Iac rezervise prostor u memoriji, pa ako u dve razlidite
datoteke definisete
procesu, trebalo bi da indikator bude volatile, kako prevodilac ne bi pretpostavio
neku istoimenu konstantnu u."dnort (ili smestite definiciiu u datoteku zagla-
u C-u ie sasvim da moZe optimizovati pristup.
vlja), povezivai prijavliuje sukobe imena'.Namena redi const
Zapazite da volatile ne mora imati efekta ako prevodilac ne optimizuje kdd,
od namene u C++-u (ukratko, bolja je u C++-u)'
diugadija ali moZe sprediti znadajne gre5ke kada podnete da optimizujete k6d (to se
de5ava kada prevodilac podne da traZi ponovljena uditavanja).
Rezcn,isane redi const i volatile biie dodatno obiaSniene kasnijc.
Misliti na jeziku C++ Poglavlje3: CuC++-u llI
rlo
PRINT('j",j) ; PRINT("k",k)
Operatori i njihova uPotrebai C++-tt' 'i = j + k; PRINT("j + k",j);;
Ovaj odeliak cibracluie sve operatorel C-u i = j - k; pRINT(,,j _ k,,,j);
Svioperatorip.i,una.jednuwednostnaosno\,Llsvojihoperanada.ovawed. i = k / j; PRINT("k / j,,,i);
nosr se dobija bez iz-mene operanada, osim kada se
koriste operatori dodeljivanja' i = k * j; PRINT("k * j',,i);
uveianja i u,run;"nlu. tz*e.,a operanda se naziva sporedni efekat {engl. side i = k % j; PRINT("k % j',,i);
se koriste zaizazivanle ovog // )vo funkcioniSe samo za cele
effecr), operatori ko ji menjaju svoje operande obidno brojeve:
sporednog efekta, ii treba imati na umu da je ovako dobijenu wednost moguie j %= k; PRINT("j %= k", j);
cout << "Unesite broj u formatu pokretnog zareza: ,,;
koristiti kio i kod operatora bez' sporednih efekata'
cin >> v;
cout << "Unes'ite jos jedan broj u fonmatu pokretnog zareza:
Dodeljivanje desnu wednost (desto
cin >> w;
operator = sltri,i ).adodeliivanie wednosti. To znadi: ,,Uzmi PRINT("v",v) ; PRINT(,,w,,,w) ;
se naziva rluredrtost, engl" rualtrc) i kopira;
je na levu stlanu (aesto se naziva lured- u = v + w; PRINT("v + w'," u)
nosr, engl. lttaltrc)". tlweanost je bilo koja konstanta, promenljiva ili izraz koji se u = v - w; PRINT("v - 1,i,,, u)
mora biti posebna, imenovana promenljiva (znadi, u = v * w; PRINT("v * w,,, u)
mo7.e izraiunati, ali lwednost
Na primer' konstantnu u = v /w; PRINT("v /w,,, u)
mora postoiati fiz.idki prostor za sme5tanje podataka)'
vrednost mozere dodeiti promenljivoj (A = 4r, ali nista
ne mozete dodeliti kon- // 1vo takode radi i za tipove int, char
stantnoj vrednosti - ona ne moze biti lwednost
(ne smete pisati 4 = A;)' // i double:
PRINT("u",u); PRINT("v", v);
u += v; PRINT(,'u += v,,, u);
Matematicki oPeratori u -= v; PRINT("u -= v,,, u);
programskih jezika: sabi- u *= v; PRINT("u *= v", u);
osnol,ni matemati.ki,operatori su isti kao i u veiini
(/), mnozenje (*) i modulo (%), koji daje u /= v; PRINT("u /= v,,, u);
ranjc (+), oduzimanje i-), aetjenje
ostarak pri cetobioinom'deljenju'broieva. celobrojno deljenje odseca rezultat ) ///,-
(.e zaokruZr.rle). Operator niodulo se ne moZe koristiti s brojevima u formatu Dvrednosti u svim izrazima mogu, naravno, biti i mnogo sloZenije
pokretnog zareza.
c i c++ koriste i skraienu notaciju za istowemeno izvrsavanje operact;e.t Uvod u pretprocesorske makroe
dodeljivanja.Utomzapisu,izaoperatoraslediznakjednakosti.Zapisjekonsi. 4 Zapazite da se makro PRINTQ koristi da bi se manje kucalo (i pravilo manje
primer, sabiranje x sa
stentan za sve operatore lezika (kid sod ima smisla). Na gresaka). Imena pretpocesorskih makroa tradicionaino se pisu samo velikim
i dodeliivanie rez-ultata promenljivoj x, piSe se: x += 4;' slovima, tako da su upadljiva. Kasnije iete saznati da malroi mogu postati
Sledeii primer pokazuje upotrebu matematidkih operatora: opasni (mogu biti i veoma korisni).
ll: C03:MathoPs.cPP Argumenti u listi izmedu zagrada, koja sredi iza imena makroa, zamenjuju se
// Matemati<i cki oPeratori u celokupnom kodu koji se nalaziiza zatvorene zagrad,e. pretprocesor ukianja
#i ncl ude ostream> ime PRINT i zamenjuje ga kodom pri svakom pozivinju makroa. Zato prevodi-
usi ng namesPace std; lac ne moZe generisati poruke o greskama koristeii ime makroa i ne proverava
tipove argumenata (ovo poslednje moZe biti korisno, sto ie biti prikurunn .,
II Vakro za ispisivanje znakovnog niza i vrednosti ' makroima za otkrivanje gre5aka na kraju poglavlja).
#defj ne PRINT (STR, VAR) \
cout << STR " = " << VAR << endl
Operatori poredenja
int main0 { operatori poredenja uspostavljaju relaciju izmedu wednosti operanada. oni
int i, i, k; proizvode logidku wednost (tip bool u C++-u) true ako je relacija tadna i false
float u, v, w; ll VaZi i za doubie, takode ako je relacija netaana. On91_1tori poredenja su: manje od (<), veil od (>),
: manl.e
cout << "unesi te ceo broj "; od ili jednako (<=), veie od ili jednako (>=), jednako (==) i razlidito (l=). Mogu
ie
cin >> j; koristitisa svim ugradenim tipovima podataka c-a i c++-a. Mogu se posebno
cout << "unesl te ios iedan ceo broi: "; definisati za druge tipove u c++-u (o ovome iete ditati u pogiavrju r2, koje
cin ,> k; opisu je preklapan jc operatora).
Misliti na jeziku C++
Poglavlje3:CuC++-u il3

negacije (engl. nor) nad bitovima (-, poznat i kao operator pruog komplementa)
jeste unarni operator - ima samo jedan argument (svi ostali operatori nad
Logicki oPeratori i di'Vrrnkcrye (ll) daiu rezultat true ili
false' u
bitovima su binarni). Operator negacije daje suprotnu wednost u odnosu na
Logicki opcraton ron.lttnkcije(&&) se da je u c-u i c++-u
argurnenata. Prisetite ulazni bit - jedinicu ako je ulazni bit nula, a nulu ako je ulazni bit jedinica.
z.avisnosti ocl logiike vez-e iimedu nule' a false ako je vrednost
razlieitu od Operatori nad bitovima se mogu kombinovati sa znakom =, dime
rezultat i\tal'a trueuto'i'tu "tttnosi
se
'0'
jednaka ntrli. Ako p' iko''t;;;; u'"Jnu" t ipa
bool' videiete'I' za true i za false' objedinjuju operacija i dodela wednosti. Operacije &=, l= i ^= su ispravne (poSto
''-O"oiprin.rer krrristi ol)cratore porcdenia i Iogitke operatore: le - unarni operator, ne moZe se kombinovati sa znakom =).

//: C03: Bool ean ' cPP


i iki
7i Op..uto.l poredenja 1 ogi operatori '
Operatori pomeranja
#i nc'l ude <i ostrearn> Operatori pomeranja (engl. shl.7fl takode rade s bitovima. Rezultat operatora za
usj ng namesPace std; pomeranje ulevo (<<) jeste wednost operanda s leve strane operatora, pome-
rena ulevo zabroj bitova definisan s desne strane operatora. Rezultat operatora
int main0 {
za pomeranje udesno (>>) jeste wednost operanda s leve strane operatora,
i nt t j ; pomerena udesno zabroj bitova definisan s desne strane operatora. Ako je broj
'
cout << "Unesi te ceo broj: ";
iza operatora pomeranja veii od broja bitova operanda s leve strane, rezultat
cin >> i; nije definisan. Ako je operand s leve strane neoznaden, pomeranje udesno je
cout << "Unesi te jos jedan ceo broj: ";
logidko pomeranje, tako da ie gornji bitovi biti popunjeni nulama. Ako je ope-
cin >'i; <'endl' rand s leve strane oznaden, pomeranje udesno moLe, a ne mora biti logidko
cout << "T , i Je " " (i'j)
pomeranje (nije propisano standardom).
cout << "i . J je " << (i'i) " endl;
<< 'i,. j Je "" (i'= j) " endlI Pomeranja se mogu kombinovati sa znakom jednakosti (<<= i >>-). I-l tom
cout
<< ,,
i <= j je', .. (i <= 3) .. endl; sludaju se lvrednost zamenjuje lwedno5iu pomerenom za dvrednost.
cout << endlI
cout << i == J Je " " (i == i) t< Sledeii primer pokazuje upotrebu svih operatora nad bitovima. Prvo se
cout << "i l= J ie " t' (i l= l) endl; navodi funkcija op5te namene koja ispisuje jedan bajt u binamom formatu. Ona
<< endlI
cout << "i && J ie " " (i && i) je odvojena, tako da se moZe lako ponovo upotrebiti. Datoteka zaglavlja dekla-
cout << i ll i ie " " (i ll i) "
endl; riSe tunkciju:
cout << " (i < 10) && (:'10) ie "

.. ((i'10) && (J < 10)) << endl; l/: C03:printBinary.h


// Prikaz bajta u binarnom formatu
\ I ,-
II void printBinary(const unsigned char val);
promenljivih tipa-int mogu z-ameniti sa
[J navedenom programu se definicije
vidu da ie poredenie broja u formatu
float ili double. Mtd:';;'';;;;i;;tiu razli- Ovo je realizacija funkcije:
se broi dak i u'cifri naimanje tezine
pokretnog T1\reza st;l;; tit"g"' Ako koii je
kuje od dnrgog irrnroloni ,,su razliiiti,,.
Broj u formatu pokretnog zareza, I / : C03:printBinary.cpp {0}
true' #include <iostream>
nulia veii rid nule' pretvara se u vreclnost void printBinary(const unsigned char val)
"riurizi {
for(int i = 7i i >= 0; i--)
Operatori nad bitovima if(va1 & (1 .. i))
Uito"a po.jedinl':i- !]'lll-brola (poSto
omoguiavalu rad.s std::cout.. "1";
Operatori nua rade
pnseUni interni format, ovi operatori
brojevi u pokretnom'-r"r liorlrte
el se
t'po'itu' char' int ilong)' Operatori na{ Uitlvila proizvode std::cout .. "0";
samo s celobroinim
rezultat primcnom utiout uf g"U'e nad
o.dgovarajuiim bitovima argumenata' \ I I l,-
iad bitovima (&) daie iedinicu u
operator fo,,1,"''i'.i1' f r"ile t" i' engl a.ndl dis-
Funkcija printBinary0 ispisuje jedan bajt, bit po bit. Izraz:
iztaz_nom bitu ako,,;'1rir;,i^;-;a
bita"iedinice, inade daje nulu' operator (1 << i)
u izlaznom bitu ako
jurtkcije(logidkoif,' tt'-'gl' or) nad.bitovima (l) daje iedinicu
jebilokojiodulaznih.bi.nuujedinicaa.nttlusamoakosuobanule.operator
daje jedinicu u svakoj od uzastopnih pozicija bitova, binarno: 00000001,
u
or'.skr' xor) nad bitovima 1n) daie iedinicu 00000010 itd. Ako takva wednost konjunkcijom s wedno5iu val daje rezultat
isklirttiuerli.yrlrrkcr7e tengi "*tl"i* ne operator
iz_laznom bittr ako l.'i"1." "a
ulaz.nih bitova iedinica, ali oba. razlidit od nule, to znadi da val ima jedinicu na i-toj poziciji.
Misliti na jeziku C++ Poglavlje3:CuC++-u
tIs
Konadno, ova funkcija se koristi u primeru koji pokazuje operatore nad mogu i rotirati, Sto znadi rra se bitovi koji ispadnu jednog
s kraja sme.taju na
bitovima: drugi kraj, kao da se okeiu u petlji. tai<o veiina
.ut,r.,uritif, fro..ro.u i*u
: C03: Bi twi se. cpp maSinsku komandu za rotaciju_ (moZete je videti
I I
konkretnog procesora), u c-y^i c++-u ne postoli
u asemblerskom jeziku
I I \L\ pri ntBi nary neposredna p"Jrir." za o\.rlr
Prikaz rada sa bjtovima operaciju. verovatno su aulori c-a opravdari
ll izostavrlanle rotacije (teziu su, tato
#include "printBinary.h" su rek,i, minimalnom jeziku) time Sto se moZe
napiaviti ,opr,Gnu ,uredba za
#i ncl ude <i ostream> rotaciju. Na primer, sledeie funkcije rotiraju
bitove ulevo i udesnor
usi ng namespace std;
/ / : C03:Rotation.cpp {0}
// Rotacije ulevo .i udesno
ll Makro za brZe pisanje:
#defi ne PR (STR, EXPR) \ unsigned char rol (unsigned char va1)
cout << STR; printBinary(EXPR); cout << endl; int highbit; {

if(val & 0x8O) // 0x80 ima 1 samo u najviSem bitu


int main0 i highbit = 1;
unsi gned i nt getval ; el se
unsi gned char a, b; hishbit = 0;
cout << "Unesite broj izmedju 0 i 255: ";
// Pomeranje ulevo (najniii bit postaje 0):
cin >> getval; a = getval; val <<= 1.
PR("a, binarno: ", a);
i // Rotacija najviieg bita na donji kraj:
cout << "Unesite broj izmedju 0 255: "; val l= hishbit;
cin >> getval; b = getval; return va1;
PR("b, binarno: ", b); )
PR("a I b = ", a I b);
PR("a&b=",a&b); unsigned char ror(unsigned char va1)
PR("a ^ b = ", a ^ b); int lowbit; {

DD/"_r = " _r\.


r r\t ut t if(val & 7) // provera najniZes bita
PR("-b = ", -b); lowbit = 1;
I I lanin1 j i va maska bi tova: el se
unsignedcharc=0x5A; 'I
owbit = 0;
PR("c, binarno: ", c); val >>= 7; // poneranje udesno za jednu poziciju
a l= c;
// Rotacija najniZeg bita na gornli kra.l:
PR("a l= c; a = "' a); va1 l= (lowbit << 7);
b &= c; return va1 ;
PR("b &= c; b = ", b) ; ] / // :-
b ^= a;
PR('b ^= a; b = ", b); upotrebite ove funkcije u programu Bitwise.cpp. obratite
paZnju na to da
deflnicije (ili bar deklaracije) funkiija rol0 i ror0 moraju
\ / I t,- pre koriSienja tih funkcija
postojati u Birwise.cpp
Da ponovimo, pretprocesorski makro se koristi zabrLe pisanje. On ispisuje Funkcije za rad s bitovima veoma su efikasne, posto
prosledeni niz znakova, z-atim binarni oblik izraza, pa novi red. se neposredno prevode u
naredbe asemblerskogjezika. ponekad od jedne
U funkciji main0 sve promenljive su neoznadene (engl. unsignedl. Razlog je c ili c++ naiedbe naslaje jedan
red asemblerskog koda.
Sto se, u opStem sluiaju, pri radu s bajtovima ne koristi znak. Promenljiva gewal
mora biti tipa int, a ne tipa char, inade bi iskaz ,,cin >>" prvu cifru trebalo da
prikaZe kao znak. Dodeljivanjem vrednosti getval promenljivama a i b, r,rednost Unarni operatori
se konvertuje u jedan bajt (odsecanjem). operator negacijenad'bitovima nije jedini koji ima jedan
argument. Njegov par,
Operatori << i >> pomeraju bitove, ali kada se bitovi pomere s kraja broja, oni loqiika.(saciia (!), pretvara wednost true u vrednost farse
su izgubljeni (obidno se kaZe da padaju u mitsku kofu bitoua, mesto gde minus (-) i unarni prus (+) su isti operatori kao binarni
i obrnuto. Unarni
minus i pirs, a p."uoaluc
zavr5avaiu odbadeni bitovi, da bi moZda bili ponovo upotrebljeni...). Bitovi se
tI6 Misliti na jeziku C++
tt

I Poglavlje3: CUC++-u ll7


!'

otkriva niinieravanu rrltotrebrr po naiinu pisanja izraza. Na primer, odigledno je ali to nije jedina primena ovog operatora. Naravno, koristi se i u listama argume
znaicn;e iskaza: nata funkcije. MoZe se koristiti i kao operator za razdvajanje izraza, kada jt
x = -a; njegova wednost jednaka wednosti poslednjeg izraza. Ostali izrazi, razdvojen
Prevodilac razurne: zarezima u listi, izradunavaju se samo radi njihovih sporednih efekata. I
sledeiem primeru se uveiavaju promenljive u listi, a poslednja se koristi kar
x = a * -b; dwednost:
ali se ditalac moZe zbuniti, pa je sigurnif e pisati:
//: C03 :Comma0perator". cpp
x = a * (-b); #i ncl ude <i ostream>
[Jnarni rninus proizvodi suprcttnu vreclnost. []narni plus takode postoji, using namespace std;
rnada ne radi ni5ta.
Ilirnije su u ovom poglavljrr predstavljeni operatori za uveianje i umanjenje
int main0 {
(++ i --).1o sLr jedini operatori sa sporednim efektima, osim operatora dodele.
int a = 0, b = 1, c = 2, d = 3, e = 4;
a = (b++" 6++, fl++, s++);
Or,i opcratori uveia'airi ili rrmar.rjuju premenljivu za jedinicu, mada znaaenje
cout << "a = " << a << endl ;
,,jedinice" zavisi od tipa podatka - to se naroaito odnosi na pokazivaae.
// lvde su zagrade znaiajne. Bez njih,
Poslednji unarni operatori su adresa (&), dereferenciranje (* i ->), operatori
// iskaz bi se 'izradunavao kao:
za konverziir.r u C-u iC++-rr inew idelete u C++-u. Adresa i derefenciranje se (a = b++), c++, d++, s++;
koristu rrz pokazivade, 5to je opisano Ll ovom poglavlju. Konverzija se opisuje cout << rra = rt << a << endl;
kasnije u ovom poglavlju, a new i delete se uvode u poglavlju 4. I / I l,-
U opStem sludaju, najbolje je izbegavati upotrebu zareza u druge swhe osin
Ternarni operator za razdvajanje, po5to ljudi nisu navikli da ga smatraju operatorom.
'l'errrarnioperator uslovljavanja ?: neobiian je zato 5to ima tri operanda. To je
zaisra operator, posto proizvodi vrednost, za razliku od obidnog iskaza if-else.
Sastoji se ocl tn izraza: ako prvi izrar. (iza koga je ?) ima vrednost true, izradunava
Uobitajene zamke pri koriiienju operatora
Kao Sto je prethodno pokazano, jedna od zamki pri koriSienju operatora jesr,
se izlaz iza ? i njegov rezultat je vrednost operatora. Ako je prwi izraz false,
izbegavanje zagrada kada ste makar i malo nesigurni u nadin izradunavanj;
izradtrnava se treii iz,raz. (iz.a:) i njegov rezultat postaje wednost dobijena opera-
izraza (redosled izradunavan)aizrazapotraZite u svom prirudniku za C).
torom.
Druga veoma uobidajena gre5ka izgleda ovako:
[Is]orn'ri operator se rnoze koristiti zbog sporednih efekata ili zbog wednosti
koju clajc. Ovaj cleo kocla prikazuje oba sh-rdaja: //: C03: Pi tfal 1 . cpp
a = --b ? b : (b = -99); // PogreSne prjmene operatora
Ovrle Lrslo", ltroizvocli dvreclnosr. Promenljivoj a se dodeljuje wednost b ako int mainQ {
jc rezrrltat trnranjcnja b razlicit orl nrrle. Ako b postane nula, a ib dobijaju vred- int a = 1, b = 1;
nost -!)!). Prontenijiva b se uvek urnanjuje, ali joj se dodeljuje -99 samo ako whjle(a = b) (
rrnranjcnje prouzrokuje da b posrane 0. stidni iskaz se moze koristiti i bez ,,a =" //....
siirno zirog sprtreclnog clekta: )

--b ? b : (b = -99); l I I l,-


je clrugo b nepotrebno, poSto se ne koristi wednost dobijena opera- Iskaz a = b ie biti tadan uvek kada je b razlidito od nule. Promenljivoj a st
Ovcle
dodeljuje wednost b a vrednost b se dobija i operatorom =. Hteli smo da kori
toronr. Izrnedu ? i : ntora sc navesti iz.raz. lJ ovom slueaju , taj tzraz bi mogao biti
stimo operator jednakosti == u uslo,u,nom izrazu, a ne operator dodeljivanja
konstanta, Sto bi dovelo do neito brZeg izwsavanja.
Veliki broj programera pravi oru gre5ku (medutim, neki prevodioci ie ukazari n;
problem i to je korisno).
Operator zarez Slidan problem nastaje kada se koriste operatori konjunkcije i disjunkcije nat
'/,arez bitovima umesto odgovarajuCih logidkih operatora. Operatori nad bitovima st
se koristi za raz.clvajanje irncna promenljivih u viSestrukoj deflniciji, na
p rinter: piSu s jednim znakom (& ili l), dok se logidki piSu sa dva (&& i ll). Kao i u sludajr
lnt i, j, k;
- i --, lako se greSkom unese ;'edan znak umesto dva. Korisna rnnemotehnika jr.
,,Bitovi su manji, tako da njihovi operatori imaju man je znakova".
Poglavlje3: CuC++-u lll
il8 Misliti na jeziku C++

Kada ovo razumete, moZda iete krivce za greske najpre potraZiti medu kor
Operatori za konverziJl verzijama. Ali, kako pronalazite konverzije u stilu C-a? To su samo imena tipot
Ret konL,erzija (engl. casr) oznaiava ,,kaluplienje". Prevodilac ie automatski izm#u ,ugru.d.ui, ako krenete u potragu za njima, otkriiete da ih je desto te5l
smisla' Na primer' ako dodelite
fi"troritl iedan tip podatka u drugi ako to imapokretnog zateza, prevodilac ie
razlikovati od ostatka koda.
telobrojni, vrednost prornenljivolu formatu Standardni C++ uvodi operatore zaizriLito konvertovanje, koji mogu u potpr
jednu funkciiu (ili, verovatnije, dodati k6d) za pretvaranje tipa
skriveno pozvati nosti zameniti stari stil konvertovanja u C-u (nararryto, konverzije u stilu C-a
I

float. ornnguiuro izriditu promenu tipova ili promenu tipa koja prevodilaca mogli oznai
int rr Konverz.ija mogu se odbaciti bez narusavanja koda, ali bi ih autori
se inade nebi dogodila. kao"zastarele). Sintaksa izriditih konverzija omoguiava njihovo lako pronalaZen
Konverzija se vrSi tako Sto se tip podataka (ukljudujuii sve modifikatore) Sto se moZe videti po njihovim imenima:
moZe biti
smeita ,.,L,iu. zagrada, Icvo od vrednosti' Vrednost koja se pretvara
promenljiva, konstanta, rezultat iz.radunavanj aizrazaili rezultat funkcije.
ovo je Za,,neproblematidne" i,,prihvatljivo problematidne" konverzil
static-cast
jedan primer: ukliudujuii ono 5to moZete sada postiii i bez konverzije (kao I

je automatska konverziia tiPa).


I I : C03: SimPl eCast. cPP
jnt main0 { const_casl Uklanja const i/ili volatile.
int b - 200; reinterpret_cast Konvertuie u sasvim drugaiiie znadenie. Da biste koristili vre'
unsigned long a = (unsigned long int)b; nost, morate je ponovno konvertovati u originalni tip Tip u ko
\ ll l,- konvertuieuglavnomsekoristisamozapromenubitovailiur
Konvertovanje ie ntoino, ali moze izazvati glavobolje. U nekim situacijama, drugu neobidnu svrhu. Ovo je naiopasniia konverzija'
prevodilac se primorava da koristi podatak kao da je (na primer) Siri nego
Sto
dynamic_cast Zakonverziju u specifidni!i tip, uz proveru ispravnosti tipa (o
zaista,jeste,takodaiezauzetiviseprostoraumemoriji.ZbogtogasemoZe konverzija ie biti opisana u poglavlju 15)'
poka-
oStetiti vrednost drugog podatka. To se obidno dogada pri konvert.ovanju
poput prethodno prikazane'
zivaia, a ne u sludaju;ednostavnih konverziia Prve tri izridite konverzije detaljno opisujem u sledeiim odeljcima' Posledr
C++imadodatnusintaksukonverzije,pouzorunasintaksupozivanja ie biti prikazana tek u poglavlju 15, poSto viSe naudite'
poziva'
fLrnkcije. T.agrade se smeStaiu oko argumenta, kao u sludaju funkcijskog
umesto oko tipa podatka:
Operator static-cast
I I : C03: FunctionCal 1Cast.cPP Operator static-cast se koristi za sve dobro definisane konverzije. Ovim su ol
int main0 { hvaiene ,,bezbedne" promene tipova koje bi vam prevodilac dozvolio bez kt
fl oat a = fl oat (200) ; verzije i manje bezbedne promene koje su ipak dobro definisane. Tip
I I Avo le ekvivalentno sa: pro*".ru koje obuhvata static-cast su: obidne promene tipova bez izridite kt
float b - (float)200; verzije, suZivanje (gubljenje informacija), konverzije iz tipa void*, implicir
\ I ll,- promene tipova i stitieko preparanje tipova u hijerarhiji klasa (poSto joS nisr
ste napisati
LI navecienon.r sltr-aiu, naravno, konverzija vam i ne treba. Mogli videli ktasel nasledivanje, ova poslednja tema ie biti odloZena do poglavlja I
samo 200f (prevodilac ie to i uraditi u gornjem izrazu). uglavnom se
konvertuje
tip promenljivih, a ne tip konstantnih wednosti' //: C03:stati c_cast.cPP
voi d func (i nt) {}

lzricite konverzije u C++-u int main0 {


int i = Ox7fff; // Najveea pozitivna vrednost = 32767
Konverzije treba pazljivo-koristiti, poSto one saopstavaju prevodiocu: ,,zaborai 'I
ong l;
pravila
proveru iipora i .vo koristi kao da je drugog tipa'. To zna(i dazaobllazite fl oat f;
iirt"*u ripova C++-a i spredavate prevodioca da vam saopsti da ste uradili nesto
pogresr.ro .s nekirn tiporn. Sto 1e loilosije, prevodilac vam veruje i ne pokusava da ll 0) }biine promene tipova bez konverzija:
da bude uzrok raznih wsta problema. svaki pro- I = i;
otkrile greske. Konverz-ija mo7-e J - t-
gruni toli mnogo konverzija treba oprezno pregledati, bezobzfta na to sto
'rSi I / Radi 1:
iam ;e ,."4..,o da se tai program ,,morao" tako napisati. U op5tem sluiaju, kon- I = stati c_cast<l ong>(i ) ;
verz-ije bi trebalo primenjiviti retko, i to samo za resavanje odredenih
problema'
f = static cast<f1oat>(i);
t20 Misliti na jeziku C++ Poglavlje3: CuC++-u I2l

ri (2) Su2avanje: //: C03: const_cast. cPP


i - l; I I tlogu se i zgubi ti ci fre int main0 {
t = f; / I Mogu se i zgubi ti podaci constinti=0;
I I Kaie "Znam Sta radim,, i el imjnise upozorenja: int* j = (int*)&i; // NepoZeljnj oblik
j - static,cast<intr(l) ; j = const_cast<int*>(&i); ll }vo je bolje
j . static*cast<intr(f);
char c - static_cast<charr(i);
// Ne moZe se istovremeno vr5iti dodatna konverzija:
lll long* I = const_cast<1ong*>(&i); // Greika
volati.l e int k = 0;
// (3) Promena u drugi ti p i z voi d* :
i nt* u = const_cast<i nt*> (&k) ;
void* vP = ffi'
l/ Start nadin dovodj do opasne prornene:
) lll,-
f1 oat* fp = oat*) vp;
( f1 Ako uzmete adresu konstantne wednosti, dobijate pokazivad na const i on st
// Novi naci n je podjednako opasan: ne moze dodeliti pokazivadu nekonstantnog objekta bez izridite konverzije
fp = stat r c_cast<fI oat*>(vp) ; Konverzijom u starom stilu postiglo bi se isto, ali je const-cast pravo reSenje
Isto vaZi za volatile.
ll (a) t.nplicitne promene tipova, uobicajeno
// ih obav1,la prevodilac: Operator rei nterp ret-cast
double d = 0.0; i najpodloZniji j
ovo je najmanje bezbedan od svih mehanizama konverzije
int x = d; // Autonatska promena tipa greskama. Operator reinterpret_cast posmatra objekat kao Sablon bitova koji s'
x = static cast<int>(d); // lzricitiie
moZe obraditi kao da je sasvirn razlidit tip objekta. Ovo je rukovanje bitovima n
func (d) ; /f nutomatska promena tl pa
niskom nivou, po kome je C poznat. Posle upotrebe, skoro uvek iete morati d
func(static_cast<int,(d)) ; I / lzriUtije operatorom reinterprer_cast wednost watite u prvobitni tip (ili da na neki dru1
\ ilt:- nadin koristite promenljiru kao da je tog tipa) pre nego Sto bilo Sta uradite s njon
U blok. (l ) vidite one vrste promena tipova na koje ste navikli u c-u, sa izridi-
t.nr konverzijom ili bez nje. tJnapredenje iz int u long ili float nije problem, I I : C03l. rei nterpret_cast. cpp
#i ncl ude <i ostream>
posto ti tipovi r.nogu sadrzati svaku celobrojnu vrednost. tuto nije neophodno,
pomoiu static_cast moZete to i naglasiti. using namespace std;
Konverzija u drugom smeru je prikazana u bloku (2). Ovde moZete izgtrtliti
const int
sz = 100;
podatke, posto tip int ni.ie ,,sirok" kao long ili float i ne moZe sadrZati iste
wed- struct X { int a[sz]; ];
nosti brojeva. Zato se takva pretvaranja nazivaju konuerzije suzauanja.prevodi-
lac ie to r-rraditi, ali ie desto dati upozorenje. Izriditom konverzijtm moZete void print(X* x) {
eliminisati o\() r-lpozorenje i ukazati prevodiocu da ste zaista to i nameravali. for(int j 0;'i < sz; i++)
=
Dodeljivanje vrecinosti tipa voidx nekom drugom tipu pokazivada nije cout << x-ra[i] .. ' ';
dozvoljeno bez izridite konverzije u C++-u (za razliku od C_a), iao Sto se vidi u cout << endl << x------------ << endl;
blokLr (3). ovo le opasno izahteva da programeri tadno znaju sta rade.
Kada )
traZite gre5ke, Iakie je pronaii static_cast nego staru standardnu konverziju.
Blok (4) pokazuje implicitnc promene tipova koje prevodilac obidno o-bavlja int main0 (

aLltomarski. ovo se vrsi automatski i ne zahteva izriditu konverziju, ili X x;


static.,cast naglaSava ovu akciju kako bi bilo jasno Sta se de5ava. pri nt (&x) ;
int* xp = reinterpret_cast<int*>(&x) ;
Operator const_cast for(int* i = xP; i < xP + sz; i++)
*i = 0;
Kada konverzijom uklanjate oznaku const ili volatile, koristi se const_cast.
jeclina dopustena konverzija pomoiu const_cast. Ako vam istovremeno
To je // Ne moZe se xp koristiti kao X* na ovom mestu
treba i
neka clruga konverzija, nju morate sprovesti odvojenim izrazomili iete dobiti // sve dok se ne konvertuje u prvobitni tip:
pri nt (rei nterpret_castcX*>(xp) ) ;
greSku pri prevodenju.
ll ll ovon primeru takotle moZete koristiti
I I prvobi tni i dentj fi kator:
pri.nt (&x) ;
,
122 Misliti na jeziku C++ 123
Poglavlje3: CuC++-u

IJ ovonr jednostavnorn primeru, struktura struct x sadrzi niz promenljivih


Sto znadi da moZete komunicirati s C++ kodom i ograniditi asemblerski kOd na
tipa int, ali kada je napravite na steku kao u xx, svi elementi tipa int
sadrZe neophodnu meru radi veie efikasnosti ili upotrebe posebnih procesorskih
srneie (ovo rnozere videti pomoiu tunkcije printO koja ispisuje sadrZaj
stru- instrukcija. Sintaksa koju morate koristiti kada piSete na asemblerskom jeziku
kture). Vrednosr se inicijalizuje konverzijomadrese X u pokazivad
na int, koji pro- zavisi od prevodioca i moZe se pronaii u prateioj dokumentaciji.
lazikroz niz i poptrnjava ga nulama .zapaziteda se gornja granica
zaiizraiunava
,,dodavanjern" sz na xp; prcvodilac zna da se zapravo trazi element za sz
lokacija
pokazivacia rrdaljen od xp i ispravno izradunava pokazivad. lzriciti operatori
Svrha korr'erzijc reinterpret_cast jcste da je ono Sto dobijate
toliko strano da Ovo su rezervisane re(i za operatore nad bitovima i logidke operatore. Pro-
nc nroze biti korisicn., rr prvobitnorn obliku, sve dok se ne izwsi powatna grameri koji na tastaturama nemaju znakove &, l, ^, i ostale, bili su prinudeni da
konve_
rzija. o,clc'idrnr. povl?rnu konverziju pozivu funkcije print, ali posto jo5
tr Xx u koriste uZasne C-ove troznake (engl. trigraph), koji su se naporno unosili i teSko
ru'ek inrate i prvobitni identiflkator, svakako gi mozete toristiii. ditali. Ovo je u C++-u ispravljeno dodatnim rezervisanim redima:
Medutim, xp je
koristan sarn. kao int*, Sto je zaista ,,reinterpretacija,, prvobitnogX-a.
operator reinterpret_cast aesto ukazuje na nepreporualjivol/ili neprenosivo Rezervisanarei Znafenje
prograrniranje, ali jc clostupan ako ga bai morate koristiti.
&& (logiika konjun kcUa)

ll (logidka disjunkcija)
Usam ljeni operator sizeof ! (logicka negacija)
operator sizeof se razmatra posebno posto ispunjava jedan neobidan
zahtev. != (logiiko razliiito)
on.daje informaciju o koridini memorije koja se reierviSe za pojedinadne
podatke. Kao Sto je opisano ranije u ovom pogravrju, sizeofsaopstava(oliko & (konjunkcija nad bitovima)
baj-
tova zauzima konkrerna promenljiva. ovaj operator moZe takode and-eq &= (konjunkcija nad bitovima, s dodeljivanjem)
dati i velidinu
tipa podatka (bez imena promenljive):
| (disjunkcija nad bitovima)
ll: C03:sizeof.cpp or_eq l= (disjunkcija nad bitovima, s dodeljivanjem)
#include <iostream>
a (iskljuiiva disjunkcija nad bitovima)
using namespace std;
int main0 i xor_eq a= (iskljudiva disjunkcrja nad bitovima, s dodeljivanjem)
cout << "sizeof(double) = ,, .. sizeof(double); compl - (nepotpuni komplement)
cout << ", sizeof(char) = ', .. sizeof(char);
I I I l,- Svi prevodioci uskladeni sa standardom C++-a podrZavaju ove rezervisane
clefinicijije vclidina ripa char (signed, unsigned ili obidan) uvek jedan,
Po redi.
bez
obzira ,a to da li char zaista zauzimajedan baji. Za sve druge tipo,re,
rezultat
operarora sizeof jc veliiina u bajtovima.
obratit. paTn j, na to cra je sizeof operator, a ne funkcija. Ako ga primenite na Formiranje sloZenog tipa
tip, nr,ra se koristiti u prethodno prikazanom obliku sa ,agrua;-u. Osnormi tipovi podataka i njihove varijacije su bitni i krajnje jednostami. C i C++
Koristi se i
bez,t.agracla kad ga primenite na promenljivu: obezbeduju alatke za formiranje moinijih tipova podataka od osnovnih tipova.
I/ : C03: si zeof0perator. cpp Kao Sto iete videti, najvaZniji je struktura (engl. struct), koja je osnova klase
jnt main0 { (engl. class) u C++-u. SloZeniji tipovi se najjednostar,nije prave kada se tipu
tnt x; dodeli alternativno ime (pseudonim) pomoiu typedef.
'i
nt i = sizeof x;
| /l I ,-
operaror sizeof nroze dati i velidine namenskih tipova. ovo se koristi
Dodeljivanje pseudonima pomoiu typedef
u Ova rezervisana reE obeiava vi5e nego Sto pruZa: typedef podseia na ,,definicijtr
nastavku knjige.
tipa", dok bi ,,pseudonim" bio ispravniji opis njene funkcije. Sintaksa je sledeia:
typedef opis-posto j eCeg-tipa pseudonim
Rezervisana rea asm
ova rcze^,isa.a red .nroguiava da pisete asemblerski k6d za svoj hardver
unu_
tar(.++ Ilrogrilnrir. Iz irst,nrblcrskog korla sc icsto pristrrpa (_-++ p16rnernljivama,
124 Misliti na jeziku C++ Poglavlje3: CuC++-u t25

typedef se desto se koristi kada su imena tipova podataka sloZenija, da bi se Deklaracija strukture se mora zaw5iti tadkom i zarezom. U funkciji main0 se
skratilo pisanje. Ovo je uobidajena primena rezervisane redi typedef: definiSu dva primerka strukture Structurel: sl i s2. Svaki ima sopstvene verzije
typedef unsigned long ulong; elemenata c, i, f i d. To znadi da sl i s2 predstavljaju grupe potpuno nezavisnih
promenljivih. Da bi se izabrao neki element iz sl ili s2, koristi se taaka (.). To ste
Ako sada upotrebite ulong, prevodilac zna da to znaii unsigned long. MoZda
rnislite cla se to lak5e radi pretprocesorskom zamenom, ali postoje znadajne vei videii u prethodnom poglavlju, pri koriSienju objekata klase - po5to klase
nastaju iz struktura, i sintaksa potiae odatle.
situacije u kojirna prevodilac mora z-nati da ime koristite kao tip, tako da je
neophodno koristiti typedef.
Primetiiete nezgrapnost upotrebe strukture Structurel (ispostavlja se da to
vaZi samo u C, ne i u C++-u). U C-u ne moZete definisati promenljive pi5uii
Pogodnost redi typedef dolazi do izraZala kada se koristi s tipovima poka-
samo Structurel, nego morate pisati struct Structurel. Zato je ree typedef
ziva\a. Kao Sto je ranije spomenuto, ako napiSete:
posebno korisna u C-u:
int* x, y;
dobija x tipa int* i y tipa int (ne int*). Znaii da se '*' vezuje udesno, a ne ulevo.
//: C03:SimpleStructZ.cpp
se
// Primena typedef uz struct
Medutim, ako upotrebite typedef: typedef struct {

typedef nt* IntPtr;


i char c;
IntPtr x, y; int i;
fl oat f;
tadasuixiytipaint*. doubl e d;
Mozete prigovoriti da je izriditije i ditljivije ako se izbegava korisienje pseudo-
) StructureZ;
nima typedef za osno'u.ne tipove. Citanje programa zaista ubrzo postaje kompli-
kovano ako se typedef desto koristi. Medutim, rea typedef postaje posebno int main0 {
znadajna u C-u kada se koristi uz strukture struct. Structure2 s1, s2;
sl.c = 'a';
s1.i = 1;
Kombinovanje promenljivih u strukture s1.f = 3.14;
Rezervisana red struct omoguiuje da se skup promenljivih grupise u strukturu. s1.d = 0.00093;
PoSto definiSete strukturu, mozete napraviti vi5e primeraka promenljivih ovog s2.c = 'a';
,,novog" tipa koji ste izurneli. Na primer: s2.i = 1;
I / : C03:SimpleStruct.cpp s2.f = 3.14;
struct Structurel {
s2.d = 0.00093;
char c; \ //t,-
int i ; Kori5ienjem redi typedef na ovaj naain, moZete se ponaiati kao da je
f1oat f; Structure2 ugraden tip, poput int ili float, kada definiSete sl i s2 (samo u C-u;
doub'i e d;
pokuSajte da uklonite typedef iz C++ programa). Obratite paZnju na to da
); postoje samo podaci - osobine - i da ponaSanje struktura nije opisano, a to je
ono Sto dobijamo od objekata C++-a. Primetiiete da je identifikator strukture
int main0 {
na podetku izostavljeno, po5to je cilj da se definiSe tip. Medutim, postoje sluda-
struct Structurel s1, s2; jevi kada je potrebno koristiti strukturu u njenoj definiciji. U ovim situacijama
s1.c = 'a'; // Element se bira upotrebom znaka ,.,
moZete ponoviti ime strukture i u struct i u typedef:
s1.i = 1;
s1.f = 3.14; //: C03: Se1 fReferenti a1 . cpp
s1.d = 0.00093; // 0mogucava da struktura koristi samu sebe
s2.c = 'a';
s2.i = 1; typedef struct SelfReferentjal (

s2.f = 3.14; i nt i ;
s2.d = 0.00093; SelfReferential* sr; // Urti vam se u glavi?
\ I ll:- ) Sel fReferenti al ;
126 Misliti na jeziku C++ Poglavlje3: CuC++-u 127

int main0 { da pokazuju na razlidite objekte; to omoguiava fleksibilnije programiranje, kao


SelfReferenti a1 sr1, sr2; Sto iete videti.
sr1.sr = &s12; Zasad je
to sve Sto treba znati o strukturama. IoS bolje iete ih upoznati
sr2.sr = &sr1; (naroiito njihove mnogo moinije sledbenike, klase) dok budete ditali ovu
srl.i = 47; knjigu.
srZ.i = 1024t
I lll,- jasnijih programa pomoiu enum
Ako rnalo bolje pogledate, videiete da strukture srl i sr2 pokazuju jedna na
Pisanje
Nabrojivi tip podataka def,ni5e se rezervisanom redju enum, i omoguiuje pri-
drugu, a svaka sadrZi i jo5 neki podatak.
druZivanje imena brojevima, Sto program dini razumljivijim. Rezervisana red
U swari, ime uz struct ne mora biti isto kao ime uz typedef, ali se desto postupa
enum (iz C-a) automatski prebrojava identifikatore bilo koje liste i dodeljuje im
na ovaj nadir.r, radi jednostavnosti.
wednosti 0, 1, 2 itd. Promenljive tipa enum (koje se uvek predstavljaju kao celo-
brojne wednosti) mozete deklarisati. Deklaracija nabrojivog tipa slidna je
Pokazivati i strukture deklaracij i strukture.
[J navedenim primerima se svim stnrkturama rukuje kao da su objekti. Po5to su Nabrojivi tip podataka je koristan kada Zelite da opi5ete svojstvo:
i strukture podaci u n'remoriji, moZe se dobiti njihova adresa (Sto se vidi u
naveclenonr programu SelfReferential.cpp). Da bi se pristupilo elementima //z C03:.Enum.cpp
/ I }pisivanie obl i ka
oclredenc struktrrre, koristi se'.', kao u primeru. Ako imate pokazivad na struk-
tunr, elementima tc strukture morate pristupati pomoiu drugog operatora: '->'. enum ShapeType {
Sledi prirncr: circle,
I I : C03:SimpleStruct3.cpp square,
// Upotreba pokazi vaca na strukture rectangl e
typedef struct Structure3 ( l; ll Mora se zavrsiti taikom i zarezom, kao i struct
char c;
rnt i; int mainO {
f1 oat f; ShapeType shape = circle;
doubl e d; // Akti vnosti ...
) Structure3; // 0vde se radi ne5to, u zavisnosti od vrste obl'ika:
swi tch (shape) {
int main0 { case circle: /* ako je krug */ break;
Structure3 s1, s2; case square: /* ako je kvadrat */ break;
Structure3* sP = &s1; case rectangle: /* ako je pravougaonik */ break;
sp->c = 'a'' )
sP->i = 1' \ / //,-
<n->f = ? ld.
JP
Promenljiva shape je nabrojivog tipa ShapeTlpe, a njena wednost se
sp->d = 0.00093; uporeduje s wednoSiu u listi. Po5to je shape tipa int, to moZe biti bilo koja celo-
sP = &s2; ll Pokazuje na razlic'itu strukturu brojna wednost (ukljudujuii i negativan broj). Celobrojnu promenljivu moZete
SP->C - 'a' '
uporedivati s wedno5iu iz liste.
sP->i - 1'
<n->f Treba imati na umu da se navedeni primer kori5ienja nabrojivog tipa u
= ? ld.
iskazu switch smatra problematidnim nadinom programiranja. C++ ima mnogo
sp->d - 0.00093;
I lll:- bolji nadin za pisanje takvih iskaza, a objasniiu ga kasnije.
Ako vam ne odgovara naiin na koji prevodilac dodeljuje wednosti, to moZete
LI funkciji main0, pokazivai sp u podetku pokazuje na sl, a dlanovi sl se uraditi i sami, kao u primeru:
inicijalizuju tako Sto irn se pristupa operatorom'->' (isti operator se koristi i za
rrtitavar.r je ovih ilanova) . Zatim sp pokazuje na s2 i promenljive se inicijalizuju enum ShapeType (

na isti nadin. I)nrga prednost pokazivada je Sto se mogu dinamidki preusmeriti


circle = 10, square = 20, rectangle = 50
);
I28
Misliti na jeziku C++ Poglavlje3: CuC++-u I. t
ne' prevodilac ie sam uptst- deklarisati vi5e primeraka jednog tipa podataka u uniji (osim ako to radite
Ako nekint ittlctlima clodelite vrednosti' a nekim biste koristili razlidito ime).
r,:rti sledcdtt celobrrljntr vrednost Na prirner:
crackle = 25, PoP };
//: C03:Union.cpp
enum snaP { // Uelieina i jednostavna primena unije
26'
Pret'oclilac prorrlenljivoj pop clodeljuje vrednost #i ncl ude <i ostream>
koristite nabrojive tipove poda-
obratitc paznir.r ,lu,.ra'u].ioa eitilivi;i kada using namespace std;
izvt-st'to; rrleri, poktrSai da se (tr C-u) uradi
'lir jc, tt ono Sto reSavamo
taka.
da iete videti da se u c++-u enum retko koristi. union Packed | // Deklar.iie se slidno kao klasa
porr.roiu klasa r.r c++-u, tako
char i;
short j;
Provera tiPa u sluiaju nabrajanja
"tralnle .i
nt k;
s' jednostami' povezuju celobroine
C-ovi nabroiivi tipovi po'aututu long 1;
weclnosti s imenima, aii ne obezbecluiu proveru
tipa' U C++-u se' kao Sto vero-
fl oat f;
i za nabrajanja' Kada definisete
vatno i odektliete, tip stro;o proverava'a ovo vaZi doubl e d;
nabrojiv tip, zapravo ;;*i" nov tip' Iednako postupate. i s klasom: ime biti velidine tipa
prevedenoj celini' // Unija de
nnt.,ruiiuog ,ipa postale rez-ervisana red u toi // double, posto je to najiiri element
Osirn toga, provera ,ipo,u nabrojive-podatke je stroZa u C++-u nego u C-u' l:// Na kraju deklaracije je taeka i zarez, slidno strukturj
'u napisati a++' a na
Utotito a piim"rat nabrojivog tipi color' na C-u moZete
1e
nabrojivog tipa podrazumeva dve
C++-u ne moZete' nuriog ;"'Sto"t'utiu'ut'i" int main0 {
je u C++-u' a druga nije' Prvo se cout << "sizeof(Packed) =
k,nverzile tipova, ,ra toiitr iedna doz-voljena
se wednost
"
iz color u int, zatim
vre.d,ost nabroiivog tlpu'ir.,..,p'.itno konveriuie << sizeof(Packed) << end1.
U C++-u ovo niie dopusteno'
uveiava i najzad ." ini konu.rtuie nazad u color. znati da
Packed x;
je logidno' jer' kako moZete x.i ='c';
poSto je color poseba" iip, t"'iieit od in1
.To
Ako iroiete da uveiavate vrednost tipa cout << x.i << endl;
ie rrveda.. vreclnosr uiii'tr tisri boia?
uveiavania)'
color, riicla 5i rrt:5a6 ,i., toy tip realilujete kao klasu
(sa operacijom x.d = 3.14159;
nc kao nattrojrvi tifr"f-l,,.f,tlnfto, pt'ito ie klasa mnogo bezbednija' KOd koii cout << x.d << endl;
a
oznadava kao potenci- ) / / /,-
zahr.,a irr.rplicitn, kgnrlerziju u nabrojivi tip prevodilac
jalntt greSktt. Prevodilac ispra'rno dodeljuje wednost izabranom ilanu unije.
Na rrnijc (opisane u nastavku) slidno se
primeniuie dodatna provera tipova u Posle dodele wednosti, prevodilac ne vodi raduna o tome Sta radite s unijo
(,++ -t t. u navedenom primeru, mogli ste uniji x dodeliti wednost u formatu pokretn
zarezai

Uiteda memorije Pomoiu unija x.f = 2.222;


"rukovati tipovima podataka pomoiu iste
I)o.ekacl ie progranr razliditim i zatim p oslati wednost na standardn i izlaz kao daj e tipa int:
mozete napraviti strukturu
promenllive. d ovoj situaciji imate dve moguinosti: cout << x.i;
tipove koji su vam potrebni ili moZete upotrebiti
koja sarirT-i sve nroguie razli'ite
pravi unila, tip koii slaie sve podatke u isti plostol odreduluii To bi, naravno, bilo besmisleno.
rec union.'lintc se
nulsiti element Upotrebite union da biste
r,e'liii.r.t prostorit pni,.i,nng 'u
uStcdeli menlori jskr prostor'
unije, ali koristi samo N izovi
\lrednost sc svaki pr.rt smesta oi1 istog mesta na poietku Nizovi su wsta sloZenog tipa i omoguiavaju da grupisete veii broj promenljiv
onoliko prostora koliko joi le neophodno' Na taj nadin
pravite "super-
Sve adrese pro-
jednu za drugom, pod istim imenom. Ako napi5ete:
unije.
pronrcnljivrr,, koja moTe cra iaclrzi bilo koju promenljivu
n-I.nr;*i1., unije sir jednake (arirese polja u klasi, odnosno strukturi, razlidite su)' int a[10];
upotrebe uniie' Poku5ajte da uklonite razlidite ele-
Slecii primer jednostavne rezervi5ete prostor za l0 promenljivih tipa int, sloZenih sekvencijalno u mem
oclrazava na velidinu unlje. zapazite da nema smisla
nrenrc i vidite kako se to r||i, bez jedinstvenih imena za svaku promenljir.u. umesto toga, promenlji
imaju zajednidko ime a.
i30 Misliti na jeziku C++ Poglavlje3:CuC++-u l3r

Da bi se pristupilo elem.entu riiza, koristi se ista sintaksa sa uglastim zagra- Da biste videli da je svaki element u memoriji pored sledeieg, prikazite
dama, kao i za definiciju niza: njihove adrese na sledeii nadin:
aIs] = a7; / I : C03 : ArcayAddresses. cpp
#i ncl ude <i ostream>
Iako je ntza ueliiine 10, elementima niza pristupate od nule (ovo se ponekad
naziva indeksiran.ie od nule, engl. zero indexing), tako da moZete pristupati ele-
using namespace std;
mentima 0-9, kao ir prirnertt:
int main0 {
ll: C03:Arrays.cpp 1nt a[10];
#include <iostream> cout << "sizeof(1[t) =".. sizeof(int) << endl'
us i ng namespace std; for(1nti=0;i<10;i++)
cout << "&a[".. i << "] -- "
int main0 { << (1ong)&aIi] << endl.
int a[10]; I lll,-
for(inti=0;i<10; i ++) {
Kada izvr5avate ovaj program, videiete da je svaki element udaljen od pre-
a[i]=i*10;
cout << "a[" " i " ,,] = ,, .. a[i] << endl . thodnog za velidinu tipa int. To znadi da su poredani sekvencijalno.
)

I I I l,- Pokazivaii i nizovi


Pristup nizu je izuzetno brz. Medutim, ni5ta vas ne spredava da upotrebite Ime niza se razlikuje od imena obidnih promenljivih. Iedna od razlika je Sto ime
veii indeks od maksimalnog - pristupaiete drugim promenljivama. Drugi nedo- niza nije lr,,rednost; ne moZe mu se dodeljivati wednost. Ime niza je samo deo
statak je 5to veliiina niz.a mora biti definisana u weme prevodenja; ako hoiete da identifikatora u sintaksi sa uglastim zagradama, a ako navedete samo ime niza,
promenite velidinu niza tokom izvrsavania, za to ne moZete koristiti navedenu bez uglastih zagrada, dobijate podetnu adresu niza:
sintaksu ((. inra naiin cla dinamidki Itapravi niz, ali je to mnogo komplikovanije). //: C03:Arrayldenti fier.cpp
C++ ima tip vector, predstavljen u prethodnom poglavlju. Vektor je objekat slidan #i ncl ude <i ostream>
nizu koji automatski menja velidinu. Zato je mnogo bolje primeniti vektor ako using namespace std;
velidina niza nije poznata u vreme prevodenja.
MoZete definisati niz bilo kog tipa, dak i niz struktura: int mainfl {
: C03 StructArray.cpp
int a[10];
/ I cout << "a = " << a << endl;
// Ni z struktura
cout << "&a[01 =" << &a[0] << endl;
typedef struct {
I ///,-
int j, j, k; Pri izvr5avanju programa, videiete da su ove dve adrese iste (biie ispisane u
) ThreeDpoi nt; heksadecimalnom formatu, poSto nisu konvertovane u tip long.
Lakse iete sve ovo razumeti ako ime niza posmatrate kao pokazivai na
int main0 { podetak niza, dostupan samo za ditanje. Iako ne mozemo promeniti ime niza
ThreeDporrt p[10]; tako da pokazuje na drugu lokaciju, moiemonapraviti drugi pokazivad i koristiti
for(int i = 0; i < 10; i++) { ga za kretanje po nizu. U stvari, sintaksa sa ugaonim zagradama moZe da se pri-
p[r].i = i + t; meni i na pokaziva(,e:
p[il. j = i + 2;
p[r].k = r + :; / / : C03 :Poi ntersAndBrackets. cpp
int main0 {
)
int a[10];
\ ll l,- int* iP = 6'
Zapaz.\te da je element i strukture nezavisan od promenljive i u petlji for. for(inti=0;i<10;i++)
iP[i]=i*10;
I ///,-
132 Misliti na jeziku C++ Poglavlje3: CuC++-r.r l3

einjenica da se navodenjem imena niza dobija njegova poaetna adresa postaje kopiju niza koji prosledujete funkciji. Znaei, kada menjate niz, uvek menja
veoma znacajna kad hoiete da prosledite niz funkciji. Ako deklarisete niz kao spoljni objekat. To vas moZe malo zbunjivati na poaetku, ako oiekujete pro
argurnent tirnkcije, zapravo deklarisete pokazivad. Na taj naein, funcl0 i func2O ledivanje po wednosti koje omoguiavaju uobiaajeni argumenti.
Lr sledeiem primenr imaju iste liste argumenata:
Primetiiete da se u lunkciji printQ koristi sintaksa sa uglastim zagradama
I I : C03: ArrayArguments. cpp argument koji je niz. Kada niz prosledujete funkciji kao argument, ravnopravl
li ncl ude <i ostream> mozete koristiti sintaksu pokazivada ili sintaksu s uglastim zagradama. Kada
ti ncl ude <strr ng> koriste uglaste zagtade, ditaocu je jasnije da je argument niz.
usr ng namespace std; Zapazite da se argument size (velidina) prosleduje u svakom sludaju. pr
sledivanje same adrese niza nije dovoljno; morate znati i koliki je niz u funkc
vojd funcl(lnt a[], int size) { da ne biste prekoradili kraj.
for(int i = 0; i < size; i++) Nizovi mogu biti bilo kog tipa, ukljudujuii i nizove pokazivada. Zapravo, (
a[i] = i * i - j; C++ imaju posebnu listu argumenata za funkciju main0, koia prihvata arg
)
mente s komandne linije programa.
void func2(int* a, int size) { int main(int argc, char* argv[]) { // "."
for(int i = 0; i. size'i++) Prvi argument ie broj elemenara niza, drugi argument je taj niz. Drugi arg
a[r] - ' r + r; ment je uvek niz elemenata tipa char*, posto se argumenti prosleduju
i komandne linije kao nizovi znakova (ne zaboravite, niz se moze proslediti san
kao pokazivad). Svaka od grupa znakova, koje su razdvojene prazninom, l
vord prrnt(int a[], strrng name, int size) i komandnoj liniji postaje poseban niz. Sledeii program ispisuje sve argumen
for(int i = 0; i < size; i++) sa komandne linije, prolaze (ikroz niz:
codt << nale << "[" .. i .. "l = '
t' aIi] << endl; //: C03 : CommandLi neArgs. cpp
)
#include <iostream>
using namespace std;
jnt majn0 {
int a[5], b[s]; int main(int argc, char* argvU ) {
// Verovatno besmi sl ene vrednosti :
cout << "argc = " << argc << endl;
print(a, "a", 5); for(int i = 0; i < argc; -i++)
pri nt (b, "b", S) ; cout << "argv[" .. i .. "] = "
/ I lntsiiulrzacija nizova:
.. argv[i] << endl;
funcl (a, 5); I / / /t-
funcl (b, 5) : Primetiiete da se u nizu argv[O] nalaze putanja i ime samog programa. O,
prlnt(a, "a", 5) ; omoguiava programu da otkrije informacije o sebi. Time se dodaje jedan el
pri nt (b, "b", S) ; ment nizu argumenata programa, a programeri desto greSe pri iitanju argum
ll Prinetite da su nizovj svakako izmenjeni: nata sa komandne linije jer uzimaju argvl0l umesto argvlll.
func2 (a, 5) ; Ne morate koristiti argc i argv kao identifikatore u funkciji main0; ovo su kor
func2 (b, 5) ;
vencionalna imena (ali, biie zbunjujuie ako ih ne koristite). postoji i alternativ
print(a, "a", 5); nadin da se deklari5e argv:
print(b, "b", S);
\ lll,- i nt mai n (i nt argc, char** argv) { / / .. .

Iako su argilrnenti lLrnkcija funcl0 ifunc20 razliiito deklarisani, oni se ova dva oblika su ekvivalentna, ali mislim da se verzija korisiena u ovoj knji
koristc na isti naiin. ovaj prirner trkazuje na sledeie: nizovi se ne mogu pro- lakSe razume, poSto neposredno saop5tava: ,,Ovo je niz znakovnih pokazivada"
sleclivati po vrcdnosri:1, Sto znadi da nikada automatski ne dobijate lokalnu S komandne linije dobijate samo nizove znakova. Ako hoiete da sa argumer
tom radite kao da je nekog drugog tipa, morate ga konvertovati. Da bi se olaksa
osirn ako raurrncre vr'onra s(ro!l pristtrp cia ,,se svi argunrenti u c-u i c++-u prosleduju po wednosti, a konverzija u brojeve, postoje pomoine funkcije u standardnoj c bibliotec
'r'reclnost' niza je ono slo predstavlja njegovo ime: adresa". Ovo ntoZe biti tadno sa stanoviSti asemblerskog
iczika, ali nlislim cla nije pritrten)jivo na viSem nivou. Dodatno, reference u C++-u dine ,,prosledivan;e samo
lltt vredtlosli' arglltltcnala zl)unjujlr(:inr, toliko da smatram da je korisnije raznti5ljati o,,prosledivanju po
trlrlttrr.li' trr'go.Iro.lr,rltrtrnjtr ttrlrr,r;t'
Misliti na jeziku C++ Poglavlje3: CuC++-u t35
134

)
deklarisaneu<cstdlib>.Najjednostavnijesekoristeatoi(),atol()iatofOzakon. double d = atof(argv[1]);
verz.iiu ASCII niza
i"l.l:"* i double' ovo ie primer kori-
,nutouu?'ila*tiiiip" unsigned char* cp
pozivaiu na isti nadin):
=

;;i; i;;k;tie atoig tat"g" dve funkciie se


reinterpret_cast<unsigned char*>(&d) ;
: CO3:ArgsTolnts'cPP
for(int j = sizeof(double); 1 > 0 ; i -= 2) {
I I linije u cele brojeve pri ntBi nary (cp Ii - 1] ) ;
// Konverzija utg"tnu'u s komandne
pri ntBi nary (cp Ii ] ) ;
#include <iostream>
#i ncl ude <cstdl i b> )

us i ng namesPace std;
| ///:-
Prvo, program utwduje da ste mu prosledili jedan argument tako Sto prove-
int main(int argc, char* argvU) ( rava wednost argc. Vrednost je dva ako postoji jedan argument (jedan je ako
for(int i = 1; i < argc; i++) nema argumenata, po5to je ime programa uvek prvi element niza argv). Ako
cout << atoi (argv[i]) '< endl; postoji greSka, ispisuje se poruka i poziva se standardna funkcija exitQ, kojom se
\t ltt'
il1.- zawSava rad programa.
ovog pro-
argumenata na komandnu liniiu
MoZete staviti proiz-volian broj ime programau Argument s komandne linije konvertuje se u tip double funkcijom atofQ.
srama. Primetiiete
o' pliii' r"i rytt"i::9 t*ako bi preskodila
tadku' Zatim se broj tipa double obraduje kao niz bajtova tako Sto se uzima adresa i
argvl0l Ako na rnntiniit' liniiu upiSete broi koii sadrZi decimalnu konvertuje se u tip unsigned char*. Svaki od ovih bajtova se prosleduje funkciji
funkcije atoiO za
funkciia atoi0 dita tuilo tif" ao aeiimatn" tuekt' V"dnost printBinary0 radi prikazivanja.
nenumeridke Podatke je nula Ovaj primer je podeSen tako da ispisuje bajtove redosledom po kome se prvo
pojavljuje bit za znak - na mom radunaru. VaS je moZda drugadiji, tako da iete
zateza
lstra2ivanje formata pokretnog
hteti da preuredite nadin ispisivanja. Treba imati na umu da brojeve u formatu
je za
prikizana u ovom poglavlju' pogodna
*t'i-ir]: poketnog zareza oije Iako razumeti. Na primer, eksponent i mantisa u opStem
Funkciia printninary(i ie format
ispitivar.rje interne *"th l'1"^'^1.l"dataka' Najzanimljiviji
velikih i veoma
sluiaju nisu ogranideni bajtovima, nego je odredeni broj bitova rezervisan za
pokretnog
"*ti""
zareza Koliu C-u i C++-u omoguiava duvanje veoma
potpunosti
svaki od njih i oni se pakuju u memoriju Sto je gu5ie moguie. Da biste videli Sta se
iako se ovde ne mogu u
malih broievu u o*'ui'J"'iorn pto"n'u'
de5ava, treba da otkrijete velidine svih delova broja (uvek je iedan bit za znak, ali
unutar tipova float i double pode- su eksponenti i mantise razliditih velidina) i odvojeno ispiSete bitove svakog dela.
izloZiti svi detalji, t"p"*"t"it"'ia
su bitovi
i bit za znak' To znaii da se za euvanje
ljeni u tri oblasti: tk5;;;;;;' '"^ntisu omoguiava da-eksperimen-
vrednosri koristi nau"#;;;';;ii;';itJecip'ogrum u formatu pokretnog zateza' Aritmetika pokazivata
.urtieitih broiLva
tisete, ispisuiuii uina'rrie sem. format pokretnog Kada bi pokazivad na niz samo bio alternatirmo ime niza, takvi pokazivadi ne bi
Sami (etc izvestl zatliuike o iemi tolu prevodilac koristi za bili narodito zanimljivi. Medutim, pokazivadi su mnogo fleksibilniji, po5to se
ga se vas pre-
za pokretni zarez, ali mozda
zareza (obidn. i. ,"'i'nii,,i".a"ra mogu izmeniti tako da pokazuju negde drugde (ali, treba zapamtiri da se ime
vodilac ne PridrT-ava) : niza ne moZe tako koristiti)"
Termin aritmetika pokaziuaia odnosi se na primenu aritmetiekih operatora
I I : CO3: Fl oati
ngAsBi narY ' cPP
na pokazivade. Aritmetika pokazivada je drugadija od obidne aritmetike zaro Sto
//{Li PrintBinarY
se pri primeni pokazivada moraju po5tovati posebna ogranidenja da bi se oni
//(T) 3.141se
ispravno pona5ali. Na primer, uobidajeni operator koji se primenjuje na poka-
#include "PrintBinarY'h"
+i ncl ude <cstdl i b> zivade je ++, koji ,dodaje jedinicu pokazivadu". Ovo znaii da se pokazivad menja
#i nc'l ude <i ostream> tako da pokazuje na,,sledeiu wednost", Sta god to znadilo. Ovo je primer:
usi ng narnesPace std; // : C03 :Poi nterl ncrement. cpp
#include <iostream>
int main(int argc, char* argvU) t using namespace std;
if(argc l= ,\ I I i ni ju" << endl ;
cout << 'ri.jt," uneti broj na
komandnu
int main0 {
exit(1); int i [10];
double d[10];
int* ip = i'
136 Misliti na jeziku C++ Poglavlje3:CuC++-u r37

double* dp = d; Tako moZete videti da prevodilac ispramo pomera pokazivade na strukture


cout << "ip = " << (1ong)iP << endl' (aliiklaseiunije).
iP++' Aritmetika pokazivada radi i sa operatorima --, + i -, ali su poslednja dva ope-
cout << "ip - " .. (long)iP << endl' ratora ogranidena. Ne moZete sabirati dva pokazivada, a ako oduzmete poka-
cout << "dp = " << (1ong)dP << endl' ziva(,e, rezultat je broj elemenata izmedu ta dva pokazivada. Medutim, moZete
dP++ ' sabirati i oduzimati celobrojnu vrednost i pokazivad. Ovaj primer prikazuje pri-
cout << "dP = " .. (long)dp " endl; menu aritmetike pokazivada:
I lll,- I I z C03:Poi nterAri thmeti c.cpp
Pri jednom izvr5avanju na mom raaunaru, dobija se: #include <iostream>
ip = 6684124 using namespace std;
ip = 6684128
dP = 6684044 #define P(EX) cout << #EX << ": " << EX << endl;
dp = 6684052
int main0 {
Zanimljivo je da, ako se koristi ista operacija ++ i za int* i za double*, poka- int a[10];
zivad se pomera samo za 4 bajta za int*, ali za B bajtova za double*. Nije sludaj- for(inti=0;i<10;i++)
nost da su to velieine tipova int i double na mom radunaru. U tome je trik aIi] = i; // Dodeljuju se vrednostj indeksa
raitrnanja sa pokazivaaima: prevodilac odreduje za koliko treba izmeniti poka- int* iP = 6'
z-ivad da bi on pokazivao sledeii element u nizu (aritmetika pokazivada ima P(*ip);
smisla samo unutar nizova). Ovo deluje dak i sa nizom struktura: P (*++i P1 '
I I : C03: Poi nterl ncrement2. cPP P(*(iP + 5));
#i ncl ude <i ostream> int* iP2 = ip + 5;
usi ng namespace std; P (*i p2) ;
P(*(ip2 - a));
typedef struct {
P(*--i p2) ;
char c; P(ip2 - ip); // Daje broj elemenata
short s; ) I I l,-
i nt i ; Makro na poaetku koristi svojswo pretprocesora pod nazivom dodauanje
long 1; nauodnika oko znakounog niza (engl. stringizing) - realizuje se znakom '#'
float f; ispred izraza. Ova karakteristika pretvara bilo koji izraz u znakolTti niz. To je
doubl e d; pogodno, po5to omogudava ispisivanje izraza, dve tadke i wednosti izraza. tJ
1 ong doubl e 1 d; funkciji mainQ moZete videti ovaj korisni skraieni zapis.
) Primi ti ves;
Iako se i prefiksne i sufiksne verzije ++ i -- mogu primeniti na pokazivade, u
primeru se koriste samo prefiksne verzije po5to se primenjuju pre dereferenci-
int main0 {
ranja pokazivada u navedenim izrazima, tako da omoguiavaju da vidite rezul-
Primitives pIt0];
Primitives* pp = pi tate ovih operacija. Zapazite da se dodaju i oduzimaju samo celobrojne
cout << "sizeof(Primitives) = " wednosti; prevodilac ne bi dozvolio ovakvo kombinovanje pokazivada.
.. sizeof(Primitives) " endl; Ovo je rezultat navedenog programa:
cout << "PP = " " (long)PP t' endl; *ip: o
pp++; *++i p: I
cout << "pp = " .. (long)PP << endl; *(iP + 5): 6
I lll,- *ip2:6
*(ipZ - 4): 2
Pri jednom rzvrSavanju na mom raaunaru, dobija se: *--i p2: 5
srzeof(Primitives) = 4g
pp = 6683764 Svi izrazi sa pokazivadima u svim sludajevima daju pokazivai, izmenjen tako
= 6683804 da pokazuje na,,pravo mesto", izradunato pomoiu Sirine elementa na koji poka-
PP
zuie.
r38 Misliti na jeziku C++ Poglavlje3:CuC++-u t39

Ako aritntetika pokazivaca, na prvi pogled, malo zbunjuje, ne brinite. Veiina C i C++ prevodilaca dozvoliie vam da defini5ete pretprocesorski indika-
Naj-eSie treba samo da definiSete nizove i pristupate njihovim elementima tor i s komandne iinije, tako da moZete ponovo prevesti k6d i dodati informacije
pomoirt [], a najsloZenija operacija s pokazivadima ie obidno biti ++ ili --. Arit- za otkrivanje greSaka pomoiu jedne komande (poZeljno datoteke makefile, Sto ie
metika pokazivaea se uglavnom koristi u moinijim i sloZenijim programima, a biti ukra&o opisano). Detalje potraZite u dokumentaciji svog prevodioca.
kontejneri standardne C++ biblioteke naldeSie skrivaju veiinu ovih detalja, tako
da o njirna ne moratc brinuti.
lndikatori za pronalaZenje greiaka tokom izvr5avanja
U nekim situacijama je pogodnije ukljudivati i iskljudivati indikatore za otkrivanjc
greSaka tokom izvr5avanja progama, narodito s komandne linije' Zamorno je
Saveti za pronalaZenje g reiaka ponovo prevoditi velike programe samo da bi se dodao kod za otkrivanje gresaka.
U idealnorn sludaju, na raspolaganju imate odlidan program za nalaZenje Da bi se kod za otkrivanje gresaka dinamidki ukljudivao i iskljudivao, defini-
greSaka, koji lako otkriva ponaSanje programa i brzo pronalazi greSke. Za veiinu
Site Iogidke indikatore:
prograrra za pronalaZenje greSaka postoje nevidljive tadke i to zahteva da u pro-
granr ubacujete delove koda, koji vam pomaZu da razumete Sta se deSava. Osim //: C03 :Dynami cDebugFl ags.cpp
toga, moZda razvijate program u okruZenju (kao Sto je ugradeni sistem, u #include <iostream>
kakvom sam proveo svoje stvaraladke godine) koje nema program za otkrivanje #include <string>
using std;
namespace
gre5aka i moZda daje samo Sture powatne informacije (na primer, linijski LED
ll Indikatorj za otkrivanje greSaka ne moraju biti globalni:
displej). U ovakvim slueajevima postajete kreativni i pronalazite razne nadine za
bool debug = false;
otkrivanje i prikazivanje informacija o izvrSavanju programa. Ovaj odeljak pre-
poruduje neke tehnike. int main(int argc, char* argv[]) {
for(int i = 0; i < argc; i++)
lndikatori za pronalaZenje gre5aka if(string(arqvIi]) == "--debug=ukliuci ")
debug = true;
Ako kod za otkrivanje gre5aka umctnete direktno u program, moZete upasti u
bool go = true;
problerne. Dohijatc previ5e informacija, sto oteZava izolovanje gre5aka. Kada
whi I e(go) {
pornislite da ste pronaSli gre5kr.r, podinjete da uklanjate kOd za njeno otkrivanje,
i f(debug) {
i ubrzo saznajete da ga morate vratiti. Ove probleme moZete reSiti pomoiu dve )vde ie kOd za otkrivanje gre5aka
ll
vrstc indikatora, a to su pretprocesorski indikatori za otkrivanje gre5aka i izwSni cout << "0tkrivanje gresaka je sada ukliuceno!" << endl;
indikatori. ) else {
cout << " 0tkrivanje gresaka ie sada iskliuceno." << endl;
Pretprocesorski indikatori za pronalaZenje greSaka )
Pomoiu pretprocesorske komande #define moZete definisti jedan ili viSe indi- cout << "0tkrivanie gresaka [ukljuci/iskljuci/krai]: ";
katora za pronalaZenje gre5aka (najbolje u datoteci zaglavlja).lndikator moZete string reply;
ispitivati pomoiu pretprocesorske komande #ifdef i uslovno ukljuditi k6d za cin >> reply;
otkrivanje gre5aka. Kada mislite da je zawSeno otkrivanje greSaka, primenite if(reply == "ukljuci") debug = true; // Ukljudi otkrivanje gre5aka
#undef na indikator(e) i k6d ie se automatski ukloniti (smanjiiete velidinu if(reply == "iskliuci") debug = false; // Iskl3udi
izvrine datoteke i trajanje njenog izvr5avanja). if(reply == "krai") break; /l |zlaz iz 'while'
Nalbolle je da srnislite imena indikarora za otkrivanje gre5aka pre podetka )

izgradnje projekta, da bi imena ostala konsistentna. Imena pretprocesorskih I / / /,-


indikatora se, po tradiciji, piSu velikim slovima da bi se razlikovala od imena ovaj program dozvoljava da ukljuiujete i iskljudujete indikator za otkrivanje
promenljivih. lJobidajeno ime indikatora je DEBUG (ali, pazite da ne upotrebite gresaka sve dok ne unesete ,,kraj" i tako oznaiite da ste zawsili tad. Zapazite da
NDEBUG, koje je rezervisano u C-u). Niz iskaza bi mogao biti: se zahteva unos celih redi, a ne samo slova (moZete, ako hoiete, uvesti skaie-
nice). Argument komandne linije se moZe koristiti opciono, da bi se otkivanje
#define DEBUG l/ Verovatno u datoteci zaglavlja
greSaka ukljudilo pri aktiviranju programa - ovaj argument se moZe nalaziti bilo
/t... gde na komandnoj liniji, posto se ispituju svi argumenti. Testiranje je sasvim
#ifdef DEBUG ll Provera da li je indikator def.inisan
/* ovde je kod za otkrivanje gresaka */ jednostavmo, s obzirom naizraz'.
#endif // DEBUG stri ng (argv Ii ] )
t40 Misliti na jeziku C++ Poglavlje3:CuC++-u l4

Od niz-a znakova argvtil pravi se objekat tipa string, koji se zatim moZe lako Makro assertO
uporedivati pomoiu operatora ==. Program traZi kompletan znakormi niz U standardnoj datoteci zaglavlja <cassert> pronaii iete makro assertQ, pog,
--debug=ukljuci. PotraZite --debug= i pogledajte Sta sledi iza toga, da biste dan za otkrivanje gre5aka. Makrou assert0 prosledujete argument, izraz zakr
otkrili viSe nroguinosti. U drtrgom tomu (dostupan je na www.BruceEckel.com) ,,twdite da je tadan". Pretprocesor generiSe k6d koji ie proveriti rwdenje. Al
postoji celo poglavlje posveieno standardnoi klasi string u jeziku C++' fvrdenje nije istinito, program ie se zaustaviti posle ispisivanja poruke o greS,
Ilelativno sr-r n'ralobrojni sludaievi kada ima smisla koristiti globalnu promen- koja vam saop5tava koje twdenje nije bilo tadno. Ovo je jednostavan primer:
Ijii,u. MoZete je primeniti u indikatoru z-a otkrivanje greSaka, ali nije obavezno.
Zapaz,ite da ie promenljiva napisana malim slovima, da bi se ditalac podsetio da
//: C03:Assert.cpp
to nije pretprocesorski indikator.
// Upotreba makroa assert0 za otkrivanje greSaka
#include <cassert> // SadrZi makro
using namespace std;
Pretvaranje u znakovne nizove 'i nt mainO (
Pri sastavljanju koda za otkrivanje greSaka, naporno je pisati poruke koje se
sastoje od niza znakova, imena promenljive i njene wednosti. Sredom, stan-
int i = 100;

dardni C pretprocesor podrZava operator'#' za dodauanie nauodnika oko znak-


assert(i != 100); // netadno

ot,nog niza, koji je ranije kori5ien u ovom poglavlju. Kada napi5ete # ispred
t //t:
argumenta u pretprocesorskom makrou, pretprocesor pretvara argument u niz Makro potide iz standardnog C-a, tako da je dostupan i u datoteci zaglav
znakova. Ovaj operator (setite se da se nizovi znakova, koji nisu razdvojeni inter- assert.h.
pLrnkci.jskim z-nakovima, spajaju u jedan niz znakova) omoguiava da napravite Kada zaw5ite otkrivanje gre5aka, moZete ukloniti kOd generisan makroo
veorra pogodan rnakro za ispisivanje vrednosti promenljivih tokom otkrivanja U programu, pre ukljudivanja zaglavlja <cassert>, navedite
greSaka: #defi ne NDEBUG

#define PR(x) cout << #x " = " << x <' "\n"; Umesto toga, moZete da defini5ete indikator NDEBUG na komandnoj lir
lspisivanje promenljive a pomoiu makroa PR(a), to ie imati isti efekat kao prevodioca. Ovaj indikator se koristi u zaglavlju <cassert> za promenu nadi
k6d: generisanja koda.
Kasnije iete u ovoj knjizi videti neke sloZenije zamene makroa assertQ.
cout << "a = " << a .< "\n";
Isti postr,rpak moZe da se primeni i na kompletne izraze. Sledeii program
koristi makro da bi skratio ispisivanje izraza sa dodatim navodnicima, zatim Adrese funkcija
izraiunava vrednost izr aza i prikazu j e rezultat: Po5to se funkcija prevede i udita radi izvr5avan;a, ona zauzima cieo memorije.
II: C03:StringizingExpressions.cpp memorija, samim tim i funkcija, ima adresu.
#include <iostream> C je uvek omoguiavao pun pristup svim pojedinostima programa. Adrt
us r ng narespace std; funkcija moZete koristiti s pokazivadima, kao Sto moZete koristiti adrese pr
menljivih. Deklaracija i upotreba pokazivada na funkcije u podetku deluju mr
#defjne P(A) cout << #A << rr' rr << (A) .. 9.6l' nepristupadno, ali su konsistentne s drugim elementima jezika.

int main0 {
int a = 1, b = 2, c = 3; Definisanje pokazivada na funkcije
P(a); P(b); P(c); Da bi se definisao pokazivad na funkciju koja nema rezultat ni argumente, tre
P(a + b) ; napisati:
P((c - a)/b); void (*funcPtr) 0;
\ ll l,- Kada posmatrate neku sloZenu definiciju kao Sto je ova, najbolji nadin je
-fehnika poput ove ubrzo mo7-e postati neophodna, narodito ako nemate pro-
podete od sredine i pronadete izlaz. ,,Pod od sredine" znadi da se poiinje
gram za otklanjanje gresaka (ili morate koristiti viSe razvojnih okruZen;'a). Kada imena promenljive, u ovom sludaju funcPtr. ,,PronalaZenje izlaza" zna(i
hoiete da izostavite otkrivanie greSaka, dodajte komandu #undef kako bi ime traZite najbliZi element s desne strane (u ovom sludaju ga nema, ubrzo r
P(A) postalo,,nedefi nisano''. zaustavlja desna zagrada), zatim gledate levo (pokazivad oznaden zvezdicor
142 Misliti na jeziku C++ Poglavlje3: CuC++-u r43

zatirn glt,date clesno (prazna lista rrkaztrje da funkcija nema argumente), zatim Broj 4 je deklaracija funkcije, a ne definiciia promenljive. KaZe da ie "f4
glerlate levo (void trkaz.ujc da irrrrkcija nema rezultat). Ovo kretanje desno-levo funkcija koja waia pokazivad na niz od 10 pokazivada na funkcije koje waiaiu
-clesno jc pogoclno za veiinrr deklaracija. cele brojeve".
I)ogledajrno ponovo: ,,polazite od sredir.re" (,,funcPtr je..."), idete desno MoZda vam nikad neie trebati ovako sloZene deklaracije i definicije ili iete ih
(nenra nicega, zarrstavlja vas desna zagrada), idete levo i nalazite'*'(,,...poka- retko koristiti. Ako naudite da otkrivate njihovo znaaenje, nikada vas neie uzne-
zivai.,."), idete desno i nalazite praznu listu argumenata (,,...funkcije bez argu- miriti kad u praksi naidete na njih.
menata..."), idete levo i nalazite void (,,funcPtr je pokazivad na funkciju bez
argumenata koja nema rezultat").
MoZda se pitate zaito *funcPtr mora da se stavi u zagrade. Da ih niste kori-
Kori5ienje pokazivaia na funkcije
stili. prcvodilac hi vidco: Kada definiSete pokazivad na funkciju, morate mu, pre koriSienja, dodeliti
adresu funkcije. Kao Sto adresu niza arr[10] daje ime nizabez zagrada (arr),
voi d *funcPtr0 ; adresu funkcije funcQ daje ime funkcije bez liste argumenata (func). MoZete
'lako i.listc deklarisali ftrnkciju (koia waia void*) umesto da defini5ete pro- koristiti i jasniju sintaksu &func0. Da biste pozvali funkciju, dereferencirajte
menljivu. Zarnislitc da prevodilac na isti nadin kao i vi odreduje Sta predstavlja pokazivad na isti nadin kao sto ste ga deklarisali (zapamtite da definicije u
neka deklaracija, odnosno deflnicija. Zagrade su potrebne kao granidnik, tako jezicima C i C++ skoro uvek izgledaju isto kao kori5ienje). Sledeii primer poka-
da se prevodilac waia ulevo i pronalazi '*' umesto da napreduje udesno i pro- zuje kako se defini5e i koristi pokazivad na funkcije.
nade praznu listrr argtrmenata.
//: C03:PointerToFunction.cpp
/l Definisanje i upotreba pokazivada na funkciiu
#i ncl ude <i ostream>
Komplikovane deklaracije i definicije using namespace std;
I)odajenr da, kada otkriicte sintaksu deklaracija u C-u i C++-u, moZete praviti
i nrnogo sloZenije elemcnte. Na primer: void funcO {
I I : C03:Comp1 i catedDefinitions.cpp cout << "pozvana je funkcija func0 ... " << endl i
)

l* 1.*l void " (*(-fp1)(jnt))[10];


int main0 {

l. 2. -l float (*(*fp2)(int,int,float))(int); void (*fp) 0; // Definicija pokazivada na funkciju


fp = func; // Inicijalizacija pokaziva-a na funkciju
l- 3. -l typedef double (*(*(.fp3) 0) [t0]) 0; (*fp)0; // Dereferenciranie poziva funkcije
fp3 a; 0 = func; // Definicija i iniciial
void (*fp2) izaciia
(.fp2) 0 ;
l* 4.*l int (*(*f40)[t0])0; I I / /,-
Po5to je definisan pokazivad na funkciju fu, dodeljuje mu se adresa funkcije
int mainO {\ lll:- func0 u izrazu fp = func (zapazimo da nedostaje lista argumenata uz ime
Prodite kroz svaku definiciju i koristite princip desno-levo, da biste protu- funkcije). Drugi sludaj pokazuje istowemeno definisanje i inicijalizaciju.
rnaiili definir:ijrr. Ilroj I kaZc da je,,fpl pokazivad na funkciju koja ima jedan
celobrojni argun)cnt i vraia pokazivad na niz od I0 void pokazivada".
13roj 2 ka7-c da je ,,fp2 pokazivad na funkciju ko.ja ima tri argumenta (int, int i Nizovi pokazivata na funkcije
float) i koja vraia pokazivac na hrnkciju s jednim celobrojnim argumentom i Jedna od zanimljivijih konstrukcija koje moZete napraviti jeste niz pokazivada
rczuItatorr.r tipa float". na funkcije. Da biste izabrali funkciju, pomoiu indeksa pristupite elementu niza
Ako piSete veii bro j sloZenih definicija, moZda iete hteti da koristite red type- i dereferencirajte pokazivad. Ovako se pravi tabelarno uoden kOd (eogl. table-
def. Ilroj 3 pokazuje da nas typedef po5teduje unosa komplikovanih opisa. Ovaj driuen code). Umesto da upotrebljavate uslo'urte iskaze, funkcije koje ie se
primer kaTe da je ,,fp3 pokazivad na funkciju bez argumenata, koja waia poka- izwSavati birate na osnovu promenljive stanja (ili kombinacije promenljivih
zivad na niz od 10 pokazivada na funkcije bez argumenata, koje waiaju we- stanja). Ovaj nadin projektovanja moZe biti koristan ako desto dodajete ili
dnosti tipa double". Tatim kai.e da je ,,a tipa fp3". Red typedef je, generalno, uklanjate funkcije iz tabele (ili ako hoiete dinamidki da pravite ili menjate takr.u
korisna za gradenje sloZenih opisa od jednostavnih. tabelu).
144 Misliti na jeziku C++ Poglavlje3: CuC++-u 145 I
I

pomoiu pretproce- Re5enje ovog problema, razvijeno za Unix, ali sluda dostupno u nekom
I.Jsledeierr.r printeru se definiSe nekoliko laznih funkcija obliku, jeste program make. UsluZni program make upravija pojedinadnim
sorskog makroa, zatim se automatskom agregatnom
iniciializaciiom napravi niz
dodaiu u datotekama projekta. Kada izmenite neke datoteke projekta i pokrenete make,
p,rfori"oeo nil ovc lirnkciie. Kao 5to vidite' funkcije se iednostavno ovaj program sledi uputswa iz datoteke makefile i uporeduje wemena poslednje
(samim tin.r, uklania se i funkcionalnost iz programa)'
iabelu i uklaniajrr iz nje izmene izvornih i odredi5nih datoteka. Zatim, make prevodi izvorne datoteke
Samo treba Promeniti mali deo koda: koje su promenjene od poslednjeg prevodenja, kao i sve izvorne datoteke na koje
I I : C03: Funct i onTabl e. cPP izmenjene datoteke utidu. Kada korlstite program make, ne morate ponovo pre-
// Upotreba niza pokazivaca na funkciie voditi sve datoteke projekta svaki put kada napravite neku izmenu, niti treba
#i ncl ude <i ostream> proveravati da Ii je sve isprar.no uradeno. Datoteka makefile sadrZi sve instru-
usi ng namesPace std; kcije za izgradnju projekta. Ako nauiite da koristite program make, u5tedeiete
mnogo vremena i manje iete se nervirati. Otkriiete da se softver na Unix i Lintx
ll u,akro za definisanie laZnih funkclja: sistemima obidno instalira pomoiu programa make, mada su datoteke makefile
#define DF(N) void N0 {\ u tom sludaju mnogo sloZenije od onih koje ovde opisujemo.
Po5to program make u nekom obliku postoji za skoro sve C++ prevodioce (i
ako ne postoji, moZete koristiti besplatne verzi)e programa make uz svaki pre-
DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(s); vodilac), ova alatka ie se koristiti u primerima u celoj knjizi. Autori prevodioca
su napravili i sopstvene alatke za izgradnju projekata. Te alatke pitaju koje
void (*func-tableU)0 = { a, b, c, d, e, f' S }i
datoteke pripadaju projektu, i sve veze izmedu njih same odreduju. One koriste
int marn0 tehniku slidnu programu make, uglavnom uz projektnu datoteku (engl. project
{

hihile(1) {
file), ali ovu datoteku odrZava razvojno okruZenje, tako da ne morate brinuti o

cout << "Prl ti snutl neki taster od 'a' do 'g' njoj. Projektne datoteke se drugadije konflguri5u i koriste u razliditim razvojnim
"ili k za kraj" << end'l ; okruZenjima. Zato morate pronaii odgovarajuiu dokumentacilu o njihovoj
char c, cr; upotrebi (iako su alatke koje rade s projektnim datotekama i ispcruiuju se uz
crn.get(c); cin.get(cr) ; I I dru}l cin je za CR prevodilac obidno toliko jednostavne da ih moZete savladati eksperimenti5uii
if ( c =- 'k' ) - moj omiljeni nadin udenja).
break; // .. ' izlaz iz while(1) Trebalo bi da datoteke makefile koje se koriste u ovoj knjizi rade, dak i s alat-
rf ( 6 ' 'a' ll c' 'S' ) kama za izgradnju projekta, koje se isporuiuju uz va5 prevodilac.
cortlnue;
(*func-tab1eIc -'a']) 0 ;
)
Sta radi make?
\ I I l,- Kada pokrenete make (ili odgovarajuii program), u tekuiem direktorijumu se
zamisliti koliko je korisna ova tehnika kada pisete interpretator
traZi datoteka pod nazivom makefile. Ova datoteka sadrZi listu zavisnosti
Sacla mo7-ete
Iista'
izmedu datoteka izvornog koda. Program make posmatra wemena nastanka
ili Progranl za ollradu
datoteka. Ako je zavisna datoteka starija od datoteke od koje zavisi, program
make je prevodi na opisan nadin.

Program make: upravljanig prevod-enjeT Svi komentari u datotekama makefile podinju sa # i nastavljaju se do kraja
reda"
Kadakoristitetlclvojenoprevodenje(delitek6dnaveiibrojcelina),trebavam Evo jednosta'rnog primera. Datoteka makefile za program pod nazivom
povezivadu da od svih
rraiin cla nuto.nat.ki prevedete ,uuk, dutot"ku i saopstite
,,zdravo" mogla bi da sadrZi:
delova,z.aiednosao.lgoua'aiuiimbibliotekamaiinicijalizacionimkodom'
iz.gradiizvriniprngro-.'V"iinaprevodilacaomoguiavadatouraditejednom # Komentar
naredbomsakomandnelinije.Naprimer,kadkoristiteGNUC++prevodilac, zdravo,exe: zdravo.cpp
prevodi 1 ac zdravo. cpp
moZete naPisati:
g++ datotekal.cPP datoteka2.cPP Ovim se saopStava da zdravo.exe (odrediSte) zavisi od datoteke zdravo.cpp.
Kada je zdravo.cpp novija od zdravo.exe, make izwSava ,,pravilo" prevodilac
pr.blenr , o\1orn pristupu ie sto ie prevodilac prvo prevesti svaku pojedi-
ponovno prevodenje ove zdravo.cpp. MoZe postojati viSe zavisnosti i vi5e pravila. Mnogi programi make
nadnu clatoteku, bez- obziia na to da li je potrebno zahtevaju da sva pravila zapodinju tabulatorom. U ostalim sluiajevima, pra-
tlatoteke.Akopr<ljckatinranlnclgodatoteka,moZebitineracionalnoponovo znine se zanemaruju, tako da formatiranjem moZete postiii boljir clitljivost.
llrt'r'oditi s"'e poslc prolll('nc satno icclntl datoteke'
t46 Misliti na jeziku C++ Poglavlje3: CuC++-u
147

Pravila nisr-r ogranidena na aktiviranje prevodioca; moZete pozvati bilo koji prevodenja bilo koje datoteke s nastavkom imena cpp u datoteku
sa nastavkom
progranr. I)osle formiranja grupa medusobno povezanih skupova pravila imena exe" (ako je cpp datoteka novija od exe datoieke). Kao i ranije,
koristi se
moZete nter.rjati clatoteke izvornog koda, pokrenuti make i biti sigurni da ie sve makro g(cPP), ali vidite i neSto novo: oznaku $<. posto oznaka poein;.
sa,g,, to
potrebne datoteke ponovo biti pravilno izgradene. je jgdy od specijalnih ugradenih makroa programa make. oznaka $< se moze
koristiti samo u pravilima o nastavcima , a ina(7 ,,zasvaki preduslov
koji je aktivi-
Makroi rao pravilo" (ponekad se zove zauisni elemenf) i u ovom stleaju
se prevodi u ,,ona
Datoteka makefile moZe sadrZati makroe (z-apazile da su oni sasvim razliditi od cpp datoteka koju treba prevesti,,.
pretprocesorskih makroa). Makroi omoguiavaju pogodnu zamenu znakormih Po5to se deflni5u pravila o nastavcima, moZete napisati, na primer,
--
Union.exe i pravilo o nastavcima ie definisati prevodenje, dak i ako
,,make
nizova. Datoteke makefile u ovoi kniizi aktiviraju C++ prevodilac pomoiu ma- se ,,union,,
kroa. Na primer: ne spominje u datoteci makefile.

CPP = prevodi lac


zdravo. exe: zdravo. cpp Pod razu mevana od red iita
$ (CPP) zdravo. cpp
Posle makroa i pravila o nastavcima, make trazi prvo
,,odrediste,, u datoteci i gradi
ga, osim ako ne defini5ete drugadije. posmatramo sledeiu datoteku makefire:
Znak = se koristi da bi se CPP identifikovao kao makro, a $ i zagrade
zamenjuju makro. U ovom sludaiu, zamena znadi da ie $(CPP) biti zamenien CPP = prevodilac
znakovnim nizom prevodilac. Ako hoiete da koristite drugi prevodilac, pod .SUFFIXES:.exe.cpp
nazivom cpp, makro izmenite u: . cpp. exe:
$(cPP) $.
CPP = cpp odredi stel . exe:
Makrou takode ntoZete dodati indikatore prevodioca ili moZete koristiti odredi ste2. exe:
odvojene makroe za doclavanje indikatora prevodioca' Ako unesete samo make, napraviie se datoteka odredistel.exe (primenom
podrazumevanog pravila o nastavcima), po$to je to prvo odredilte
naiole make
Pravila o nastavcima imena datoteka nailazi. Da bi se izgradila datoteka odrediste2.exe, morate izridito
navesti,make
Kada znate da se uvek istim postupkom saopStava programu make kako da odrediste2.exe. ovo postaje zamorno, tako da obidno definisete
fod.azume-
pozove prevodilac za svaku pojedinadnu cpp datoteku u projektu, to postaje vano ,,lazno" odrediste koje zavisi od svih ostalih odredista,
kao u primerr:
z-arlorno. Posto je make napisan da Stedi weme, aktilrrosti, koje zavise od CPP = prevodllac
nastavka inrena clatoteka rnogu se pisati skraieno. Ovi skraieni postupci Se .SUFFIXES:.exe.cpp
nazivaju prauila o nastaucima. Kad primenite pravilo o nastavcima, program . cpp. exe:
make mo2e da prcvede datoteku s iecinim tipom nastavka (na primer, .cpp) u $(cee;5'
clatotektr sa clrr.rgim tipom nastavka (.obi ili .exe). Po5to napi5ete pravila pra- al I : odred i stel. exe odredi ste2. exe
vljenja jedne vrste datoteka od druge, treba da zadale i zavisnosti izmedu U ovom sludaju ,all' ne postoji, nema datoteke pod nazivom all. Kad god
datoteka. Kada make pronade datoteku stariju od datoteke od koje zavisi, na unesete make, program vidi ,aII, kao prvo odrediSte u listi (samim
osnoml pravila konstrui5e nove datoteke. tim, podra_
zumevano odrediste), zatim vidi da datoteka ,all, ne postoji, pa pokusavi
Pravilo o nastavcima saop5tava programu make da mu nisu potrebna izridita da je
napravi od navedenih datoteka. Zato posmatra odiedister.exe i (primenom
pravila izgraclnjc z-a svaku clatoteku, nego da moZe da odredi nadin izgradnje na pravila o nasravcima) ispituje da li (l) odredistel.exe postoji
osnow nastavka imena clatoteke. U ovom sludaju kaZe: ,,Da bi se od datoteke s i iil au U j"
datoteka odredistel.cpp novija od odredistel.exe, i akole to'tadno,
nastavkom cpp izgradila datoteka iije ime se zaw$ava na exe, aktiviraj sledeiu praviio o nastavcima (ako zadate izridito pravilo za odredeno
izwsaua
komandu". Evo kako to izgleda u navedenom primeru: odrediste, ovo
pravilo ie se koristiti). Zatim nastavlja .u iledeio- datotekom
u listi podra_
Cpp = prevodi Iac zumevanih odredi5ta. pravljenjem podrazumevane liste odrediSta (po
konven_
. S U FF I XES : .ex e .cpp cijise naziva'alll ali joj moZete dati bilo koje ime), opisujete praviio
. cpp. exe:
zaizgrad,nju
svake izvr5ne datoteke u projektu. osim podrazumevane liste
(cPP) $' odrediita, mozete
$ imati i druge liste za druge namene - na primer, komandom make debug
mogu
Komanda .SUFFIXES saop5tava programu make da obrati paZnju na sve se prevesti sve datoteke u reZimu za otklanjanje gresaka.
navedene nastavke imena datoteka, po5to oni imaju posebno znadenje u toj
datoteci. Zatim vidite pravilo o sufiksima .cpp.exe, koje kaZe: ,,Ovo je nadin
t48 Misliti na jeziku C++ Poglavlje3: CuC++-u
r49

Datoteke makefile koriSiene u ovoj knjizi Declare: Declare.o


I)rogramom Extractcode.cpp iz drugog toma ove knjige, svi listinzi, navedeni u $(Cnel 516p1AG)Declare Dectare.o
knjizi, automatski se izdvajaju iz tekstualne verzije knjige ismestaju u poddire-
ktoriiume prema poglavljima. osim toga, Extractcode.cpp pravi nekoliko dato- Ifthen: Ifthen.o
teka makefile tr svakom direktorijumu (s razliditim imenima), tako da moZete $ (CPP) $ (OFLAG) I fthen I fthen. o
preii u taj poddirektorijum i uneti make -f prevodilac.makefiIe (unesite ime
svog prevodioca umesto 'prevodilac', indikator ,-f' zna(i ,,ono Sto sledi je Guess: Guess.o
datoteka makefile"). Najzad, ExtractCode.cpp pravi,,glavnu,, datoteku makefile $(cPP) g(0FLAG)Guess Guess.o
u osnovnom direktorijumu, u kome su raspakovane datoteke knjige. Ta datoteka
sltrzi za prevodenje primera iz svih programa, odjednom. Na ovaj nadin mozete Guess2: Guess2.o
prevesti sav k6cl iz knjige jednim pozivom komande make, a postupak ie se $(CPP) $(0FLAG)GuessZ Guess2.o
zaustaviti ako prevodilac ne nroze da obradi odredenu datoteku (zapazite da bi
prevoclilac koji odgovara standardu c++-a trebalo da prevede sve datoteke iz Return.o: Return.cpp
Declare.o: Declare.cpp
knjige). Poito realizacija programa make zavisi od sistema, u generisanim
Ifthen.o: Ifthen.cpp
datotekama makefile koriste sc samo osnovne, zajednieke moguinosti.
Guess.o: Guess.cpp
Guess2.o: Guess2.cpp
Primer datoteke makefile Makro cPP sadrZi ime prevodioca. Ako koristite neki drugi prevodilac,
Kao sto je ranije redeno, aiatka za izdvajanje koda, Extractcode.cpp, automatski izmenite datoteku makefile ili promenite vrednost makroa na koria.ronoj
liniji,
generiSe clatoteke makefile za svako poglavlje. s obzirom na to, ove datoteke na primer:
makefile za svako poglavlje se ne navode u knjizi (sve ove datoteke su spakovane make Cpp=cpp
sa izvornim kodorn koji moZete preneti sa acirese www.BntceEckel.com). Medu-
tirn, korisno je pogledati primer jedne datoteke makefile. Sledi skraienaverzija Zapazite da Extractcode.cpp automatski pravi datoteku makeflle
za dodatne
prevodioce.
arrtornatski generisane datoteke r.a ovo poglavlje. u svakom poddirektorijumu
pronaii iete viSe od jedne datoteke makefile (one imaju razlidita imena, a poje_ Drugi makro,
oFr-{G, jeste
indikator koji ukazuje na ime tzrazne datoteke.
clinainu datotekrr l.rozivate pontoir.r 'make -f'). Ova datoteka je namenjena za Iako mnogi prevodioci automatski pretpostavljaj u da izlazna
datoteka ima isto
prevoclilac (iNll C++: osnovno ime kao ulazna, za neke to ne vaZi (primer su Linux/Unix prevodioci
koji podrazumevano prave datoteku a.out).
cPP = g++
OFLAG - -o . Ov{e postoje dva pravila o nastavcima, jedno za cpp datoteke i jedno za c
datoteke (u sludaju da treba prevesti izvorni c toal. podrizumevano
.SUFFIXES : .o .cpp .c odrediste je
all, a svaki red za ovo odrediste se,,nastavlja" pomoiu obrnute
. cpp.0 :
kose crte, sve do
Guess2. To je poslednji element liste i zatose ne navodi
$(CPP) $(CPPFLAGS) -c $. obrnuta kosa- crta. Radi
jednosta',T rosti, navedene su samo neke
datoteke iz ovog pogruulju_
U pravilima o nastavclma vodi se raduna o pravrler4u"oblektnih clatoteka
$ (CPP) 5 (CPPFLAGS) -c $<
(s nastavkom .o) iz cpp datoteka. Treba
izridito navesti p.uuiiu za izgrad,nj'
izw5nog programa, posto se izwsna datoteka uobidajeno prau
all: \ povezivanjem
viSe razliditih objektnih datoteka, a make ne moze preipostaviti
Return \ tole su. Thkode,
Decl are \ u sludaju Linux/Unix sistema, ne postoji standardni nistavak
ime.na zaizvrsne
Ifthen \ datoteke, tako da pravilo o nastavcima neie funkcionisati.
Zato proue.ite lesu Ii
Guess \ sva pravila zaizradu konadnih izwsnih programa
izridito navedena.
Guess2 ova datoteka makefire primenjuje najbezbedniji put tako sto koristi
sto
# Nisu prikazane ostale datoteke ovog poglav1ja manji broj moguinosti programa make. Koriste ,. ,u.no osnovni koncepti
odredi5ta, zavisnosti, kao i makroa. Na ovaj nadin se prividno
omoguJura .ad sa
Return: Return. o Stoveiim brojem programa make. Zbog toga mora da se napravi rieia datoteka
$(CPP) $(0rLAG)Retunn Return.o makefile, ali to nije tako lo5e, po5to nju iutomatski p.u,ri prog.u,,",
Extract_
Code.cpp.
t50 Misliti na jeziku C++ Poglavlje3: CuC++-u I5r

Postoje rnnoge clrtrge rnogr"rinosti programa make, koje se neie koristiti u 4. Izmenite Menu.cpp tako da koristi iskaze switch umesto iskaza if.
ovoj knjiz.i, kao inovije isavrSenije verzije ivarijante programa, sa predicama 5. Napi5ite program koji izradunava dva izraza iz odeljka o prioritetima ope-
koje mogu uStedeti dosta vremena. Dodatne osobine programa make pronaii ratora.
iete u dokumentaciji svog prevodioca. Vi5e o ovom programu moZete nauditi iz 6. IzmeniteYourPets2.cpp tako da koristi razlidite tipove podataka (char, int,
krrlrge i\farraging Projects tui.th Make, koju su napisali Oram iTalbott (O'Reilly, float, double i njihove varijante). Izw5ite program i analizirajte dobijenu
19!13). Ako vaS prevodilac nema make ili koristi nestandardnu verziju, moZete
strukture memorije. Ako imate pristup jo5 nekoj wsti radunara, opera-
pronaii GNtJ-olu verziju programa make za skoro svaki raiunarski sistem. Pre- tivnog sistema ili prevodioca, uradite ovaj eksperiment u sto vise varijanti.
tra2ite GNU arhive na lnternetu (ima ih mnogo).
7. Napi5ite dve funkcije, jednu diji je argument tipa string* i jednu diji je argu-
ment tipa string&. svaka od ovih funkcija treba da izmeni spoljni objekat
tipastring na svoj nadin. U funkciji main( ), napravite i inicijalizujte jedan
Sa2etak objekat tipa string, ispiSite ga, zatim ga prosledite obema funicijama i ispi-
U ovom poglavlju smo prilidno brzo pro5li kroz sve osnovne osobine sintakse
Site rezultate.
C++-a, od kojih su mnoge nasledene iz C-a (rezultat je hvaljena kompatibilnost
C++-a sa stariiim C-om). Iako su predstavljene neke osobine C++-a, ovaj pregled
8. Napi5ite program koji koristi sve troznake, da biste proverili da li ih va5
je prvenstveno namenjen osobama upuienim u programiranje kojima treba uvod prevodilac podrZava.
u osnove sintakse C-a i C++-a. Ako vei znate C, moZda ste prona5li jednu ili dve 9. Prevedite i izwsite static.cpp. uklonite iz koda rezervisanu red static,
nepoznate stvari o tom jeziku. Osobine C++-a najverovatnije su vam nove. Ako ponovo prevedite program, izwsite ga i objasnite Sta se deSava.
vam je ovo poglavljc ipak preopSirno, trebalo bi da prodete kroz kurs na CD-u I 0. Pokusajte da prevedete i poveZete FileStatic.cpp sa FileStatic2.cpp. sta
'l-ltittkirtg itt C: I-orutdarions.for C++ a.nd
laua, koji sadrZi lekcije, zadatke i re5enja. znadi dobijena poruka o greSci?
I L Izmenite Boolean.cpp tako da radi s wednostima tipa double umesto int.
12. Izmenite Boolean.cpp i Bitwise.cpp tako da koriste izridite operatore (vas
VeZ be prevodilac ie ovo podrZati ako odgovara standardu C++-a).
Ilesenia r/al)rarllh zatlalaka nalaze se u elektronskonr dokumentu Tlte Thinking in C++ Annotated Solution
(irrrr,1c ko ji se, uz malu nacloknadu, n)oze preuzeti s adrese lww.BruceEckel.com. I 3. Izmenite Bitwise.cpp tako da koristi funkcije iz Rotation.cpp. uverite se
1 . Napravite datoteku zaglavlja (s nastavkom'.h'). U ovoj datoteci deklariSite da prikazujete rezultate tako da bude jasno 5ta se desava tokbm rotacija.
grupu funkcija s razliditim listama argumenata i tipovima rezultata, bira- 14. Izmenite Ifthen.cpp tako da koristi ternarni operator uslovljavanja (?:).
juii tipove: void, char, int i float. Zatim napi5ite .cpp datoteku koja I 5. Napravite strukturu (struct) koja sadrZi dva objekta tipa string i promen_
ukljuduje vaSu datoteku zaglavlja i definiSe sve ove funkcije. Svaka funkcija ljivu tipa int. upotrebite typedef za definisanje imena itrukture. Niapravite
treba jednosta'".no da ispiSe ime funkcije, listu argumenata i tip rezultata, jedan primerak strukture, inicijalizujte sve tri wednosti i ispisite ih. Uzmite
tako da znate da je pozvana. Napi5ite drugu .cpp datoteku koja ukljuduje adresu primerka i dodelite je pokazivadu. promenite sve tri wednosti
datoteku z.aglavlja i defini5e funkciju int main( ), u kojoj se pozivaju sve primerka i ispi5ite ih, koristeii pokazivad.
funkcije. Prevedite i izvrSite svoj program. 16. Napi5ite program koji koristi nabrojivi tip za boje. Napravite promenljir,u
2. NapiSitc program koji u dve ugneZdene petlje for pomoiu operatora ovog tipa i u petlji for ispiSite sve brojeve koji odgovaraju nazivima boja.
mocirrlo ("/o) odredr-rie i ispisr.rje proste brojeve (cele brojeve koji nisu deljivi
17. Eksperimentisite sa union.cpp tako sto iete uklanjati razlidite elemente
s drugim brojevima, osim samim sobom ijedinicom).
unije, da biste uodili uticaj na velidinu dobijene unije. Dodelite wednost
3. Napi5itc program koji koristi petlju while za uditavanje redi sa standard- jednom elementu unije i ispisite razlidite elemente (znadi, razliditog tipa).
nog ulaznog toka (cin) u znakovni niz (string). Ovo je ,,beskonadna' petlja Posmatrajte Sta se de5ava.
while, koju prekidate (i izlazite iz programa) primenom iskaza break. Za I 8. Napi5ite program koji definise, jed,an za drugim, dva niza sa elementima
svaktr ucitanu rcd upotrebite niz iskaza il koji ie ,,preslikati" red u celo-
tipa int. Preko indeksa pristupite prvom nizu iza njegovog kraja i dodelite
brojnu vrednost, a z-atim upotrebite iskaz switch, koji koristi tu celobrojnu
wednost elementu drugog niza. Ispisite drugi niz, da blstJuoeili promene.
vrednost kao selektor (ovakva tehnika se ne smatra dobrim stilom pro-
sada definiSite promenljivu tipa char izmedu definicija prvog i drugog
grarnirar.rja, jedir.ra namena je da veZbate kontrolu toka programa). Unutar
niza i ponovite eksperiment. Mozda iete hteti da napravite funkciju zi
s,,,akog iskaza case, ispi5ite neku poruku. Odludite koje su ,,zanimljive" redi
prikazivanje nizova, da biste pojednostaviii pisanje programa.
i Sta znade. Moratc odluditi i koja red oznaiava kraj programa. Testirajte
program prer.rsmeravanjem standardnog ulaznog toka na neku datoteku I 9. Izmenite ArrayAddresses.cpp tako da radi s tipovima podataka char, Iong
(ova datoteka moZc biti izvorna datoteka programa). int, float i double.
153
Misliti na jeziku C++ Poglavlje3:CuC++-u
152

3l . Izmenite StringizingExpressions'cpp tako da se P(A) uslormo defini5e


20. t)rintenite tchnikrr iz ArrayAddresses.cpp da biste ispisali velidirle struk- komandom #ifael tito tiste o*ogr-ill da k6d za otklanjanje gresaka
bude
tttre i adrese elctttettata triza u StructArray'cpp' automatskiizostavljenakoseaenniseindikatornakomandnojliniji.
2 I . Napravite niz oblekata tipa string i svakom elementu dodelite
znakormi
Pogledajte dokumentaciju uz prevodilac, da biste videli kako
da na
niz. IspiSite niz- koristeii petliu for. koirandnoj liniji za pozivprevodioca defini5ete i poni5tite pretprocesorske
2 2. NapiSite dva nova prograrna, podinjuii od ArgsTolnts.cpp, tako da koriste wednosti.
atolO iatofo. 32.Defini5itefunkcijudijiargumentjetipadouble,awaiawednosttipaint'
2 3. Izmenite Pointerlncrement2.cpp tako da koristi uniiu umesto
strukture. Napraviteiinicijalizujte-pokazivadnaor,rrfunkcijuipozovitefunkciju
2 4. Izrlenire PointerArithmetic.cpp tako da radi s tipovima
long i long double. preko pokazivada.
33. Deklari5ite pokazivad na funkciju s argumentom tipa int' diji rezultat
je
25. Definisite promenljir.u tipa float. Uzmite njenu adresu, konvertujte tu
tipa char i rezultatom tipa float.
adresu u rip unsigned char i dodelite je pokazivadu na tip unsigned char' pokazivae na zuntcllu s argumentom
34. Izmenite FunctionTable.cpp tako da svaka funkcija waia wednost
tipa
Korisienjem ovog pokazivada i oznaka I l, preko indeksa pristupite pro-
menljivol tipa float i upotrebite funkciju printBinary( ), definisanu u string (umesto ispisivanja poruke) i da se ova wednost ispisuie u funkciii
ovompoglavljtr,dabisteprikazalistrukturuwednostitipafloat(ideteod0 maino.
to sizeof(float)). Promenite vrednost promenljive tipa float i poku5ajte da 35.NapravitedatotekumakefiIezajedanodprethodnihzadataka(posvom
otkriiete Sta se deSava (float sadrZi kodirane podatke)' izbbru), koja vam omoguiava da komandom make izgradite finalnu
ver-
26. Definisite niz elentenata tipa int. Uzmite podetnu adresu ovog niza i ope- ziju programa, a koman"dom make debug izgradite program sa ukljudenim
rarorom sratic_cast pretvorite je u tip void*. Napisite funkciju iiji argu- informacijama za otklanjanje gre5aka'
menri su pokazivad tipa void*, jedan broj (ukazuje na broj bajtova), i
jednu
wednost lukazuje na wednost koju treba smestiti u svaki bajg. Trebalo bi
da ova funkcija postavi svaki bajt definisanog intervala na zadatu
definisanu wednoit. poku5ajte da ovu funkciju primenite na niz eleme-
nata tipa int.
2 7. Napravite konstantan niz elemenata tipa double i niz elemenata
tipa dou-
ble, oznaden sa volatile. Preko indeksa pristupajte svim elementima
niz.ova i r.rpotrebite const_cast da biste sa svakog elementa uklonili oznake
const i volatile. Svakom elementu dodelite vrednost'
28. NapiSite funkciju diji je argument pokazivad na niz elemenata tipa double
iwednost koja ukazuie navelidinu tog niza. Trebalo bi da funkcija ispisuje
svaki element niza. Sada napravite niz elemenata tipa double i svaki ele-
ment inicijalizujte na nulu, zatim upotrebite funkciju zaprlkaz niza. ope-
ratorom reinterpret_cast pretvorite po.etnu adresu niza u tip unsigned
char*, i svaki bajt postavite na 1 (savet: operatorom sizeofizradunajte broj
bajtova podatka tipa double). Sada upotrebite funkciju zaprikaz niza, da
biite ispisali rezuliate. Sta mislite, zaSto svaki element nije dobio odgo-
varajuiu wednost?
29. (lzazovno) Izmenite FloatingAsBinary.cpp tako da ispisuie svaki deo vred-
nosti tipa double kao odvojenu grupu bitova. Pozive funkcije printBinary
moraiete da zamenite svoiim speciializovanim kodom da biste ovo uradili
(k6d moTete izvesti iz printBinary( )). Moraiete znati format broieva u
pokretnom 7,arel.u, kao i raspored baitova kod vaseg prevodioca (ovo je
izazovni deo).
3 0. Napravite datoteku makefile koja prevodi YourPetsl.cpp
i YourPets2.cpp
i izvrsava oba programa. obavezno koristite pravila o nastavcima.
ri

4=
I56 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka l5;

ZaSto bistc se trudili da predete s nekog lezika koji vei znate i produktivno ga nastanka, tokom izw5avanja programa. Nazvaiu ga cstash. Iako je k6d napisar
koristite na novi jez-ik, iako iete neko vreme biti manjeproduktivni dok ne otkri- na C++-u, pridrZava se stila kakvim biste pisali na C_u.
jete pravi naein rada? Zato sto znate da iete imati veliku dobit od upotrebe ovog
novog sreclstva. //: C04:CLib.h
I)roduktivnost u radrrnarskom programiranju znadi da manji broj osoba // Oatoteka zaglavija za bjblioteku na jeziku C

nroZe napisati n.rr.togo sloZenije i rnoinije programe zakra1e weme. Kada treba // Element slidan nizu koji se pravi u vreme izvr5avanja
izabrati iezik, valja raznrisliti o sledeiim osobinama: efikasnost (da li jezik pro-
typedef struct CStashTag {
r.rz.rokuje lrsprlravan je i narastanje koda), bezbednost (hoie Ii vas program uvek
int size; / / uelidina svakog prostora
raditi ono Sto planirate i da li ie elegar-rtno obradivati greSke) i odrZavanje i nt quanti ty; // Vel i ei na skl adj Sta
(moZete li pisati kOd koji se lako razume, menja i proSiruje). To su znadajni dini-
int next; // Sledeei prazan prostor
oci koji ie biti ispitani u ovoj knjizi.
Produktivnost takode znadi da ie program koji su ranije tri osobe pisale
// Niz bajtova koji se dinamidki pravi:
unsigned char* storage;
nedelju dana sada jedna osoba moii da napiSe za dan ili dva. To na viSe nadina ) CStash;
utiie na ekonomidnost. Vi ste sreini poSto ste neSto izgradili, vaS klijent (ili Sef) void initial ize(CStash* s, int size);
je sreian zato Sto z.a proizvodnju treba manje wemena i ljudi, a potroSadi su void cleanup(CStash* s) ;
sreini 5to dobiiaju proizvode po niZoj ceni. Iedini nadin da se postigne veliko int add(CStash* s, const void* element);
ltoveianje proclrrktivnosti icste da se iskoriste moguinosti koda koji su drugi voj d* fetch (CStash* s, i nt i ndex) ;
napisali. To znaii da treba upotrebiti biblioteku. i nt count (CStash* s) ;
Biblioteka je skup delova koda koji je neko drugi napisao i spakovao u celinu. void inflate(CStash" s, int increase);
Cesto je na jrnanji pakct sadinjen od jedne datoteke s nastavkom imena lib i jedne
ili viSe datoteka zaglavlja koje saopStavaju prevodiocu Sta se nalazi u biblioteci. oznaka, poput cStashTag, ugravnom se koristi za strukturu koja se obrai;
Povezivad zna kako da pretraZi biblioteku i izdvoji odgovarajuii prevedeni k6d. samoj sebi. Na primer, pri definisan ju pouezane lisre (svaki elemeni liste sadrZ
Medutint, to je samo jedan nadin da se isporuii biblioteka. Pod operatir..nim siste- pokazivad na sledeii element), treba vam pokazivad na sledeiu strukturu. Dr
mima koji rade na raiunarima raznowsnih arhitektura, kao Sto su Linux/Unix, biste to dobili, opi5ite tip pokazivada na strukturu u telu strukture. Skoro uvel
-csto jc jedino razumno da se biblioteka isporudi u obliku izvornog koda, tako da
iete u c biblioteci videti iskaz typedef za svaku strukturu, kao u prethodnon
se nroZe ponovo podesiti i prevesti na ciljnom sistemu. primeru, da biste mogli da radite sa strukturom kao s novim tipom i definisetr
Prema tome, koriSienje biblioteka je verovatno najvaZniji nadin poboljSanja promenljive tog tipa, kao u sludaju:
produktivnosti. Iedan od primarnih ciljeva C++-a jeste da se upotreba biblioteka
ucini iednostavnijom. lz ovoga proizllazi da postoje te5koie pri kori5ienju bibli-
CStash A, B, C;

oteka u C-u. Razumevanje tih te5koia ie vam dati prvi uvid u projekat C++-a i, Pokazivad storage je tipa unsigned char*. Tip unsigned char je najmanj
na taj naiin, uvid u njegol,u upotrebu. sme5tajni prostor koji podrZava prevodilac za c, iako na nekim iadunarimr
moze biti iste velidine kao i najveii dostupni tip. velidina zayisi od prevodioca
ali desto iznosi jedan bajt. Mogli biste pomislitiaa ui tip void* ovde bio pogod
Jedna mala biblioteka na jeziku C niji,_posto je cstash napravljen rako da moZe sadrZati bilo koji tip promLnljive
Biblioteka se obidno zapodinje kao skup funkcija, aii, ako ste koristili gotove C Medutim, naS cilj nije da ovaj prostor obradujemo blok nepoznaiog tipa,'ver
biblioteke, znate da desto sadrZe viSe od toga. Swarni svet se ne sastoji baS samo blok uzastopnih bajtova.
od ponaSanja, aktivnosti i funkcija. Postol'e i osobine (boja, masa, struktura, Izvorni kOd datoteke sa realizacijom funkcija (koji neiete dobiti ako kupitr
osvetljenost) koje se u radunaru predstavljaju podacima. Cim podnete da opisu- gotovu biblioteku - moZere dobiti samo prevedeni oblik obj ili lib ili dll iid.)
iete skup osobina na jeziku C, shvatiiete da je korisno da ih grupi5ete u struk- izgleda ovako:
tttnr, naroiito ako hoiete da predstavite vi5e slidnih stvari u prostoru problema //: C1a:CLib.cpp (0)
(prostor problerna obuhvata informacije koje se odnose na re5avanje postavlje- // Realizacija biblioteke na jeziku C
tlog zadatka, a ne lta radunar na kome se zadatak reSava). Zatim moZete napra- // Deklaracija strukture i funkcija:
vitr vi5e promenljivih tog ripa. #include "CLib.h"
Veiina biblioteka na jeziku C ima skup struktura i skup funkcija za rad s tim #i ncl ude <i ostream>
stnlktrlrama. Da biste razumeli ovakav sistem, pogledajte primer programskog #i ncl ude <cassert>
elementa koji se ponaSa kao niz, ali mu se velidina moZe definisati u weme using namespace std;
ls8 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka 159

I I BroS elemenata koje treba dodati void cleanup(CStash* s) i


/1 pri poveiavanju skladi5ta: if(s->storage != 0) (

const int increment = 100; cout << "oslobadia se prostor" << endl;
del ete [] s->storage;
void initialize(CStash* s, int sz) { )
s->si ze = sz; j lll,-
s->quanti tY = 0; Funkcija initialize( ) priprema strukturu tipa struct CStash za kori5ienje
s->storage = 0; tako Sto dodeljuje odgovarajuie wednosti unutraSnjim promenljivama. Na
s->next = 0; podetku je pokazivad storage postavljen na nulu, Sto znadi da skladi5te io5 nije
)
napravljeno.
Funkcija add( ) dodaje elemente u strukturu tipa CStash od sledeie raspo-
i nt add (CStash* s, const voi d* el ement) {
loZive lokacije. Ona prvo proverava da li je ostalo dovoljno prostora. Ako nije,
i f(s->next >= s->quanti tV) I lDa I i je ostalo dovoljno prostora?
i nflate(s, increment) skladi5te se poveiava funkcijom inflate( ), koja ie biti opisana kasnije.
;
Po5to prevodilac ne zna tip promenljive koja ie biti sme5tena (funkcija dobija
// E1 ement se kopi ra u skl adi 5te, samo void*), ne mozete dodeliti wednost, Sto bi svakako bilo pogodno' Umesto
ll od sledeceg praznog mesta:
int startBytes = s->next * s->size; toga, morate kopirati bajt po bajt promenljive. Najjasniji nadin kopiranja je pri-
unsigned char* e = (unsigned char*)element; mena indeksaniza. Obidno ved postoje neki podaci u skladi5tu, na Sta ukazuje
for(int i 0; i. s->size; i++)
= wednost next. Da bi se zapodelo od pravog bajta, next se mnoZi velidinom ele-
s-,storageIstartBytes + l] = eIi]. menta (u bajtovima) i dobija se startBytes.Zatim se argument element pretvara
s->next++; u tip unsigned char*, tako da se pojedinadni bajtovi mogu kopirati u raspoloZivi
return(s->next - 1); ll Broj indeksa prostor skladi5ta. Pokazivad next se uveiava, tako da ukazuje na sledeii raspolo-
) Zivi deo skladi5ta i ,,broj indeksa' gde je sme5tena wednost, pa se do wednosti
moZe doii prosledivanjem indeksa funkciji fetch( ).
voj d* fetch (CStash* s, j nt i ndex) { Funkcija fetch0 proverava da li je indeks ispravan i zatim waia adresu tra-
// Provera grani ca 'i ndeksa: Zene promenljive, izradunatu pomoiu argumenta index. PoSto index ukazuje na
assert (0 <= r ndex) ; pomeraj elementa u strukturi tipa CStash, mora se pomnoZiti velidinom ele-
i f(i ndex >= s->next) menta u bajtovima, kako bi se dobio pomeraj u bajtovima. Kada se ovaj pomeraj
return 0; ll Ukazule na kraj koristi kao indeks niza za pristup promenljivoj storage, ne dobija se adresa,
I I Daje pokazi vad na traZenj el ement: nego bajt na toj adresi. Da biste dobili adresu, morate koristiti operator za adre-
return &(s->storageIindex * s-rsize] );
siranje &.
)
Funkcija count( ) moZe, na prvi pogled, delovati malo neobilno iskusnom pro-
grameru. Izgleda kao da treba mnogo raditi da bi se postiglo ne5to Sto bi se lak5e
i nt count (CStash* s) {
return s->next; Elementi u strukturi uradilo rudno. Ako, na primer, imate strukturu tipa CStash pod nazivom intStash,
II CStash
izgledalo bi razumnije da se pronade broj njenih elemenata pomoiu dlana
)
intStash.nextumesto pozivanjem funkcije (Sto traje duZe), kao count(&intStash).
vol d i nfl ate (CStash* s , 'j nt i ncrease) { Ako ste hteli da promenite unutra5njost strukture tipa CStash i, samim tim, naein
assert (i ncrease > 0) ; izradunavanja broja elemenata, funkcija pruZa neophodnu fleksibilnost. Na7-a-
i nt newQuanti ty = s->quanti ty + 1 ncrease; lost, mnogi programeri se neie truditi da pronadu ,,bolje" reSenje za biblioteku.
i nt newBytes = newQuanti ty " s->si ze; Oni ie videti strukturu i pokupiie sledeiu wednost, a moZda ie dak i promeniti
i nt o1 dBytes = s->quanti ty * s->si ze; dlan next bez va5e dozvole. Kada bi samo postojao neki nadin da autor biblioteke
unslgned char* b = new unsigned char[newBytes]; kontroli5e ovakve stvari! (Da, to je nagove5taj.)
for(int i = 0; j < oldBytes; i++)
= s->storageIi]; II Kopira stari sadrZaj u novo sk'ladi5te
bIi]
de1ete [] (s-,storage) ; / I Bri 5e staro skl adi 5te Dinamitko zauzimanje memorUe
s->storage = b; ll Pokazuje na novi memorijski prostor Nikada ne znate unapred koliko prostora treba za strukturu tipa CStash, tako da
s->quanti tY = newQuanti tY; se memorija na koju pokazuje storage zauzima iz dinamiike memoriie (engl.
)
t-
t60 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka t6r

liea|r), I)inamieka ntcrnorija ie veliki blok memoriie iz kojeg se programi dode- sintaksa za uklanjanje niza. Prevodiocu morate reii da pokazivad ne ukazuje
ijLrju rnanji clelovi tokorn izvriavania. Ktlristite je (dinamieku memoriju) kada, samo na jedan objekat, nego na niz objekata. Ispred pokazivada na niz ko ji treba
tokonr pisanja progranta, ne znate koliko ie vam memorije biti potrebno. Na osloboditi postavljaju se prazne uglaste zagrade:
promenljivih
llrimcr, santo tokont izvr5avania moZete otkriti da vam treba 200 del ete [] ni z;
nckog tipir unlesto 20. Na stanciardnom c'u, iunkcije za dinamiiko upravljanje
Poito se oslobodi stari memorijski prostor, adresa novog prostora se moze
nrcrnirrijorn trkljue trjrr malloc( ), calloc( ), realloc( ) i free( ). Umesto poziva bibli-
dodeliti pokazivadu storage. Velidina se pode5ava i funkcija inflate( ) je obavila
oteckih firnkcija, c++ irna napredniii (i jednostar.ni;i) pristup dinamidkoj memo-
zadatak.
riii, koji je irrregrisan Lr jezik preko rezeruisanih reai new (novi) i delete (ukloni).
zapazite da je mehanizarrt za upravljanje dinamidkom memorijom krajnje
Funkcija inflate( ) korrsti opcrator new da bi dobila veii komad memorije za jednostavan. Daje delove memorije i uzima ih kada se obrise pomoiu reii delete.
stnrktrrru tipa CStash. I.J ovoi sitr-raciii sanlo proSirttiemo memoriju - ne suZa-
Ne sadrZi nikakve funkcije za sazimanje dinamiike memorije, koje bi kompri-
varno jc. Irunkcija assert( ) ie garantovati da se negativan broj ne prosleduje
movale zauzetu memoriju i obezbedile veie slobodne delove. Ako program vise
ftrnkciji inflate( ) kao vrednost increase (kolieina dodatne memorije). Novi broj puta zauzima i oslobada dinamidke blokove memorije, moze doii do
elentcnata koji se rnogu dr-rvati, po zavrSetku funkcije inflate( ), izradunava se fragmenta-
crye dinamidke memorije. Biie dosta slobodnog prostora, ali nijedan deo neie
kao newQuantity i mnozi se broiem bajtova po elementu, dajuii newBytes, koji
biti dovoljno veliki. Modut za saZimanje dinamidke memorije usloZnjava pro-
preclstavlja broj z.atrzetih bajtova. I)a bismo znali koliko bajtova treba kopirati iz
gram, posto premesta delove memorije, pa pokazivadi ne zadrLavaju isprawre
starog skladiSta, oldBytes se izradunava kori5ienjem stale wednosti quantity.
wednosti. u neka radna okruZenja ugraden je mehanizam za saiimanje dina-
Mernorija se z-auzima izrazont rlerr, koji sadrZi rezervisanu red new:
midke memorije, ali ona zahtevaju da umesto pokazivada koristite posebne
new unsigned charInewBytes] ; memorijske identifikatore (koji se mogu priwemeno konvertovati u pokazivade,
OpSti oblik izraz.a nov je: posle zakljudavanja memorije, kojim se spredava saZimanje). MoZete napraviti i
sopstveni mehanizam za salimanje dinamidke rnemorije, ali ovaj zadatak ne
new Tip;
treba shvatiti olako.
Ir korl.le Tip oltisuje tip prontenljivc koju Zelite da napravite u dinamidkoi Kada tokom prevodenja napravite promenljivu na steku, prevodilac auto-
[.] ovot't.t sludaju, treba nam niz elemenata tipa unsigned char duZine
rnentoriji. matski zauzima i oslobada prostor za ovu promenljivu. prevodilac zna koliko je
newBytes i on se pojavljuje kao Tip. Prostor moZete dodeliti i neiem tako jed- tadno prostora potrebno i zna Zivotni vek promenljivih, s obzirom na oblasti
nostavnom kao Sto je ceo broj, na primer: vazenja. U sludaju dinamidkog zauzimanja memorije, prevodilac ne zna koliko
new i nt; ie prostora biti potrebno i ne zna zivotni vek tog prostora. To znadi da se prostor
ne briSe automatski. zato ste vi odgovorni za oslobadanje prostora primenom
Iako se ovo retko racii, primetiiete da je sintaksa dosledna.
redi delete, koja saopStava modulu za upravljanje dinamidkom memorijom da
lzraz,new vraca pctkaziuaina podatak traZenog tipa. Dakle, ako napisete new
taj prostor moZe dodeliti nekom drugom. U nasoj biblioteci je }ogidno mesto za
Tip, clobiicte pokaz.ivad na Tip. Ako napiSete new int, dobiiete pokazivad na ceo
oslobadanje memorije funkcija cleanup( ), posto se u njoj obavljaju svi zawini
broj. lr.ritt. new unsigned char I2001, daje pokazivad na prvi element niza odgo-
poslovi odrZavanja.
varajr.rceg trpa. Prevodilac ie oltezbediti da se povratna vrednost izraza new
Da bi se testirale biblioteke, definisane su dve promenljive tipa cStash. prva
clotlt'lju1t' pokirzirai'tt isllravnog tip;t.
sadrZi cele brojeve a druga nizove duZine B0 znakova:
NarAvlro, svaki put ka<la zalrtcvatc ntentorijski prostor, postoji moguinost da
zahtev burlc ocibijen, ako vi5e nema raspoloZive memorije. Kao Sto iete videti, / / : C04:CLi bTest. cpp
(,++ ima rnehaniz-me za ribavestavanjc o greskama ako memoriia ne moZe da //{L) ct-iu
br.rcle clociel;ena. / I Iesti ranje bl b1 i oteke
PoSto sc zauzrre novi prostor r.r memoriji, moraju se kopilati podaci iz starog #i ncl ude "CLi b. hu
jednog po ncl ude <fstream>
l)rostora.'lir sc ponovo reSava indeksiranjem niza, kopiranjem u petlji
#i
jeclnog bajta. Posle kopiranja podataka, staro skladi5te se mola osloboditi, tako #i ncl ude <i ostream>
plograma. Rezervisana red delete je #i ncl ude <stri ng>
da se nioT-e koristiti rr clrugim delovima
#'i ncl ude <cassert>
korlplementarna s recjr.t new i tnora se primeniti za oslobadanje prostora zau-
using namespace std;
z-etog pomoiu reii new. Ako zaboravite da oslobodite memoriju, zatzeti prostor
ostaje rrt'dostrrpan i ako se ovo takozvano arrenie memoriie (engl. memory leak)
int main0 (
ponavlja, iskoristiicte svu dostr.tpnu memoriiu. Osim toga, postoii posebna
// Promenljive se defini5u na podetku
/l b1oka, kao na C-u:
162 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka r63

CStash j ntStash, stri ngstash; Zapazi(ete i dodatnu koverziju u:


int i;
char* cp; 6p = (char*)fetch(&stringStash,i++)
ifstream tn; Ovo je potrebno zbog stroZe provere tipova u C++-u, koja ne dozvoljava da se
string line; wednost pokazivada tipa void* dodeli pokazivadu nekog drugog tipa (C ovo
const i nt bufsi ze = B0; dopuSta).
l/ Settte se da inicijalizujete promenljive:
initial 1ze(&intStash, sizeof (int) ) ;
for(i = 0; i < 100i ++) .i
Loie pretpostavke
ntStash, &i ) ;
add (&i Pre nego Sto se upustimo u op5te probleme pisanja C biblioteke treba razumeti
for(i = 0; i < count(&intStash); j++) joS jednu vaZnu tema. Datoteka zaglavlja Clib.h morabiti ukljudena u svaku
cout << "fetch(&intStash, rr << i << ") = " datoteku koja koristi tip CStash, poSto prevodilac ne moZe ni da pretpostavi
<< *(int*)fetch(&jntStash, i) kako izgleda ta struktura. Medutim, on moieptetpostaviti kako izgleda funkcija;
<. endl; ovo zr,rrdi kao korisna osobina, ali se ispostavlja da je veliki nedostatak C-a.
ll SadrZt nizove od B0 znakova: Iako bi uvek trebalo da deklariSete funkcije ukljudivanjem datoteke zaglavlla,
j ni ti ai i ze (&stri ngstash,
si zeof (char) *bufsi ze) ; deklaracije funkcija u C-u nisu neophodne. U C-u je moguie (ali ne i na C++-u)
i n. open ( "CLi blest. cpp,,) ;
pozvati funkciju koja nije deklarisana. Dobar prevodilac ie vas upozoriti da bi
assert (i n) ;
verovatno trebalo prvo da deklari5ete funkciju, ali se na tome ne insistira u stan-
whi1e(getl r ne(rn, 1 ine) )
dardu jezika C. Ovo je opasno, po5to C prevodilac moZe pretpostaviti da funkcija
add(&stringstash, 1 ine.c_str0) ;
koju ste pozvali s celobrojnim argumentom ima iistu argumenata koja sadrZi tip
i = 0;
whi )e( (cp = (char*)fetch(&stringstash,t++) ) l=0)
int, dak i ako zapravo sadrZi tip float. To moZe proizvesti gre5ke koje se veoma
cout << "fetch(&str ingStash, " << j << r') = ', teSko pronalaze,kao Sto iete videti.
<< cp << endl; Svaka datoteka realizacije (s nastavkom imena .c) jeste jedinica preuodenja
cleanup(&intStash); (engl. translation unit ). To znadi da se prevodilac aktivira posebno za svaku
c1 eanup (&stri ngstash)
jedinicu prevodenja i tokom rada je svestan samo te jedinice. Zato 1e svaka infor-
;
\ ilt:- macija koju obezbedujete ukljudivanjem datoteka zaglavlja veoma zna(ajna
poSto odreduje nadin na koji prevodilac shvata ostatak programa. Deklaracije u
Da bi se odrzala forma koju c zahteva, sve promenljive se definisu na podetku
datotekama zaglavlja su narodito bitne, po5to fe prevodilac taino znati Sta da
ftrnkcije maino. Naravno, morate se setiti da, pozivanjem funkcije initialize( u
), uradi na svakom mestu gde postoji zaglavlje. Ako, na primer, u datoteci zaglavlja
nastavku bloka inicijalizujete promenljive tipa cStash- Korisniku morate paZljivo
postoji deklaracija void func(float), prevodilac zna da pri poziru te funkcije s
objasniti koliko su, pri korisienju c biblioteke, znadajne funkcije za inlcililizatilu
celobrojnim argumentom treba konvertovati argument tipa int u tip float (ovo
i hrisan je. Ako se ne pozo'!v,rl ove funkcije, biie dosta nevolja. NaZalost, korisnik
ne se naziva unapredenje, engl. promotion). Bez deklaracije, C prevodilac bi pretpo-
razmiSlja uvek da li su inicijalizacija i brisanje neophodni. Korisnici biblioteke
stavio da je postojala funkcija func(int), ne bi unapredio tip argumenta i pogre-
znaitr Sta hoie i ne obraiaju previse paLnle na vasa upozorenja. Neki korisnici
dak Sni podaci bi neprimetno bili prosledeni funkciji tunc( ).
sami inicijalizuju elemenre srrukture. U c-u ne postoji nikakav mehanizam koji
Prevodilac za svaku jedinicu prevodenja pravi objektnu datoteku, s nastav-
bi to spredio (joS ledan nagove5taj).
kom imena.o ili.obj ili slidno. Ove objektne datoteke, uz neophodan kOd za ini-
struktura intstash se popunjava celim brojevima, a stringstash nizovima
cijalizaciju, povezivad grupi5e u izvrSni program. Zaweme povezivanja, moraju
znakova. ovi nizovi z.akova se dobijaju otvaranjem datoteki izvornog koda se razreSiti sve spoljne veze. Na primer, u datoteci ClibTest.cpp, funkcije kao Sto
clibTest.cpp i uiitavanjem rcdova u objekat tipa string pod nazivom line posle
su initialize( ) i fetch( ) deklarisane su (znadi da prevodilac zna kako izgledaju) i
dcga se pomoiu tirnkcije dlanice c_str( ) pravi pokaiivad na znakor.ni niz sa koriste se, ali nisu definisane. One su definisane na drugom mestu, u datoteci
saclrT.ajem objekta line.
Clib.cpp. Zato su pozivi u Clib.cpp spoljne reference. Pri grupisanju svih objek-
Posle punjenja struktura, njihov sadrzaj se prikazuje. promenljiva intStash
se
ispisrrje primenonr perlie for koja koristi funkciju count( ) za oiredivanje gra-
tnih datoteka, povezivad mora pronadi stvarne adrese za spoljne reference. Te
adrese u izw5nom programu zamenjuju spoljne reference.
nice. Promenljiva stringStash se ispisuje u petlji while koja se prekida kada
VaZno je razumeti da su, u C-u, spoljne reference koje povezivad traZi samo
funkcija fetch( ) vrati nulu, dime ukazuje da je sav sadrZay proe itan.
imena funkcija, uglar,rrom sa znakom podvladenja ispred imena. Povezivae
samo treba da upari ime funkcije na mestu poziva s telom funkcije u objektnol
Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka t65
164

daroterci, i tO je sve. Ak<t sludaino naveclete poziv koii ie


prevod.ilac protumadio Osnovni objekat
kao func(int), a postoji tclo iunkcije za func(float) u nekoj
drugoj objektnoj Upravo skrivanje imena funkcija je prvi korak ka objektnom programiranju. C++
ie jednom i na drugom mestu videti i smatraie da
clatotcci, po','"rira. i na -{un"c funkcije se mogu smestiti unutar struktura kao ,,funkcije dlanice". Evo kako to
,jcsvettredu.Namestupoziva,smestiie^ceobrojnaStek,atelofunkcijefunc() izgleda posle konvertovanja strukture CStash na jeziku C u Stash na jeziku C++:
ne upisuje vred-
ie oiekivati ,..Io ,,.tu broi tipa float. Ako funkcija samo uditava-a //: C0a:CppLib.h
nosr, ona neie iskvariti ri.[. tl stvari, vrednost tipa float, koju
funkcija uditava sa
smisla' Tim gore, po5to je teZe otkriti gre5ku. //Biblioteka na jeziku C konvertovana u C++
Steka, mo7,e dak imati nekog
struct Stash {
int size; // Uelieina svakog prostora
Sta nije u redu? i nt ty; / / Ue1 i Ei na skl adi 5ta
quanti
coiet ;e veoma prilagodljiv dak i u
situacijama u kojima lozd.u ne bi trebalo da int next; // Sledeei prazan prostor
Ako malo bolje
bude. Svi programeri'na jeziku c pisu biblioteke nalik na cStash' // Niz bajtova koji se dinamiiki pravi:
prilidno" nez.Sg{1n' Da biste kori-
pogledate, otiiriietc da je ovaj naiin pisanja ' unsigned char* storage;
Pri ditanju
srili strukturu, morate prostedivatl ceiu adresu funkcijama biblioteke' // Funkcije!
naiin rada biblioteke i namenu funkcija, Sto je zbunju- void initialize(int size)
ko<ja, treba da otkrijete i ;
juie kada pokuSavate ria shvatite Sta se deSava' void cl eanup0 i
u sukob imena i nt add (const voi
d* e1 ement)
Iednu od najveiih smetnji pri kori5ienju biblioteka !-1.pt3d ;
(engl. rnnte clashes). C ima jedan imenski prostor za funkciie.i povezivad traZi void* fetch(int index) ;
jedinstvenoj listi. Osim toga, kada prevodilac radi na jedinici pre- j nt count 0 ;
ime funkcije u
voclenia, mo7-e raditi samo s jednom funkcijom odredenog imena'
void inflate(int increase) ;

sacla prcpostavin'ro da steodltrdili da kupite dve biblioteke.razliiitih


proizvo- \; ///:-
koja mora biti inicijaliz-ovana i izbri-
claia i cia obe biblioteke imaiu strukturu Prvo, zapazite da ne posto.ii iskaz typedef. Umesto da zahteva od vas da
su smatrala da su initialize( ) i cleanup( ) dobra imena' definiSete tip, C++ prevodilac pretvara ime strukture u ime novog tipa (kao Sto su
sana. oba proiz.vodada
u jednu jedinicu
Sta ie uraditi c prevodilac ako ukljudite obe datoteke zaglavlja int, char, float i double imena tipova).
postoii dvo-
prevodenja'l Sreiom, C vam prijavljule gre5ku' sa obja5njenjem da Svi podaci dlanovi su potpuno isti kao ranije, ali su funkcije sada u telu struk-
ne ukljudite u istu jedinicu prevo-
smislenosr. Ali, i ako obe daioteke zaglavlia ture. Osim toga, zapazite da je uklonjen prvi argument izverzije funkcija pisanih
denia, povezivad ie i dalje imati probleme' Dobar povezivad ie prepoznati na C-u. U C++-u prevodilac vas ne primorava da prosledite adresu strukture kao
koju
problem sukoba imena, aii ie neki povezivadi uzeti ime prve funkcije na prvi argument svim funkcijama koje je obraduju, nego to diskretno obavlja
naidudokpretraZujuskupobjektnihdatotekaredosledomzadatimulistiza umesto vas. Sada se svi argumenti funkcija odnose na ono Sta funkcija radi, ane
poSto vam dozvo-
povezivanje. (Ovo se dak rnoZe smatrati dobrom osobinom' na mehanizme rada funkcije.
ilaua cla bibliotedku funkciju zamenite svojom verzijom') VaZno je razumeti da je prevedeni kOd funkcije isti kao u C verziji biblioteke.
-
L-l sr,,akom sludaju, ne mozete koristiti <]ve
C biblioteke koje sadrZe funkciju sa Isti je broj argumenata (iako ne vidite da se prenosi adresa strukture, ona je ipak
desto dodaiu
istin-r imenom. Da'bi resili ovaj problem, proizvodadi c biblioteka tamo) i postoji samo jedno telo svake funkcije. Znaii, to Sto piSete :
jedinstvene oznake ispred naziva svih wojih funkcija. Tako bi initialize( )i
Ovo je logidan Stash A, B, C;
cteanup{ ) mogli portoii Cstash-initialize( ) i CStash-cleanup( ).
pu.tupuk, poSto ime strukture koju funkcija obraduje "dopunjava' ime te ne znadi da za svaku promenljivu dobijate razliditu funkciju add( ).
K6d je skoro identidan sa onim koji biste napisali za verziju biblioteke na
lunkcije.
jeziku C. Zanimljivo je da ovo ukljuduje ,dopunjavanje imena" kao Sto je
SadajevrenleclasetrapraviprvikorakuformiranjuklasauC++.u.Imena
pro- Stash_initialize( ), Stash_cleanup( ) i tako dalje. Kada je ime funkcije u struk-
promenllivih unutar strukiura ne sukobljavaju se sa imenima globalnih
te funk- turi, prevodilac radi istu stvar. Zato funkcija initialize( ) unutar strukture Stash
menljivih. Zasto se ova prednost ne bi iskoristila za lmena funkcija, ako
ne bi postale ne(e izazvati dvosmislenost ako postoji funkcija pod imenom initialize( ) unu-
cije obracluju odredenu strukturu? Drugim reiima, za5to funkcije
tar neke druge strukture, dak ni ako postoji globalna funkcija initialize( ). Uglav-
dlanice struktura'.2
nom ne morate voditi raduna o dopunjavanju imena funkcije - koristite obidno
ime. Ponekad morate definisati da ova funkcija initialize( ) pripada strukturi
Stash, a ne nekoj drugoj strukturi. Konkretno, prl definisanju funkcije, treba da
precizno zadate o kojoj funkciji se radi. Da bi se postigla preciznost, C++ koristi
167
r66 Misliti na jeziku C++ Poglavlje 4: APstrakcija PeqStaka

;i, operotor razreiauanja opsega (engl. scope resolution operator). Nazvan je tako void Stash: :inflate(int increase) {

zaro Sto imena sacla mogu biti u razliiitim opsezima vaZenja: globalnom ili assert (i ncrease > 0) ;
opsegu neke strukture. Na primer, ako hoiete da definisete funkciju initialize( ),
int newQuantjty = quantity +* increase;
koja pripada stnrkturi Stash, pisete Stash::initialize(int size). Pogledajte kako se
int newBytes = newQuantitY size;
int oldBYtes = quantitY * sjze;
operator raz.reiavanja opsega koristi u definicijama funkcila:
unsigned char* b = new unsigned charlnewBytes];
ll: C04:CppLib.cpp {0} for(int i = 0; i < oldBYtes; i++)
ll Btblioteka za C, prevedena na C++ b[i] = storageli); ll Kopira sadrZaj starog skladiSta u novo

II Deklaracije strukture i funkcrja: del ete U storaget // Bri 5e staro skl adi 5te
#include "CppLib.h" storage = t; // Pokazivad na novu memoriju
#i ncl ude .i ostream> quantity = newQuantitY;
#i ncl ude <cassert> )
us i ng namespace std;

II i se dodaj u
Broj el emenata koj void Stash::cleanuP0 {
II pr) poveeavanju sk1adi5ta: jf(storage != 0) {
const int jncrement = 100; cout << "oslobadjanje prostorar'<< endl;
delete []storage;
void Stash::jnitialize(int sz) { )
size = sz; | /ll,-
quantity = 0; zahteua
Postoji jos nekoliko razlika izmedu jezika c i c++. Prvo, prevodilac
storage = 0; U C++-u ne mo2ete pozvati funkciju koju
next = 0; aeUaracile u datotekama zaglavlja.
inade ie prevodilac prikazati poruku.o gre5ci' Ovo ie
niste preihodno deklarisali,
I
da bi se obezbedila konsistentnost poziva funkcija s njihovim def,nici-
znadajno
i nt Stash: : add (const voi d* el ement) { jama.'PrimoravajuiivasdadeklariSetefunkcijuprenegostojepozovete'C++
datoteku zaglavlja- Ako istu
if(next >= quanti ly) /l Da li je ostalo dovolino prostora? frevoditac osiguiava da Cete ukljuditi odgovarajuiu
nfl ate(i ncrement) ;
i iatoteku zaglivllaukljudite i tamo gde su definicije funkcija, prevodilac prove-
To znadi
// E1 ement se kopi ra u skl adi Ste, rava da li seteklaraciji u datoteci ziglavliaslaZe s definicijom funkcije.
da datoteka zaglavlja postaje provereno skladiste deklaracija funkcija i obezbe-
ll od sledeieg praznog mesta:
i nt s ta rt Bytes = next * s i ze; duje konsistenino koriSienje funkcija u svim jedinicama prevodenja'
unsigned char* e = (unsigned char")element; Nu,u.^o, globalne funkcije se i dalje mogu rudno deklarisati svuda gde se defi-
for(int i = 0; i < size; i++) Medutim'
nisu i koriste. (ovo je toliko zamorno, da postaje veoma nepozeljno.)
storageIstartBYtes + i] = eIi]; strukture se uvek moraju deklarisati pre nego Sto se definisu ili koriste. Najpo-
next++; g"a"U" mesto za definiciju struktureleste datoteka zaglavlja, osim za strukture
return(next - t); II Broj indeksa koje namerno skrivate u nekoj datoteci.
) obratitepaZnjunatodasvefunkcijedlaniceizgledajuskoroistokaokadasu
prvi argument
bile napisane na C-u, osim razresavanja opsega i dinjenice da se
void* Stash::fetch(int index) {
iz C virzije biblioteke vi5e ne navodi izridito. On je, naramo, i dalje prisutan,
I Provera grani ca i ndeksa:
I je
plS,o zurrl.ila treba da radi s konkretnom strukturom. Ali, zapazite da iz funk-
assert (0 <= j ndex) ; sz; pisete
cile elanice takode nestao izbor dlanova! To znadi da umesto s->size =
if(index >= next) elimini5ete dosadni s->. Izgleda da C++ prevodilac dodaje to umesto
return 0; l/ Ukazuje na kraj =
vas. u"rii
"L. stvari, on uzima ,,skriveni" prvi argument (adresu strukture koju smo
I I Daje pokazivai traZenog elementa: i pristupa ilanovima te strukture. To znadi da se unu-
return &(storageIindex * size] )I
ranije rudno prosledivali)
(i drugoi
tar funkcija Slanica struktuie moZete obraiati svakom podatku dlanu
i
funkciji dianici) tako Sto navedete njegovo ime. Prevodilac ie pretraZiti imena
lokatne strukture pre traZenja globalne verzije tog imena' Otkriiete
da ova
i nt Stash: : count ( ) {
return next ; I I Broj el emenata strukture moguinost pojednostavljuje i pisanje i ditanje koda'
)
168 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka r69

Sta ako, iz. nekog razioga, ho(ete da koristite adresu strukture? To je bilo lako u u sledeiem programu vidite vi5e novina u nadinu korisienja c++ verzije
verziji C ltibliotckc, poSto jc prvi argumenr svake funkcije bila promenljiva s tipa strukture Stash:
cstash*. [.] c++-u je to jos konsistentnije. Postoji posebna rezervisana red pod
I / : C04:CppLi bTest. cpp
nazivonr this, koja tlaje adrestr strtrkture. To je ekvivalentno sa,s'u verziji C
bibliotcke, gdc jc s bio prvi argumcnr. Stilu C-a vraiamo se kad napi5emo: //{L} cppLjb
// Iest C++ biblioteke
this->stze = Size; #include "CppLib.h"
Kod koli generiSe prevodilac potpuno je isti, tako da ne morate koristiti red #include "../require.h"
#i ncl ude <fstream>
this na takav naiin. Povremeno iete vidati kod u kome se izridito koristi this->: to
#include <iostream>
ne doprinosi smislu koda i eesto ukazuje na neiskustvo programera. Koristite this
#include <string>
samo kacl vant zatreba (u nekim primerima u nastavku knjige koristi se this).
using namespace std;
Ponrenuier.r.ro jo5 ncSto. Na c-u ste mogli dodeliti wednost pokazivada tipa
void* bilo kont clnrgont ltokazivadu, na slecleii nadin: int main0 {
rnt i = 10; Stash i ntStash;
void" vp - &i; /f Ispravno je i na C-u i na C++-u i ntStash. i n'i t i al i ze(si zeof (i nt) ) ;
rnt" 1p - vp; l/ lspravno 3e samo na C-u for(int i = 0; i < 100; i++)
i ntStash. add (&i )
i prevodilac se nije lalio. AIi, na c++-u nije dozvoljen ovaj iskaz. zaito? Zato sto c ;

ne odreduje baS precizno tipove pokazivada, tako da dozvoljava dodelu wedno-


for(int j = 0; j < intStash.count0; j++)
sti pokazirrada nedeftnisanog tipa pokazivadu deflnisanog tipa. U C++-u nije cout << "intStash.fetch(" .. j << ") = "
<< *(i nt*) i ntStash. fetch (j
tako. 'l'ip je veoma znadajan C++-u i prevodilac oStro reaguje kada postoje bilo )
<< endl
kaki,a ncslaganja tipova. tb je uvek bilo znadajno, ali je posebno bitno u C++-u. 3

poSto postoje funkcije dlanice u strukturama. Ako biste u C++-u mogli proizvo- // Sadrii nizove od B0 znakova:
Stash stri ngStash;
ljno prosledivati pokazivade struktura, tada biste, u krajnjem sludaju, mogli da const int bufsize = B0;
pozovetc iunkciju dlanicu strukture, koja u toj strukturi uopste ne postoji! pravi stringStash. initialize(sizeof(char) * bufsize) ;
recept za katastrolu. Iz tog razloga, dok c++ dozvoljava dodeljivanje vrednosti i fstream in("CppLi bTest.cpp',) ;
bilo kog tipa pokazivada promenljivoj tipa void* (ovo je bila prvobitna namena assure(in, "CppLibTest.cpp',) ;
tipa void*, od koga se z-ahteva Sirina dovoljna za smeStaj pokazivada bilo kog string line;
lipa), ttete vam dozvoliti da dodelite vrednost pokazivada na void nekom dru- whi le(get1ine(in, Iine))
gonr ti1.lu pokazivaia. ljvek se zahteva konverzija kojom saopstavate aitaocu i stri ngStash.add(1 ine.c str0 );
prevodiocu da vrednost zaista hoiete da pretvorite u odredi5ni tip. intk=0;
Ovo pokreie z-animljiru tcmu. Iedan od vaZnih ciljeva C++-a jeste da prevede char* cp;
Sto \.iSe postojeieg C kclda, kako bi se omoguiio lak prelazak na novi jezik. while((cp =(char*)stringstash.fetch(k++)) I= 0)
Medutirn, to ne znaci da c++ automatski dozvoljava sve Sto dozvoljava c. postoji cout << "stringStash.fetch(,, << k << ',) = "
izvestan broj postupaka, opasnih i podlo2nih gieSkama, koje vam C prevodilac << cp << endl;
dozvoljava. (Viclciete ih kasnije u knjiz-i.) U ovim situacijama, C++ prevodilac i ntStash. cl eanup 0 ;
prijavljuje rrprozorcnja i grcSke. 1b jc desto, u mnogo veioj meri, prednost nego stri ngStash. c1 eanup 0 ;
preprcka. [.[ rnnogirn sitrracijanra pokuiavate da otkrijete gre5ku u c-u i ne uspe- | / / /,-
vare, ali prcvociilac c++ ukaztrje na problem! U c-u iesto postizcte da se pro- Zapazi&te da su sve promenljive usputno deflnisane (Sto je objaSnjeno u
grarrr prcr,ecle, ali z.atirn ga moratc naterati i da radi. Ako je prevodenje programa prethodnom poglavlju). To znadi da su deflnisane na bilo kom mestll u opsegu
ru (.++-u proilo korektno, tacla on uglavnorn i radil Jezik c++ mnogo stroze pro- vaZenja i ne moraju se, kao u C-u, definisati samo na poeetku ovog opsega.
verava slaganje tipova. Program je prilidno slidan programu clibTest.cpp, ali se funkcija dlanica
poziva primenom operatora zaizbor dlana'.', ispred koga se nalazi ime promen-
ljive. ovo je pogodna sintaksa, poSto oponasa pristup podatku dlana strukture.
Razlika je u tome Sto je ovo funkcija dlanica, tako da ima listu argumenara.
Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka 171
170

Naravno,poz-ivkojiprevodilacstuarnogeneriSemnogoviSelidinaprvobitnu Apstraktni tipovi podataka


'ia-ko, uzimaiuii u oirzir dopunu imena i_skriveno prosle- Pakovanje podataka zajedno s funkcijama omoguiava vam da napravite novi tip
funkciitr c uibliotercel
clivar.rje parametra inir, poriu C++ funkciie
intSiash.initialize(sizeof(int)' 100) podataka. Ovo se desto naziva kapsuliranje (eng\. encapsulation)r. Postojeii tip
postaje poput funkcii. Siurn-i"itialize(&intStash,
sizeof(int), 100)' Ako se upi- podataka moZe imati nekoliko delova zajedno spakovanih podataka. Na primer,
je prvobitni C++ prevodilac
tate Sta se de5ava itp"O p"*Site' prisetite se da tip float ima eksponent, mantisu i bit za znak. MoZete od njega zahtevati da se
je taj k6d prevoden u masin-
cfront, proiz-vodada ,AT& l,'proizvotiio C tOa' a zatim sabira s drugim brojem u formatu pokretnog zarezu s celim brojem i tako dalje.
skijezikCprevodioce.r.,.ZbogtogaSecfrontmogaobrzoprenetinabilokojiradu. On ima osobine i ponaSanje.
Sireniu iezika C++. Posto je Deflnicija strukture Stash pravi nov tip podatka. MoZete dodati podatke
nar koji je imao C prevoclilacl Sto je doprinelo bizom
()++prevodilacmoraodageneri5eC,znate-dasvakakopostojinadindasesintaksa funkcijom add( ), uditati ih funkcijom fetch( ) i pro5iriti strukturu funkcijom
joS uvek omoguiavaiu da dobijete C kod)' inflate( ). Primerak strukture moZete da napravite iskazom Stash s, kao Sto jedan
C++-aizraz,tu c-1, f ,reti pilunaioci vam
Postoii joS jedna izmena u odnosu na program ClibTest'cpp'.i to ie ukljudi- broj u formatu pokretnog zareza deflni5ete iskazom float f. Struktura Stash ima i
vanje datotek",ugiurtlu require'h tu datoieki sam napravio radi ove knjige' da osobine i pona5anje. Iako se pona5a kao pravi, ugradeni tip podataka, tu struk-
assert(.)' Datoteka require'h
bi se naprednil. pr*""uuule gre5ke nego funkcijom turu nazivamo apstraktnim tipom podataka, moZda zato Sto omoguiava
funkciju assure( ), koja se
sadrZi nekoliku t.,,..,t .iiu, ukliiirujuii ovhe upotrebljenu apstrakciju koncepta iz oblasti problema u oblast reSenja. Osim toga, prevodilac
koristizadatoteke.Ovafunkcijaploveravadalijedatotekauspesnootvorena,l, koristi Stash kao nov tip podatka i ako kaZete da funkcija odekuje tip Stash, pre-
akoniie,Saljeodgovarajuiuporukunastandardniiz]raznitokzagreSke(Zatoje vodilac proverava da Ii toj funkciji prosledujete podatak ispravnog tipa. Isti nivo
iz dato-
Funkcije
porrebno ime darorekc kao diugi argument) i\zlaziizprograma. provere se primenjuje na apstraktne tipove podataka (ponekad se nazival'u
komandni red sadrZi
teke require.tr ce se t<orlstiti u k;jizi da bi se obezbedilo da namenski tipoui) kao i na ugradene tipove.
tadanbrojargumenataidasudatotekeispravnootvorene.ovefunkcijezame- Razliku u nadinu izwSavanja operacija nad objektima uodiiete odmah. PiSete
njuju ponavljanie zbur.rjr-rjuieg koda 'u p'o'etu greS.ak1
i obezbeduiu korisne obiekat.funkcija(argumenti). To je ,,pozivanje funkcije dlanice objekta'. U objek-
potpuno obiasnjene.
poruke o greskanra. u nisiavki knjige ove funkcije ie
biti tno orijentisanom Zargonu, ovo se zove i,,slanje poruke objektu". U sludaju Stash
s, iskaz s.add(&i) ,,Salje poruku objektu s" sa znadenjem ,,dodaj (engl. add( )) ovo
sebi". Su5tina objektno orijentisanog programiranje se moZe saZeti u jednu frazu:
Sta 1e objekat? slanje poruka objektima. Stvarno, to je sve Sto radite - napravite skup objekata i
Postostevideliuvodniprimer,vremejedasenapravikorakunazadiobjasniter- Saljete im poruke. Ve5tina je, naravno, u tome da se odredi 5ra su objekti i
minologijtr.UnoSe,lcfunkciiautt"'kt"tosnovajeonogaStoC++dodajeC-ui poruke. Kada ovo re5ite, realizacija na C++-u je iznenadujuie jednostavna.
C-u je struktura skup poda-
to z-ahteva ,-,uvl noein iu,.*isi;u";u o strukturama' U
obradivati. Ipak, tesko
taka, nadin p"k";i; ;;Ju,uiu iako da ih moZete grupno
je razrnisljati o tome kao o bilo demu drugom osim kao o
pri progra-
pogodnosti Detalj i objekata
mestima'
miraniu. Funkciie koje rade nad tim 't"kt"umu.nalaze 3e-11 !-rugim da
Na seminarima se desto postavlja pitanje: ,,Koliki je objekat i kako izgleda?" Odgo-
struktura postaje nova tvorevina, sposobna vor je:,,Otprilike onoliki i onakavkao Sto odekujete od strukture u C-u". K6d kojiC
Meclutint, . i,nt.i;oir-,u u paketu,
(kao strukir.rra u C-u) I ponas-anja. Koncept objekta kao samostal- prevodilac generiSe za C strukturu (bez dodataka C++-a) obieno ce izgledari pot-
opiSe i osobi.e
sam se nameie'
nog, ograni-enog entiteta ko)i moZe pamtiti i delovati puno isto kao kOd koji se dobija od C++ prevodioca. Ovo je znadajno programe-
LJ (.++-u, nf,;Jtot je samo promenljiva' a najdistija definicija je "oblast-sme- rima na jeziku C iiji k6d zavisi od detalja veliiine i rasporeda (ako iz nekog razloga
kaie ,,objekat mora imati jedinstveni identi- neposredno pristupaju bajtovima strukture umesto da koriste identiflkatore).
iraja,. (ovo i. o,f r.J.,.,iji r-raiin da se
fikator",Stole,ujez-i'kuC++,jedinstvenamemorijskaadresa)'Utoioblasti Program koji zavisi od konkretne velidine i rasporeda u strukturi nije prenosiv.
moZete sme5tati poaatte.
podrazumeva se da postoje i operacije koje se mogu Velidinu strukture dine velidine svih njenih dlanova. Pri rasporedivanju ele-
izwSavati nad tim podacima' menata strukture, prevodilac ponekad dodaje viSak bajtova zbog porar.nanja u
iako su pri-
NaZalost,oviterminisenekoristekonsistentnouS!1m]ezlcl ima, je memoriji - to moZe poveiati efikasnost izwdavanja. U poglavlju 15 iete videti
ponekad iete naiii na neslaganje o tome Sta objektno
lidno dobro prihvaieni. kako se, u nekim sludajevima, strukturi dodaju ,,skriveni" pokazivadi, ali o tome
orijentisani ;erlt, ariizgreda da ie dosad napravljena
priliino dobra klasiflkacija. trenutno ne morate brinuti.
Nekiiez-ici ,r,ot'iniiriZosnortani(engl'objict-based')'sto11u.1idaimajuobjekte je
slicne c++-ovim strukrurama s funkiilama, koje ste vei videli. Medutim, ovo
samodeooblettnoorijentisanogjez'ika.lezicinakojimajesamomoguiepako.
r., .,r,.,k,,''" podiiaka iesu objektno zasnovani' a
ne objektno
vanje fr.rnkciio I Ovaj termin moZe izazvati polemiku. Neki ga koriste kako je ovde definisan, drugi ga koriste za oprs upra-
oriicntisani. vljanja pristupom, 3to se razmatra u sledeiem poglavlju.
Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka 173
172

Velitirttr strttktttre tlroz.ete odreciiti pomoiu operatora


sizeof. Evo malog Pravila rada s datotekama zaglavlja
yr rirne ra: Kada pravite strukturu koja sadrZi funkcije dlanice, vi pravite nov tip podataka.
U op5tem sludaju, taj novi tip treba da bude lako dostupan. Osim toga, treba da
ll: C]a:Sizeof.cPP razdvojite interfejs (deklaracije) od realizacije (definicije funkcija dlanica), tako
/i VelIclne struktura da se realizacija moZe menjati bez pono'"rrog prevodenja celog sistema. Ovo se
#include "CLib.h"
postiZe smeStanjem deklaracije novog tipa u datoteku zaglavl)a,
#include "CPPLlb.h"
#i ncl ude <i ostream> Kada sam podeo da udim jezik C, datoteke zaglavlla su mi bile tajanstvene.
us i ng names Pace std;
Mnoge knjige o C-u ih ne istiiu posebno, a prevodilac nije nametao deklarisanje
funkcija, tako da je izgledalo da nisu obavezne, osim pri deklaraciji struktura. U
struct A { C++-u, upotreba datoteka zaglavlja postaje potpuno jasna. One su skoro neop-
i nt i [100] ; hodne za jednostavan razvoj programa, a u njih smeState sasvim odredene
); informacije: deklaracije. Datoteka zaglavlja opisuje prevodiocu dostupne ele-
mente biblioteke. Biblioteku moZete koristiti dak i ako imate samo datoteku
struct B { zaglavlja i objektnu datoteku ili biblioteku; ne morate imati izvorni k6d. Dato-
void f 0; teku zaglavlja opisuje interfejs.
I; Iako vas prevodilac na to ne primorava, koristite biblioteke jer iete tako naj-
lakSe zaw5iti veliki projekat. Srodne funkcije se grupiSu u istu objektnu datoteku
vojd B::f0 {i ili biblioteku, a datoteka zagJ.avlja sadrZi sve deklaracije ovih funkcija. To pravilo
se strogo primenjuje u C++-u. Biblioteka jezika C moZe da sadrZi bilo kakve
int main0 (
funkcije, ali apstraktni tipovi podataka u C++-u grupi5u srodne funkcije po tome
cout << "velicina strukture A = "
<< si zeof (A)
Sto pristupaju podacima iste strukture. Svaka funkcija dlanica mora biti dekla-
<< " baitova" << endl;
risana u deklaraciji strukture; ne moZete je staviti na drugo mesto. U C-u je bilo
cout << "velicina strukture B = " " si zeof(B) preporudljivo koristiti biblioteke funkcija, a u C++-u su postale neophodne.
<< " bajtova" <' endl;
cout << "vel i ci na strukture CStash u L-U =
si zeof(CStash) << " bajtova"
.. << endl;
cout << "vel i ci na strukture Stash u L++-U = Znaiaj datote ka zag avlj a I

<< sizeof(Stash) '< " bajtova" << endl; Pri kori5ienju bibliotedke funkcije, C vam dozvoijava da ignoriSete datoteku
\ lll,- zaglavlja i da rudno deklariSete funkciju. U proSlosti bi se ovo ponekad radilo,
prvi iskaz ispisuje 200' kako bi se malo ubrzalo prevodenje (ovo obidno ne utide na sawemene prevodi-
Na rrott.t t'ili:tttlant (vaii rcz-tritati mogubiti drugadiji)' oce). Na primer, printf( ) (iz <stdio.h>) jeste posebno lenja deklaracija C funkcije:
B neprirodna'
posto .svaka vrcdttost tifa int zauzrmi. dva,bajta' Struktura ie
u C-u' ali u C++-u moze da se printf(...);
f oiio ..-u podatke alairove
ovo nije dozvoljeno
opseg za imena funkcija' pa
napravi struktura diji je ie<tini 'adatak da obezbedi Tri taake definiSu promenljiuu listu argttmenataz (engl. uariable argument list),
ispisuje pomalo iznenadujuii
je ovakva definiciia anri'lii.nu Drugi iskaz- ipak Sto za prevodilac znadi da printf( ) ima neke argumente. Svaki od njih ima neki tip,
rez-ultat, r,rec-l.ost raz.liditu od nule.-U ranim
verzilama jezika, velidina je bila ali se to ignori5e. Samo treba uzeti i prihvatiti navedene argumente. Kori5ien.jem
ntrla, ali pri pravlienlu- objekata dolazi do neobidnog problema: oni ove vrste deklaracije spredavate svaku proveru gre5aka u argumentima.
","t"if'
imaju istu adresu fuo oUl"ttut koji ie definisan neposredno
posle njih' tako da
Ovaj postupak moZe izazvati probleme koji se te5ko otkrivaju. Ako rudno
jeste da svaki objekat
nisLr razliditi. Iedno od n.iro"nilr pravita u vezi s objektima deklariSete funkcije, moZete napraviti gre5ku u jednoj datoteci. Po5to prevodilac
da ie i struktuie bez podataka dlanova uvek
ntora irnati jcdinstvenu adresu, tako vidi samo vaSu deklaraciju u toj datoteci, moZda ie biti u stanju da je prihvati.
imati veliiinu razliditu od nule' Program ie biti ispravno povezan, ali ie upotreba te funkcije u toj jednoj dato-
poslednja dva iskaz_a ,J"or pokazuiu da su velidine ekvivalentnih struktura teci biti pogre5na. Ta greSka se te5ko pronalazi, a lako se izbegava kad se koristi
vi5kove'
jez.ika C i (-++ iste. C++ pokuiava da izbegne nepotrebne datoteka zaglavlja.

2 Morate koristiti posebne tehnike za eitanie parametara, funkcije koja zaista ima promenljim listu argume-
nata, ali bi to trebalo izbegavati u C++-u. Detalje o promenljivoj listi argumenata pronaii iete u svom
prirueniku o C-u.
Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka 175
174

neko od zaglavlja olazno-izlaznih tokova. Ako u jednoj izvornoj datoteci kori


AkosvcclcklaracijefLrnkcijaSmestiteudatotekuzaglavljaiukljuiite.zaglavlje stite vi5e vrsta struktura (obidno ukljudujuii datoteku zaglavlja za svaku od njih)
deklaraciia u
svucia gdc koristite i clcfiniSete funkcije, osiguravate konsistentnost zaglavlle <iostream> ie verovatno biti ukljuaeno vi5e puta.
definicijom obezbedujete
celun]"sister-,-,u. iJkljudivanjem z-aglavlja i u datoteku s
Prevodilac smatra gre5kom ponovnu deklaraciju strukture (ovo se odnosi i n,
i usagla5enost deklaracije i definicije' strukture i na klase), inade bi dozvolio da razliditi tipovi imaju isto ime. Da bi s,
Ulolikoko je struktuia deklarisina u datoteci zaglavlla u c++-u, tu,datoteku spredila ova greSka pri ukljudivanju veieg broja datoteka zaglavlja, pomoiu pret
z.aglavlja nlotateukljuditi svuda gde se struktura koristi i gde se
definisu niene
procesora napravite pametnije datoteke zaglavlja (standardne datoteke zagla
funtcile dlanice. C++ prevodilac ie prijaviti gre5ku ako pokuSate da pozovete
bezprethodnog vlja C++-a, kao Sto je <iostream>, napravljene su na taj nadin).
obidnu funkciju ili ako pozovete ili deflni5ete funkciju dlanicu I C i C++ vam dozvoljavaju pono'v-nu deklaraciju funkcije, sve dok su te dv
tome da pravilno koriste datoteke zaglavlja'
cleklarisanja. IjoSto se in.sistira na se
koda u bibliotekama. Broj gresaka se umanjuje deklaracije usaglaSene, ali nijedan od ovih jezika vam ne dozvoljava ponovnr
obezbedtrje se konsistcntnost
deklaraciju strukture. Ovo pravilo je posebno vaZno u C++-u, jer, ako bi prevodr
ako se na svitn nlestima koristi jedinstven interfejs' Iac dozvolio da ponovo deklari5ete strukturu i ako bi se deklaracije razlikovalt
ugovor opi-
Zaglavlje je ugovor iz-medu vas i korisnika vaSe biblioteke' Ovaj
argumenata i rezu-ltata u pozivima koju bi on koristio?
,r,1. ,'z,se ,i.,itt,,i. podataka i utvrduje tipove
radi to i to". Korisniku su, za razvoi Problem ponovne deklaracije je znadajan u C++-u, poSto za svaki tip podatk
lirnkcija. on saopSrava: ,,Moja biblioteka
su potrebne sve da (struktura s funkcijama) uglavnom postoji posebna datoteka zaglavlja, a r
aplikacije, potrebr-re neke od ovih informacija, a prevodiocu
ukljuduje zaglavlja, pravi morate ukljuditi jedno zaglavlje u drugo ako drugi tip podatka koristi prvi. Verc
t,l g.n"ii.un ispravan k6ci. Korisnik strukture {atgteklr
i povezuje objektni modul ili bibli- vatno je da iete u svaku izvornu datoteku u projektu ukljuditi nekoliko datotek
ut.,l"tt. (prirnerke) srrtrkrure iz biblioteke
zaglavljakoje i same ukljuduju druge datoteke zaglavlja. Prevodilac moZe nekc
oteku (tj. prevedeni kdd).
prevodilac podrZava ugovor i zahteva da deklari5ete sve strukture i funkcije liko puta videti istu datoteku zaglavlja tokom prevodenja jedne izvorne datt
smestite teke. Ako ne5to ne preduzmete, prevodilac ie videti da je struktura ponov
pre koriSienia, a funkciie.-dlanice pre definisanja' Zbog't'ogaTolat: da
to u datoteku s definicijama funk- deklarisana i prijaviie gre5ku. Da biste re5ili ovaj problem, treba da znate ne5t
deklaracije u zaglavlje i da ukliudite zaglavlje
posto se jedna datoteka zag- viSe o pretprocesoru.
cija dlanica i u latoieke u koiima se one koriste.
lavlja, koia opisuie va5u biblioteku, koristi u celom sistemu' prevodilac
moZe
r>bezbeciiti konsistentnost i sprediti gre5ke' Pretprocesorske komande #define, #ifdef i #endif
Postoje neke vaine teme koie morate poznavati kako biste pravilno organizo- Pretprocesorska komanda #define se moZe koristiti za deflnisanje indikatora z
k6cl i pisali (lohre datoteke zaglavlia. Prva teme se odnosi na to Sta
moZete
prevodenje. Saop5ite pretprocesoru da je indikator definisan, bez dodeljivan;
'ali je
srnestiti u datoteke z-aglavlja. Osnormo pravilo ,,samo deklaracije", to jest samo
wednosti:
informaciie prevodioc-u, uii nistu 5to zauzima memoriju (k6d funkcije ili defini-
jedinica #define
cije promenijivlh). Datoreka zaglavlja se obiino ukljuduje u nekoliko
INDIKATOR

pieubaen;a u istom projektu i, ako se zajedan identifikator rezervi5e prostor na ili mu dodelite wednost (to je uobidajeni nadin deflnisanja konstante u C-u):
definisanja (ovo je prauilo
vi5e mesta, povez-ivid ie naiii na gre5kuvi5estrukog #define PI 3.14159
jedne definicrTe u C++-u: mo7-ete dektarisati neSto koliko god puta hoiete' ali ga
U svakom sludaju, sada pretprocesor moZe ispitati da li je oznaka definisana:
nrorate definisati samo jednom)'
ovo pravilo nijc sawim dvrsto i postojano. Ako unutar datoteke zaglavlja #i fdef INDI KAT0R
dcfirri5eic pror.c.ljivu koja ;e ,,statiaka u datoteci" (vidljiva samo unutar
dato-
neie
Ako je indikator definisan, prevodilac ie videti k6d iza komande #ifde
teke), postoiaic viSe prirneraka tog podatka u projektu, ali povezivad to
Ukljudivanje se zaustavlja kada pretprocesor naide na komandu:
.,.1o,ru,i gr.iknn',.' Ditoteka zaglavlja ne sme daizazove dvosmislenost tokom
povezivania.
#endi f
ili
Problem vi5estruke deklaracije #endif ll INDiKATOR

Drrrga va7.na tema u vezi sa datotekom zaglavljajeste: kada smestite deklaraciju Iza #endif u istom redu moZe da se nalazi isljudivo komentar, iako neki prt
srrtrkrure u datoteku z-aglavlja, ta datoteka u nekom sloZenom programu moze vodioci ne prijavljuju greSku ako ima jo5 nedega. Parovi komandi #ifdef/#end
biti ukljudivana viSe puia. Oobar primer su ulazno-izlazni tokovi' U datoteci mogu biti ugneZdeni.
je ukljuieno
zaglavlia za srrukruruioia uditava podatke ili ih ispisuje, verovatno

I U starrdartlnotn (.++ rt izbcgava sc osohina.,stati'nosti u datoteci'


176 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka 177

Konrancli #define 1e suprotna komanda #undef (skraienica od ,,un-deflne", lmenski prostori u zaglavljima
poniSti definiciju). Ako je definicija indikatora poniStena, preskade se kOd koji se zapazi(,ete da se komande using koriste u skoro svim primerima u ovoj knjizi,
uslovljava komandom #ifdef INDIKATOR. Komanda #undef moZe takode obidno u obliku:
prouzrokovati da pretprocesor prestane da koristi makro. Komandi #ifdef je
sLrprotna komanda #ifndef, koja ukljuduje k6d ako indikator nije deflnisan (olu using namespace std;
komandu ienro koristiti u datotekama zaglavlja). Posto je std imenski prostor koji obuhvata celu standardnu C++ biblioteku,
Pretprocesor jezika C ima joS neke korisne komande. Detaljne informacije o cva komanda omoguiava upotrebu imena standardne C++ biblioteke bez ograni-
tonre potraZite u clokumentaciji svog prevodioca. denja. Medutim, skoro nikada neiete videti komandu using u datoteci zaglavlja
(bar ne izvan opsega). Razlog je Sto ova komanda elimini$e za5titu nuued.nog
imenskog prostora, a njen efekat traje do kraja tekuie jedinice prevodenja. Ako
Standard za datoteke zaglavlja unesete takvu komandu (izvan opsega) u datoteku zaglavlja, znadi da se zastita
U svakoj datoteci zaglavlja, koja sadrZi strukturu, trebalo bi da prvo proverite da imenskog prostora zaobilazi u svakoj datoteci koja ukljuduje ovo zaglavlje, a desto
li je ova datoteka zaglavlja vei ukljudena u tekuiu izvornu datoteku. Ovo se i u drugim datotekama zaglavl']a. Ako podnete da stavljate kominde using u
postiZe ispitivanjem pretprocesorskog indikatora. Kada indikator nije definisan, datoteke za$avl1a, na kraju iete,,iskljuditi za5titu" imenskih prostora skoro sr,1da
clatoteka nije ukljudena i trebalo bi da defini5ete indikator (tako da ova struktura i tako poni5titi korisne efekte imenskih prostora.
ne moZe biti ponovo deklarisana) i deklariSete strukturu. Ako je indikator vei Ukratko: nemojte stavljati komande using u datoteke zaglavlja.
bio definisan, tacla je taj tip vei deklarisan i trebalo bi da zanemarite k6d koji ga
dcklariSe. L:vo kako bi trebalo da izgleda datoteka zaglavlja:
#i fndef INDIKAT0R
KoriSienje zaglavlja u projektima
#defi ne INDIKAT0R Projekat na C++-u, obidno iete praviti od mnoSrva razliditih tipova (struktura
trp... podataka s pridruzenim funkcijama). Najsesie iete deklaraciju svakog tipa i1i
ll 1vde se deklari5e
grupe povezanih tipova smestati u posebnu datoteku zaglavlja, a zatim u jedi-
iendtf I / INDIKAT0R
nici prevodenja definisati funkcije za taj tip. Kada korisrite raj tip, morate uklju-
Kao sto vidite pri prvom ditanju, pretprocesor ukljuduje sadrZaj datoteke
diti datoteku zaglavlja, kako bi bio ispravno deklarisan.
zaglavlja (obuhvatajuii i deklaraciju tipa). Pri svakom sledeiem ditanju tog
Ponekad ie se taj Sablon koristiti u ovoj kry'izi, ali ie deSie primeri biti veoma
z.aglavlja u jednoj jeclinici prevodenja, deklaracija ovog tipa se ignori5e. Ime
katki, pa se deklaracije struktura, definicije funkcija i funkcija main( ) poja-
INDIKATOR moZe biti bilo koje jedinstveno ime, ali bi trebalo slediti pouzdani
vljuju u jednoj datoteci. Imajte na umu da ie se u praksi desie ioriste odvolene
standard da se koristi ime datoteke zaglavlja ispisano svim velikim slovima, pri
datoteke i datoteke zaglavlja.
demu se umesto taeaka koriste potcrte (ne treba da koristite imena koja podinju
potcrtom, po5to n jih interno koristi prevodilac). Sledi jedan primer:
//: C04:Simple.h UgneZdene strukture
,// Jednostavno zaglavl3e koje spreiava ponovnu definiciju Pogodnost definisanja imena podataka i funkcija van globalnog imenskog pro-
#i f ndef SII'1PLt_H stora primenljiva je i na strukture. MoZete umetnuti jednu strukturu u.rrta.
{define SIMPLE
dirge
H
i tako zajedno duvati povezane elemente. Sintaksa deklaracije je oeekivana, Sio
iete videti u sledeioj strukturi koja reaiizuje potisni stek (engl. puslt-down stack)
struct Simpl e i kao jednostarmu povezanu listu, tako da,,nikada,, ne moZe di se prepuni:
int i,j,k;
initialize0 { i = i =k= 0; } //: C04:Stack.h
); // Ugneidena struktura u povezanoj listi
#endif ll SIIPLE_H lll:- #ifndef STACK_H
#defi ne STACK_H
Iako je SIMPLE_H iza #endif u komentaru i zato ga pretprocesor zanemaruje,
r.ravodenje imena na taj nadir.r dini k6d ditljivijim.
struct Stack {
Ove pretprocesorske komande koje spredavaju vi5estruko ukljudivanje desto struct Link {
sc naziva jtr zaititont od ukl.ittiiuatt ja (engl. ittcLude guards). voi d* data;
Li nk* next;
void injtjal ize(void* dat, Link* nxt);
178 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka 179

l
- head; voi d* Stack: : peek 0 {
void initialrze0; require(head != 0, "Stek je prazan,');
vor d push (voi d* dat) ; return head->data;
voi d* peek ( ) ; )
void* pop0;
voi d cl eanup 0 ; void* Stack::pop0 {
); if(head == 0) return 0;
tendif ll SrACK_u ///:- void* result = head->data;
Link* oldHead = head;
LJgrreZtier.rastruktirra se naziva Link i ona sadrZi pokazivad na sledeiu struk-
head = head->next;
tllre tipa Link u listi i pokazivad na podatke sme5tene u strukturu Link. Ako delete ol dHead;
pokazivaa next ima wednost 0, radi se o poslednjem elementu liste'
return resul t;
lapat.ite da je pokaz-ivad head definisan neposredno iza deklaracije strukture
)
Link, umesto posebne definicije Link* head. Ova sintaksa potide iz C-a, ali ona
nagla5ava znaaaj taake izarez.a posle deklaracije strukture; taaka izarezukazuje void Stack::cleanup0 {
na kraj liste dcfinir:ija, razdr,oienih zarezima, tipa te strukture. (Obidno je lista require(head == 0, "Stek nije prazan,,);
prazna.) | /l/,-
Llgnczdena stnlktura ima sopstvenu funkciju initialize( ), kao i sve strukture
Prva definicija je posebno zanimljiva, poSto pokazuje kako se definise dlan
prikaz.ane dosad, 5to obezbeduje ispravnu inicijalizaciju. Stack ima funkcije ini-
ugneZdene strukture. upotrebite dodatni nivo razresavanja opsega kako biste
tialize( ) i cleanup( ), kao i funkciju push( ), diji je parametar pokazivad na poda-
naveli ime obuhvatajuie strukture. Stack:Link::initialize( ) samo dodeljuje wed-
tak koji hoiete da smestite u stek (pretpostavka je da je rezervisan dinamidki
nosti argumenata dlanovima strukture.
memorijski prostor), i funkciju pop( ), koja vraia pokazivad data s wha steka i
Funkcija Stack::initialize( ) pokazivadu head dodeljuje wednosr 0, rako da
uklanja najvi5i element. (Kada pozovete funkciju pop( ), odgovorni ste za uni-
objekat zna da je lista prazna.
Stavan je objekta na koji pokazuje data.) Funkcija peek( ) takode waia pokazivad
Funkcija Stack:push( ) sme5ta na wh steka argument, pokazivad na promen-
data najviSeg elernenta, ali ga ostavlja na steku.
ljivu koju hoiete da saduvate. Prvo pomoiu new rezervise prostor za strukturu
Ovo srr clefinicijc lunkcija dlanica:
tipa Link koju ie dodati na wh. zatim poziva funkciju initialize( ) te strukture da
ll: C)a:Stack.cpp {0} bi se njenim dlanovima dodelile odgovarajuie vrednosti. zapazite da se tekuia
// Povezana I j sta s ugneZdenim strukturama wednost head dodeljuje pokazivadu next, zatim se pokazivaiu head dodeljuje
#r ncl ude "Stack. h" pokazivad na novu strukturu tipa Link. Tako se nova struktura smelta na
rinclude "../require.h" podetak liste.
usi ng ndmespace std;
Funkcija Stack:pop( ) dita pokazivad data iz strukture na whu steka, zarim
pomera pokazivad head nadole i brise stari wh steka, pa waia proditani poka-
vor d
zivad. Kada pop( ) ukloni i poslednji element, head ponovo dobija wednost 0,
Stack::Ljnk: :initjalize(void* dat, Link* nxt) {
Sto znadi da je stek prazan.
data = dat;
Funkcija stack::cleanup( ) ne briSe niSta. umesto toga, ustanovaljava dwsto
next = nxt;
pravilo da ste ,,vi (programer koji koristi ovaj objekat Stack) odgovorni za preuzi-
)
manje svih elemenata sa steka i njihovo brisanje". Funkcija require( ) se koristi da
void Stack::initialrze0 { head - 0; }
ukaZe na gre5ku u programu ako stek nije ptazan.
Zasto destruktor strukture stack ne obrise sve objekte koje programer nije
void Stack::push(void* dat) {
preuzeo funkcijom pop( )? Problem je Sto Stack sadrlipokaziva(e tipa void*, a u
Link* newLink = new Link; poglavlju 13 iete videti da se operator delete ne primenjuje ispravno na tip
newLink->initi al'ize(dat, head) ; void*. Tema ,,ko je odgovoran za memoriju" nije (ak ni tako jednostavna, kao
head = newLi nk; Sto Cemo videti u kasnijim poglavljima.
I
t80 Misliti na jeziku C++ Poglavlje 4: Apstrakcija podataka t8l

Ovo je primer koji testira Stack: Razre5avanje globalnog opsega


ll: C)a:StackTest.cpp operator za razresavanje opsega izvladi vas iz situacija u kojima ime koje pre-
//{ Li Stack vodilac bira kao unapred definisano (,,najbliZe" ime) nije ono sto hoiete. Na
//{T} StackTest.cpp primer, pretpostavimo da imate strukturu s iokainim identifikatorom a i hoiete
ll lest ugneZdene povezane liste da, iz funkcije dlanice, koristite globalni identifikator a. Prevodilac bi podra-
#i ncl ude "Stack. h" zumevao izbor lokalnog, tako da mu morate reci da postupi drugaiije. Kada
#include "../require.h" hocete da zadate globalno ime pomoiu razreSavanja opsega, koristite operator
#i ncl ude <fstream> ne navodeii niSta ispred njega. ovo je primer razreSavanja globalnog opsega i za
#include <iostream> promenljivu i za funkciju:
4i ncl ude <stri ng>
usi ng namespace std; //: C04:Scoperes.cpp
// RazreSavanje globalnog opsega
i nt mai n ( i nt argc, char* argv [] ) i int a;
requireArgs(argc, 1); // Argument je ime datoteke void f0 {}
jfstream in(argvIl]);
assure(in, argv[1]); struct S {
Stack textl i nes; int a;
text I i nes. i n i ti al i ze 0 ;
void f 0;
string line; ];
I I Cita datoteku 1 upisuje redove na stek:
vold S::f0 {
whi 1e(get1 i ne(in, 1 ine) )
textl i nes . push (new stri ng (1 i ne) ) ; ::f0; ll Inade bi ovo bila rekurzija!
i ispisuje :za++: ll Globalna promenljiva a
ff Preuzina redove sa steka th:
a--: // Promenljiva a u opsegu strukture
stri ng* s;
whi le((s = (string*)textlines.pop0) != 0) ( )

cout << *s .. endl ;


de1 ete s; int main0 { S s; f0 I //l:-
) Bez razre5avanja opsega u S::f( ), prevodilac bi podrazumevao da se pristupa
t e x tIi ne s.cI e a n u p( ) ; dlanovima f( ) i a strukture.
j lll:-
Ovo je slidno jednom ranijem primeru, ali se redovi datoteke (kao pokazivadi
na tip string) smeitajtr na stek, a zatim se preuzimaju, Sto dovodi do ispisivanja SaZetak
redova datoteke obrnutim redosledom. Zapazimo da funkcija dlanica pop( ) U ovom poglavlju ste saznali osnovnu razliku izmedu C++-a i C-a. U C++-u funk-
vraia vrednost tipa void*, ko ja se mora pre kori5ienja konvertovati u tip string*. cije moZete smeStati unutar struktura. Ovaj novi tip strr,rkture se naziva apstrak-
[)okazivaC se clerelerencira da bi sc ispisao znakovni niz. tni tip podataka, a promenljive koje definiSete koriSienjem ove strukture se
'fokolrr popLrnjavanja steka textlines, sadrZaj promenijive line nazivaju obiektiili instancetogtipa. Pozivanje funkcije elanice objekta se naziva
se ,,klonira' u
svakonr pozivu tirnkcijc push( ) pomoiu new string(line). Operator new u ovom slanie poruke tom objektu. Osnovna akti."most u objektno orijentisanom progra-
slLrcaju, vraia pokaz-ivai na nov znakovni niz u koji je kopiran sadrZaj promen- miranju jeste slanje poruka objektima.
ljive line. Da ste jednostavno prosledili adresu promenljive line funkciji push( ), Zajednidko pakovanje podataka i funkcija znadajno poboljsava organizaciju
na krajtr biste imali stek popunjen identidnim adresama koje bi pokazivale na koda i olakSava upotrebu biblioteka zato sto skrivanje imena spredava dvosmi-
line. O ovom procestr ,,kloniranja" iete saznati viSe u nastavku knjige. slenosti. osim toga, mozete uraditi i mnogo vise da biste programe na u c++-u
Ime datoteke se uzima s komandnog reda. Da bi se obezbedio dovoljan broj udinili bezbednijim. U sledeiem poglavlju iete nauditi kako da zastitite poje-
argumenata na komandnom redu, koriste se druga funkcija iz datoteke zaglavlja dine dlanove strukture, tako da samo vi moZete da im pristupite. ovo usposta-
require.h: tunkcija requireArgs( ). Ona uporeduje argc sa zahtevanim brojem vlja jasnu granicu izmedu onoga Sto moZe promeniti korisnik strukture i onoga
argunrenata, ispisujc odgovarajuiu poruku o gre5ci i izlazi iz programa ako Sto moZe menjati samo programer.
r-renra dor,ol jno argurncnata.
183
Misliti na jeziku C++ Poglavlje 4: Apstrakcija Podataka
182
tako da se
I I . Napi5ite program s kodom koji se uslo'uno prevodi 1*uill )'
Ve2be jedna poiuka ispisuje ako je definisan pretprocesorski indikator' a druga
Reielljaizabranihzar]atakasenalazeuelektronskonlrlokumentuTheThinkinginC++AnnotatedSolution uto ,rij" definisan. Prevedite ovaj k6d eksperimentiSuii sa komandom
zadati
(irririe
koii st', ttz malu
"iJot'iuai''
n'oz" prertz-eti s adrese ww'BruceEckel com' #define unutar programa. Zatim pronadite kako iete prevodiocu
znakova na konzoli
l. Funkcija puts( ) standardne C biblioteke ispisuje niz pretprocesorske definicije s komandnog reda i to isprobajte'
(mozete nufitu,i puts("zdravo")) Napi5ite program C-u koji koristi jednim argumentom koii
1a.
ovu funk- I 2. Napi5ite program koji koristi funkciju assert( ) s
deklarise
puts( ), ofi ,i. utf;ue"je <stdio'h>' niti na drugi nadin ,rr"t i.nu *"anost false (nula) i posmatrajte Sta se de5ava dok ga izvrSa-
ciju.(NekiprogramiobuhvatajuiprevodilaczaC++iprevodilaczaC;akoie vate. Zatim prevedite program s komandom #define NDEBUG i izw5ite ga
C-a.) prevodenje sa
takav i uuS p.l?oJiluc, pronadite indikator koji aktivira ponovo da biste videli razliku'
i uodite razliku.
sada prevelite program pomoiu c++ prevodioca I 3. Napravite apstraktni tip podatka koji oredstavlia video kasetu
u vider
dianicom' a zatim
2. Napi5ite deklaraciju strukture s jednom funkcijom Hutu. pokutajte da ,--rrrbt.it" sve podatke i operacije koji bi mogli bit
definisite t, funt.i1,dlanicu. Napravite objekat novog tipa i pozovite neophodni raiipvid"o, kako bi dobro funkcionisao u sistemu upravljanjr
firnkciiu clanictt' video klubom. Ukljudite tunkciju dlanicu printO koja prikazuje infor
3.IzmenitereSenjezadatka2,takodasestrukturadeklari5euisprarmozasti- macije o objektu tiPaVideo.
e"nol Outui..i s definicijom u jednoj datoteci tipa cpp i funkci- 14. Napravite stek koji sadrZi objekte tipa Video iz prethodnog zadatka
'agta't1a,
Napravite nekoliko objekata tipa Video' smestite ih na stek, a zatim
jom mainO u drugoi' il

4. Napravite struktttru s iednim podatkom dlanom tipa


int i dve globalne prikaZite korisienjemVideo::print( )'
pokazivaai na tu strukturu. Prva funkcija ima i velidine svi
ftrnkcije, e iii puionl.tri su 15. Napi5ite program koji, primenom operatora sizeof, ispisuje
int, i celobroinom podatku i7 strukture dodeljuje
,trrgi urgr',ir',In,' tipu osnovnih tipova podataka na radunaru'
Druga funkcija prikizuje celobrojni podatak struk- ,l6.
r.reclnosr
"rgr*."rL. Izmenite stash tako da koristi vector<char> kao osnovnu struktur
ture. Testiraite ove funkcije' podataka.
5.Ponoviteprethodnizadatak,takodaovefunkcijebududlanicestrukturei 'l7. Dinamieki zauzmite memoriju za podatke sledeiih tipova, koristeii nev
Ponovo ih testiraite' int, long, niz od 100 elemenita tipa char, niz od 100 elemenata tipa floa
6.Napraviteklasukojapomoiurezervisaneredithis(odnosisenaadresu priiaziti njihove adrese i zatim oslobodite memoriju koristeii delete.
tekuieg objekta) pristupa podatku dlanu i funkciji dlanici' l8.Napisitefunkcijusjednimargumentomtipachar*.Koristeiioperatolne\
double' Popunite je sa
7. Napravite strukturu Stash koja sadrZi podatke tipa dinamidki rezervisite prostoiza niz eiemenata tipa char, iste veiidine
ka
25 wednosti tipa double i ispi5ite ih na konzoli' je niz znakova kojise prosleduje funkciji. Primenom indeksiranja niz
Sto
(ne zaboravir
8. Ponovite prethodni zadatak za Stack' kopirajte znakove iz irgumenta u dinamidki napravljeni niz
jednim.argumentom tipa inti or.tut , kraja niza) i waiite pokazivai na kopiju' U funkciji testiraj
1ai1t ) zatir
9. Napravite datoteku koia sadrZi funkciju f( ) s a
ispisuie ga na konzoli iori5ieniem funkcije printf( ) iz zaglavlja <stdio'h> ovu funkciju prosledujuii itatifki niz znakova pod navodnicima,
na steaeCi nadin: printf(,,%din" i)' gde je iceo broj koji hoiete da dobijeni ."rritut po.toro prosledite funkciji' Ispisite oba znako'rna niza

Naf ru,rit" po."bnu datoteku koja sadrZi funkciju main( ) i obapokazivada,paietevidetidasenalazenarazliditimmestima'PI


pritazete. "^9ygj
datotecideklari5itefunkcijuf().ijijeargumenttipafloat.Pozovitef()iz i *".tor., op".atori delete, oslobodite zauzeti dinamidki memorijski prosto
prevodiocem (ugneider
main( )' eotusalte da prevedete i poutZ"te program C++ 19. PrikaZite primer strukture deklarisane unutar druge strukture
C prevodio-
a"Su"u' Sada prwedite i poveZite program i defir
po..nurrul*- Siu tt strukturaj.Deklari5ite podatke ilanove u obe strukture i deklari5ite
cem i posmatraite Sta se deSava iri izwsavanju' Objasnite ovo pona5anje' Site funkcije ilanice ubbe strukture. Napisite funkciju main( ) koja testi

l0.otkrijtekakomoZeteprevestiplogramnaasemblerskijezikpomocusvojih va5e nove tiPove.


jednom funkci-
c i (,++ prevodilaca. Napisite iunlciju na c-u i strukturu s 20. Koliko je struktura velika? Napisite program koji ispisuje velidine razliiit
jomilanicomnaC++-u'Prevediteihnaasemblerskik6dipronadite struktura. Napravite strukture koje imaju samo podatke dlanove istruktu
imenafunkcijadobijenanaosnovtlCfunkcijeiC++funkcije6lanice,tako koje imaju i iodatke dlanove i funkcije dlanice. Zatim napravite strukru
rezult
da moZete uoditi kako prevodilac dopunjuje imena' bez ikakvih dlanova. Ispisite velidine svih ovih struktula. objasnite
dobijen za strukturu bez dlanova.
184 Misliti na jeziku C++ t
21. (.++ z.a stnrkture aLltontatski pravi definiciju tipa (ekvavilent izrazatype-
def), kao Sto ste videli u ovom poglavlju. Isto radi i za nabrojive tipove i
unije. NapiSite mali program kojim se to pokazuje.
22. Napravite stek koji sadrZi objekte tipa Stash. Svaki objekat tipa Stash ie
sadrZati pet redova iz ulazne datoteke. Objekte tipa Stash napravite
pomoiu operatora new Ueitajte datoteku u stek, a zatim je ispi5ite tako
Sto iete ditati redove iz steka.
23.lzmenite zadatak 22: spoljnu struktura za stek koji sadrZi objekte tipa
Stash. Korisnik moZe da dodaje i uzima redove samo preko funkcija dla-
nica, ali struktura u suStini koristi stek objekata tipa Stash.
24. Napravite strukturu koja sadrZi podatak tipa int i pokazivad na drugu
instancu iste strukture. Napi5ite funkciju diji su argumenti adresa jedne od
ovih struktura i ceo broj koji ukazuje na duZinu liste koju hoiete da
napravite. Ova lunkcija treba da napravi ceo lanac struktura (pouezanu
llsru), poiev od argumenta (glaualiste), pri demu svaka struktura pokazuje
na sledeiu. Nove strukture pravite primenom operatora new a broj (redni \. it ..l.
broj objekta) smestite u podatak tipa int. U poslednjoj strukturi liste poka-
zivadu dodelite vrednost 0, kako bi se ukazalo daje to kraj. Napi5ite drugu
funkciju diji je argument glava liste i koje se pomera do njenog kraja,
ispisujuii za svaku strukturu wednost pokazivaea i celobrojnu vrednost.
25. Ponovite zadatak 24, ali funkcije smestite unutar strukture, umesto da
:.r]$'
koristite obidne strukture i funkcije.
I86 Misliti na jeziku C++ Poglavlje 5: Skrivanje realizaciie I87

I)eklaracije funkcija su smeStene unutar strukture, pa je promenjen naiin na struct A (

koji sc ltrnkcije pozivaju, a adresa strukture se ne prosleduje kao prvi argument. int i;
ll (.++ se dehnisar.rjern stnrkture programu dodaje novo ime tipa, tako da u struk- char j ;
turi lre nrorate koristiti rezervisanu red typedef. fl oat f;
Sve ove pogodnosti vam pomaZu da organizujete k6d i da ga Iakie eitate i void func0;
piSete. Kada je red o pojednostavljivanju biblioteka u jeziku C++, postoje i druge );
va2ne temc, posebno one koje se odnose na bezbednost i kontrolu. Ovo pogla-
r,'l je razmatra ogranicenja struktura. vo'i d A::func0 ()

struct B {
Postavljanje og ran ice nja int'i ;

U s*ak.m orlrrosrr jc vazno da postoje granice koje svi poStuju. Kada pravite char j;
fl oat f;
lriblioteku, r,i zapravo uspostavljate odnos s programerom klijentom koji ie
void func0;
koristiti tu bibliotekr,r da bi napravio aplikaciju ili drugu biblioteku.
);
U stnrkturama jezika C, kao i u veiini drugih konstrukcija tog jezika, pravila
nema. Klijenti rnogu s njima da rade Sta god Zele, inema nadina da im se pri tome void B::func0 {}
namotnu ograniCenja. Na primer, iako ste u prethodnom poglavlju uvideli znadaj
Iunkcija initialize0 i cleanup0, programeri ne moraju da pozoru te funkcije. int main0 {
(l-l sledeiem poglavlju iemo razmotriti bolji pristup.) Iako biste voleli da progra- A a; B b;
meri ne rade direktno s nekim dlanovima strukture, u jeziku C ne postoji nadin da a.i = b.i = l;
to spredite. Sve im je na dohvat ruke. a.i = b.i = rcr'
Pristup dlanovima treba kontrolisati iz dva razloga. Prvi je, da se drugi progra- a.f = b.f = 3.14159;
meri zadrZe dalje od alata koje ne bi trebalo da diraju, a to su alatke neophodne a. func 0 ;
za internu olrraclr.r podataka, i nistr deo interfejsa koji je programeru klijentu b. func 0 ;
potreban za reSavanjc r.rjegovog problema. Ograniden pristup je usluga progra- ) l//,-
rnerinra, jer rnogrr lako da vide 5ta je za njih vaZno, a Sta mogu da zanemare. Rezervisana rea private, znadi da niko, osim vas koji ste napravili strukturu,
I)rugi razlog za kontrolu pristupa jeste da se tvorcu biblioteke omoguii da pro- ne moze da pristupi funkciji dlanici tog tipa. Rezervisana rei private je zid
tttetti interno fttttkcionisanje strukture, a da pri tome ne brine kako ie to uticati izmedu vas i programera klijenta; ako klijent pokusa da pristupi privatnom
na klijente. U primeru za stek, u prethodnom poglavlju, moZete poZeleti da, ilanu, prevodilac ie prijaviti greSku. Evo kako iete sakriti neke delove strukture
brzine radi, rezerviSete veie memorijske blokove, umesto da pravite novo skladi- (to jest, neke podatke dlanove), tako da budu dostupni samo vama:
5te svaki put kada dodajete element. Ovo moZete postiii ako su interfejs i realiza-
cija jasno raz-granideni i za5tiieni, i pri tome iete od programera klijenta zahtevati //: C05:Private.cPP
samo da ponovo poveZe svoj k6d s bibliotekom. // Postavljanje ogranidenja
struct B {
Kontrola pristupa u leziku C++ pri vate:
char j;
(.++ uvodi trt ttovc rc'zervisane reii za ogranidavanje pristupa strukturi: public float f;
(jar,ni), private (privatni) iprotected (zaitiieni). Njihova upotreba i znadenje su public:
veoma jasni. Ovi specif katori pristupa (engl. access specifiers) koriste se samo u int i;
dcklaraciji strukture i menjaju prava pristupa za sve deklaracije koje slede. Iza vojd func0;
specifikatora za pristup uvek morate staviti dve tadke. );
Clanovi diie su deklaracije navedene posle rezervisane redi public su javni, i
dostupni su svima. Javni ilanovi srr kao dlanovi strukture jezika C. Na primer, void B::funcQ {
sledeie cleklaracijc stnrktr.lra su identidne: i = 0;
i ln l-
- v
ll: C05:Publrc.cpp .l

f = 0.0;
t

II Javni cl anovi su kao dl anovi strukture jezi ka C


l-
r88 Misliti na jeziku C++ Poglavlje 5 : Skrivanje realizacije It t
int main0 {
structX{//Definicija
B b; pri vate:
b.i = i; I I u redu, dlan je javni int i;
l ll b.j = 'l' ; // nepravilno, clan je privatni publ i c:

lll b.f = l.o; // nepravilno, clan je privatni void initialize0;


\ I ll,- friend void g(X*, int); // Globalna prijateljska funkcija
je friend void Y::f(X*); // Prijateljski ilan strukture
Iako funkcija funcO mo7.e da pristupi bilo kom dlanu strukture B (jer i ona friend struct \ // Cela struktura je prijateljska
ilan te strukture, sto joj automatski omoguiuie pristup), obidna, globalna
friend void h0;
funkcija, kao 5to ie main0, ne moZe pristupiti ilanovima strukture B. Nararmo, t.
clanovima strukture B neie moii da pristupe ni funkcije koje su dlanice drugih
struktura. Pristup privatnim dlanovima imaju samo funkcije koje su jasno nave- voi d X::initialize0 {
dene u deklaraciii strukture (u ,,ugovoru"). i=0;
Specifikatori pristupa se ne moraju pojavljivati po odredenom redosledu i )
mogu se ponavljati. Specifikator utiae na sve alanove deklarisane nakon njega,
do pojavli ivanja sledeieg specifikatora. void g(X* x, int i) {
x->i = i;
Specifi kator protected
)

poslednji specifikator pristupa je protected. Rezervisana red protected deluje voi d Y: : f(X* x) {
isto kao i private, s jednim izuzetkom, o kome jo5 uvek ne mozemo govoriti: x->i = 47;
je pri-
,,naslednicima" (koji ne mogu pristupiti privatnim dlanovima), dozvoljen )
stup zastiienim (engl. protectes dlanovima. ovo ie postati jasnije u poglavlju 14,

gde se uvodi pojam nasledivanja. Zasad smatrajte da su za5tiieni ilanovi isto Sto struct Z {
i privatni. pri vate:
int j;
publ i c:
Prijatelji strukture void initialize0;
Zamislite da izridito Zelite da dodelite pravo pristupa funkciji koja niie dlanica void g(X* x);
l.
tekuie srrukture. To iete postiii deklarisanjem te funkcije kao prijatelja (engl.
je se deklaracija prija-
friend)strukture, unutar deklaracije strukture. VaZno da void Z::initialize0
ielja poiavi u deklaraciji strukture, jer se mora omoguiiti vama (i prevodiocu) da {
j = 9e;
iz deklaracije strukture vidite sva pravila o velidini i ponaSanju tog tipa podataka.
vazno pravilo u svakom odnosu glasi: ,,Ko moZe da pristupi mojoj realizaciii?"
)

I(asa kontrolise koji deo koda moZe da pristupi njenim dlanovima. Ne postoji void Z::g(X* x)
neki daroban nadin da pristupite klasi, ako niste njen priiatelj; ne moZete deklari-
{
x->i += j.
sati novu klasu, a onda reii: ,Zdravo, ja sam prijatelj klase Pl" i odekivati da vidite
)
privatne i zaStiiene dlanove klase P.
Kao prijatelja mozete deklarisati globalnu funkciju, funkciju dlanicu neke void h0 {
druge strukture, ili dak celu strukturu. Evo jednog primera: X x;
I I : C05: Fri end ' cPP x.i = 100; // Direktan rad s podacima
ff Rezervisana rei fniend dozvoljava poseban pristup )

I I Deklaracija (nepotpuna specifikacija tipa) : int main0 {


struct X; X x;
7 z.
struct Y { z. g (&x) ;
void f(X*);
.I:
I l//,-
r90 Misliti na jeziku C++ Poglavlje 5 : Skrivanje realizacije l9l

Stnrktura Y ima fr-rnkcijr-r dlanicu f( ) koja menja objekat tipa X. Ovo je pomalo struct Holder {
zagonetno, jcr C++ prevodilac zahteva da unapred deklari5ete sve na Sta se pozi- pni vate:
vate. Tako morate deklarisati strukturu Y pre nego Sto se njen ilan Y::f[X*) moZe int aIsz];
deklarisati kao prijatelj u strukturi X. A1i, da bi se deklarisao dlan Y::f(X*), pre- publ i c:
thodno sc nlora deklarisati struktura X! void initialize0;
Evo, kako se to re5ava. Obratite paZnju na to da ilan Y::f(X*) uzima adresu struct Poi nter;
objekta X. Prevodilac uvek zna kako da prosledi adresu, jer su adrese fiksne friend Pointer;
dtrZine, bez obzira na tip objekta o kome se radi. Pre nego Sto vam dopusti da struct Pointer {
deklariiete {'unkcijrr kao 5to je Y::g[X), prevodilac mora da vidi celu definiciju pri vate:
strukture X, da bi zr.rao velidinu objekta. Holder* h;
[)oSto sc prosleduje adresa stnrkture X, prevodilac vam dozvoljava da za tu i nt* p;
publ i c:
strrrktrrru napravite tlepotputlu specifikaciju tipa,pre nego 5to dek-lariSeteY::f[X*).
'Io se postiTe sledeiom
dcklaracijom: void injtial ize(Holder* h);
struct X;
// Kreeift se kroz niz:
void next0;
Ova deklaracija kaZe prevodiocu da postoji struktura pod traZenim imenom, voi d previ ous 0 ;
Sto jc dovoljno ila joj se pristupi u sluiajevima kada nije neophodna puna void topO;
definicija. void end0;
Sada se funkcija Y::f(X*) mo'ze,bez problema, deklarisati kao prijatelj struk- // eri stupne vrednost i :

ture X. Da ste pokuSali da je dek-lariSete pre nego Sto je prevodilac video punu int read0;
specifikaciju za Y dobili biste greSku. Ovo je sigurnosna karakteristika koja void set(int i);
obczbeduje doslednost i elimini5e greSke. );
Primetite i druge dve prijateljske tunkcije. Prva deklariSe obidnu globalnu );
prijateljsku funkciju g( ). Ali, funkciju g( ) nismo prethodno deklarisali u global-
noj oblasti r,aZenja! Iz ovoga sledi da se, koriSienjem rezervisane redi friend na
voi d Hol der: : i ni ti al i ze0 {
memset (a, 0, sz * sizeof(i nt) ) ;
ovaj naiin, furnkcija moZe istowemeno deklarisati i proglasiti prijateljem. To se
l
proSiruje i na celrr strukturu:
fri end struct Z; void Holder: :Pointer: :injtialize(Ho1der" rv) (

Ovo je nepotpuna specifikacija tipa za strukturu Z, h = rv;


i istowemeno se celoj
strukturi dodeljuje status prijatelja. P = rv->a;
)

UgneZdeni prijatelji void Holder: :Pointer: :next0 {


IJgne2dene struktlrre ne dobijaju automatski pristup privatnim dlanovima. Da if(p < &(h->a[sz - 1])) p**;
bistc to postigli, rnorate proii kroz sledeii postupak: najpre, deklariSite (bez )

definisanja) ugncZdenu stnrkturu, zatim je deklariSite kao prijatelja, i na kraju,


void Ho'lder: :Pointer: :previous0
defini5ite stnrkturu. Definicija strukture se mora odvojiti od deklaracije prija- {

telja, inai:e prevodilac neie smatrati ugneZdenu strukturu dlanom klase.


if(p > &(h->a[0] )) p--;
)
I-.vo jednog primera:

I l: C05: NestFriend.cpp voj d Hol der: : Poi nter: : top 0 {


// UgneZdeni prijatel j j p = &(h->a [0] ) ;
*i ncl ude <i ostream> )
#include <cstring> // memset0
usi ng namespace std; voi d Hol der: : Poi nter: : end 0 {
const int sz = 20; p=&(h->a[sz-1]);
)
192 Misliti na jeziku C++ Poglavlje 5: Skrivanje realizacije 193 t
i nt Hol der: : Poi nter: : read ( ) { Da li je C++ ,,tist" jezik?
return *p; Iz definicije klase vidite koje funkcije mogu da menjaju privatne delove k]ase. Ako
)
je funkcija prijatelj, znadi da ona nije dlan, ali da vi ipak Zelite da joj dozvolite da
pristupa privatnim podacima. To onda mora biti navedeno u definiciii klase, tako
void Holder: :Pointer: :set(int i) {
*P = i ; da svi vide da se radi o jednoj od privilegovanih funkcija.
C++ je hibridni objektno orijentisani jezik, a ne dist, i rezenrisana rea friend je
i
dodata da bi se savladali praktidne probleme koji mogu da iskrsnu. Treba istaii
int main0 da ovakvi dodaci dine jezik manje distim, ali C++ je osmisljen tako da bude prak-
{
Ho1 der h; tidan, a ne da teZi nekom apstraktnom idealu.
Hol der: : Poi nter hp, hp2;
int i ;
Raspored objekata stru ktu re
h.initialize0; U poglavlju 4 smo Wrdili da ie struktura napisana na C-u, a kasnije prevedena
hp.initialize(&h); C++ prevodiocem, ostati nepromenjena. Ovo se, pre svega, odnosilo na raspored
hp2.initjalize(&h); objekata strukture, to jest, na poziciju svake od promenljivih u okviru memorije
for(i = 0; i < sz; i++) { rezervisane za taj objekat. Ako C++ prevodilac promeni raspored objekata struk-
hp.set(i ); ture u C-u, svi delovi koda u C-u, koji koriste informacije o poziciji promenljivih
hp. next 0 ; u strukturi (Sto baS i nije preporudljivo), neie raditi'
) Kad podnete da koristite specifikatore pristupa, potpuno prelazite u carstvo
hp. top 0 ; C++-a, i stvari se menjaju. U okviru odredenog ,,pristupnog bloka' (to je lista
hp2. end 0 ;
deklaracija ispred kojih se nalazi specifikator pristupa), promenljive ie sigurno
for('i = 0; i < sz; i++) { biti rasporedene jedna iza druge, kao u C-u. Medutim, pristupni blokovi se
cout << "hP = " << hP.read() fizidki mogu pojaviti u objektu po, redosledu drugadijem od onog po kome ste ih
.. " , hp2 = ,, .. hp2. read 0 << end'l .
deklarisali. Mada ie prevodilac najieiierasporediti blokove tadno onako kako ih
hp. next 0l vidite, tu ipak nema pravila. Arhitektura radunara i/ili operativni sistem mogu
hp2. previ ous ( ) ;
imati specijalnu podr5ku za privatne i zaStiiene dlanove, Sto zahteva da se takvi
blokovi smeste na posebno mesto u memoriji. Ovakvu pogodnost specifikacija
)

I lll,- jezika ne sme da ometa.


Kacla je struktura Pointer deklarisana, dodeljuje joj se pristup privatnim Specifikatori pristupa su deo strukture i ne utidu na objekte napravljene van
ilanovinra strukture Holder, tako Sto kaZemo: strukture. Sve informacije o pravima pristupa nestaju pre izw5avanja programa;
fri end Poi nter; ovo se ugla'rnom de5ava tokom prevodenja. Za weme izw5avanja programa'
Strr.rktura Holder sadrZi niz cetih brojeva i Pointer omoguiava da im pristu- objekti postaju ,,oblasti za skladiStenje" i niSta viSe. Ako ba5 Zelite, moZete prekr-
pate. Posto je struktura Pointer awsto povezana sa strukturom Holder, razumno Siti sva pravila i direktno pristupiti memoriji, kao u jeziku c. c++ nije osmisljen
je da postane alan te strukture. Ali, Pointer i Holder su odvojene klase, pa u tako da vas spredava u bilo demu. On vam samo obezbeduje alternative koje se
glavnom programu moZete napraviti viSe objekata te strukture koje iete koristiti mnogo lakSe koriste.
za pristup razliditim delovima niza. Pointer je ovde struktura, a ne obidan poka-
U op5tem sludaju, nije dobra ideja da pri pisanju programa zavisite od specifl-
zivae kao u jeziku C, tako da moZete biti sigurni da ie uvek bezbedno pokazivati dnosti realizacije prevodioca. Ako je to neophodno, onda specifidnosti od kojih
unutar struktlrrc Holder. zavisite kapsulirajte unutar strukture. Kasnije iete lakse prilagoditi program
IJ naveclenorn programu (u <cstring>) kao olak5ica je upotrebljena funkcija drugim prevodiocima, po5to su sve specifidnosti na jednom mestu.
memset( ) iz stanclardne bibliotekc jczika C. Ona popunjava memoriju, poaev
ocl arlresc (iz. prvog argtrnrenta), upisujrrii vrednost drugog argumenta, u broj
bajtova zaclat treiinr argumentom. Naravno da ste mogli da koristite petlju za Klase
pnrlaz.ak kroz rrernoriju i r-rnos vreclnosti, ali na raspolaganju vam je proverena Kontrola pristupa se desto naziva i skriuanje realizacije. Uk-ljudivanje funkcija u
firnkcija memset ( ), s koionr ietc teZe pogre5iti i koja je verovatno efikasnija od strukture (kapsuliranjell) proizvodi tip podataka s odredenim karakteristikama
koda koji bistc napisali. i ponaSanjem, a kontrola pristupa reguli5e prava pristupa tom tipu podataka, i
I Vei smo naglasili da se za kontrolu pristupa koristi termin kapstlliranie
t94 Misliti na jeziku C++ Poglavlje 5 : Skrivanje realizaclje 195

to iz dva va2na razloga. Prvi je da se utvrdi Sta klijent moZe da koristi, a Sta ne int B::f0 {
moZe.-fada moZete u struktrlru r-rgraditi interne mehanizme, bez brige da ie ih returni+j+k;
progran'rcri koristiti kao ileo interlejsa. )
Ovo nas dovodi do clrtrgog razloga, a to je odvajanje interfejsa od realizacije.
Ako se struktura koristi u viSe programa, a klijenti mogu da pristupe samo jav- void B::90 {
nom interfejsu, onda vi moZete da promenite sve Sto ima privatni status, i pri i = j = k = a;
tome neiete z-ahtevati bilo kakve izmene u kodu klijenata. )

Spoj kapsuliranja i kontrole pristupa predstavlja ne5to vi5e od strukture u


jeziku C. tJ svetu objektno orijentisanog programiranja, struktura opisuje klasu int main0 {
A a;
obiekata, kao 5to biste vi opisali vrstu riba ili ptica: svi objekti jedne klase imaju
B b;
zajednidke karakteristike i pona5anja. Tako je deklaracija strukture postala opis
izglecla i pona5anja objekata te strukture.
a.f0; a.s0;
b.f 0; b's0;
LJ prvom objektno ori,;entisanom jeziku, Simuii-67, rezervisana ree class kori-
j / // ,-
stila se za opis novog tipa podataka. Ista rezervisana red pojavljuje se i u C++-u,
nagla5avajuii poentu tog programskog jezika: pravljenje novih tipova podataka Klase predstavljaju osnovni koncept obiektno oriientisanog programiranja
koji su bolji od C struktura s funkcijama. Ovo, svakako, izgleda kao adekvatno na C++-u. Prelazak na klase je toliko vaZan da bi Stroustrup (koji je klase uveo u
opravdanje za no\.tl rezervisanu red. C++) najradije potpuno izbacio strukture, ali to ne dozvoljava potreba za kom-
lI C++-u je rezervisana red class skoro nepotrebna. Od rezervisane redi struct patibilnoSiu sa C-om.
razlikuje se samo u sledeiem: class podrazumeva privatni status za sve elemente, Mnogi pi5u klase na nadin koji vi5e odgovara strukturama, navodenjem jav-
dok struct podrazumeva javni. Evo primera dve strukture koje daju isti rezultat: nih elemenata na poaetku, dime se menja podrazumevani privatni status eleme-
nata klase:
Il: C05 C\ ass. cpp
// S1 i -nost i zmedu strukture i kl ase class X
publ i c:
{

struct A {
void i nterfejs_funkciia0 ;
prjvate: pri vate:
int i, j, k; void privatna_funkci ja0 ;
publ 1 c: i nt i nterno_pri kazivanie;
int f0; );
vord g0; Klase se pi5u ovako jer je ditaocu vazno da najpre vidi dlanove koji su njemu
); bitni, a da sve sto stoji iza reai private moZe da zanemari. Ostali se ilanovi dekla-
riSu da bi se omoguiilo prevodiocu da sazna velidinu objekata i da mu pravilno
int A::f0 ( dodeli prostor u memoriji, Sto garantuje konsistentnost.
returni+j+k; U primerima navedenim u ovoj knjizi, ipak iemo prvo deklarisati privatne
)
dlanove:
void A::90 { class X {
i = j = k = 0; void privatna_funkciia0 ;

)
i nt interno_pri kazi vanie;
publ i c:
I I lsti rezul tati se dobijaju sa: void i nterfejs_funkciia0 ;
);
class B (

int i, j, k;
publ i c:
int f0;
void g0;
.};
197
r96 Misliti na jeziku C++ Poglavlje 5: Skrivanje realizacije t-

Neko ie se dak pomtrciti da sam obeleZi privatna imena: Kontrola pristupa steku
class Y U drugom primeru prepraviiemo stek tako da postane klasa. Sada je ugneZdena
struktura fodataka privatna, sto je dobro, jer obezbeduje da klijent ne mora da
{

public:
void f0; vidi interni izgled steka, niti da od njega zavisi:
pri vate: //: C05:Stack2.h
r r.t rX; / 0or sro ire ff Povezana lista ugneZdene strukture
); #i fndef STACKZ_H

I)oSto jc mX sakriven tr klasiY, ncpotrebno ie staviti i oznaku m (za dlana,


VCL' #defi ne STACKz_H

engl. nteniber). tJ projektima sa puno globalnih promenljivih (5to treba rzbega-


vail), valja koristiti rnoguinosr da se u okviru definicije tunkcije dlanice razlikuju class Stack i
gl<,rbalni podaci od clanova.
struct Link {
vojd* datal
Link* next;
Upravljanje pristupom dinamickom nizu void initialize(void* dat, Link* nxt);
Iz-meniiemo primere iz aetvrtog poglavlja da bismo u njima upotrebili klase i )* head;
publ i c:
upravljanje pristupom. Primetite kako se deo interfejsa, namenjen klijentima,
sada jasno izdvaja od ostatka koda, pa vise ne postoji moguinost da klijenti
void initialize0;
voi d push (voi d* dat) ;
petljaju s ostalim delovima klase.
voj d* peek 0 ;
//: C05: Stash. h void* pop0;
// Upravlianje Pri stuPom voi d cl eanup 0 ;
#i fndef STASH_H
);
#defi ne STASH_H #endif ll SIACKZ-H l/l:-
class Stash Kao i ranije, realizacrja se ne menja, pa je ovde nismo ponavljali. Datoteka za
{

i nt si I I 'le1i il na svakog skl adi 5ta


ze; testiranje, takode, ostaje ista. Jedina promena je poboliSanje interfejsa klase. Zna-
i nt ty; I I Brq skl adi 5ta
quanti daj uprivljanje pristupom je u tome Sto vas tokom razvoja aplikacije spreaava da
i nt next; // Sl edece prazno skl adi 5te prekoradite ovlasienja. Zapravo, jedino je prevodilac upoznat s ovlasienjima za
// Dinamiiki dodelien niz bajtova: pristup svim dlanovima klase. U imenima dlanova se ne provladi nikakva infor-
unsi gnedchar* storage; maciji o ovla5ienjima koja bi se mogla preneti do programa za povezivanie. Pre-
void inflate(int increase) ; vodilac zawSava proveru zaStite pre podetka izvrSavanja programa'
publ i c: Interfejs koji se sada prikazuje programeru klijentu zaista je interfejs poti-
vord jnrtjalize(int slze) ; snog steka. On je realizovan u vidu povezane liste, ali to moZete promeniti, bez
voi d cl eanup 0 ; ikakvih posledica po rad klijenta i njegov kOd.
int add(void* element) ;

void* fetch(int jndex) ;


i nt count 0 ; Klase ruaki
); Kontrola pristupa u C++-u omoguiava vam da razdvojite interfejs od realizacije,
*endif ll STASH_H ///:- ali ovakvo skrivinje realizacije je samo delimidno. Prevodilac i dalje mora da vidi
FLrnkciji inflate( ) dodelili smo privatni status, jer nju koristi samo funkcija deklaracije svih delova objekta da bi ga pravilno naplavio i radio s njim' Mogli
add( ), pa je ona cleo interne realizacije, a ne deo interfejsa. Ovo znadi da kasnije biste zamisliti programski jezik koji zahteva samo javni interfejs objekta i
moZete promeniti internu realizaciju da biste drugadije upravljali memorijom. dozvoljava skrivinje privatne realizacije, ali u c++ se tipovi proveravaju, koliko
Osirn intena datoteke z.aglavlja, u ostalim datotekama koje koriste ovu klasu god je mogu (e, za weme prevodenja.To znaai da cete za gresku saznati Sto je
ne menja sc niSra. Izvorni k6d realizacije i program za testiranje ostaju isti. moguie pre. Ovo va5 rad dini jo5 efikasnijim.
Ukljudivanje privatne realizacije u opis kiase ima dva efekta: prvo, realizacija je
vidljiva, dak i ako joj ne moZete lako pristupiti, a drugo, moie prouzrokovati
bespotrebno Ponovno Prevodenje.
r98 Misliti na jeziku C++ Poglavlje 5 : Skrivanje realizacije 199

Skrivanje realizacije Ovo je sve Sto programer klijent moZe da vidi. Sledeii red:
U nekim projektima, klijenti ne smeju videti realizaciju. U datoteci zaglavlja bibli- struct Cheshi re;
oteke, mogu biti vidljive strate5ke informacije koje kompanija ne Zeli da stavi na jeste nepotpuna specifikacija tipaili deklaracija klase (definic4a kiase ukljuduje i
raspolaganje konkurenciji. Ako radite na nekom bezbednosnom projektu, kao Sto
telo klase). Ona prevodiocu ne saop5tava nikakve druge detalje o strukturi, osim
je algoritam za Sifrovanje, siglrrno neiete Zeleti da tr datoteci zaglavlja otkrivate
da je ime te strukture Cheshire. Ova informacija je dovoljna samo za pravljenje
bilo 5ta Sto i.li pomoglo zlonamernicima. IIi, moZe se desiti da svoju biblioteku pokazivada na strukturu; ne moZete praviti objekat bez tela strukture. U ovoj
stavljate u ,,neprijateljsko" okruZenje, gde ie programeri pristupati privatnim
tehnici, telo strukture smo sakrili u datoteci realizacije:
komponentama biblioteke, koristeii pokazivade i izriditu konverziju. U ovakvim
situacijama, bolje je da se struktura prevodi unutar datoteke realizacije, nego da //: C05:Handle.cpp {0}
se izloZi u datoteci zaglavlja. // Realizacija rudki
#include "Handle.h"
#include "../require.h"
Opti m izacija prevodenja
Upravljai projektom (engl. project menager), u va5em programerskom okru- l/ Defini5ite realizaciju klase rudkj:
Zenju, zahtevaie da se datoteka ponovo prevede ako se izmeni, ili ako se struct Handle: :Cheshire {
promeni bilo koja druga datoteka od koje ona zavisi, kao Sto su datoteke zagla- int i;
vlja. To znae i da iete, svaki pur kada izmenite klasu, bilo da ste promenili javni )r
interfejs ili deklaraciju privatnog dlana, prouzrokovati prevodenje svega Sto
ukljuduje datoteku zaglavlja. Ovo se desto naziva problem krhke osnoune klase void Handle: :initial ize0 {

(engl. fragile base-class problem). Ovaj problem dolazi do izraZaja u ranoj fazi smile = new Cheshire;
razvoja velikih projekata, kada se interna realizacija desto menja; ako je projekat
smile->i = 0;
)
veliki, predugo prevodenje moZe onemoguiiti brze preokrete.
'l-ehnika koja se koristi za re5avanje ovog problema
nekada se naziva ,,klase void Handle: :c1eanup0 {
rrrdki" (engl. handle classes) ili ,,Cheshire cat"2 - sve vezano za realizaciju, osim delete smile;
pokazivada, nestaje. Ovaj pokazivad se odnosi na strukturu dija se definicija
)
nalazi u datoteci realizacije, zajedno sa definicijama funkcija dlanica. Prema
tome, dokle god se interfejs ne promeni, datoteka zaglavlja ie biti netaknuta. int Handle::read0 {
Realizaciju moZemo da promenimo, i pri tome iemo samo datoteku realizacije return smi 1 e->i ;
morati ponovo da prevedemo ipoveZemo s projektom. )
Evo jednostarrnog primera koji prikazuje olu tehniku. Datoteka zaglavlla
sadrZi santo jami interlejs i jedan pokazivad nepotpuno zadate klase: void Handle::change(int x) {

//: C05: Handl e. h


smile->i = x;
// K1 ase rudki I // /:-
#i fndef HANDLE_H Struktura Cheshire je ugneZdenar po se mora navesti puna oblast vaZenja
#defi ne HANDLE_H prilikom definisanja:

c1 ass Handl e {
struct Handl e: : Cheshi re {
struct Cheshire; // Samo deklaracija klase Iskazom Handle::initialize( ), strukturi Cheshire je dodeljen prostor u memo-
Chesh i re* smi l e; riji, a iskazom Handle::cleanup( ) prostor je osloboden. Ovaj prostor je kori5ien
publ i c: umesto podataka koje biste inade stavi.li u privatni deo klase. Kada prevodite
void injtjalize0; datoteku Handle.cpp, definicija strukture je skrivena u objektnoj datoteci, gde je
void cleanup0; niko ne moZe videti. Ako promenite elemente strukture Cheshire, jedina datoteka
jnt read0; koja se ponovo mora prevesti je Handle.cpp, jer je datoteka zaglavlja netaknuta.
vold change(int);
);
, endif I I HANDLE_H ///:-
20r
f-
200 Misliti na jeziku C++ Poglavlje 5: Skrivanje realizacije

Klase ruiki se koriste kao bilo koje druge klase: ukljudite zaglavlje, napravite 2. NapiSite strukturu Lib, koja sadrZi tri promenljive a, b i c tipa string. U glav-
objekte i Saljcte portrke. nom programu napravite objekat x koji je tipa Lib i dodelite wednost
poljima >ca, xb i xc. Ispi5ite wednosti. Sada zamenite objekte a, b i c nizom
//: C05: UseHandl e. cpp string s[3]. PokaZite kako ova promena naru5ava k6d u glavnom programu.
//i L) Handl e Napravite klasu pod imenom Libc s privatnim znakovnim nizovima a, b i c,
I I Kort sti te kl asu ruck'j
#include "Handle.h" i funkcijama dlanicama seta( ), geta( ), setb( ), getb( ), setc( ) i getc( ) za
promenu i ditanje wednosti. Napi5ite glawi program, kao i pre. Ponovo
int main0 {
zamenite privatne objekte a, b i c, privatnim nizom string s[3]. PokaZite da
Handl e u; ova promena nrye naru5ila kOd u glarmom programu.
u.initialize0; 3. Napravite klasu i globalnu prijateljsku funkciju koja radi s privatnim ala-
u. read 0 ; novima klase.
u.change(1); 4. Napi5ite dve klase tako da svaka ima funkciju dlanicu diji parametar je
u. cl eanup ( ) ;
pokazivad na objekat druge klase. Napravite instance obe klase u glavnom
I lll,- programu i pozovite pomenute funkcije.
Programer klijent n.roZe da pristupi samo javnom interfejsu, tako da, dok je 5. Napravite tri klase. Neka prva klasa sadrZi privatne podatke, i neka dodeli
realizacija jedina stvar koja moZe da se promeni, neie biti potrebno da se dato- status prijatelja celoj drugoj klasi i funkcijama dlanicama treie klase. Poka-
teke ponovo prevode. Iako ovo nije sawSeno skrivanje realizacije, ipak je veliki Zite u glavnom programu da sve ovo dobro funkcioniSe.
korak unapred u tom smeru.
6. Napravite klasu Hen, pa u nju, ugnezdite klasu Nest. U klasu Nest, ugnezdite
klasu Egg. Svaka klasa treba da ima funkciju dlanicu display( )' U glamom
programu napravite instance ovih klasa i pozovite funkciju display( ) za
SaZetak svaku od njih.
IJprarrljartje pristupom omoguiava alltoru klase da odredi kako se ona upotrebl-
java, a korisnicinra olakSava da jasno vide Sta mogu da koriste, a Sta da ignori5u. 7. Promenite veZbu 6 tako da klase Nest i Egg sadrZe privatne dlanove. Spolja-
I 5to je joS vaZnije, obezbeduje da programeri klijenti ne zavise od svakog dela Snjim klasama dodelite statuse prijatelja, da bi mogle pristupati tim privat-
interne relizacije klase. Znadi da vi, kao autor klase, moZete da promenite nim dlanovima.
internrt realiz-acijrr klase, a klijente neie pogoditi promena, jer nemaju pristup 8. Napravite klasu u kojoj su podaci dlanovi raspodeljeni po brojnim jamim,
tom delu klase. privatnim i zaStiienim obiastima. Dodajte funkciju dlanicu showMap( ) koja
Moguinost menjanja interne realizacije znadi da iete kasnije moii da je una- Stampa imena i adrese ovih podataka dlanova. Ako je moguie, prevedite i
predite, ali i da moZete da pravite greSke u realizaciji. Koliko god paZljivo plani- izvr5ite ovaj program s razliditim prevodiocima i/ili na razliditim radunarima
rali i pravili svoju klasu, gre5ke se uvek potkradu. Saznanje da su greSke relativno i operatirnim sistemima, da vidite da li ima razlika u strukturi objekata.
bezopasne, pomoii ie var.n da brZe udite, kroz eksperimentisanje, i da pre zaw- 9. Kopirajte datoteku realizacije i probni program za dinamiiki niz u pogla-
5ite svoj projekat. vlju 4, tako da moZete da prevedete i testirate datoteku Stash.h u ovom
Progran.reri klijenti uide samo jatmi interfejs klase, pa je zato vaZno da se ovaj poglavlju.
deo klase dobro osmisli i napravi. Cak i tu se mogu naknadno unositi izmene. 10. Objekte klase Hen, izveLbe 6, smestite u dinamidki niz. Uzmite ih i ispisite
Ako interfejs niste odmah napravili kako treba, moZete mu dodatinove funkcije, (moraiete da dodate Hen::print( ), ako to vei niste uradili).
alr ne moZete ukloniti hrnkciju koju su programeri klilenti vei koristili. I 1 . Kopirajte datoteku realizacije i probni program za stek iz poglavlja 4, tako
da moZete da prevedete i testirate datoteku Stek.h u ovom poglavlju.

VeZbe
'I
2. Objekte klase Hen, izveLbe 6, smestite u stek. Uzmite ih i ispisite (mora-
Reienia o\ih ve2bi nalaze sc rr 'l'hc tlliilking itl O++ Attnotated Solution ()uide,kojimoZete preuzeti sa lokacije
iete da dodate Hen::print( ), ako to vei niste uradili).
ilrvu. BruceI-lc kel.co nt. 13.Izmenite klasu Cheshire u datoteci Handle.cpp, i uverite se da ie upra-
1 . Napravite klasu koja sadrZi javne, privatne i za5tiiene funkcije dlanice i vljad projektom ponovo prevesti i povezati samo o\,'u datoteku, a ne dato-
podatke dlanove. Napravite objekat ove klase i pogledajte kakve poruke teku UseHandle.cpp.
dobiiate od prevodioca kada poku5ate da pristupite svakom ilanu funkcije.
202 Misliti na jeziku C++

14. Napravite klasu Stackoflnt (stek za cele brojeve) kori5ienjem tehnike


,,Cheshire cat".
'ia tehnika skriva strukturu podataka niskog nivoa, koju
koristite za sme5tanje elemenata u klasu Stacklmp. Realizujte dve verzije
klase Stacklmp: jednu koja koristi niz celih brojeva fiksne duZine, i drugu
koja koristi vector<int>. U prvoj verziji ne morate da brinete o proSirivanju
niza, jcr ste unapred zadali maksimalntr veliiinu steka. Obratite paZnju na
to cla klasa Stackoflnt.h ne mora da se menja zajedno sa Stacklmp.

,i
t)

v'

6; lr.ucrJALrzAcUA I ctscENJE
MEI\,IOR lJ,E''i
;
jer
U, poglavJig'4.s'tno znaE4jtr'o,,tipapqg-dili koriS(enie biblioteke,'
smo r:iasrite ktirnp.oletlgi' uoli{aiene bibliotg}ie jgzifa, C skupili i
tapsutirali'u' strukturti {apqtr,a]+4i,tip podl3ka, koji iemo odsad
zvatiklaia).' ''': . ', ' " f:1 i:.i:. ''i: .:.
204
r
Misliti na jeziku C++
I

Poglavlje 6: lnicijalizacija i iiiienje memorije

Ovo omoguiava pristup komponentama biblioteke iz jedne osnovne


tadke i Pitanje je kako nazvati oru funkciju. Tu se pojavljuju dva problema. prvo: koje
krije imena funkcija u okviru klase. tJ pogravlju 5, predstavljeno je upravljanje
god ime da iskoristite, ono vam kasnije moZe praviti probleme pri izboru imena
pristupom (skrivanje realizacije), sto omoguiaru uutoru klaie da postavi jasne
granrce kojima se odrcduje Sta klijent sme da koristi. To znaii da za dlanove klase. Drugo; prevodilac je zaduZen za pozivanje konstruktora, pa
autor klasekon- uvek mora znati koju funkciju da pozove. Stroustrup je, izgleda, izabrao najlak5e
troiise interne mehanizme za rad s podacima, a klijentu je jasno na koje
dlanove i najlogidnije re5enje: ime konstruktora je isto kao ime klase. sada ima smisla sto
nroTe i trelta da oltrati pa2njrr.
Kaps.lirar.rje i upravrjanje pristupom, zajedno, znadajno olaksavaju ie se ova funkcija automatski pozivati pri inicijatizaciji.
kori- Evo primera jednostar.ne klase s konstruktorom:
Sienje biblioreke. Koncepr ,,novog tipa podataka", koji se na ovaj nadin
uvodi,
bolji 1e od posto jeiih ugradenih tipova podataka u jeziiu c. sada i++ prevodilac class X {
moze proveravati kako se koristi novi tip podataka, dime se postize
odredeni
int i;
nivo bezbednosti. publ i c:
Kada govorimo.o bezbednosti, prevodilac moze da uradi za nas vise
od onoga
XO; ll Konstruktor
Sto jezik c predvida. u ovom i narednim pogravljima, videiete );
dodatne *og,rZ-
nosti koje su ugradene.u o++, zbog kojih programske gre.ke postaju Sada, kada je objekat definisan:
uodljilvije,
nekada dak i pre prev,denja programa. Najdesie se javfaju , ourit,_,,.,poroi".rju
i gresaka koje prijavrjuje prevodirac. Uskoro iere se naviZi na pomaro
void f0 {
neodeki- X a;
vanrr situaciju: uspesno pre'eden c++ program aesto se taino izwsi
prvom llokuiajrr.
vei pri //...
)
tJ pitanja bezbecinosti spadaju inicijalizacija i disfenje memorije. Veliki
broj desiie se isto 5to bi se desilo da je a celobrojnog tipa: memorija se rezerviSe za
gre5aka u programima na jeziku c pojavljuje se kada programeri
zaborave da objekat. Kada program stigne do mesta definisanja objekta a, automatski se
inicijalizLriu ili obri5u promenljiru. ovo se desto desava u C bibllotekama,
kada poziva konstruktor. Na mestu definisanja objekta a, prevodilac neprimetno
programeri ne znaju kako da inicijalizuju strukturu, ili dak ne znaju
da to moraju umeie poziv )C:X0. Kao i za svaku funkciju dlanicu, prvi (skriveni) argument
cla uracle. (Riblioreke aesto ne sadrZe funkcije za inicijalizaciju, pa
klijent mora konstruktora je pokazivad this - adresa objekta zako'1i se poziva konstruktor. U
da srrukturu inicijalizuje ruino.) oslobadanje memorije je po..f
u" problem, ler sludaju konstruktora, pokazivad this pokazuje na neinicijalizovan memorijski
programeri na c-, zaboravljaju promenljive kada zaw5e s njima, pa
tako zabo_ blok, a posao konstruktora je da taj memorijski blok pravilno inicijalizuje.
ravljaj, i da ih obri5u, nrada je to u nekim strukturama biblioteka neophodno.
Konccpt inicijarizacije i didienla memorije u c++-u je krjudan za jednostarmo Kao i druge funkcije, konstruktor moZe imati argumente za odredivanje
koriiic.je biblioreka i za elirninisanje velikog broja prikrivenih gresaka koje nadina na koji ie objekat biti napravljen, za dodelu inicijalne wednosti itd. Argu-
nasrajLr kada prograrneri zaborave na ova dva postupki. U menti konstruktora omoguiavaju da svi delovi objekta budu inicijalizovani na
ovom pogravlju ispi- odgovarajuie wednosti. Ako, na primer, klasa Drvo ima konstruktor sa jednim
taiemo n'roguinosti c++-a koje obezbeduju pravilnu inicijalizaciju i aisie;je
rnentorijc. celobrojnim argumentom koji oznadava visinu drveta, onda objekat klase Drvo
morate napraviti na sledeii nadin:
Drvo t(12); // drvo visine 12 metara
Carantovana i nicijal izacija konstruktorom Ako je Drvo(int) jedini konstruktor u klasi, prevodilac vam neie dozvoliti da
I klasa stash i klasa stack, koje smo ranije definisali, imaju funkc4u napravite objekat na drugi nadin. (u sledeiem poglavlju iemo razmotriti klase s
initialize( ).
56mo ime funkcije upuiuje nas da je pozovemo pre izvodenja bilokakvih vi5e konstruktora i razlidite nadine za njihovo pozivanje.)
drugi-h
operacija nad objektom. Nazalost, ovo je ostavljeno progrimerima krijentiria. Ovo bi bilo sve o konstruktoru: to je funkcija posebnog imena, koju prevodi-
oni morajtr da pravilno inicijalizuju strukturu. U bezglivoj Zurbi da iskoriste lac poziva automatski, za svaki objekat, na mestu pravljenja tog objekta. Iako
le
bibliotek, za rciavanje svog problema, oni su skloni di zaborave na detalj kao veoma jednostavna, ova funkcija je izuzetno vredna, jer eliminise ceo niz- pro-
sto je inicijalizacija. tJ c++-u, inicijalizacija je isuvise vaZna blema i pojednostavljuje ditanje i pisanje programa. u kodu koji sledi, na pri-
da biste;.e prepustili
prograrneru klijentu. Autor klase moZe garantovati inicijalizaciju mer, ne vidi se izriiit poziv funkcije initialize( ) koji bi bio logidki razdvojen od
svakog oty"ttu
tako ito r:etc napisatr specijarnu ftrnkcijtr kofa se zore' konstruktor (engr. definicije. U c++-u, definicija i inicijalizacija dine jedinstven koncept i ne mogu
con-
strtrctorJ. r\ko kl:rsa ima konstruktor, prevodilac ie ga automatski se razdvojiti.
pozlvati na
mesr, pravrjen;a objekra, znadi pre nego sto prog.u-"r krijent dobijb Sansu
da
.ru prisrul.li. Klijent uopste ne moze rudno da porove konsiruktor; njega poziva
prcvociilac na mcstu deftnisanja objekta.
iiSienje memorije 207
206 Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i

Konstruktor i destruktor su neobidni tipovi funkcija: oni nemaju rezultat. class Tree {

Ovo je sasvim drtrgadije od funkcije iiji tip rezultata je void, gde funkcija takode i nt he i ght;
ne vraia nikaklru vrednost, ali to moZete da promenite. Konstruktor i destruktor publ i c:
ne waiaju niSta. Postupci pravljenja i uniStavanja objekta su odvojeni, i prevodi- Tree(int initialHeight); // Konstruktor
lac uvek sam poziva konstruktor i destruktor da bi se ovi postupci osigurali. Ako -Tree0; // Destruktor
bi postojao rezultat, i kada biste mogli sami da ga izaberete, prevodilac bi morao voi d grow(i nt Years) ;
da z-na Sta s njim da radi, ili bi klijent morao izridito da poziva konstruktor i void printsize0;
destruktor, pa sigrrrno pozivanje viSe ne bi bilo garantovano. );
Tree: :Tree(int injtialHeight) {

height = initialHeight;
Carantovano ci5ienje memorije )
destru ktorom
Kao programer na C-u, desto mislite o znadenju inicijalizacije, ali se rede setite Tree::-Tree0 {

di5ienja memorije. Sta treba udiniti da biste obrisali celobrojnu promenljivu? cout << "U destruktoru" << endl ;
Recimo da je dovoljno da je zaboravite. Medutim, u bibliotekama nije bezbedno printsize0;
zaboraviti objekat s kojim ste zawSili. Sta ako on utide na neki deo hardvera, ili )

ispisuje ne5to na ekranu, ili je zauzeo dinamidku memoriju? Ako zaboravite na


voi d Tree: :grow( i nt Years) {
taj objekat, on nikada neie nestati sam od sebe. U C++-u, diSienje memorije je
height += Years;
isto toliko vaZno koliko i inicijalizacija,izato se koristi destruktor (engl. destruc-
)
rof koji garantuje ispravno di5ienje.
Sintaksa destruktora je sliina sintaksi konstruktora: za ime funkcije koristi se
voi d Tree: : Pr j nts'i ze 0 {
imc klase. I)cstruktor se razlikuje od konstruktora po tildi (-) koja mu prethodi. cout << "Visina ie " height << end'l;
Pored toga, destruktor nema nijedan argument, jer njemu nisu potrebne "'
)
nikakve opcije. Ovako izgleda dekJaracija destruktora:
class Y { int main0 {
publ i c: cout << "Pre otvorene zagrade" << endl;
-Y0; {

); Tree t (12) ;
cout << "Posle Pravlienia" << endl;
Prevodilac automatski poziva destruktor kada se izade iz oblasti vaZenja
t.printsize0;
objekta. Mesto pozivanja konstruktora odredeno je mestom definisanja objekta,
t.grow(4);
a jedini nagove5taj o pozivanju destruktora je zatvorena zagrada oblasti vaZenja
cout << "Pre zatvorene zagrade" << endl;
koja obuhvata posmatrani objekat. Destruktor se ipak poziva, dak i kada koris-
)
tite iskaz goto za iz.lazak iz. oblasti vaienja. (lskaz goto i dalje postoji u C++-u, cout << "Posle zatvorene zagrade" endl;
'<
z-bog kornpatibilnosti sa jezikom C, ali i zato Sto je ponekad koristan.) Obratite
paZn ju na to da kori5ienje iskaza za skok uan lokalne oblasti, koji se primenjuje
u firnkcijama standardne C biblioteke setjmp( ) i longjmp( ), neie prouzroko- Evo Sta ispisuje prikazani program:
vati pozivanje destruktora. (To je propisano standardom, dak i ako va5 prevodi- Pre otvorene zagrade
lac to realizuje na drugi nadin. Ako se oslanjate na moguinosti koje nisu u Posle pravljenja
skladu sa specifikacijom, k6d neie biti prenosiv.) Visina ie 12
Sledeii primer prikazuje osobine konstruktora i destruktora koje ste dosad Pre zatvorene zagrade
upoznali: U destruktoru

: C06: Cons t ruc torl cpp


Visina ie 16
I I .
Posle zatvorene zagrade
// Konstruktori i destruktori
# i nc I ude <i os t ream> vidite da je destruktor pozvan automatski na mestu zatvorene zagrade kojonr
usi ng namespace std; se ogranidava oblast vaZenia.
208 Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i tiiienje memorije 209 I
cin >> retval;
Eliminisanje bloka definicija require(retval != 0);
U C-u, uvek morate definisati sve promenljive na poietku bloka, odmah iza intY=retval+3;
otvorene zagrade. Ovo nije neobidan zahtev u programskim jezicima, i smatra se G s(v);
cla je to clco ,,tclinike dobrog prograrniranja". Ja sam sumnjidav po tom pitanju. \ //1,-
Meni je, kao programeru, uvek bilo nezgodno da se waiam na poietak bloka
Vidite da je deo koda izvrsen, a zatim je promenljiva retval deflnisana, inici-
svaki put kada rni zatrcba nova promerlljiva. Takode smatram da je kdd iitljiviji
jalizovana i upotrebljena za aitanje podataka koje unosi korisnik, i tek tada su
kada sc definicija pron'renljive nalazi tamo gde se ta promenljiva upotrebljava.
definisane promenljive y i g. Definisanje promenljivih u jeziku c je dozvoljeno
Mo7-cla su ovi arglrmenti vi5e stilske prirode. U suStini, definisanje svih
samo na podetku oblasti vaZenja.
objekata na pocetkLr oblasti vaZenja predstavlja znadajan problem u C++-u. Ako
Promenljive treba da definisete tamo gde iete ih koristiti, i nakon definisanja
postoji konstruktor, on se mora pozvati pri pravljenju objekta. Ako je konstruk-
toru potreban jedan ili viSe argumenata za inicijalizaciju, kako iete znati da iete
uvek treba da ih inicijalizujte. (Za ugradene tipove, gde inicijalizacija nije
neophodna, ova primedba je viSe stilskog karaktera.) Ovo je pitanje bezbednosti,
imati te inlormacije na podetku oblasti vaZenja? U opStem sludaju i neiete znati.
jer, Sto je kraia oblast u kojoj je promenljiva dostupna, manja je i Sansa da se ta
Po5to u jcziku (, ne postoii koncept privatnih dlanova, odvajanje definicije i
promenljiva pogresno upotrebi u nekom drugom delu oblasti vaZenja. Pored
inicijalizacije nije problem. C++ garantuje da se objekat inicijalizuje istowe-
ovoga, poveiana je i ditljivost koda, jer ne morate da skaiete napred-nazad po
meno kada se i napravi. Ovo osigurava da se u sistemu ne pojavljuju neinicijali-
oblasti vaZenja da biste videli tip neke promenljive.
zovani objekti. C se ne trudi da spredi pojavu takvih objekata, dak bi se moglo
reii da to i podstie e, zahtevajuii od vas da sve promenljive definiSete na podetku
bloka, pre nego Sto sakupite sve informacije potrebne za inicijalizaciju.l Petlje for
UopSteno, C++ vam neie dozvoliti da napravite objekat pre nego Sto sakupite U C++-u, desto iete videti da se brojad petlje for definise unutar iskaza for:
inicijalizacione informacije za konstruktor. Zbog ovoga u C++-u ne bi bilo
izvodljivo cla se sve promenljive definiSu iskljudivo na podetku oblasti vaLenja.
for(int i = 0; i < 100; j++) {

Stit jezika vas podstide da definiSete objekte Sto bliZe mestu na kome iete ih
cout << "j = rr << i << endl;
)
upotrebiti. tl C++-u, svako pravilo koje se primenjuje na,,objekat" automatski se for(int i = 0; i < 100; i++)
odnosi i na podatak ugradenog tipa. Ovo znadi da se sve promenljive i objekti cout << ui = " << i << endl;
ugradenog tipa takode mogu definisati bilo gde unutar oblasti vaZenja. OdloZite
definisanje dok ne dobilete sve potrebne informacije, tako da uvek moZete Prikazani iskazi su vaZni specijalni sludajevi u c++-u koji mogu da zbune plo-
istovremeno definisati i inicijalizovati objekte: gramere podetnike.
Promenljive i i i su definisane direktno unutar iskaza for (Sto ne moZete ura-
I I : C06:Defi nelni ti al i ze. cpp
diti u C-u.) Nakon toga, one se mogu koristiti u petlji for' Ovo je zgodna sintaksa
ll Definisanje promenljivih bilo gde u kodu
zato sto se iz konteksta u kome se nalaze promenljive i i i vidi njihova swha, pa
#include "../require.h"
ne morate koristiti nezgrapna opisna imena, kao Sto je broiac-petlje-i.
#i ncl ude <i ostream>
Do zabune moZe doii ako odekujete da se Zivotni vek promenljivih i i i prosiri
#jnclude <string>
usi ng namespace std; i izvan petlje for.z
U poglavlju 3 se istide da je u iskazima while i switch takode dozvoljeno defi-
class G { nisanje objekata, mada je to manje vaZno od sliinog deflnisanja u sludaju petlje
int i ;
for.
publ i c: Pazite na lokalne promenljive koje skrivaju istoimene promenjive iz spoljne
G(int ii); oblasti vaZenja.U opSem sludaju, korisienje istog imena za ugneZdenu plomen-
); ljivu i za promenljivu koja je globalna u datoj oblasti vaaenja je zbunjujuie i
G::G(int ji) i i = ii; ) moZe dovesti do greSke.3

int main0 i
cout << "inicijalna vrednost? ";
U ranijim, grubljim verzi.jama standardazajezikC++,Livotni vek promenljive.ie bio proSiren na celu oblast
int retval - 0; vaZenja koja obuhvata petlju for. Neki prevodioci ioS uvek primen.juju ovo pravilo, ali to nije ispramo.VaS
kOd ie biti prenosiv samo ako oblast vaZenia promenliive ograniCite na petlju for.
U programikom jeziku Java, ovakva ide.ia se smatm toliko IoSom da je prevodilac priiavliuje kao greiktt.
(199, nov sranrlartl jczika (1. doz\oljava cla se pronrenljive definiau bilo gde unutar oblasti vaZenja, kao u
( ++,Ll
Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i iiiienje memorije 2ll
:lo

ima male oblasti vaienia' Ako ste


int main0 (
Smatram da dobro osmiSlien k6d treba da f(e);
mo!{a pokuSavate da s njom obavite
ispisali nekoliko ,,runu ,u ;.jnu nr1\cii1' f (11);
funkcija je korisniie i olaksava pronalaZenje
;i;;; posla. Korisie.i. "iJ*""iih | // /,-
greSaka.
U prethodnom primeru, oba iskaza, switch i goto, mogu da preskode mesto u
kodu gde se poziva konstruktor. Tako Ce objekat biti dostupan u oblasti vaLenja,
Dodetjivanje memorije . . oblasti vaZenja' pa zvuii logiino
iako konstruktor nije poz\tan, pa Ce prevodilac prijaviti gre5ku. Ovo joS jednom
Promenljir,u sada moZete definiJati bilo gde u potwduje da ne moZete napraviti objekat, a da ga ne inicijalizujete.
pre definisanja promenljive' Zapravo Dodeljivanje memorije, o kome smo govorili, deSava se na steku. Memoriju
da se skladiSt. ,u pro-.ntiir,u ne zauzimi
jeverovatnijedaieseprevoaitacponaSatikaouC.u,idaiezalzetimemorijski dodeljuje prevodilac, pomerajuCi pokazivad steka ,,nadole", (ovo je relativan
zagradu kojom ta oblast pojam, jer moZe oznadavati povedanje ili smanjenje wednosti pokazivaaa steka,
blok za celu oblast vai.enia dim naide na otvorenu
vaT.enia zapodinie. Vama, kao programeru'
to ne znadi mnogo jer ne moZete
a lako
da Sto zavisi od va5eg radunara.) Objektima se moZe dodeliti dinamidka memorija,
je obiekai dlfinisan le 5to iemo razmotriti u poglavlju I3.
pristupite skladiitu tt"'i"ri nr.llttiu) Pre nego 5to sve do mesta
bloka' konsiruktor se ne poziva
memorija zauzeta ,.ru pne"ttu
definisanjaobjekta,)er.dotadanijepoznatidentifikator'Prevodilacproverava
danistesludajnozaobiSlideflnicijuoul"ttu(pozivkonstruktora)namestugde
Dinamicki niz s konstruktorima i destruktorima
ili u nekom delu
kao Sto ie iskaz.switch' U primerima iz proSlog poglavlja, postoje odigledne funkcije initialize( ) i
se kroz progranl prolazi samo uslormo' za
Ako cleanupO, koje odgovaraju konstruktoru i destruktoru. U sledeiem primeru,
programa koii se -oz" p"skoditi iskazom,C:.t9 i!^"-1'4",'::nake
ili gresku:
iskaz.a"u ri.a.C.* primeru, dobiiemo
upozorenje zaglavlje dinamidkog niza koristi konstruktore i destruktore:
komenrar ispred
//: C06:NojumP'cPP ne moZe preskoiiti //: C06:Stash2.h
// Konstruktor se // Dinamidki niz s konstruktorima i destruktorima
#ifndef STASH2_H

class X {
#defi ne STASHz_H

publ i c:
x0 r
class Stash {

); i nt si ze;
// Ve1 i di na svakog skl adi 5ta
int quantity; 11 eroj skladiSta
X::X0 {} int next; // Sledeee prazno skladiSte
// Dinamidki napravljen niz bajtova:
void f(int i) ( unsigned char* storage;
if(i<10){ i^':_^^i d i nfl ate (i nt i ncrease)
voi ;

I ll goto
jumpl; // Gre5ka: iskaz goto preskaie inicijal izaciiu publ i c:

)
Stash(int size);
x xl; I I Ovde se Poziva konstruktor -Stash 0 ;
'i nt add (voi
d* el ement) ;
jumpl:
switch(i) {
void* fetch(int index) ;
case 1: int count0;
X xZ; I I 0vde se Poziva konstruktor
\.
t,

brea k; #endif // STASHZ_H ///:-


I ll case 2 : // Gre5ka: iskaz case preskaie iniciializaciju Ovde su promenjene samo definicije funkcija initialize( ) i cleanup( ), tako
X x3; I I Ovde se Pozi va konstruktor Sto su zamenjenekonstruktorom i destruktorom:
break;
//: C06:Stash2.cpp {0)
// Konstruktori i destruktori
)

l
#include "Stash2.h"
#include ",./require.h"
ako biste bili nevaliali i malo se poigrali s pokazivadima #1 ncl ude <i ostream>
I \1t:r.varno bisrc i mogli da m, prislrpire,
iiiienje memorije 213
212 Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i

#i ncl ude <cassert> Stash::-Stash0 {


us i ng namespace s td; if(storage != 0) {

const int increment = 100; cout << "oslobadianie memoriie" << endl;
delete []storage;
Stash::Stash(int sz) { )
(i,a = c,. I I I /z-
quantity = 0; vidite da smo umesto funkcije asserto, koristili funkcije iz zaglavlja
storage = 0; require.h, da bismo pazili na programerske greske. Rezultat neuspele funkcile
next = 0; funkcija iz zaglavlja require.h, Sto iemo
assert( ) nije toliko koristan kao reiultat
i pokazati dalje u knjizi.
' posto je funkcija inflate( ) privatna, jedini naiin da provera funkcije require( )
int Stash::add(void* e'l ement) wednost
ne uspe jlste da neka druga funkcija dlanica sludajno prosledi netadnu
{
if(next >= quantity) l/ Da l i je ostalo dovoljno prostora? iigurni di ovo ne mo7e desiti, mo7ete razmi5ljati io
inflate(increment); funkcui inflate( ). Ako ste se
,t,ta.r;'at 1" pori* f,rttt.il" require( ), ali treba da imate na umu da' sve dok klasa
II Kopi ra el enent u memori j u, nlle siaUitna, njoj se mole dodavati novi k6d, Sto moZe dovesti do gre5aka.
Cena
// pocevSi od sledece prazne lokacije: kori5ienjem pretpro-
je eliminisati
int startBytes = next * size; koriS6enja funkcije require( ) mala (i moZe se

unsigned char* e = (unsigned char*)element; cesora), a wednost ispravnog koda je velika.


for(int i = 0; j < size; j++) U siedeiem probnom programu videiete da se deflnicije objekata dinamid-
kog niza pojavljrlr, UuS tuiu * potrebne, i da se inicijalizacija pojavljuje
kao deo
storageIstartBytes + i] = eIi];
next++; definicije, u listi argumenata konstruktora:
return (next - l); I I Indeksni broj
//: C06:StashzTest.cPP
)
//{ L} Stash2
// Konstruktori i destruktort
voi d* Stash: : fetch ( i nt i ndex) { #i ncl ude "Stash2. h"
requrre(0 <= jndex, "Stash::fetch (-)index"); #i ncl ude " . . /requi re. h "
if(1ndex >= next) #i ncl ude <fstream>
return 0; ll Ukazule na kraj #include <iostream>
I I Pravi pokazivaa na element: #i ncl ude <stri ng>
return &(storageIindex * size] ); using namesPace std;
)

int main0 {
i nt 0 (
Stash: : count Stash i ntStash(si zeof (i nt) ) ;
return next; I I Broj el emenata u di nami dkom ni zu for(int i = 0; i < 100; i++)
) i ntStash. add (&i ) ;
for(int j = 0; i < intStash.count0; i++)
void Stash: :inflate(int lncrease)
require(increase > 0,
{ cout << "intStash.fetch("
<< *(int*) intStash.fetch(i)
" i " ") ='
'Stash: :inflate uvecanje nije pozitivno") ; << endl;
j nt net4Quanti ty = quanti ty + i ncrease; const int bufsize = B0;
int newBytes = newQuantity " size; Stash stringStash(sizeof(char)
* bufsize);
jnt oldBytes = quantity * size; 'i fstream i n("Stash2Test. cpp") ;
unsigned char* b = new unsigned char[newBytes]; assure(in, " Stash2Test'cPP") ;
for(int i = 0; i < oldBytes; i++) string line;
bIj] = storagelil; l/ Kopiranje starog u novi whi Ie(getl ine(in, I ine) )
de1 ete [ ] (storage) ; // Staro skl adi 5te
stringstash'add((char*)I ine.c-str0 );
storage = b; I I Pokazuje na novu .nemoriju intk=0;
quanti ty = newQuanti ty; char* cP;
)
Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i iiScenje memorije 215
)14

while((cp = (char*)stringstash.fetch(k++)) !=0) Stack::Link::Link(void* dat, Link* nxt) {

cout << "stringstash'fetch(" " k " ") = " data = dat;


t< cP << endl; next = nxt;
\ I ll'- )

obratite paT.nju na ro da se ne poziva funkcila cleanupo, ali se jos uvek Stack:;Link::-L'i nk0 { }
automalski pozivajtr destrlrktori, kacia se z.awSi oblast vai'eniaobjekata intStash Stack::Stack0 { head = 0; }
i stringStash.
U irlmeru s dinamidkim nizom, obratite paZnju na sledeie: trudim se da voi d Stack: : push (vo i d* dat) (

koristim samo ugradene tipove, to iest, one bez destruktora' Ako biste pokuSali head = new Link(dat,head);
da kopirate objekte klase u dinamidki niz, upali biste u
qomilu problema i ne
)
biste uspeli. Standardna c++ bibiioteka moze da napravi ispra'ume kopije obje-
kata u svom kontejneru, ali je to prilidno komplikovano. U sledeiem primeru za voi d* Stack: : peek 0 {

stek, videiete da se koriste pokazivadi da bi se ovakvi problemi izbegli, a u kasni- require(head != 0, "Stek je prazan'');
Iimpoglavljima,izmeniiemoidinamidkiniztakodakoristipokazivaee. return head->data;
)

Stek s konstruktorima i destruktorima liste (u


vojd* Stack::pop0 {
if(head == 0) return 0;
Korisienje konstruktora i destruktora za ponovrlo realizovanje povezane
steku) pokazuje kako oni brizljivo koriste opelatore new i delete. ovako izgleda void* result = head->data;
Link* oldHead = head;
izmeniena datoteka zaglavlia:
head = head->next;
I I : C06: Stack3. h delete oldHead;
// Stek s konstruktorom/destruktorom return result;
#ifndef STACK3 H )
#define STACK3 H
Stack::-Stack0 (
class Stack { requi re(head == 0, "Stek niie prazan");
struct Li nk { | / / /,-
voi d* data;
Li nk* next;
Konstruktor Link::Link( ) inicijalizuje pokazivade data i next, tako da u
Link(void* dat' Link* nxt); tunkciji Stack:push( ), sledeii red:
-Link0; head = new Link(dat,head);
* head;
)
dodeljuje glavi Iiste nov element (pravljenjem dinamidkog objekta pomoitt
Publ i c: rezervisane redi neq koja je predstavljena u poglavlju 4), ali i uredno inicijali-
Stack0;
zuje pokazivade na ostatak liste.
-Stack ( ) ;
MoZda iete se zapitati zasto destruktor strukture Link ne radi nista, tadnije
voi d Push (voi d* dat) ;
zasto ne obrise pokazivad data. Postoje dva problema. U poglavlju 4, gde smo se
vo'id* Peek 0 ;
voi d* pop 0 ;
upoznali sa stekom, istakli smo da se ne moZe pravilno obrisati pokazivad tipa
',roia ato pokazuje na objekat (ovu rwdnju cemo dokazati u poglavlju l3). Pored
);
tendif ///:- toga, ako bi destruktor strukture Link obrisao pokazivad data, funkcija pop( ) bi
ll STACK3-H
na kraju watila pokazivad na obrisani objekat, sto bi sigurno bila greska. Ovo se
stek ima konstnrktor i destruktor, a ima ih i ugneZdena klasa Link. ponekada nazivapitanjem uhsniitua: pokazivadi su smesteni u strukturu Link, a
//: C06: Stack3. cPP {0} samim tim i u stek, ali struktura Link i stek ne odgovaraju za njihovo brisanje.
// Konstruktori /destruktori Znaij da morate paZljivo razmotriti ko jeste odgovoran za brisanje. Na primer,
#include "Stack3.h" ako i ne obriSete pravilno sve pok.vivade sa steka, njih destruktor steka neie
#include ". ./requi re.h" automatski obrisati. Ovo moZe da bude nezgodno i daizazove curenje memorije
us i ng namesPace std; (eogl. memory leak). Ako znate ko je odgovoran za brisanje objekata, moZete
Poglavlje 6: lnicijalizacija i iiSienje memortE 217
215 Misliti na jeziku C++

prevodi-
napraviti uspeSan program, umesto programa punog greSaka. Zato (.e destruktor treba samo da mu dodelite wednost, a za inicijal\zaciju ie se pobrinuti
Iac. Postoji vise wsta dodela, u zavisnosti od tipa grupe, ali u svakom.sludaju,
Stack::-stack( ) priiaviti greSku, ako objekat steka nije prazan pre uniStavanja.
PoSto je dodeljivanje i oslobadanje memorije za objekte tipa Link skriveno u elementi koji se dodeljuju moraju biti u vitidastim zagradama. zan\z eiji su ele-
steku - to je deo interne realizacije - u probnom programu neiete primetiti da menti ugradenog tipa, ovo je jednostalTlo:
se tl procesi odvijaju, iako ste ul odgovorni za brisanje pokazivada koje waia int a[5] -- 11,2,3, 4, 5 );
tunkcija pop( ):
Ako u listi inicijalnih vrednosti ima vise elemenata nego u nizu, prevodilac ie
I I : C06 Stack3Test.cpp prijaviti gresku. Ali, Sta ie se desiti ako navedete manje wednosti nego Sto treba?
//{ L} Stack3 Na primer:
//{I} Stack3Test.cpp int b[6] = {0};
// Konstruktori /destruktori
#i ncI ude "Stack3. h" Ovde ie prevodilac upotrebiti prvu wednost zaprw element u nizu, a ostalim
#jnclude "../require.h" elementimi niza (e dodeliti wednost nula. Prevodilac se neie ovako pona5ati
ako definisete niz bez liste inicijalnih wednosti. Znadi da se plethodnim
# i ncl ude <fstream> iz'razom
#i ncl ude <i ostream> lako inicijalizuju wednosti svi-h elemenata niza nulama, bez korisienja petlje
#i ncl ude <stri ng> for, i bez'moguinosti da se izostavi neki element i tako pogreSi. l-I zavisnoti od
us i ng namespdce std; prevodilaca, ovakav nadin moZe biti i efikasniji od petlje for'
Drugaprednostgrupneinicijalizacijeuradusnizovimajesteautomatsko
i nt nt argc, char* argv [] ) {
mai n ( i brojanie (engl. automaiic countin$, pri kome prevodilac odreduje velidinu niza
requireArgs(argc, 1); ll Ine datoteke je argument na osnovu broja inicijalnih wednosti:
ifstream in(argv[1]);
assure(in, argv[1] );
'int c[] = { l, ?,3, a };
Ako odludite da dodate nizu jos jedan element, dovoljno je da dodate
jos
Stack textl i nes;
string line; jednu inicijalnu wednost. Kako odredujete velidinu niza? Iskaz sizeof clsizeoftc
I I Cita datoteku i smesta redove na stek: ivelidina celog niza podeljena s velidinom prvog elementa) raauna
velidinu' a na
whj le(getl ine(in, 1 ine) ) njega neie uticati eventualna promena velitine niza:'
t r j ng(I i
0; i < sizeof c / sizeof *c;
t tIi s. ( n ew s ));
for(int i
e x ne p u s h n e
= i++)
ll Uztna linije sa steka i ispisuje ih:
stri ng* s; c[i]++;
while((s = (string*)textlines.pop0) != 0) { Bududi da su strukture takode grupe, one se mogu inicijalizovati na slidan
cout << *s << endl; nadin. Posto su u jeziku c svi dlanovi strukturama javni, njima se wednosti
del ete s; mogu dodeliti direktno:
i struct X {
\ Iil,- int i;
U ovom sludaju, svi redovi u steku textlines su uzeti sa steka i obrisani. Da fl oat f;
nisu, funkcija require( ) bi ispisala poruku, Sto bi znadilo da je nastalo curenje char c;
memorije. );
X xl = { l, 2.2, 'c' J;
C ru pna i n icijal izacija Ako imate niz ovakvih objekata, moZete ih inicijalizovati tako sto iete za svaki
Grupa je upravo to Sto ime kaZe: gomila stvari skupljenih na jednom mestu. Ova koristiti ugneZdene vitidaste zagradei
definicija ukljuduje grupe sadinjene od razliiitih tipova, kao Sto su klase i struk-
ture. Niz je grupa sadinjena od elemenata istog tipa.
x x2[3] = { {1, 1.1, 'a'l' {2,2.2,'b'} );
Inicijalizovanje grupa elemenata moZe biti dosadno i uzrokovati greSke. Ovde je tredi objekat inicijalizovan wedno5du nula'
U C++-u, grupna inicijalizacija (engl. aggregate initialization) dini ovaj postupak
mnogo bezbednilim. Kada napravite objekat koji predstavlja grupu elemenata, s u drugom nia
tomu, videcete kako se Sabloni koriste za ios sazetiie izradunavanje velidine
2r8 Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i iiiienje memorije 219

Stvari se menjaju ako je bilo koji podatak dlan privatan (Sto je sludaj s dobro
osmiSljenim klasama u C++-u), ili dak ako je sve javno, ali postoji konstruktor. U
Podrazumevan i kon stru ktori
Podrazumeuani konstruktor se moZe pozvati bez argumenata. on se koristi za
gore navedenim primerima, inicijalne wednosti se dodeljuju direktno elemen-
pravljenje osnovne verzije objekata (engl. uanilla objects), ali je takode vaZan
tima grupe, ali konstruktori zahtevaju da se inicijalizacija obavl formalnim u
postupkom. U tom sludaju, moraju se pozvati konstruktori da inici;'alizuju situacijama kada se od prevodioca zahteva da napravi objekai o kome mu nisu
dati nikakvi detalji. Ako, na primer, prethodno definisanu strukturu y koristite u
objekte. Dakle, ako imate ovakr,u strukturu:
sledeioj definiciji:
struct Y {
fl oat f; Y yzLzl = { v(t) );
int i; Prevodilac ie
buniti jer ne moZe da pronade podrazumevani konstruktor.
se
Y(1nt a); Drugi objekat u nizu Zelimo da napravimo bez argumenata, i tu ie prevodilac
); potraziti podrazumevanog konstruktora. Zapravo, ako jednostarryro deflnisete
morate ukazati na poziv konstruktora. Najbolji je izridit pristup, kao ovaj: niz objekata tipay,
y y3[7];
Y vl [] = t Y(1), v(2) , v(3) );
To su, u stvari, tri objekta i tri poziva konstruktora. Uvek kada postoji kon- prevodilac ie se buniti, jer on mora da pozove podrazumevani konstruktor za
struktor, bilo da je u pitanju struktura, u kojoj su svi ilanovijavni, ili klasa s pri- inicijalizaciju svakog objekta u nizu.
vatnim dlanovima, inicijalizacija se mora obaviti preko konstruktora, dak i ako Isti problem se pojavljuje i pri pravljenju pojedinadnih objekata, kao sto je
koristite grupnu inicijalizaciju. ovaj:
Sledeii primer pokazuje konstruktore s vi5e argumenata: Y v4;
I I : C06:l'1u1 ti arg.cpp Zapamtite: ako postoji konstruktor, prevodilac ie se pobrinuti da konstruktor
// Konstruktori s vi 5e argumenata uuek pozouebez obzira na situaciju.
ll i grupna inicijalizacija Podrazumevani konstruktor je toliko vaZan da ako (i samo ako) ne postoje
#i nc l ude <i ostream> konstruktori za strukturu (ili klasu), prevodilac automatski pravi jedan podri_
using namespace std; zumevani konstruktor. Dakle, ovo Ce raditi:

class Z ( //: C06:AutoDefaul tConstructor. cpp


int i, i; // Automatski napravljen podrazumevani konstruktor
publ i c:
Z(int ii, int jj); class V {

void print0; int i; // privatan dlan


I. l; // nema konstruktora

Z::Z(int ii, int,tj)


jnt majn0 {
{
i = ii; V v, v2[10];
J = JJ; ) ///,-
) Ako je definisan bilo koji konstruktor, a ne postoji podrazumevani konstruk-
tor, u gornjem primeru nastace greska prilikom prevodenja zbog pokusaja da se
void Z::print0 { napravi instance klase V
cout << rr 'i = rr << i .. ", i = " .. j << endl; MoZda iete pomisliti da ovakav konstruktor, koga je napravio prevodilac,
I inteligentnije inicijalizuje objekte, kao sto je popunjavanje memorije dodeljene
objektu wednosiu nula. Ali, to nije tadno - tako bi nastao dodatni k6d koji pro-
int majn0 { gramer ne bi mogao kontrolisati. Ako zelite da se memorija inicijalizujl wed-
z zzl) = { Z(t,Z), Z(3,4), z(s,6), z(7,8) }; ' no5iu nula, to morate sami da uradite izridito u podrazumevanom konstruktoru.
for(int i = 0; i < sizeof zz / sizeof *zz; i++) Iako prevodilac pravi podrazumevani konstruktor za vas, ponaSanje tog kon-
zzIil.printO; struktora fe vam retko odgovarati. ovu moguinost posmairalte kao bezbed-
I lll,- nosnu i nemojte je desto koristiti. Treba sami da definiSete svoje konstruktore, a
Ovde izgleda kao da smo za svaki objekat u nizu pozivali odgovarajuii ne da dozvoiite prevodiocu da to radi umesto vas.
ko nstruktor.
220 Misliti na jeziku C++ Poglavlje 6: lnicijalizacija i iiiienje memorije 22l

SaZetak 9. PokaZite automatsko brojanje i grupnu inicijalizaciju na nizu ob)ekata


klase koju ste napravili u veZbi 3. U tu klasu dodajte funkciiu dlanicu koia
Mehanizmi jezika C++ koje smo razmotrili trebalo bi da vam jasno nagoveste
ispisuje poruku. izradunajte velidinu niza i kreiite se kroz njega pozivajudi
znaiaj postupaka inicijalizacije i diSienja memorije u tom jeziku. Iedno od prvih
va5u nor,'u funkciju dlanicu.
Stroustrupovih zapaianla, dok je projektovao jezik C++, bila je dinjenica da je
ogroman broj problemaizaziva nepravilna inicijalizacija promenljivih. Ovakve 10. Napravite klasu bez konstruktora i pokaZite da moZete praviti objekte
greSke se te5ko otkrivaju. Sliino vaZi i za nepravilno oslobadanje memorije. pomoiu podrazumevanog konstruktora. Sada napravite svoje konstruk-
Po5to konstruktori i destruktori garantuju pravilnu inicijalizaciju i oslobadanje tore (sa aigumentima) za klasu, i ponovo prevedete kOd' Objasnite Sta se
memorije (prevodilac neie dozvoliti pravljenje ili uni5tavanje bilo kog objekta desilo.
bez odgovarajuieg poziva konstruktora, odnosno destruktora), programer
dobija potpunu kontrolu i bezbednost.
Grupna inicijalizacija vam pomaZe da izbegnete tipidne gre5ke pri inicijaliza-
ciji objekata diji su elementi ugradenog tipa, i iini va5 k6d saZetijim.
Bezbednost prilikom pisan;'a programa vaLna je tema u C++-u. U okviru te
teme, posebno su vaZna pitanja inicijalizacije i di5ienje memorije, a u nastavku
knjige susreSiemo se s jo5 nekim vaZnim bezbednosnim pitanjima.

VeZbe
Reienja ovih veZbi nalaze se u elektronskom dokumentu ]"he Thinking in C++ Annotated Solution Guidakoji
mo2ete preuzeti sa lokacije m.BruceEckel.com.
I . Napi5ite jednostavnu klasu koja se zove Simple, s konstruktorom koji Ce
ispisati poruku o tome da je pozvan. U glavnom programu napravite obje-
kat kIase.
2. U ve7-bi I, dodajte destruktora koji ie ispisati poruku da je pozvan.
3. Izmenite veLbu2 tako da klasa sadrZi celobrojni ilan. Izmenite konstruktor
tako da ima celobrojni argument i sme5ta ga u elan klase. I konstruktor i
destruktor treba da ispisuju celobrojnu wednost, tako da moZete pratiti
pravljenje i uniStavanje objekata.
4. PokaZite da se destruktori pozivaju dak i kada se iskazom goto iskodi iz
petlie.
5. Napi5ite dve petlje for koje ispisuju vrednosti od 0 do 10. U prvoj, defini5ite
brojad pre petlje for, a u drugoj definiSite brojad u samom izrazu petlje for.
Zatim, izmenite identiflkator u drugoj petlji for, tako da ima isto ime kao i
brojad u prvoj petlji for i pogledajte kako ie prevodilac reagovati.
6. U datotekama Handle.h, Handle.cpp i UseHandle.cpp s kraja petog pogla-
vlja upotrebite konstruktore i destruktore.
7. Pomoiu grupne inicijalizacije napravite niz brojeva tipa double. Zadajle
veliiinu niza, ali navedite manje elemenata. Ispi5ite ovaj niz koristedi funk-
ciju sizeof za urwdivanje velidine niza. Zatim, napravite niz brojeva tipa
double koristeii grupnu inicijalizaciju i automatsko brojanje. Ispi5ite niz.
8. Napravite niz objekata tipa string kori5ienjem grupne inicijalizacij.
Napravite stek za duvanje tih objekata, a zatim prodite Woz niz ubacujuii
jedan po jedan objekat u stek. Na kraju, uzmite objekte iz steka i ispi5ite ih.
224 Misliti na jeziku C++ Poglavlje 7: Preklapanje funkcija i podrazumevani argumentl 225

Kada napravite objekat (promenljivu), dali ste ime jednoj oblasti u memoriji. pozivu funkcije. Prema tome, iskazi f(,Zdravo"), f(,,dao",I) i f(,,hei",2ic') mogu
Funkcija je ime odredene akcije. Izmi5ljanjem opisnih imena, pravite program pozivati istu funkciju. To takode mogu biti i pozivi za tri preklopljene funkcije, ali
koji korisnici lako razumeju i menjaju. To lidi pomalo na pisanje proze, poSto je icada su liste argumenata ovako slidne, onda uglar.nom Zelite i sliino ponasanje
cilj da se korrunicira s eitaocima. funkcija, Sto zahteva jednu funkciju.
Problem nastaje kada pokusamo da preslikamo nijanse iz govornog jezika u preidapanje funkcija i podrazumevani argumenti nisu komplikovana svojstva
programski jezik. Cesto ista rea irna viSe raz.liditih znadenja, u zavisnosti od kon- da ih koristite, a razumeiete
lezika. Oo krila ovog poglavlja, shvatiiete kada treba
teksta. Kada jedna rei irna'i5e z-nadenja - ona je preklopljena(engl. ouerload). i i.rt"r.,e mehanizme za njihovo realizovanje tokom prevodenja i povezivanja.
Preklapan je je veoma korisno, posebno kada se radi o trivijalnim razlikama. Ako,
na primer, nekome hoiete da kaZete da opere auto i majicu, upotrebiiete istu
rei ,,oprati", i ne trcba dodatno objaSnjavati Sta ta red znadi u jednom, odnosno Jo5 ponesto o obeleZavanju imena
drugom sludaju, jer je to jasno iz konteksta. Ljudski govor sadrZi suvi5ne redi, pa bbeleZavanle imena predstavljeno je u poglavlju 4. U sledeiem primeru:
i ako propustite nekoliko redi, ipak moZete da shvatite znadenje. Nama ne tre-
void f0;
baju jedinstveni identifikatori - mi shvatamo znaienje iz konteksta. f0;
class X { void };
Ll veiini programskih jezika svaka funkcija mora imati jedinswen identifrka-
tor, Ako Zelite da ispi5ete tri razlidita tipa podataka: celobrojnu wednost, zna- funkcija f( ), unutar oblasti vaZenja klase x, neie se sukobiti sa globalnom funk-
kovni niz i broj r.r formatu pokretnog zateza, u opStem sludaju, moraiete da cijom i( ). Prevodilac to postiZe tako sto interno pravi razlidita imena za globalnu
napravite tri razlidita imena za funkcije koje ispisuju te podatke: print*intQ, ftinkciju fO i funkciju fO koja se nalazi unutar oblasti vaZenja klase X' )L:fO.
print_char( ) i print float( ). Ovo ie oreZati posao i vama, koji pi5ete program, i U pogfavlju a je sugerisano da je interno ime, zapravo, ime klase ,'obeleZeno"
iitaocu koji pokudava da ga razume. imen-om funkcije, tako da bi u na5em sludaju prevodilac koristio interna imena
_f i _x_f. U svakom sludaju, ispostavilo se da
je za obeleLavanje imena funkciia
U C++-u, jo5 jedan laktor vas primorava da preklapate imena funkcija, a to je
konstruktor. PoSto je ime konstruktora unapred odredeno imenom k]ase, reklo potrebno viSe od imena klase.
bi se da moZe postojati samo jedan konstruktor. A.li, sta ako hoiete da napravite Evo zaSto: pretpostavite da hoiete da preklopite ove dve funkcije:
objekat na vi5e nadina? Pretpostavimo da pravite klasu koja moZe sama da se void print(char);
inicijalizuje na standardni nadin, ali takode i ditanjem informacija iz datoteke. voi d pri nt (fl oat) ;
Za to su potrebna dva konstruktora, jedan koji nema argumente (podrazume-
Nebitno je da li su obe funkcije unutar klase, ili su u globalnoj oblasti vazenja.
vani konstruktor), i drugi diji argument je znakormi niz, gde je taj niz ime dato-
Prevodilac ne moZe da napravi jedinsWena interna imena oslanjajuii se samo
teke potrebne za inicijalizaciju objekta. Oba su konstruktori, pa zato moraju na oblast vrtenja funkcije. Na kraju biste u oba sludaja imali funkciju *print'
imati isto ime: a to je ime klase. Zato je preklapanje funkcija od kljuinog znadaja
Sustina preklopljenih funkcija je da koristite ista imena funkcija, a razlidite liste
za dodeljivan je istih imena funkcijama - u na5em sludaju konstruktorima - kada
argumenata. Prema tome, da bi preklapanje bilo uspesno, prevodilac mora da
su njihovi argtrmenti razliditog tipa.
oultezi ime funkcije tipovima argumenta te funkcije. Gorenavedene funkcije,
Preklapanje frrnkcija je neophodno za konsrruktore, ali je, uopSte, pogodnost koje su deflnisane u globalnoj oblasti vaLenja, prevode se u interna imena koja
koja se mo2e iskoristiti z-a bilo koju funkciju, a ne samo za funkcije dianice klase.
mogu izgledati ovako: -print-char i -print-float' Ne postoji standarci po kome
Pored toga, preklapanje lunkcija z.nadi da, ako imare dve biblioteke koje sadrZe preiodloci prave inrern; imena, tako da ie razliditi prevodioci praviti razlidita
funkcije s istim imenima, dvosmislenost ne nestaje sve dok su njihove liste argu- i*".ru. (MoZete videti na Sta to lidi tako sto iete prevesti program na asemblerski
menata raz.lidite. Sve ove osobine iemo detaljno razmotriti u ovom poglavlju. jezik.) Ovo, naravno, stvara probleme kada Zelite da kupite biblioteke prevedene
Tema ovog poglavlja je pogodno koriSienje imena funkcija. Preklapanje funk-
tdredenim prevodiocem i odredenim povezivadem - ali, dak i da je obeleZavanje
cija nam omoguiava da koristimo isto ime zarazlitite funkcije, ali postoji i druga imena standardizovano, naisli bismo na druge'prepreke zbog razlika u radu
tehnika koja olakSava pozivanje funkcije. Sta ako Zelite da pozovete istu funkciju razliditih prevodilaca.
na razlicite nadine? Ako funkcija inta dugadku listu argumenata, pisanje pozivaza to bi bito sve o preklapanju funkcija: mozete koristiti isto ime za razli(ite
takvu lunkciju moze postati dosadno (a ditanje tih poziva moZe biti zbunjujuie), funkcije, sve dok se liste argumenata tih funkcija medusobno razlikuju. Prevodi-
posebno kada je veiina argumenata desto ista. U C++-u se takve wednosti mogu
lac koiisti ime, oblast vaLeoja i listu argumenata, da bi napravio interno ime
deflnisati kao poclrazutneuani argumenti (engl. default arguments). Prevodilac funkcije za svoje potrebe i za potrebe povezivada'
urneic podrazuntevanrr vrednost argumenta, ako taj argument nije zadat u
226 Misliri na jeziku C++ Poglavlje 7: Preklapanje funkcija i podrazumevani argumenti 227

Preklapanje na osnovu tipova rezultata Iako vidite da funkcija f(int) ima celobrojan argumenr, prevodilac ro ne zna
Prirodno je da se zapitate:,,Zasto koristiti samo oblasti vaLenja i liste argume- jer je u deklaraciji izridito reieno f(char), Sto znaei da je argument znakormi.
nata? Zasto ne i tipove rezultata?" Na prvi pogled, izgleda logieno da i rezultat Medutim, prevodenje ie biti uspe5no. U C-u bi i povezivanje bilo uspe5no, ali ne
ru-est"'ufe u obelezavanju imena funkcije. Tada biste mogli di preklopite funk- i u C++-u. Po5to prevodilac obeleZava imena, definisana funkcija ie biti f*int, a
cije i na osnov.rl rezultata: koristi se funkcija f-char. Kada povezivad poku5a da razreSi referencu na f_char,
void f0; naii ie samo f_int, a vama ie prijaviti greSku. To je bezbedno povezivanje. Ovaj
int f0; problem se ne pojavljuje narodito desto, ali kada se pojavi, jako se teSko otkiva,
posebno u velikim projektima. Ovo je jedan od sludajeva kada nezgodnu greSku
ovo radi dobro kada prevodilac moZe nedvosmisleno da utwdi zna(en)eiz,
u programu na jeziku C moZete naii pomoiu prevodioca zaC++.
konteksta, kao u sludaju: int x=f( ). Medutim, u C-u ste uvek mogli da pozovete
iunkciju i da pri tome zanemarite njen rezurtat (to jest, aa je "pozovlte zbog
njenih sporednih efekata). Kako prevodilac da zna o kakvom sL pozivu radi?
Verovatno je ditaocu los teze da utvrdi koji poziv je u pitanju. preklapanje
Primer preklapanja
na Sada moZemo da izmenimo ranije primere i da u njima upotrebimo preklapanle
osnovu tipa rezultata je suvise rizidno i zbog toga nije dozvoljeno u c+i-u.
funkcija. Kao Sto smo vei pomenuli, preklapanje konstruktora je posebno kori-
sno. To moZete videti u sledeioj verziji klase dinamiikog niza:
Bezbedno povezivanje //: C07:Stash3.h
Postoji jos jedna dodatna korist od obeleZavanja imena. u c-u se pojavrjuje // Preklapanje funkcija
posebno nezgodan problem kada klijent ne deklarise dobro funkcij", iti, #i fndef STASH3_H
stb i,
jo5 gore, pozove funkciju koju prethodno uopste nije deklarisao. #defi ne STASH3_H
Tada prevodi-
lac, iz natina na kojije funkcija pozvana, sam izvodi njenu dek]aracilu. Nekada
je ta deklaracija tadna, ali kada nije, nastaje greska kojase tesko
otkriva. class Stash {
Buduii da u c++-u sve funkcije moremo deklarisati pre upotrebe, verovat- i nt si ze;
// Vel i ei na svakog sk1 adi ita
noia da se pojavi ovakav problem jako je mala. prevodilaC za c++ neie automat- int quantity; // Broj skladi5ta
ski deklarisati funkciju umesto vas, rako da iete najverovatnije sami ukljuditi int next; // Sledeee prazno skladiSte
odgovarajuiu datoteku zagravrja. U svakom sludaju, ako ipak uspete da pogre- // Niz bajtova koji se dinamidki zauzima:
Site pri deklarisanju, bilo zbog rudnog deklarisanja ili zato ito rt. rttlreili unsigned char* storage;
po[re- voj d 'i nfl ate (i nt i ncrease)
Snu datoteku zaglavlja (na primer zastarelu), obeleZavanje imena ie vam ;
publ i c:
pomoii bezbednosnom opcijom koju desto nazivamo bezbedno poueziuanje
(engl. ry p e - s afe lin kage) Stash(jnt size); // Kolidina je nula
.

Razmorrite sledeiu situaciju. u jednoj datoteci je definicija funkcije:


Stash(int size, int initQuantity) ;
-Stash 0 ;
//: C07:Def.cpp (0) int add(void* element) ;
ll Definicija funkcije void* fetch(int jndex) ;
vold f(int) () i nt count 0 ;
);
U drugoj datoreci, funkcija je pogre5no deklarisana, azatimpozvana: #endif // STASH3_H ///:-
I I : C07: Use. cpp
Prvi konstruktor klase dinamidkog niza isti je kao ranije, ali drugi ima argu-
/ I {t} oet
ment initQuantity, koii ukazuje na podetni broj skladista koje treba zauzet| IJ
// Pogreino dekl ari sana funkcija definiciji vidite da dlan quantity dobija podetnu wednost nula, kao i pokazivad
void f(char) ; storage. U drugom konstruktoru, poziv funkcije inflate(initQuantig poveiava
wednost dlana quantity.
int main0 { //: C07:Stash3.cpp {0)
/l! fo); l/ tJzrokuje gre5ku prilikom povezivanja
/ / Prekl apanje funkcija
I ///:- #i ncl ude "Stash3. h"
#include "../require.h"
228 Misliti na jeziku C++ Poglavlje 7: Preklapanje funkcija i podrazumevani argumenti 229

#i ncl ude <i ostream> int Stash::count0 (


#i nc'l ude <cassert> return next; // Broj elemenata
using namespace std; )
const int increment = 100;
void Stash: :inflate(int increase) {
Stash::Stash(int sz) { assert (i ncrease ,= 0) ;
>rze - 5z; if(increase == 0) return;
quantitY = 0; 'int newQuantily = quantity + increasel
next = 0; int neviBytes = newQuantity * sjzel
storage = 0; int oldBytes = quantity * srze;
i unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
Stash::Stash(int sz, int initQuantity) { b[i]
= storagell); // Kopira stari blok u novi
si ze = sz; delete [] (storage) ; // 0sl obada staro skl adi 5te
quanti ty = 0; storage = 6; // Pokazuje na novi memorijski blok
next = 0; quantjty = newQuantity; // Podeiava velidinu
storage = 0; \ l//,-
i nf1 ate ( i ni tQuanti ty) ;
Prvi konstruktor ne zauzima memoriju za pokazival storage. Memorija se
I
zavzimatek kada prvi put dodate objekat, funkcijom add( ), kao i svaki put kada
se prepuni tekuie skladi5te.
Stash::-Stash0 {
if(storase != 0) Oba konstruktora su upotrebljena u probnom programu:
{
cout << "os1 obadjam memoriju" <. endl ; / / : C07 :Stash3Test.cpp
de1 ete [] storage; //{L) Stasna
i / I Preklapanje funkcija
) #i ncl ude "Stash3. h"
#incl ude "../requi re.h"
int Stash::add(void* element) { #i ncl ude <fstream>
i f(next >= quanti ty) I I Da 1 i je ostaio dovoljno prostora? #i ncl ude <i ostream>
inflate(increment); #include <string>
II Kopira eiemente u skladi5te, using namespace std;
ll poe;njuei od sledeceg praznog prostora:
int startBytes = next * size; int mainO {
unsi gnedchar" e = (unsi gned char*) e1 ement; Stash i ntStash (si zeof(i nt) ) ;
for(int i = 0; i < size; i++) for(int i = 0; i < 100; i++)
storageIstartBytes + i] = eIi]; i ntStash. add (&i ) ;
next++; for(int j = 0; j < intStash.count0; j++)
return(next - t); l/ Indeksni broj cout << "intStash.fetch(" .. j .. ") = "
) << *( int*) intStash.fetch(j)
<< endl;
voi d* Stash : : fetch ( i nt i ndex) { const int bufsize = B0;
require(0 <= index, "stash::fetch (-)index"); Stash stringstash(sizeof(char) * bufsize, 100) i
i f(i ndex >= next) i fstream in("Stash3Test,cpp") ;
return 0; f f Za ozna(.avanje kraja assure(in, "Stash3Test.cpp") ;
I I Pravi pokazi vad na el ement: string line;
return &(storageIindex * size] ); whi 1 e(get1 ine(in, I ine) )
I stringStash.add( (char*) l ine.c str0) ;
intk=0;
char* cpl
Misliti na jeziku C++ Poglavlje 7: Preklapanje funkcija i podra=!rn!,ren' 231
230 "!9,."

while((cp = (char*)stringstash.fetch(k++)) !=0) Na osnovu prethodnog primera, mozete pomisliti da jedinu razliku izmedu
cout << "stringstash.fetch(" " k " ") = " unije i klase iini nadin smestania podataka (u ovoj uniji se celobrojne wednosti
<' cP << endl; i biojevi u formatu pokretnog zareza smestaju u isti deo memorije). Medutim,
I I ll:- unija se ne moZe koristiti kao osnorryta klasa pri nasledivanju, Sto je ogranidava-
Konstruktor objekta stringStash koristi drugi argument; to ie korisno ako luii faktor ako se posmatra iz ugla objektne orijentisanosti (o nasledivanju iete
znate posebne detalje o problemu koji reSavate, pa moZete da izaberete podetnu
uditi u poglavlju 14).
tako funkcile dlanice reguli5u pristup uniji, ipak nema nadina da spreaite kli-
veliiintr dinamickog niza.
jenta da pristupa elementu nakon inicijalizacije unije. U navedenom-primeru,
mogli stereiiLread_float( ), iako je to neprikladno. Medutim, ,,bezbedna' unija
Unije moie biti kapsulirana u klasi. U sledeiem primeru, primetite kako rezervisana
red enum prodi5iava k6d i kako je preklapanje konstruktora zgodno iskoriSieno:
Kao Sto ste videli, jedina razlika izmedu struktura i klasa jezika C++ jeste Sto su
dlanovi strukture podrazumevano javni, a ilanovi klase su podrazumevano pri- //: C07:SuperVar.cpp
vatni. Kao sto odekujete, i strukture mogu imati konstruktore i destruktore. Ali, // Super-promenljiva
ispostavlja se da i unija (engl. union) takode moZe imati konstruktor, destruktor, #include <iostream>
funkcije ilanice, pa se iak moZe kontrolisati pristup. U sledeiem primeru se using namespace std;
ponovo moZete uveriti u korisnost preklapanja:
class SuperVar (
I I : C07: Uni onCl ass. cpP enum {
ll Unije s konstruktorima i funkcijama dlanicama character,
#i ncl ude<i ostream> i nteger,
usi ng namespace std; f1 oati ng_poi nt
) vartype; // Samo definiciia
union U { union { // Anonimna unija
pri vate: // I kontrol a Pri stuPa !
char c;
1nt i ; int i;
float f; fl oat f;
publ i c:
);
U(int a) ; publ i c:
U(float b); SuperVar(char ch);
_u0;
SuperVar(int ii);
i nt read_i nt ( ) ; SuperVar(fl oat ff) ;
fl oat read_fl oat ( ) ; void print0;
); t.
U::U(int a) {j = a; ) SuperVar: :SuperVar(char ch) {
vartype = character;
U::U(float b) {f = b;i c=ch;
)
U: :-U0 { cout .. "U; :-U0\n"; }

SuperVar: :Supervar(int ii) {


'i nt U::read int0 { return i; ) vartype = integer;
'i = ii;
float U::read*float0 { return f; }
)

rnt main0 { SuperVar: :SuperVar(float ff) {


u x(12), Y(1.9F); vartype = f Ioating_Point;
cout << X. read_i nt 0 << endl ' f=ff;
cout << Y . read_f l oat ( ) << endl ; )
\ I I t,-
232 Misliti na jeziku C++ Poglavlje 7: Preklapanje funkcUa i podrazumevani argumenti 233

void SuperVar: :print0 ( v{rrtn e za kontrolu cele grupe unija, sto ne bi zauzelo mnogo prostora. IoS bolji
swi tch (vartype) { pristup je obuhvatanje koda u kome se koristi promenljiva varrype pretprocesor-
case character: skom komandom #ifdef Sto garantuje ispravno kori5Cenje svih elemenata tokom
cout << "znak: " << c << endl i ruzvoja i testiranja. U konadnoj verziji programa, moZe se izbeii dodatno zauzi-
brea k; manie prostora i neee se tro5iti weme na obradu.
case i nteger:
cout << "ceo broj: " << j << endl;
break;
case fl oati ng_poi nt:
Pod razumevan i arg u menti
U primeru Stash3.h proudite dva konstruktora za dinamidki niz. Ne razlikuju se
cout << "rea'lan broj: " << f << endl;
ba5 mnogo, zar ne? Izgleda kao da je prui konstruktor specijalan sludaj drugog
break;
konstruktora, s tim Sto je podetna wednost promenljive size postavljena na nulu.
)
Reklo bi se da ste malo tradiii trud pravedi i odrZavajuii dve razlidite verzije slidne
)
tunkcije.
jnt main0 C++ nudi re5enje s podrazumeuanim argumentima (engl. default arguments).
i
SuperVar A('c'), B(12), C(1.4aF); Podrazumevani argument je vrednost argumenta koja je data u deklaraciji, a koju
A.print0; prevodilac automatski umede, ukoliko ne navedete wednost u pozi!'u funkcije.
8.print0; U primeru za dinamidki niz, moZemo zameniti dve funkcije:
C.print0; Stash(int size); // vrednost argumenta quantity ie nula
I lll:- Stash(int size, int initQuantity) ;
U prethodnom primeru, nabrojiv tip nema ime (to je neoznaeena nabrojiva jednom funkcijom:
lista). Ovo je prihvatljivo ako iete odmah definisati instance tog nabrojivog tipa,
Stash(int size, int initQuantity = 0);
kao Sto je uradeno. Ime tog tipa neie biti potrebno u nastavku programa, ono je
opciono. Definicija za Stash(int) je izbadena, a treba nam samo jedna definicija, za
Unija nema ime niti se deklariSe promenljiva tog tipa. To je anonimna unija Stash(int, int).
(engl. anonymous union) koja pravi prostor za uniju, ali ne zahteva pristup ele- Sada ie definicije dva objekta:
mentima unije s imenima promenljivih i tadkom. Na primer: Stash A(100), B(100, 0);
I I : C07 :AnonymousUnion. cpp proizvesti potpuno isti rezultat. U oba sludaja se poziva isti konstruktor, ali u
int main0 { nizu A prevodilac automatski upisuje drugi argument kada vidi da je prvi argu-
uni on { ment celobrojna vrednost, a da drugog nema. Kada prevodilac vidi podrazume-
int i; vani argument, on zna da moZe da pozove funkciju ako drugi argument zameni
f1 oat f; njegovom podrazumevanom vrednosdu. To ste mu vi upravo i rekli da uradi
); kada ste napravili podrazumevani argument.
// Pristup dlanovima bez upotrebe kval.ifikatora:
Podrazumevani argumenti su pogodnost, kao Sto je i preklapanje funkcija.
i = 12; Obe metode vam omogudavaju da koristite isto ime funkcije u razliiitim situaci-
f = t.z2; jama. Razlika pri kori5ienju podrazumevanih argumenata je u tome Sto pre-
\ lll,- vodilac zamenjuje argumente kada ih vi sami ne stavite. U sledeiem primeru je
Primetite da dlanovima anonimne unije pristupate kao da su obidne pro- dobro iskoristiti podrazumevane argumente umesto preklapanja funkcija inade
menl,ive. Jedina razlika je u tome Sto obe promenljive zauzimaju isto mesto u biste dobili dve ili vi5e funkcija koje imaju slidan potpis i pona5anje. Ako se
memoriji. Ako je anonimna unija u oblasti vaZenja datoteke (van svih funkcija i pona5anje funkcija puno razlikuje, nema smisla koristiti podrazumevane argu-
klasa), onda mora biti deklarisana kao statidka da bi bila interno povezana. mente (u takvom sludaju moZda je bolje ispitati da Ii takve dve funkcije uop5te
Iako je promenljiva SuperVar sada bezbedna, korist koju od nje imamo je treba da imaju isto ime).
diskutabilna s obzirom na razlog zbog koga uopSte koristimo uniju, a to je u5teda Kada koristite podrazumevane argumente, treba da imate na umu dva pravila.
prostora. Dodavanje promenljive vartype zauzima dodatan prostor, u zavisnosti Prvo, podrazumevani argumenti moraju biti na kraju liste argumenata. Posle
od podataka u uniji, pa nema u5tede. Postoji nekoliko moguinosti da ovo pro- podrazumevanog argumenta mogu slediti samo podrazumevani argumenti.
radi. Ako bi sve unije bile istog tipa, onda bi bila dovoljna jedna promenljiva
Poglavlje 7: Preklapanje funkcija i podrazumevani argumenti 23s
234 Misliti na ieziku C++

da izostavite i sve class Mem {


Drugo, kada izostavite neki argument u pozivu funkcije, morate byte* mem;
sledeie argumente (Sto sledi iz prvog pravila)' i nt si ze;
podrazumevani argumenti iu smeStenl samo u deklaraciji funkcije (koja se
void ensureMinSize(int minSize) ;
obidno nalazi u datoieci zaglavlja). Prevodilac mora da vidi podrazumevane publ i c:
wednosri pre nego Sto moZela i-h koristi. Neko ie staviti i komentare koji
opi-
Mem0;
suju podrazumevane wednosti argumenata u definiciii, radi dokumentaciie:
Mem( i nt sz) ;
void fn(int x / * = 0.l) \ 11 ... -Mem0;
int msizeO;
byte* po i nter0 ;
LaZni argumenti byte* poi nter(i nt mi nSi ze) ;
U deklaracijina iunkcija, argumentimogu deklarisati bez identifikatora. Ovo
se l.
moze izgledati dudno ako se koristi uz podrazumevane argumente. Na
kraju #endif // MEM_H lll:-
moZete dobiti ovo: objekat tipa Mem upravlja blokom bajtova i osigurava da postoji dovoljnt
void f(int x, jnt = 0, float = t'1); mesta za sme5tanje. osnovni konstruktor ne rezervi$e skladi$te, a drugi kon
U C++-u vam ne trebaju identifikatori ni u definiciji funkcije: struktor osigurava da u objektu postoji skladi5te za sz bajtova. Destruktor oslo
bada zauzeti memorijski blok, msize vam govori koliko bajtova trenutno ima
r

void f(int x, int, float flt) { /. "' "l \


objektu, a pointer( ) pravi pokazivad na podetnu adresu memorijskog blok
U telu funkcije, mozete da pristupate argumentima x i flt, ali ne i argumentu
u (Mem je alatka niskog nivoa). Postoji preklopljena verzija funkcije pointer( ), o,
sredini, jer on nema ime. Ipak, priLikom pozivanja funkcije mora da se navede
tole niient moze zahtevati da napravi pokazivad na blok bajtova koji je nek
wednosi i za ova) laZni argument, na primer f(1) ili f(I,2,3'0)' Ova sintaksa vam minimalne velidine, zadate sa minSize, i funkcija dlanica ie to obezbediti.
jeda iete kasnije,
omoguiava da ubacite lazni argument, a da ga ne koristite. Ideja I konstruktor i funkcija pointer( ) koriste privatnu funkciju dlanicu ensur(
mozaa, Zeleti da promenite definiciju funkcije tako da koristite i laZni argument, Minsize( ), da bi poveiali velidinu memorijskog bloka (primetite da nije bezbedn
a
gde ta funkcij.a poziva. ovo,
da pri tome ne morate da menjate k6d svuda se koristiti raniji reiultat funkcije pointero posle promene velidine memorijsko
na.lurro, moZete postiii i kori5ienjem imenovanog argumenta' ali ako defini5ete bloka).
argument a ne koristite ga, veiinaprevodilaca vas upozorava na lokalnu gfe$ku' Evo realizacije klase:
Ali ako namerno izostavite ime argumenta, izbeii iete ovo upozorenje.
I 5to je joS va7-niie, ako ste podeii da koristite neki argument funkcije,
a kasnije //: C07:Mem.cPP {0)

otkloniti, bez upozorenja, i #include "Mem,h"


ste odludili da vam on ne treta, moZete ga efikasno
#i ncl ude <cstri ng>
pri tome neiete poremetiti bilo koji deo koda koji je pozivao raniiu verziju te using namesPace std;
tunkcije.
Mem::Mem0 { mem = 0; size = 0; }

Sta izabrati: preklapanje ili pod razumevane Mem::Mem(int sz) {


mem = 0;
argumente? size = 0;
I preklapanje i podrazumevani argumenti obezbeduju pogodnosti pri pozivanju
ensureMi nSi ze(sz) ;
imena funkcije. Ponekad neiete biti sigurni koju od ove dve tehnike treba izbe-
)
gavati. Na primer, razmotrite sledeiu alatku koja je osmi5ljena tako da automat-
ski upravlja blokovima memorije: Mem::-MemO { delete []mem; ]
//: C07:Mem.h
'int Mem::msize0 { return size;
#i f ndef 14Et'l_H )
#defi ne MEM_H
typedef unsigned char byte; void Mem: :ensureMinSize(int minSize) {
'i f (s ize < mi nSi ze) {
byte* newnem = new bytelminSize];
memset(newmem + size, 0, minSize - size);
Poglavlje 7: Preklapanje funkcija i podrazumevant argumentt
237
236 Misliti na jeziku C++

memcpy(newmem, mem, s j ze) MyString::MyString0 { buf = 0; )


;

del ete [] mem;


str)
MyString: :MyString(char* {
mem = newmem;
t);
buf = new Mem(strlen(str) +
size = minSize;
strcpy( (char*) buf->pointer0, str) ;

)
i

voi d MyStri ng: : concat (char* str) {


byte* Mem::Pointer0 { return mem; }
1f(!buf) buf = new Mem;
strcat ( (char*) buf->Poi nter (
byte* Mem::Pointer(int minSize)
buf->msize0 + strlen(str) + 1), str);
{

ensuret'1j nSi ze (mi nSi ze) ;


)
return mem;

\ ilt:- void MyString: :print(ostream& os) {


Vidite da funkcija ensureMinsize0 iedina zalrzima memoriju, i da je koriste if(!buf) returni
drugi konstruktor i preklopljena verzija funkcije pointer0. Ako je memorijski os << buf->pointerfl << endl;
blok" dovoljno veliki, u okviiu funkcije ensureMinSize0 ne treba nista raditi.
Ako
)
rreba zauzeri novo skladiste, da bi se memorijski blok poveiao (Sto je takode
sludaj posle upotrebe osnovnog konstruktora, kada je blok veliiine nula), MyString::-MyString0 { delete buf; }

dodaina memorija se popunjava nulama, koriSienjem funkcije memsetg iz


srandardne c biblioteke, koju smo upoznali u poglavlju 5. sledi poziv funkcije int mainO {

memcpy0, iz standardne C biblioteke, koja u ovom sluiaju kopira (uglamom na MyString s("Probni tekst") ;

efikasan naain) postojeie baitove iz stale u nol'1-l memoriju. Konaino, stara s. pri nt (cout) ;
memorija se oslobada, a nova memorija i veiidina se dodeljuju odgovarajuiim s.concat(" dodatne sitnice") ;

dlanovima. s. pri nt (cout ) ;


Klasa Mem je osmisljena kao alatka koja se koristi u drugim klasama, za poje- MyString s2;
s2.concat("Podrazumevani konstruktor") ;
dnostavljivanje upravlianja memorijom (moZe se koristiti i za skrivanje napred-
s2. pri nt (cout) ;
nijeg sisierna.za upravljanje memorijom, koji, na primer obezbeduje operatirmi
sliteml. Klasa Mem je na z_godan naain testirana u sledeiem primeru, kroz t il/:
pravljenje,,tekstualne" klase: sve Sto moZere da uradite sa klasom Mystring, jeste da nadoveZete tekst i da
ga ispisete u tok tipa ostre.rm. I(asa sadrzi samo pokazivad na klasu Mem, ali
pri-
ll: C07:MemTest.cPP iretiie razliku izmedu podrazumevanog konstruktora, koji postavlja wednost
I I Iesti ranje k)ase Mem
pokazivada na nulu, i drugog konstruktora, koji pravi objekat tipa Mem i kopira
//{L} t'rem podatke u njega. Prednosi podt*utt'"t'anog konstruktora je u tome sto' na pri-
#include "Mem.h"
*er, moZ"te irrlo lednostavno napraviti niz praznih objekata tipa MyString,
#i ncl ude <cstri ng>
#i ncl ude <i ostream> poSto svaki objekal sadrZi samo jedan pokazivad, i jedini posao osnovnog kon-
using namespace std; struktora jeste dodeljivanje nulte wednosti tom pokazivadu. Koliko resursa zau-
zima objeiat tipa MyString, videiete tek kada podnete da nadovezujete podatke.
cl ass l.4yStri ng { U tom tienutku, objekat tipa Mem je vei sigurno napravljen. U svakom sludaju,
Mem* buf; ako koristite podrazumevani konstruktor i nikada ne spajate podatke, pozivanje
publ i c: destruktora je jos uvek bezbedno, jer je pozivanie operatora delete za.wednost
f4yStrjng0; nula definisano tako da ne pokusava da oslobodi dodeljenu memoril'u niti da
l4yString(char* str); napravi neki drugi problem.
-l4yStri ng 0 ; Kada posmatrate ova dva konstruktora, udiniie vam se da su oni najbolji kan-
voi d concat (char* str) ; didati za upotrebu podrazumevanih algumenata. Medutim, ako izostavite podra-
voi d pri nt (ostream& os) ;
zumevani konstruktor, a u drugi napisete s podrazumevanim argumentima:
); str = "");
MyString(char*
238 Misliti na jeziku C++ Poglavlje 7: Preklapanje funkcija i podrazumevani argumenti 239

sve ie taano raditi, ali ie se uvek praviti objekti tipa Mem i izgubiiete efikasnost jest, njeni javni dlanovi koji su dostupni programeru klijentu. Ako pomoiu njih
koju ste irnali. Da biste povratili tu efikasnost, morate da izmenite konstruktor:
napravite klasu koja se lako koristi, postigli ste uspeh. Ako treba, efikasnost se
MyString: :MyString(char* str) { moZe naknadno poboljSati, ali ako programer lo5e osmisli klasu, jer je bio obu-
if(!*str) | l/ Pokazuje na prazan znakovni niz zet postizanjem efikasnosti, rezultat je poraZavajuii. VaSa glarna briga treba da
buf = 0; bude pravljenje interfejsa koji ima smisla za one koji ga ditaju i koriste. Primetite
return; da se u datoteci MemTest.cpp kori5ienje klase MyString ne menja, bez obzira
)
na to da li se koristi osno'rni konstruktor i kakva je efikasnost.
buf = new Mem(str1 en (str) + 1) ;
strcpy( (char*)buf->pointer0, str) ;
)
SaZetak
ovo znadi da podrazumevana wednost postaje indikator koji prouzrokuje Ideja vodilja glasi: ne treba da koristite podrazumevani argument kao indikator
izrr5avanje razliditih delova koda, u sruda]'u kada se ne koristi podiuru*"ruru na osnovu koga ie se delovi koda usio'rno izwsavati. Umesto toga, ra5dlanite
Iako ovakav pristup izgleda prilidno bezazleno u sludaju malih kon- funkciju u dve ili vi5e preklopljenih funkcija, ako moZere. podrazumevani argu-
'red.nost.
struktora, u opstem sludaju, moi-e da izazove probleme. Ako moiate d.a traiite menti treba stvarno da se koriste u funkcijama. Podrazumevana wednost treba
podrazumevanu wednost, umesto da je koristite kao obidnu wednost, to je da bude najverovatnija vrednost, tako da klijenti mogu da je ignoriSu ili da je
nago-
ve5taj da iete, u telu jedne funkcije, imati dve razlidite funkcije: jednu promene.
za norma-
lan sludaj, a jednu za podrazumevane wednosti. Mozete, takode, da razdvojite Podrazumevani argument sluZi da bi se lak5e pozivala funkcija, posebno ako
ove funkcije u dva tela i da izbor prepustite prevodiocu. Rezultat ie biti malo ima puno argumenata sa tipidnim wednostima. Oni olak5avaju pisanje poziva, i
(obidno neprimetno) poveianje efikasnosti, zato sto se dodatni njihovo ditanje, a narodito ako autor klase moZe da poreda argumente tako da se
argument ne
prosleduje i dodatni k6d za testiranje uslova se ne izvrSava. I sto je podrazumevani argumenti koji se najrede menjaju budu poslednji i u listi
los vaZnije,
kOd za dve odvojene ftrnkcije duvate unutar dve odvojene funkcije, umesto argumenata.
da ga
kombinujete u jednoj funkciji, koriSienjem podrazumevanih argumenata. odva- Podrazumevani argumenti su posebno korisni u sludaju kada ste podeli da
janje lunkcija olaksava njihovo odrzavanje, posebno ako su funicije koristite funkciju, i nakon nekog wemena ste shvatili da u tu listu treba dodati
velike.
Razrnorrimo klasu Mem. Ako pogledate definicije dva konsiruktora i dve joS argumenata. Dodeljujuii novim argumentima podrazumevane wednosti,
funkcije pointer0, videiete da korisienje podrazumevanih argumenata u oba neiete naruSiti k6d koji koristi prethodni interfejs.
sluiaja ne(e izazvati nikak'u promenu u definicijama funkciJa dlanica. Zato,
klasa moZe lako biti:
/ / : C07: Mem2. h VeZbe
ndef MEf42 H
#i f Resenja ovih veZbi mogu se nadi u elektronskom dokumentu The thinking in C++ Annotated Sotution Guide
koii mozete preuzeti sa lokacije w.BruceEckel.com.
#define MEM2 H
I . Napravite klasu Text, koja sadrZi objekat tipa string za smeStanje teksta iz
typedef unsigned char byte;
datoteke. Dodajte joj i dva konstruktora, jedan podrazumevani i drugi diji je
class Mem { argument znako,rni niz koji predstavlja ime datoteke. Kada se koristi drugi
byte* mem; konstruktor, otvorite datoteku i proditajte sadrZaj. Dodajte funkciju con-
int size; tentsQ, koja waia sadrZaj u objektu tipa string, tako da on moZe (na pri-
void ensurel,linSi ze(i nt minSi ze) mer) da se ispi5e. U glavnom programu, otvorite datoteku koristeii klasu
;
pubi i c: Text i ispi5ite sadrZaj.
t4em(int sz = 0); 2. Napravite klasu Message s konstruktorom koji ima samo jedan argument
-MemO; tipa string s podrazumevanom wedno5iu. Napravite privatni dlan tipa
i nt msi ze0 ; string i u konstruktoru dodelite svom internom znako'urrom nizu wednost
byte* pointer(int minSize = 0); argumenta. Napravite dve preklopljene funkcije dlanice koje se zow
); print0: jednu koja nema argumente i ispisuje poruku koja se nalazi u
#endif /l uEttz H l//:- objektu, i drugu koja ima argument tipa string i ispisuje ga uz internu
Primetite da ie poziv funkcije ensureMinSize(O) uvek biti prilidno efikasan. poruku. Da Ii ima smisla da koristite ovaj prisrup umesto onog koji ste
Ia sam u oba sludaja odluke donosio sa stanovista efikasnosti, ali vi morate koristili za konstruktore?
biti pazljivi, jer mozete upasti u zamku ako razmatrate samo efikasnost (koliko
god da vas ona okupira). NajvaZnija stvar pri pravljenju klase je interfeis klase,
to
240 Misliti na jeziku C++

3. Lltwdite kako vas prevodiiac moZe da napravi asemblerski prevod i ekspe-


rimentiSite da biste utwdili Semu za obeleZavanje imena'
4. Napravite klasu s detiri funkcije dlanice, koje imaju 0, 1,2 i 3 celobrojna
argumenta. Napisite glavni program koji pravi objekat te klase i poziva
.rik, funk.i;u 8lanicu. Sada izmenite klasu tako da ima samo jednu funk-
ciju dlanicu diji su svi argrtmenti podrazumevani. Da li ovo menja vas glavni
program?
5. Napravite funkciju s dva argumenta ipozovite je iz glavnog programa'
Zaiim od jednog argumenta napravite laZni argument (bez identifikatora)
i pogledaite da li se menja poziv u glavnom programu. i ;1.

6. Izmenite datoteke Stash3.h i Stash3.cpp da biste upotrebili podrazume- l' r'

vane argumente u konstruktoru. Testirajte konstruktor praveii dve razli- .i,i


dite verzije objekta dinamidkog niza. 'i.' 1
Lt !i,
.

7. Napravite nor,u verziju klase steka (iz poglavlja 6), koja sadrZi podrazume- ..i'r'ii'::
vani konstruktor, kao i ranije, i ios jedan konstruktor koji ima sledece argu-
mente: niz pokazivada na objekte i velidinu tog niza. Ovaj konstruktor bi
trebalo da se kreie krozoiz i stavlja svaki pokazivad na stek. Testirajte vasu
klasu pomoiu niza podataka tipa string.
8. Izmenite promenljivu SuperVar tako da se komandom #ifdef obuhvati kod
u kome se koristi vartlpe, kao Sto smo objasnili razmatrajuii nabrojivi tip.
Od vartype napravite regularnu i javnu nabrojir,u listu (bez instanci) i izme-
Ir'
nite funkciju printO tako da zahteva argument tipa vartype da bi znala sta !]/

da uradi. lr'
9. Realizujte Mem2.h tako da izmenjena klasa i dalje radi s datotekom
MemTest.cpp.
10. Iskoristite klasu Mem za realizaciju dinamidkog niza. Posto je realizacija 1,.'

privatna, znadi skrivena od klijenta, probni kdd ne mora da se menja' I

I l. U klasi Mem dodajte funkciju ilanicu movedO koja na osnovu rezultata i': '

funkcije pointerO govori da li se pokazivad pomerio (usled naknadnog dode-


ljivanja memorije). Napisite glavni program koji testira funkciju moved0. Da
Ii ima vise smisla da koristite funkciju movedO, ili da pozivate funkciiu
pointer0 svaki put kada treba da pristupite memoriji u klasi Mem?
242 Misliti na jeziku C++ Poglavlje 8: Konstante 243

Ocl kako je Lrvcclena, rezervisana rei const koriSiena je u brojne i razlidite ovom poglavlju). Zbog prikrivenih gre5aka s kojima se moZe suoditi pretproce-
svrhe. LI meduvremenu prodirala je i u lezik c gde je njeno znaeenje prome- sor, uvek koristite rezervisanu ree const, umesto zamene vrednosti pretproce-
n jenO. Sve ovo moZe izgledati malo zbunjujuie na podetku, ali
u ovom poglavlju sorskom komandom #define.
icte naLre iti kako, kadai z.a5to da koristite rezervisanu rei const' Pomenuiemo i
rczervisanu red volatile koja je srodna rezervisanoj redi const jer se obe odnose
na prome ne i trnajr.r sliintl sintaksu.
Konstante u datotekama zaglavlja
Da biste koristili red const umesto komande #define, neophodno je da definiciju
[)rvr rnotiv z-a uvoclenje konstanti bio je, izgleda, da se izbegne upotreba pret-
konstante smestite u datoteku zaglavlja. Na ovaj nadin, konstanta se definise na
procesorske kornande #define 7,a T.amenv vrednosti. Od tada se konstante jednom mestu, a uvozi se u jedinice za prevodenje ukljudivanjem datoteke
i<oriste za pokazivate, argumente funkciia, tipove rezultata, objekte klasa i
zaglavrla. Za konstante u c++-u se podrazumeva unutrainje poveziuanje (engl.
funkcije dlanice. [J ovim pri-"na-a, konstante imaiu pomalo razlidita, ali kom-
internal linkage),Sto znadi da je konstanta vidljiva samo u okyiru datoteke u
patibiina znadenja, koja iemo razmatrati u posebnom odeljku ovog poglavlja.
kojoj je definisana. uvek morate dodeliti vrednost konstanti koju deflnisete,
osimkada izridito deklari5ete spoljasnju wednost korisienjem rezervisane redi
Zamena vrednosti extern:
Pretprocesor se desto koristi za pravljenje makroa i zamenu wednosti u progla- extern const i nt ve1 i ci na;
minia na jeziku C. Posto pretprocesor zamenjuje tekst i ne moZe da proverava Standardno, C++ prevodilac ne dodeljuje memoriju konstanti, vei umesto
tipove, zamena wednosti u pretprocesoru dovodi do problema koji se mogu toga definiciju duva u tabeli simbola. Kada koristite rezervisanu red extern pri
ii.lbeii u ieziku C++ koriSienjem konstantnih vrednosti' definisanju konstante, primoravate prevodioca da toj konstanti dodeli skladiste
Tipidna primena pretprocesora za zamenu wednosti, na jeziku c, izgleda (isto se desava u joS nekim sludajevima, kao sto je ditanje adrese konstante).
ovako: Skladi5te se mora dodeliti zato sto rezervisana red extern zahteva da se koristi
#def1 ne VTLICINA 100 spoljasnje povezivanje. To znadi da nekoliko jedinica za prevodenje moZe pri-
stupati konstanti, pa konstanta mora fizidki da postoji.
Ime VELICINA postoji samo tokom rada pretprocesora, sto znadi da ono ne
U op5tem sludaju, kada u deflniciji nije upotrebljena rei extern, memorija se
zauzima rnemorijtr i mo7-e biti smesteno u datoteci zaglavlja da bi obezbedilo
je ne dodeljuje. Konstanta se, jednostamo zameni svojom wedno5iu za weme
istr.r vreclnost z.a sve jeclinice prevodenja koje ga koriste. Za odrlavanje koda
prevodenja.
va7.no da se koristi zamena vrednosti, umesto takozvanih ,,magidnih broieva'.
U komplikovanim strukturama desto se ne moZe izbeii dodeljivanje memo-
Ako koristite magidne brojeve u svom kodu, ditalac neie znati odakle vam ti bro-
rije konstantama. Svaki put kada prevodilac mora da dodeli memoriju, spreiava
jer,,i i 5ta predstavljaju, a i ako odludite da promenite neku wednost, moraiete to
se zamena konstanti lrednostima (posto prevodilac ne moZe da bude siguran
rla uradite ruino. Pri tome vam neka vrednost moZe promaii, i1i moZete izmeniti
koja je wednost u skladi5tu - ako bi to znao, ne bi morao da zauzima memoriju).
pogreSnu
' wednost.
Posto prevodilac ne moze uvek da izbegne dodeljivanje skladista konstantama,
VgftCtNe ie se uglavnom ponasati kao obiina promenljiva, ali ne bas uvek.
konstante se moraju povezivati unutraSnje, samo unutar jedinice za prevodenje.
Pored toga, ne postoji nikakva informacija o tipu tog podataka. To moZe izazvati
U suprotnom, komplikovanije konstante bi dovodile do problema u povezivanju,
greike koje se veoma tesko otkrivaju. Rezervisana red const jezika C++ relava
zato Sto se njima dodeljuje memorija u vi5e cpp datoteka. povezivad bi, video istu
problen-r, tako 5to z.amenu wednosti stavlja u domen prevodioca. Sada moZete
definiciju u viSe objektnih datoteka i bunio bi se. posto se za konsrante podra-
reii:
zumeva unutrasnje povezivanje, povezivad ne poku5ava da poveze ove deflnicije
const i nt vel i ci na = 100; u okviru jedinice za prevodenje i ne dolazi do sukoba. prevodilac uvek moZe da
Ime velicina moZete koristiti sr,uda gde prevodilac, tokom prevodenja, mora da zameni konstante ugradenih tipova njihovim wednostima.
z-na vrednost. Prevcldilac moZe koristiti ime velicina za zamenu konstante (engl.
constant folcllng) pri iemu se komplikovan izraz pojednostavljuje izradunavanje
tokorn prevodenja. Ovo je posebno vai,no za definicije nizova:
Bezbednosne konstante
Kori5ienje rezervisane redi const nije ogranideno na zamenu komande #define
char ni z [vef ici na] ; u konstantnim izrazima. Ako inicijalizujete promenljivu wedno5iu koja je
Konsrante mo7-ete praviti od svih ugradenih tipova (znakovnih nizova, celo- stvorena za weme izwsavanja programa, i ako znate da se ta wednost neie
brojnih vrednosti, i brojeva u formatu pokretnog zaleza jednostruke i dvostruke menjati tokom Zivotnog veka promenljive, tada je dobro da promenljir,u
preciznosti), i ocl njihovih varijanti (kao i od objekata klasa, Sto iete videti dalje u
244 Misliti na jeziku C++ Poglavlje 8: Konstante 245

pretvorite u konstantu, da bi vam prevodilac prijavio gre5ku ako pokuSate da je //: COB:Constag.cpp
promenite. F.vo primera: // Konstante i grupe
const int iU = { 1, Z, 3, 4 };
ll: C1B:Safecons.cpp
//t tloat fli [3]l; ff nepravilna definicija
II Kori Scenje konstanti radi bezbednostj
struct S { int i, j; };
#i ncl ude <i ostream> const S sU = { { 1, Z }, { 3, 4 } };
using namespace std;
//l double d[sIt].jl; ,// nepravitna definicija
j = 100; ll Itpiina konstanta int mainO {l ///:-
const int
const int j = i + lO; I I Vrednost se raiuna na osnovu konstantnog izraza u definiciji niza, prevodilac generiSe k6d koji ie pomerati pokazivad steka. U
Ionq address = (long)&;; II Mora da se dodeli skladi5te nevaZeiim deflnicijama koje su prethodno prikazane, prevodilac se buni jer ne
char buf[i + lo]; I I Ovo je joS uvek konstantan izraz moZe da izraduna konstantne wednosti u definiciji niza.

int main0 {
cout << "unesi te znaki pri ti sni te ENTER: "; Razlike u odnosu na jezik C
const char c = cin.get0; // Ne moZe da se promeni Rezervisana red const uvedena je u ranim verzrlama jezika c++, odnosno tokom
const char c2 = c + 'a' ; zawSavanja standardne specifikacije jezika c. odbor koji se bavi standardima
cout << c2; jezikac odludio je da ukljudi tu ree u c, gde je dobila znadenje ,,obidne promen-
il. liive koja se ne moZe promeniti". U jeziku c, konstante imaju globalna imena i
\ lll,- uvek zauzimaju skladi5te u memoriji. Jezik c ne podrZava wednosti koje su kon-
stantne u toku prevodenja. Ako na jeziku C napisete:
Mozete vicleti da je i konstantna wednost tokom prevodenja, a konstanta j ie
izradrrnata na osnow i. Po5to je i konstanta, wednost zaiko)a se izradunava iz const i nt vel i ci na = 100;
konstantnog izraza takode je konstantna vrednost u toku prevodenja. U
i char ni z [ve1 i ci na] ;
sledeiern reilu, od prevodioca se trazi adresa za i, dime se on primorava da toj dobicete greSku, iako ovo izgleda racionaino. posto velicina postoji u memoriji,
konstanti docleli skladiSte. Ovo ne speaava da se j koristi pri odredivanju velidine prevodilac jezika c ne rnoi.e znati tu wednost. Umesto toga na c-u je ispravno;
niza buf, zato 5ro prevodilac zna da ie i konstanta i da je njena wednost ispravna
const i nt ve1 i ci na;
iako joj je negde u programu dodeljeno skladi5te.
t) glavnom programu, identifrkatoru c se dodeljuju razlidite konstantne wed- Sto nije ispramo na c++-u. Prevodilac lezika c ie ovo prihvatiti kao deklaraciju
nosti koje nisu poznate prilikom prevodenja. Ovo znadi da se zahteva skladiste i koja kaze da negde posroji dodeljeno skladiste. ovo ima smisla, posto se u c-u
da prevodilac ne pokuiava da bilo Sta saduva u tabeli simbola (isto kao u jeziku podrazumeva spoljasnje povezivanje konstanti. u c++-u se podrazumeva unu-
C). Vrednost se mora inicijalizovati prilikom definisanja, i kasnije se ne moZe traSnje povezivanje konstanti, pa ako zelite da postignete isto sto se datim iska-
pronteniti. MoZete videti da se konstanta c2 izradunava na osnovu konstante c, zom postiZe u c-u, morate izridito da zadate spoljasnje povezivanje. Koristite
kao icla se oblast vaZenja za konstante utvrduje isto kao i za promenljive, Sto je rezeryisanu red extern:
joi jecina prednost odnosu na koriSienje komande #define. extern const i nt vel i cina;
r-t

tl praksi, ako rnislite da se neka vrcdnost neie menjati, moZete od nje da


/ / Samo dek l araci j a

Ovaj red je dozvoljen i u C-u.


napra,,.ire konstantu. Tako iete je zaStititi od sludajnih izmena, i omoguiiti pre-
u c++-u, rezeMsana red const ne mora da znadi da ie wednost fizidki posto-
VOdiocu da naprar.i efikasniji k6d izbegavajuii dodeljivanje iditanje memorije. jati u memoriji. u c-u, const se uvek odnosi na memorijsku lokaciju. Da li ie
memorija biti rezervisana za konstantu u c++u, zavisi od nadina na koji se ta
Crupe konstanta koristi. Kada se const koristi da ime zameni wednosiu (baS kao Sto
MoTcte napraviti i konstantne grupe wednosti, ali prevodilac najverovatnije biste koristili #define), onda konstanta ne mora da se sme5ta u memoriju. Ako
neic rnoii da cirzi celu grupu r.r tabeli simbola, vei ie joj dodeliti skladiste. U memorija nije zauzeta (Sto zavisi od sloZenosti tipa podataka i moguinosti pre-
ovakvim situacijama, red const znadi ,,deo skladista koji se ne moZe menjati". vodioca), wednosti se mogu umetnuti u k6d, radi veie efikasnosti, ali tek pbsle
Medutim, vrednosti iz- grupe se ne mogu koristiti kao konstante za weme provere tipova, (a ne pre toga, kao u sludaju komande #define). ukoliko u pro-
prevodenia, jer se od prevodioca ne zahteva dazoasadrZaj skladista. Iskazi, koje gramu ditate adresu konstante (dak i posredno, prosledujuii je funkciji po refe-
iete videti u sledeiem primeru nisu ispravni: renci argument), ili ako je defini5ete kao spoljasnju, onda se konstanti dodeljuje
skladi5te u memoriji.
246 Misliti na jeziku C++ Poglavlje 8: Konstante 247

U C++-u, oblast vaZenja konstante koja je van svih funkcija jeste cela dato-
teka (to jest, nevidljiva je van datoteke). To znadi da se podrazumeva unutraSnje
Pokazivadi na konstante
Trik s definicijom pokazivada, kao i s drugim komplikovanim definicijama, jestt
povezivanje. Ovo se znadajno razlikuje od svih drugih identifikatora u C++-u
da podnete da je ditate od identifikatora nadalje. specifikator const se vezu)e zit
(i od konstar.rti u jeziku C!) kOd kojih se podrazumeva spolja5nje povezivan.je.
najbliZi element. Da biste spredili izmenu elementa na koji pokazuje neki poka
Prema tome, ako u dve razlieite datoteke deklariSete konstante koje imaju isto
zivad, napiSite ovakvu definiciju:
imc, i ako ne iitate adrese konstanti, niti ih defini5ete kao spoljaSnje, idealni C++
prevodilac ne(e zauzeti memoriju za te konstante, vei ie ih zameniti u kodu. const int* u;
Po5to ie konstanta vidljiva u oblasti vaLenja datoteke, u C++-u je moZete staviti u Kreiuii od identifikatora, ditamo: ,,u je pokazivad koji pokazuje na wednosr
datoteke zaglavlja, dime neiete izazvati probleme pri povezivanju. tipa const int". ovde nije potrebna inicijalizacija, zato sto vi kaZete da u moZe da
Buduii da se za konstante u C++-u podrazumeva unutra5nje povezivanje, ne pokazuje na bilo Sta (znadi da u nije konstanta), ali ono na 5ta pokazuje ne mozr
moZete definisati konstantu u jednoj datoteci i pristupati joj kao spoljaSnjoj u da se menja.
drugoj datoteci. Da biste na konstantu primenili spolja5nje povezivanje kako Evo, Sta moZe da vas zbuni. Ako pokazivad ne treba da se menja, to jest akc
biste joi pristupili iz druge datoteke, morate je izriiito definisati kao spolja5nju, hoiete daspredite promenu adrese smestene u pokazivadu,r,
ovako: da je dovoljno da pomerite rezervisanu red const iza int, ovako:
-oz.t. pomislit
extern const int x = i; int const* v;
Ako konstanti pridruZite podetnu wednost i deklariSete je kao spoljaSnju, pri- uopste nije Sa5avo pomisliti da se ovo dita: ,,v je konstantan pokazivad r.ri,
moravate prevodioca da je napravi u memoriji (mada prevodilac joS uvek moZe int". Medutim,to se prauilno dita ovako: ,,v je obidan pokazivad na tip int, a wed,
da zameni vrednost u kodu). Zbog inicijalizacije, ovo se smatra definicijom, a ne nost na koju pokazuje je konstantna". Rezervisana red const r" porouo vezala za
deklaracijom. Deklaracija: int, i efekatje isti kao i u prethodnoj definiciji. Zbunjuje dinjenica da su ove dve
-bolje
extern const int x; definicije iste. Da ne biste zbunjivali onog ko dita vas k6d, je da se drzite
prvog nadina.
tu C++-u znadi da definicija postoji drugde (ovo ne mora da vaZi u C-u). Sada
r.idite za5to C++ zahteva da prilikom definisanja konstante dodelite podetnu
wednost: po poietnoj wednosti deklaracija se razlikuje od definicije (u C-u Konstantni pokazivaci
postoje samo definicije, pa inicijalna wednost nije potrebna). U sludaju dekla- Da biste napravili konstantan pokazivad, specifikator const morate smestiti
racije spoljaSnje konstante, prevodilac ne moZe da zameni wednost u kodu, jer desno od operatora *, ovako:
ne zna njenu vrednost.
Upotreba konstanti u C-u nije narodito korisna, i ako unutar konstantnog
int d= 1;
int*constw=&dl
izraza i.elite da koristite imenovanu wednost (koja se mora izradunati tokom
prevodenja), C vas prosto prisiljaua da koristite pretprocesorsku komandu Sada se to dita: ,,w je pokazivad, koji je konstantan, i pokazuje na wednosr
#define. tipa int". Po5to je sada pokazivad konstanta, prevodilac zahtelra da mu se dodeli
podetna vrednost, koja se kasnije ne moZe menjati. ono na sta w pokazuje moZe
da se promeni, ako kaZete:
Po kaz ivac i *w=2i
MoZere napraviti i konstantne pokazivade. Prevodilac ie se i dalje truditi da Takode moZete napraviti konstantan pokazivad na konstantu, koristeii bilo
spreai zauzimanje memorije i da zameni konstantne pokazivade njihovim vred- koji od ova dva nadina:
nostima, ali u ovom sludaju, takva moguinost nije preterano korisna. VaZnije je
to 5to ie vas prevodilac upozoriti ako poku5ate da promenite konstantan poka-
int d = 1;
const int* const x = &d; // (t)
z-ivad, jer to poveiava bezbednost.
int const* const x2 = &d; // (Z)
Kacla koristite rez-ervisanu red const zapokaziva(e, imate dve opcije: const se
mo7.e primeniti na ono na 5ta pokazuje pokazivad, ili na adresu koja je sme5tena Sada se ne mogu promeniti ni pokazivad, ni wednost.
u sarrlom pokaziva-u. I-l oba sludaja, sintaksa ie vas u poietku malo zbuniti, a.li Pristalice drugog nadina istidu da je on konsistentniji, zato sto rezervisana red
iete se vremenolrt naviii. const uvek stoji s desne strane objekta na koji utide. Vi sami odaberite naiin.
249
Misliti na jeziku C++ Poglavlje 8: Konstante
248

koia mo7-e da se prevede:


Literali znakovnih nizova
Sve opisane llrinlcre srnestili smo u datoteku tl literalima znakovnih nizova, konstantnost odredena rezervisanom rediu const

//: C0B:ConstPointers.cPP ne primenjuje se striktno. MoZete reii:


const int* u;
char* cP = "zdravo"I
i nt const* vi
i prevodilac ie to prihvatiti' Formalno, ovo je greska zato.Sto prevodilac pravl
int d = 1;
Iiieral (u ovom sludalu ,,zdravo") kao konstantan niz znakova' a rezultat
niztr
int*constw=&d; Menjanje bik
const int* const x = &d; // (1) znakova pod navodnicima je njegova podetna adresa u memoriji'
predstavlja gresku tokom izwsavanja, mada to nt
int const* const x2 = ed I I (2) kog znaki u nizu trebalo bi'da
int main(\ \\ lll,- sprovode pravilno svi prevodioci'
zna(i da su literali znakorrnih nizova zapravo konstantni znakormi nizovi
jer s'
Prevodilac ie vam dozvoliti da s njima radite kao da nisu konstantni
Formatiranje redu i inicijali- koda napisanog na jeziku C oslanja na tu moguinost' U sva
mnogo postojedeg-mozete
U *o1f.n;lri slvaku definiciiu pokazivaia upis.ujemo u zasebnom operator * piedvideti ponasanje prevodioca kada pokusate d'
je to moguie' Zato kom"sluraju, ne
,uf.*o svaki pokazivae priiltom definisanja' kada promenite'wednost u literhu, ali ietsverovatno na veiini radunara uspeti da i'
moZemo da PiSemo uz tip Podatka:
promenite.
int* u = &i; Ako zelite da ostavite sebi mogucnost da menjate znakorrni niz, stavite 8a
podatka. Takav k6d je razumljiviji' ali naZalost' stvari
se ne
kao claje int- tip niz:
odvrjalubaSoruko.Op..utot*sevezujezaidentifikator'arlezatip'MoZesesta- char cP[] = "zdravo";
da napisete ovo:
,ir, tifo gde izmedu imena tipa i ideniifikatora'Zna(i' moZete
PoStoprevodiocidestonepraverazlikuizmeduovadvapristupa,neieva
int *u = &i, v = 0; podsetiti da koristite drugi naein.
desto zbunjuje
Sto ie napraviti int*u, kao i ranije, i int v, koji nije pokazivad. ovo
pa je bolje piSete programe kao Sto smo mi pisali primere'
ai,oo.., da
Argumenti
-
funkcija i rezultati i rezultat
Upotreba rezeryisane rEdi const za zadavanle tipova argumenata
Dodela i Provera tiPova a to se odnosi i zuntcilajo5jejednomestogdevaskonstantemoguzbuniti.Kadaprosleduje
tl progru*i*a na iez-iku C++ veoma strogo se proveravaju tipovi' objekat po u'rednosti,specififator const nema zoa(aiaza klijenta
(const znaei r

nadodeluvrednostipokazivadima.KonstantnompokazivadumoZetedodeliti seprosledeniurgr*".rtrr"moZemenjatiunutarfunkcije)'Usludajudakoristi
menjati ne5to Sto
udr.r, obiekta koji nile konstantan, jer obeiavate da neiete koristite const za waianje objektne vrednosti, onda rezultat funkcije ne
mo'
dodeliti adresu konstante obidnom pokazi-
moZe da se promeni. ati, ne moZete
da se menja. Ako prosledujeta i waiate adrese, specifi.kator const znadi da :

wednost' ali to spada u IoSe odredi5te adrese neie Promeniti.


".e,'l..timekaZetedamoZetepromenitiobjekatprekopokazivaia.Nararmo
da moT.ete konvertovati tip da bi;te ipak promenili
objekta kao i bez-
tehnike programiranju ,uto sto time narusavate konstantnost
bednost koiu nudi rezervisana red const' Na primer: Prosledivanie po konstantnoj vrednosli prosledujete
: COB Poi nterAssi gnment ' cPP
MoZete zadati da-argumenti funkcije budu konstantni, kada ih I
I I
int d = 1; wednosti, na Primerl
constinte=2; void f1(const jnt i) {
int* u = ed; ll u redu -- d nije konstanta :**; ll Ovo je nepravilno i izazvaee greiku pri prevodenju
ll\ inl* v = &e; // Nepravilno --alie je konstanta
niie preporueliivo
)
int" w = (int")&e; ll Pravilno, ali,Staovoznadi?Viobeiavatedafunkcijafl()neiepromenitiizvornuwednc
int mainO {\ lll,- promenljive.Po5toseargumentprosledujepowednosti,automatskisepra
IakoC++pomaZeuspredavanjugreSaka,onvasneStitiodproblemakoje icopila oiiginalne promenljive, tako da cete odrzati obeianje dato
klijentu.
mehanizme' ne moZe pr
namerno izazivale,ako Zelite da naru5ite bezbednosne Unutaifunkcije, const dobija sledede znatenje: argument se
meniti.Toseodnosinaautorafunkcije,anenaonogkopozivafunkciju.
Poglavlje 8: Konstante 251
250 Misliti na jeziku C++

class X
Da biste izbegti zbunjivanje korisnika, bolje je da argument udinite konstant-
{
pomoiu
'i nt i;
nint unutar fun[cije, umesto u listi argumenata. Ovo moZete da uradite publ i c:
pokaz-ivada, ali dobiiete lepsu sintaksu ako koristile reference (tu temu iemo X(jnt ii = 0);
obraditi tr poglavlju I l). Ukratko, referenca je kao konstantan pokazivad koji se
voj d modi fy 0 ;
arrtontatski clJrefercncira, tako da se on ponasa kao alternatirmo ime objekta'
Da
& u definiciji. Dakle, definicija funk- );
biste napravili referencu, koristite simbol
cije koja neie zbunjivati, izgleda ovako: X::X(int ii) { i = ij; }

void f2(int ic) {


const int& i = 'i c; void X::modifY0 { i++; 1

,*rt I I Ovo je nepravi I no i i zazvace gre5ku pri prevodenju


)
xfso {
return X0;
Ponovo iete dobiti poruku o gresci, aii ovog puta konstantnost lokalnog
objekta nije deo potpisi funkcije; ona je bitna samo za realizaciju funkcije i zato
)

je skrivena od kliienta. const x f60 {


return X0;
Vraianje konstantne vred nosti )

Slidna prairila vai-e i zarezultat funkcije. Ako kaZete da je rezultat konstantan: niie
void f7(X& x) | /I Prosledivanje po referenci koja konstantna
const int g0; x.modi fy 0 ;
jednom
to z.lati cia se originalna promenljiva (iz funkcije) neie promeniti. IoS )

cla ponovinro: z-ata) Sto ie Jpitanju vraianje po vrednosti, originalna promenljiva


se kopira tako da se ne moZe promeniti preko rezultata'
int main0 {
f50 = X(1) i / /'u redu - rezultat nije konstantna
Ovo, na prvi pogled, dini specifikaciju const besmislenom' U ovom primeru
je vraianje konstante po vrednosti odigledno suviino:
f50.modifyOi /l 0K

// Prouzrokuje gre5ke u prevodenju:


// : C0B: Constval . cPP Ilt f7 (t5o);
// Vracan.le konstanti po vrednosti
nena smisla za ugradene tiPove
llt f6o = x(1);
ll //t f6O.modify0;
1lt ft(f6o);
int f30 { return 1; ) I ll/,-
const int f40 { return i;
f5o waia objekat ripa x koji nije konstantan, dok f6o waia konstantan
}

jnt main0 objekat tipa X. Konstantna wednost se moze koristiti kao lwednost. Zato ie
vaZno da ie const koristi kada se objekat waia po rrednosti, a kada Zelite da
{

const jnt i = f30; ll Flno radi


int k = fqO; II Ali, i ovo fino radi! spredite da se on koristi kao lwednost.
Razlog zbog kogaje const suvisan pri vraianju ugradenih tipova po wednosti
I I ll,- je taj Sto prevodilac sam spreeava da se taj rezultat koristi kao lwednost (zato Sto
je
Za ugradene tipove niie bitno cia li vraiate konstantne wednosti, tako da je touveiwednost, a ne promenliiva). O korisienju Iezultata funkcije kao lwed-
bolje da nc zbur.rjujete kliler.rte, vei da izostavite rezervisanu red const. nosti treba razmi5ljati samo kada se radi o objektima.
Vraianje konstantne vrednosti postaje vaZno kada radite sa objektnim tipo- Argument funkcije f/( ) je referenca koja nije konstantna (referenca je jos
vima. Ako funkcija waia konstantan obiekat klase, rezultat funkcije ne moZe biti jedan nadin za rad sa adresama u C++-u, sto je tema poglavlja 1l). Referenca je u
wednost(tojest,njemusenemoZedodelitiwednostnitiseonamoZenadrugi iustini koriSienje pokazivada koji nije konstantan, samo je sintaksa drugaiija.
naein promeniti). Na Primer: Primer se neie prevesti zbog pravljenja priwemenih objekata.
//: C0B: ConstReturnVal ues. cPP
// Vraeanje konstantne vrednosti
I I Rezultat se ne moTe koristiti
kao lvrednost
252 Misliti na jeziku C++ Poglavlje 8: Konstante 253

Da li iete watiti pokazivad ili referencu na konstantu, zavisi od toga Sta Zelite
Privremeni objekti da dozvolite klijentu da s njom radi. Evo jednog primera koji prikazuje
priuremene
Ponekad, tokom izradunavanja iz.raza, prevodilac mora da napravi
obiekti kao i svi drugi: prave se pomoiu koriSienje konstantnih pokazivada kao argumenata funkcije i kao rezultat.
objekte(e,gl. rernporn rv objeits). Ovo su
konstrtrkt,ria, zar.rzinlajrt rnemoriju, i, na kraju' uni5tavaiu se pomoiu destruk- //: COB:ConstPointer.cpp
tora. Ilazlika u tor.ne StO njih nikacla ne viclite - prevodilac odluduje kada se // Konstantan pokazi vai kao argument funkci je/rezul tat
1c
prave i kako ireba da iz.glec1aju. I)ri.u,remeni obiekti imaju jednu vaZnu osobinu:
oni srr atrtontatski konsiantni. akn pokuSate da promenite neki od
priwemenih void t(int*) {)
objekata, skoro sigurnrl iete napraviti gre5ku, zato sto im uglavnom nemate
pristup i ne mo2eie cla ih korisiite direktno. Prevodilac ie vas obavestiti kada
void u(const int* cip) {
napravite takvu gre5ktr, s obzirom na to da je sve priwemene objekte automatski //l'intxcip =*cip;
z; // Nepravilno - menja vrednost
i = // Ispravno - kopira vrednost
proglasio konstantnim.
' ii prethodnom primeru, fu.kcija t5( ) waia objekat tipa x koii nije konstan- /ll int* ip2 = cip; // Nepravilno: nije konstanta
)
tan. Ali. u izraz.tt:
fz(fs0); const char* v0 {

prevodilac mora cia napravi priwemeni objekat u kome ie duvati rezultate // Uraea adresu statidkog znakovnog niza:
return "rezultat funkcije v0";
iunkcije f5( ), da bi rnogao cla je prosledi f,nkciji ff( ). Ovo bi bilo dobro
ako bi se
argumenri fi.rnkcije fZi') prenosio po wednosti; tada bi se priwemeni objekat )

topiruoufT()inebinambilobitnoStasede5avasaoriginalom.Medutim, const int* const w()


prenosi argument po referenci,Sto znadi da u ovom primeru ona
{
firnkciji 17( ) se
static int i;
promeni pri-
dobija adresu privrerr.renog obiekta tipa X' Funkcija f'7( ) moZe da return &i I
urgr..nt nije referenca konstante. Ali, prevodilac
vremeni objekat zaro ito ni.,.,
obiekat neitati dim se zawsi izradunavanj e izraza' Posto je )
zna cla ie piivrer.neni
prevodilai sve privremene obiekte proglasio konstantnim, u ovakvoj situaciji int mainO {
dobiiete porukir tokom prevodenia, tako da neiete napraviti gresku koju biste 'i ntx=0;

kasnijc veolna teSko otkrili. int* iP = 6x'


Pogledaite sledeie ispravne iskaze: const int* ciP = g*'
fs0 = x(1); t(ip); // 0K
f50.modifY0; llt t(c;p); // niie lspravno
su problematidni. Funkcija f5( ) waia
u(ip); / / Ispravno
Iako ie ih prevoclilac prihvatiti, ipak u(cip); // takode u redu
objekat tipa X, a prevodilat mora da napravi priwemeni objekat u kome
ie duvati
privremeni objekat se menja, i dim se izrazizra(una, //t char* cp = v0; // Nije ispravno
reirltat. Dakle, u oba izraza const char* ccp = vO; ll Ispravno
priwemeni objekat se briSe. Promena obiekta postaje beznadajna, tako da ovai l/t int* ip2 = w0; // Niie ispravno
i<6d nalverovainije predstavlja gre5ku, ali prevodilac vam neie
ni5ta prijaviti. U
const int* const ccip = wO; // Ispravno
ovako iednostavnim izrazim,a moZete odmah da uodite problem, ali kada pro- const int* cipz = wO; // Ispravno
pukotine'
gru.n por,u.," sloZeniji, moguie je da se greska prolude kroz ovakve
//! .wO = t; // Nije ispravno
Kasnije u ovom poglavllu, vicleiete kako se iuva konstantnost objekta
klase'
l / //:-
Argument funkcije t( ) je obidan pokazivad, a argument funkcije u( ) je poka-
Prosledivanje i vraianje adresa ziva( na konstantu. Videiete da je pokuSaj da promenite wednost odredi5ta
Ako prosledujerelli vraiate adresu (bilo pokazivad ili referencu), klijent
moZe pokazivada unutar funkcije u( ) nedozvoljen, ali moZete da kopirate wednost u
pomoiu nje da izmeni izvornu vrednost. ovo mozete da spredite ako wednost promenljivu koja nije konstanta. Prevodilac vas takode spredava da napravite
na kojr.r r,rkazuju pokazivad ili relerenca udinite konstantnom. Argument
koji se obidan pokazivad od adrese sme5tene u pokazivadu na konstantu.
po adresi prosieduje funkciji uvek treba da udinite konstantnim, ako
je moguie. Funkcije v( ) i w( ) prikazuju semantiku rezultata. Funkcija v( ) waia pokazivad
Ako to ne uradite, neiete moii da prosleduiete konstantne vrednosti funkciji' tipa char* na konstantan znakor.ni niz koji je napravljen od literala. Ovaj iskaz
waia adresu znakomog literala, nakon Sto ga je prevodilac napravio i smestio u
254 Misliti na jeziku C++ Poglavlje 8: Konstante 255

statickr.r rnemoriju. Kao Sto smo vei pomenuli, takav niz znakova je praktidno priwemenog objekta po referenci, argument funkcije mora biti referenca kon-
konstantan, Sto se na pravi nadin izra'zava kroz tip rezultata funkcije v( ). stante. Evo jednog primera:
Ilezultat funkcije w( ) zahteva da i pokazivad i wednost na koju pokazuje //: COB: ConstTemporary. cpp
budu konstante. Kao funkcija v( ), funkcija w( ) je ispravna zato sto waia adresu // Privremeni objekti su konstante
statiakog elcrnenta. Nikada ne treba da vraiate pokazivade na promenljive lokal-
nog steka, zato Sto ie oni biti nevaZeii nakon izwSenl'a funkcije i oslobadanja class X {);
steka. (Obidno icte vraiati adresu u dinamidkoj memoriji, koja vaZi i nakon
izwienja funkcije.) X f0 { return X0; } // Yrafanje po vrednosti
U glavnom programu funkcije su testirane s razliditim argumentima. Vidite
da funkcija t( ) prihvata kao argument pokazivad na promenljivu. Ako poku5ate void 91(X&) () // Prosledivanje po referenci na promenljivu
da joj prosledite pokazivad na konstantu, dolazi do greSke, jer nije baS sigurno void 92(const X&) O l/ Prosledivanje po referenci konstante
da funkcija t( ) neie menjati prosledeni objekat. Argument funkcije u( ) je poka-
zivad na konstantu tako da ie prihvatiti oba tipa argumenata. Sledi da je funkcija int main0 {
diji argument je pokazivad na konstantu uop5tenija od onih diji argument su // Gre5ka: funkcija f0 pravi konstantan pri vremeni objekat:
pokazivadi na pronrerrljive. //r gt(tO);
Kao Sto smo i odekivali, rezultat funkcje v( ) se moZe dodeliti samo pokazivadu // Ispravno je: parametar 92 je referenca konstante:
na konstantu. MoZda sada oiekujete da prevodilac odbije da dodeli rezultat s2(f0);
funkcije w( ) pokazivadu koji ne pokazuje na konstantu, a prihvati da je dodeli I ///,-
pokazivadu na tip const intxconst. U tom sludaju iete se iznenaditi, jer ie pre- f( ) waia po urednosti objekat klase X Kada rezultat funkcije f( ) odmah pro-
vodilac prihvatiti i pokazivai tipa const int*, koji ne odgovara potpuno tip rezul- sledite drugoj tunkciji, kao Sto je slue aj u pozivima funkcija gl ( ) i g2( ), pravi se
tata. Da ponovimo: zbog kopiranja wednosti (to jest adrese iz pokazivada), konstantan priwemeni objekat. Zbogtoga poziv funkcije gl( ) nije ispravan, jer
autornalski jc garantovano da se originalna promenljiva neie promeniti. Sledi da argument g1( ) nije referenca konstanre, dok je poziv funkcije 92( ) ispravan.
drr,rga oznaka const u izrazu const int*const ima znadenje samo kada rezultat
fr.rnkcije pokuSate da upotrebite kao lwednost, u demu ie vas prevodilac sprediti.
Klase
Prosledivanje standardnih argumenata U ovom odeljku iemo pokazati kako se rezervisana red const koristi uz klase.
MoZda Cete Zeleti da u klasi napravite lokalnu konstantu i koristite je u izrazima
LJ C-u je uobieajeno prosledivanje po wednosti, pa kada Zelite da prosledite
adresu morate da koristite pokazivada.l U C++-u se ne daje prednost ni jednom
koji se izradunavaju za weme prevodenja. Medutim, znadenje rezervisane redi
const je drugadije u klasama, tako da morate razumeti koje su vam moguinosti
od ova dva pristupa. Umesto toga, va5 prvi izbor treba da bude prosledivanje
za pravljenje konstantnih dlanova na raspolaganju.
argumenta po referenci, i to po referenci na konstantu. Za klijenta je sinataksa ista
Takode moZete da napravite ceo objekat konstantnim (videli ste da prevodi-
kao kada se prosleduje wednost, tako da nema zbrke s pokazivadima - klijenti ne
lac uvek pravi konstantne priwemene objekte). Ali mnogo je teze saduvati kon-
moraju ni da razmi5ljaju o pokazivadima. Za autora funkcije, prosledivanje adrese
je efikasnije od prosledivanja celog objekta klase. Po5to prosledujete referencu stantnost objekta. Prevodilac moZe da obezbedi konstantnost ugradenih tipova,
ali ne moZe da nadgleda sve Sto se deSava u klasi. Da bi se garantovala konstant-
na, konstantu funkcija neie promeniti odredi5te adrese, tako da je efekat za kli-
jenta isti kao da se prosleduje po wednosti (samo Sto je ovaj nadin joS eflkasniji). nost objekta klase, uvodi se konstantna funkcija dlanica: samo konstantna
Zbog sintakse relerenci (koja izgleda kao prosledivanje po wednosti) moguie
funkcija dlanica moZe da se pozove za konstantan objekat.
je proslediti priwemeni objekat funkciji koja odekuje referencu na konstantu,
dok to nije moguie s funkci;'om koja odekuje pokazivad - u sludaju pokazivada Konstante u klasama
izridito se uzima adresa. Na ovaj nadin je prosledivanje po referenci stvorilo I(ase su jedno od mesta gde valja koristiti konstante. Tipidan primer je pra-
nov.u situaciju koju nismo imali u C-u: adresa priwemenog objekta, koji je uvek vljenje niza unutar klase, pri demu ne treba da koristite pretprocesorski makro
konstantan, moZe se proslediti funkciji. Da bi se omoguiilo prosledivanje za definisanje dimenzija, vei konstantnu wednost. Velidinu niza treba da sakri-
jete unutar k]ase, tako da za nju moZete da koristite ime size, na primer, i da
L Neki aistunci nrde da se .sue u C-u prosleduje po wednosti, zato Sto se pravi kopija i kada prosledujete
budete sigurni da nece doii do dvosmislenosti s drugim promenljivama. pret-
pokazivai (tako da prosledujetc pokazivai po vrednosti). Koliko god da je ovo objalnlenje precizno, mi- procesor sve identifikatore definisane komandom #define posmatra globalno,
slinr da sanro rrnosi zahrrrrrr od tadke definisanja pa nadalje, tako da sa njima ne biste postigli Zeljeni efekat.
zs4
Misliti na jeziku C++
Poglavlje 8: Konstante
255
t
priwemenog objekta po referenci, argument funkcije mora biti referenca kon-
staticku rnemoriilr. Kao 5to smo vei pomenuli' takav niz znakova je praktidno stante. Evo jednog Primera:
konstalltan.stosenapravinadinizraL^avakroztiprezultatafunkcijev(). //: COB:ConstTemPorarY'cPP
,rt ,.unit'u da i pokazivae i vrednost na koju
pokazuie
Reztrltat hrnkcije I // Privremeni obiekti su konstante
je ispravna zato sto waia adresu
budtr korsta.rc. Ka. rr.,,-rt.,ro "t ), funkci w( )
ja

statiikrlgt.lerllctrta'Nikadanetrcbaclavraiatepokazivadenapromenljivelokal- class X {};


tlrlgsteka,Zat()stoietlrlibitirrevaTeiitlakonizvr5enjafunkcijeioslobadanja
koja vaZi i nakon
steka. (Obicrl,, .cte ,',oJoti ud"'u u clir.ramidkoi mernoriii' X f0 { return X0; I ll Yraeanje po vrednosti
izvrSenja lr.rnkcije.) .. ;^^+;-^h^s razliditim argumentlrn ra. Vidite void g1(X&) {} // Prosledivanje po referenci na promenljivu
tJ glarn.rom programu tunkcije su testirane
na promenlji*:.to poku5ate
da funkciia tO prihvatal<uo u'gt"'"r" vold g2(const X&) {) // Prosledivanje po referenci konstante
pokazivad
dolazi do greske' jer- nije bas sigurno
da joj prosledite pota,iuaJnu'kon"uni''
Argument funkciie'u( ) ie poka-
da iur.rkciia t( ) neie *;;)" i;;;ledeni obiekat da je funkciia
int main0 {
zivac na konstanru t"t" i" cJp.,nvatiti oba
tipa argumenata..sledi // Gre5ka: funkciia f0 pravi konstantan privremeni obiekat:
od onih diji argument su
l /t gt(f O\;
eili urgu*.nt ie pokazivad na konstantu uopStenija
pokaz.ivadi na Promenliive' // Ispravno je: parametar 92 je referenca konstante:
Kaoitosn.roiodekivali,rezurtatfunkcjevosemozedoderitisamopokazivadu s2(f 0);
prevodilac odbije da doderi rezultat I / I l,-
na konsranru. Mozda sada odekujete da
konstantu' a prihvati da je dodeli
funkcije wO pokaziva* t"ii"" p"kazuje na f()waiapourednostiobjekatklaseX.Kadarezu]tatfunkcijef()odmahpro-
iete se iznenaditi, jer ie pre- g2( ), pravi se
ookazivaiu ,.lu ,ip .o.,rt irril"o.,r,. tI tom sludaju sledite drugoj funkciji, kao Sto je sludaj u pozivima funkcija g1( ) i
tipa const int*' koiine odgovara potpuno tip rezul- konstantaripriwemeni objekal. zbogtoga poziv funkcije gr ( ) nije ispravan, jer
ffir.:;,[.,;;,';i;;;;;;d (to jest adrese iz pokazivada)' ispravan'
tata. I)a ponovimo: ,rrog-topi*nla wednosti argument gi t ) .tij" referenca konstante, dok je poziv funkcije 92( )
au originalna promenljiva neie promeniti' Sledi da
automatski ;" goro,',tu,ut'o "
rlrtrgaoz-nakaconsttliT-razuconstint*constimaznadenjesamokadarezultat
f-Lrnkcijepoktlsateouupn.,.ui,.kaolvrednost,udemuievasprevodilacspreiiti. Klase
U ovom odeljku iemo pokazati kako se rezenrisana red const koristi uz klase'
lokalnu konstantu i koristite je u izrazima
Prosledivanje standardnih argu menatapa kada Zelite da prosledite MoZda iete Zeleti da u klasi napravite
izraiunavaju za weme prevodenja. Medutim, znadenje rezervisane redi
Ll C-u ie trobidaieno p,".rcJi"""it pJ wednosti' koji se
adresu morare au r.nrilii" f okazivaca.l u c++-u
se ne daje prednost ni jednom const je drugadije u klasama, tako da morate lazumeti koje su vam moguinosti
prvi izbor treba da budeprosledivanie za pravljenje konstantnih dlanova na raspolaganju'
ocl ova clva pristtrpa. i;;;t;' toga' vas (videli ste da prevodi-
na konstantu' Za klijenta ie sinataksa ista Takode moZete da napravite ceo objekat konstantnim
argumenta pn ,"f"r.n.i,'i tn po "i"'"nti
kaokaclaseprosleduiewetlnost,takodanemazbrkespokazivadima-klijentine Iacuvekpravikonstantnepriwemeneobjekte).Alimnogojeteaesaduvatikon.
morajtrr-ridaraz-nliSljaluopokazivatima.Taautorafunkcije,prosledivanjeadrese ,tu.rt.rori objekta. Prevodiiac moZe da obezbedi konstantnost ugradenih tipova,
je efikasniie oO p.orrJJiuJnlu ttfog objekta klase'
Po5to prosledujete referencu ali ne moZe da nadgleda sve Sto se de5ava u klasi. Da bi se garantovala konstant-
na, konsrantu rr.,r.iiJn"cJ prom;niti'oarediste
adrese, tako da je efekat za kli- nost objekta klase] uvodi se konstantna funkcija dlanica: samo konstantna
(samo je ovaj naiin ioS efikasniii)' funkcijadlanica moZe da se pozove za konstantan objekat'
jenta isti kao da .. p.,i.f po wednosti Sto
"A';" prosledivanje po wednosti) moguie
Zbog sintakse ,.f.r.n.i itola iz-gteaa ta.o
referencu na konstantu'
jc proslediti prl*..n"ni nble(at firnkciii kola odekuje Konstante u klasama
pokazivad.- u sludaju pokazivada
cl,k to r.rije moguie . ir,"L.ii". kola o3ekuje po. referenci stvorilo I(ase su jedno od mesta gde valja koristiti konstante. Tipidan primer
je pra-
ovaj nadin je prosledivanje
izridito se uzima adresa. Na vljenje niza unutar klase, pli demu ne treba da koristite pletprocesorskj makro
objekta, koji |e uvek
nor,tl situacijt.r kojtl nisnlo imali u C-u: adres,apriwemenog prosledivanie ,u aennisunl" dimenzija, vei konstantnu wednost. Velidinu niza treba da sakri-
konstantan, ."2. ,. irrosLeaiti runtcili. Da bi se omoguiilo
jete unutar idase, tako da za nju moZete da koristite ime size, na primer, i da
tudete sigurni da neie doii do dvosmislenosti s drugim promenljivama. Pret-
ffiuC'uprosledujepowednosti,Z.atostoSepravikopijaikadaprosIedujete procesor lve identifikatore definisane komandom #define posmatra giobaino,
i.ril,, god da 1e ovo oblasnjenje precizno' mi- La taete definisanja pa nadalje, tako da sa njima ne biste postigli Zeljeni
efekat'
,rrt.rzir.rc ,r.rt,r rl.r ,rr:.tr.rlrr1l;ili";';","il;".r,ro.,il.
.lttl d.t sartto ttnori zllltttllt
257
256 Misliti na jeziku C++ Poglavlje 8: Konstante

Na prvi pogled, izgled liste inicijalizatora u prethodnom plimelu je zbu-


lvlogli bisre pretpostaviti da je Logidno staviti rezervisantt rei const
unutar
rezultata koji Zelite. U klasi, rezervisana njujuii, zato sto dosad niste vidali da se ugradeni tip iniciializuje kao da ima
klase. Meclutim, to vas neie dovesti do
konstruktor.
rea const se tlelirnidrlo ','raia onom znaienju koje ima u C-u'
Ona zauzima
mentoriju i preclstavlja vrednost koia se jednom iniciializuje unutar svakog
objekta i r.ise se ne moZe prorneniti. Upotreba redi const unutar k-lase znaii: ,,Konstruktori" za ugradene tiPove
,,ovo je konsranra u toku celog zivotnog veka objekta". Razliditi objekti iste klase S razvojem jezika i ulaganjem napora da se tipovi koje je definisao korisnik udine
rnogu inrati razlidite vrednosti z-a tu konstantu' sliinim ugradenim tipovima, ispostavilo se da je u nekim situaciiama korisno da
/-ato,kadatrklasipraviteobidnukonstantu(kojanijeStati.ka),nemoZetejoj ugradeniiipovi izgledaju kao k]ase. U iisti inicijalizatora konstruktora, ugraden
u kon-
dati podetnu weclnost. Naravno da ova wednost mora da se inicijalizuje tip se moZe koristiti kao da ima konstruktor:
strr.lktoru, ali na posebnom mestu. Posto konstanta mora biti inicijalizovana na
//: COB:Bui I tlnTypeConstructors.cpp
mestltgdejenapravljena,unutarglavnogtelakonstruktorakonstantaue6mora #i ncl ude <i ostream>
Ultt iniiilatizovaria. Ako biste moglida odloZite inicijalizaciiu u telu konstruktora, using namespace std;
ne bi spre-
konstania bi jeclno vrerne bila neiniciializovana. Pored toga, nista vas
cilo da promenite weclrrost konstantc na raz-nim mestima u telu konStruktora' class B {
int i;
publ i c:
Konstru ktorska sta i nicijal izatora
Ii
lista inicijalizatora (engl B(int ii);
Poscbna tadka u inicijalizaciji ..-ror. konstruktorska
(ta tema je obra- void print0;
consrnt('tor irtirinlizer llsr)i najpre je koriSiena pri nasledivanju
je prisutna samo );
iiena r.r poglavljtr 14). Konstrlrktorska lista inicijalizatora -koja
iz naziva moZe zakljueiti - zapravo je lista
Lr defrniciji'konsrruktora, kao Sto se
konstruktora i dvotadke, a pre B::B(int ii) : i(ii) {)
nakon liste argumenata
dodela koje se navode
ovo treba da vas void B::print0 { cout .. i << endl; )
otvorcne vitiaaste zagraclc ko;om podinje telo konstruktora.
podseti cla se vreclnost iz- liste inicijalizuje pre izwsavanja tela konstruktora' Na
Pravilna r'rpotreba konstanti int main0 {
,nn] ,-,,,r,,, treba inicijalizovati vrednosti konstanti. B a(1), b(2);
u klasi je prikaz-alltr ovde: f1oat pi (3. 1ai59) ;
//: C0B:Constlnj tial ization.cPP a.print0; b.print0;
/i lnicijalizacija konstanti u klasama cout << pi << endl ;

#include <iostream> j l//,-


usi ng namesPace std; ovo je posebno vazno pri inicijalizaciji konstantnih podataka dlanova, jer se
oni moraju inicijalizovati pre ulaska u telo konstruktora.
c lass l- red i
Imalo je smisla uop5titi ovaj ,,konstruktor" za ugradeni tip podataka (ili,
const j nt si ze; jednostarmo redeno, ovo dodeljivanje). Zbog toga je ispra'u,na definicija float
publ i c:
pi(3.1a159), u prethodnom primeru.
Fred ( i nt sz) ;
Takode je korisno kapsulirati ugradeni tip unutar klase, dime se garantuje ini-
void Print0;
cijalizacijakonstruktorom. Kao primer ie posluZiti klasa Integer:
l;
I I : C)Bt EncaPsul ati ngTYPes. cPP
Fred::Fred(rni sz) : size(sz) i) #i ncl ude <i ostream>
void Fred::print0 { cout << size " endl; i usi ng namespace std;

int main0 { class Integer (

Fred a(1), b(2), c(3); int i;


a.print0, b.Print0, c'Print0; public:
\ I I l,- Integer(int 1i = 0);
void print0;
t.
258 Misliti na jeziku C++ Poglavlje 8: Konstante 259 t
Integer::lnteger(int ii) : i(ii) {} publ i c:
void Integer::print0 { cout.. i..' '; }
Stri ngStack0 ;
void push(const string* s);
jnt main0 i const stri ng* pop 0 ;
Integer 1 [100] ; );
for(int J = 0; : < 100; j++)
j[:].print0; Stringstack: :StringStack0 : index(0) {

I I ll,- memset(stack, 0, size * sizeof(string*));


i
Elementi tipa Integer u glavnom programu se automatski inicijalizuju na
wednoSiu nula. Ova inicijalizacija ne mora da koSta viSe od upotrebe petlje for void Stringstack::push(const string* s) {
ili funkcije memset( ). Mnogi prevodioci lako optimizuju ovakav nadin inicijali- if(index < size)
zacije i dobija se veoma brz rezultat. stackIindex++] = 5;
i
Vrednosti u klasama koje su konstantne u toku const string* Stringstack::pop0 {
prevodenja if(index > 0) {
KoriSienje rezervisane redi const na nadin koji smo prikazali zanimljivo je i const string* rv = stack[--index];
korisno u nekim sluiajevima, ali ne reSava osnovno pitanje:,,Kako unutar klase stackIindex] = 0;
naprar,rti wednosti koje su konstantne tokom prevodenja?" Odgovor na ovo return rv;
pitanje zahteva kori5ienje dodatne rezervisane redi, static, koja neie biti pot- )
puno objaSnjena sve do clesetog poglavlja. Rezervisana red static, u ovoj situ- return 0;
aciji, znadi ,,postoji samo jedna instanca, bez obzira na to koliko objekata klase )

je napravljeno", a to jc upravo ono 5to nam treba: dlan klase koji je konstantan i
koji je isti u svim obiektima te klase. Dakle, statidka konstanta ugradenog tipa string IceCreamU = {

mo7-e se posmatrati kao vrednost koja je konstantna tokom prevodenja. "vani I a",
"1 esni k",
Kada se koriste u klasama, statidke konstante imaju jednu, pomalo neobidnu
badem" ,
osobinu: na mestu definisanja statiike konstante morate inicijalizovati njenu "
" borovni ca " ,
vrednost. Ovo vaZi samo za statidke konstante; koliko god biste Zeleli da upotre-
"mal i na",
bite ovakr,u inicijalizaciju i u drugim situacijama, neiete moii, zato Sto se svi
"I imun",
ostali podaci dlanovi mogu inicijalizovati samo u konstruktoru ili u drugum
"sumsko voce",
funkcijama dlanicama. coko-moko "
"
Evo primera koji prikaz-u;e pravljenje i upotrebu statidke konstante size, unu-
);
tar klasL koja pred.stavlja stek pokazivada na objekte tipa string:2
//: C0B: Stri ngStack. cpp const int iCsz =

I I Kori5cenje statickih konstanti za pravljenje vrednosti u sizeof iceCream / sizeof *iceCream;


// klasama koje su konstantne tokom prevodenja
li ncl ude <stri ng> int main0 {
#i ncl ude <i ostream> StringStack ss;
usi rg naaespace std; for(int j = 0; i < iCsz; i++)
ss. push (&i ceCreamI i ] ) ;
cl ass Strj ngStack ( const strjng* cp;
stati c const i nt si ze = 100; while((cp = ss.pop0) != 0)
const stri ng* stack Is i ze] ; cout << *cp << endl'
i nt i ndex: \ I I l,-
Po5to konstantu size koristimo da bismo odredili velidinu niza stack, onda ie
I Nekr prexrrliocl jos nc podrzavaju ovakvtt moguinost ona zaista konstantna wednost tokom prevodenja, ali je skrivena u klasi.
260 Misliti na jeziku C++ Poglavlje 8: Konstante 26r

Prinretite da je argument lunkcije push( ) pokazivad ripa const string*, funk_


cija popo vraia wednost tipa const string*, a u klasu btringStack se smesta Konstantni objekti i funkcije clanice
rT ednosr ripa const string*. Kada ovo ne bi bilo tako, vi Funkcije dlanice kJasa mogu biti konstantne. Sta to znadi? Da biste ovo razumeli,
ne biJte mogli da kori_
stite klasu StringStack za smestanje pokazivaia u niz icecream. ovo vas takode morate najpre razumeti konstantne objekate.
spreiava cla trradire bilo sta sto bi promenilo objekte sadrZane u steku tipa Konstantni objekti se defini5u isto za ugradene tipove i za korisnidke tipove.
Stringstack. Nararnto, ne prave se svi kontejneri sa ovim ogranieenjem. Na primer:
constinti=1;
,,trik enum" u starom kodu const b1 ob b (2) ;
LI starijim verzijama c++-a statidke konstante nisu bile podrZane u klasama. ovde je b konstantan objekat tipa blob. Njegov konstruktor je pozvan s argu-
ovo znadi da je rezervisana red const bila beskorisna za konstantne izraze u kla- mentom koji ima wednost dva. Da bi prevodilac primenio konstantnost, on
sama. Medutim, tipidno resenje za konstante wednosti, n€Lzvano mora obezbediti da se nijedan dlan objekta ne promeni za weme Zivotnog veka
,,trik enum,
(engl. enum lnck) bilo je korisienje neoznadene nabrojive liste objekta. on lako moZe da obezbedi da se javni dlanovi ne menjaju, ali kako da
bez instanci"
Vrednosti nabrojive liste se moraju utwditi za weme prevodenja; ona je lokalna zna da li ie neka funkcija dlanica promeniti podatak i koje funkcije neie uricati
za klasu i njene wednosti mogu da se koriste u konstantnim izrazima. prema na konstantan objekat.
tome, desto iete vidati: Ako deklari5ete funkciju dlanicu tako da bude konstantna, rekli sre prevodi-
ocu da tu funkciju moze pozvati za konstanran objekat. ukoliko funkciju dlanicu
/I : C}B: EnumHack. cpp
#include <iostream> niste izridito deklarisali konstantom, smatraie se da ona moZe da promeni
usi ng namespace std; podatke dlanove u objektu, i prevodilac neie dozvoliti da je pozovete za kon-
stantne objekte.
c) ass Bunch { Medutim, to nije kraj. Turdenjem da je funkcija dlanica konstantna, ne garan-
enum { size = 1000 }; tujete da ie se ona tako pona5ati, pa ie prevodilac od vas traziti da ponovite spe-
int i [size]; cifikator const kada defini5ete funkciju. (const postaje deo potpisifunkcije, pa i
); prevodilac i povezivad proveravaju konstantnost.) Zatim primenjuju tu konstant-
nost tokom definisanja funkcije tako Sto izdaju poruke o gresci. Ako pokusate da
int main0 { u konstantnoj funkciji promenite bilo kog dlana objekta ili pozovete funkciju koja
cout << "sizeof(Bunch) = ".. sizeof(Bunch) nije konstantna, dolazi do greske prilikom izvodenja. Zbog ovoga ie se svaka
..,, , sizeof(i[1000] ) = ,,
funkcija elanica koju deklari5ete kao konstantnu sigurno tako i ponaiati.
<< si zeof(i nt [1000] ) .< endl ; ukoliko biste ispred deklaracije funkcije stavili specifikator const, to bi znadilo
I l/l:- da je rezultat funkcije konstantna. umesto roga, da bi funkcija bila konstantna,
lJpotreba rezervisane redi enum na ovom mestu garantuje da se za objekat specifikator const treba da stavite izaliste argumenata. Na primer:
neie rezervisati prostor u memoriji i da su konstante wednosii iz liste izradunate
z-a vreme prevodenja. Vrednosti za konstante mozete
//: C08:ConstMember.cpp
izriiito zadati u listi: class X {
enum { one = I, two = 2, three }; int i;
publ i c:
ulistama celobrojnog tipa, prevodilac ie nastaviti da broji od prethodne
wednosti, tako da ie treia konstanta dobiti wednost tri.
X(int ii);
U prikazanom primeru datoteke StringStack.cpp, red:
int f0 const;
1,
static const int size = 100;
bismo zamenili redom: X::X(int i1) : i (ii) t)
int X::f0 const ( return i; )
enum { size = 100 };
Iako iete desto r.idati ovaj trik u starom kodu, treba da znate da je moguinost int main0 (
deklarisanja sratidkih konstanti dodata u c++ bas zbog re5avanja istog pro- x xl (10) ;
blema. Ne postoji neki jadi razrog zbog koga biste se opredelili za itatidke kon- const X x2(20);
stante umesto za trik enum. U ovoj knjizi se koristi trik enurn zato sto ga x1.f0;
podrZava vi5e prevodilaca, u weme dok ovo pi5em. x2.'f O ;
I ///:-
Misliti na jeziku C++ Poglavlje 8: Konstante 263
262

Primetite da se rezervisana red const mora pojaviti i u definiciji, inaie ie pre- const 'int qsize = sizeof quotes/sizeof *quotes;
vodilac smatrati da se radi o nekoj drugoj funkciji. Funkcija f( ) je konstantna int qnum = randQ % qsize;
f1lnkcija ilanica, pa ako pokusa da promeni objekat i na bilo koji nadin, lll da while(lastquote >= 0 && qnum == lastquote)
pozove drugu funkciju dlanicu koja nije konstantna, prevodilac prijavljuje greSku.
qnum=randfl%qsize;
Konstantnu funkciiu dlanicu moZete pozvati i za konstantne i za promenljive
return quotes[lastquote = qnumJ;

ob jekte. Zato konstantne funkcije moZete posmatrati kao najopstiji oblik funkcija
)

dlanica (i zbog toga je Steta Sto se za sve funkcije dlanice automatski ne podra-
int mainO {
zumeva da su konstantne). Sve funkcije koje ne menjaju podatke dlanove trebalo
Quoter q;
bi deklarisati kao konstantne, tako da se mogu pozivati za konstantne objekte. const Quoter cq;
Evo primera u kome su prikazane konstantne i obidne funkciie dlanice: cq.lastQuote0; // U redu
//: C0B:Quoter.cpp //l cq.quote0; // Niie u redu; funkciia nije konstantna
// Sl udajni i zbor ci tata for(inti=0;i<20;i++)
#i ncl ude <i ostream> cout << q.quoteQ << endl;
#i ncl ude <cstdl i b> // Generator s1 ueaj ni h broieva I l/1,-
#include <ctime> /l Za inicijalizovanje generatora sludajnih bro.leva Ni konstruktori ni destruktori ne mogu biti konstantne funkcije zalo sto prak-
us i ng namespace std;
tidno uvek menjaju objekte tokom inicijalizacije i oslobadanja memorije. Funk-
cija quoteo takode ne moze biti konstantna zato Sto menja dlan lastquote
class Quoter
tpogledalte iskaz return). Medutim, funkcija lastQuote( ) ne menja objekat, tako
{
i nt I astquote;
d-a moZe biti konstantna i moZemo je bezbedno pozvati za konstantan objekat cq
publ i c:
Quoter ( ) ;
i nt i astQuote 0 const; Rezervisana rea mutable: memorijska ili logicka konstanta
const char* quote0; i da promenitt
Sta ako Zelite da napravite konstantnu funkciju, ali biste voleli
); neke poda&e u objektut O ovome se ponekad govori kao o razlikama izmedt
memorijske i logiike konstante (koja se naziva i objekat s konstantnim dlano
Quoter::Quoter0 { vima). Svaki bit memorijske konstante je stalan, tako da se slika objekta u memo
lastquote = -1; riji nikada neie promeniti. Logidka konstanta znadi da ;'e ceo objekat logidk
srand(time(0)) ; I lnicijalizovanje generatora sludajnih brojeva
I konstantan, ali da moZe biti nekih promena od dlana do ilana. Ako je prevodioct
I redeno da je objekat konstantan, on Ce se svom snagom truditi da,objektu obe
zbedi konitantnost. Da biste uticali na logidku konstantu, postoje dr"a nadina dr
i nt Quoter: : I astQuote ( ) const i
se promeni podatak dlan unutar konstantne funkciju dlanice.
return I astquote;
Prvi prisiup je veoma star i zove se odbaciuanie konstantnosti. On se izvodi n;
)
prilidno dudin naein. Rezervisanu red this (koja pokazu;'e adresu tekuie:
const char* Quoter::quote0 {
tUl"t tu) konvertujte u pokazivad na objekat tekuieg tipa. Izgledaie kao da i
stati c const char* quotes [] = {
this uei takav pokazivai. Unutar konstantne funkcije dlanice, this je zaprav'
"Da Ii se vec zabavliamo?", konstantan pokazivad pa njegovim konvertovanjem u obidan pokazivad, ukidat
"Doktori uvek sve znaju", konstantnost objekta. Evo primera:
"Da 1i je ... Atomsko?", /l: COB:Castavlay.cPP
"Strah je neprl stojan", //,,0dbacivanje" konstantnosti
"Ne postoji naucni dokaz "
" i podrzava i dej u "
koj class Y {
"da je zjvot ozbiljan", int i;
"stvari koje nas cine srecnim, cine nas pametnijim"' publ i c:
); Y0;
void f0 const;
);
264 Misliti na jeziku C++ Poglavlje 8: Konstante 26s

Y::YO i i = 0; ) Moguinost smeitanja objekta u ROM memoriju


Ako je objekat definisan kao konstantan, on je kandidat za sme5tanje u ROM
void Y::f0 const { (engl. read-only memory)Sto je desto vaZno na ugradenim sistemima. U tom slu-
I ll t**; // - konstantna funkcija clanica
Gre5ka daju nije dovoljno objekat udiniti konstantnim, jer su zahtevi koje treba da zado-
((Y.)thjs)->i++; // Ispravno: odbacivanje konstantnosti volji objekat da bi se smestio u ROM mnogo stroZiji. Nararmo, objekat mora biti
I I Bol I i naci n: kori st1 te zri di tu si ntaksu u C++-u:
j
memorijski konstantan, a ne logidki konstantan. To je lako videti ako je logidka
(const_cast<Y*, ( thi s ) ) -ri **, konstantnost realizovana pomoiu rezerrrisane redi mutable, ali prevodilac neie
)
moii da otkrije odbacivanje konstantnosti unutar konstantne funkcije dlanice.
Da dodamo i ovo:
int main0 {

const Y yy; L lCase ili struktura ne smeju imati konstruktore i destruktore koje su defini-
yy.f0; /l Taista se menja sali korisnici.
\ I I l'- 2. Nijedna osnovna klasa niti objekti dlanovi ne mogu imati konstruktore i
Ovaj naiin radi, i vidaiete ga u starim programima, ali se ne preporuiuje. destruktore (o osnovnim klasama se govori u poglavlju 14).
Problem je Sto se ovaj nedostatak konstantnosti krije u definiciji funkcije, i na Rezultat operacije pisanja po bilo kom delu konstantnog objekta koji se moZe
osnovLr interfejsa klase ne moZete pogoditi da su podaci objekta izmenjeni, osim smestiti u ROM, nedefinisan je. Iako se objekti, koji su napravljeni na pogodan
ako imate pristup izvornom kodu (i morate sami posumnjati da je konstantnost nadin mogu smestiti u ROM, to se ni za jedan objekat nikada ne zahteva.
odbaiena). Da biste sve izneli na otvoreno, u deklaraciji klase treba da koristite
rezervisanu rei mutable kojorn zadajete da se odredeni ilan moZe promeniti
unutar konstantnog objekta: Rezervisana ref volati le
//: COB: Mutabl e. cpp Sintaksa za rezervisanu red volatile je ista kao i za rezervisanu rea const, ali vola-
// Rezervisana red mutable tile znadi: ,,ovaj podatak se moZe promeniti bezznanja prevodioca". Izvr5no okru-
Zenje menja taj podatak verovatno kroz istowemeno izw5avanje vi5e programa
class Z {
(engl. multitasklng), istovremeno izw5avanje viSe niti (engl, multithreadinfi ili
i nt i ; kroz prekide (enfl,. interrupf) ,,rezervisana ree" volatile kaZe prevodiocu da ne
mutable int j; pretpostavlja da je wednost tog podatka stabilna, posebno za vreme optimizacije.
publ i c: Ako prevodilac pomisli:,,Stavio sam ovaj podatak u registar ranije, i vi5e
z0; nisam dirao taj registar", naravno da neie morati ponovo da dita taj podatak. Ali,
void f0 const; ako je podatak deklarisan kao nestabilan (engl. uolatile),prevodilac ne sme da
); pravi ovakve pretpostavke. Neki drugi proces mogao da je promeni podatak, pa
prevodilac mora ponovo da ga prodita. U sludaju da podatak nije deklarisan kao
Z::20 : i(0), j(0) {} nestabilan, ponovno ditanje bi predstavljalo redundantan k6d koji bi prevodilac
odbacio tokom optimizacije.
void Z::f0 const { Nestabilne objekte pravite koristeii istu sintaksu kao i za konstantne objekte.
I I I i++; // GreSka - Konstantna funkcija dl ani ca
MoZete napraviti i konstantan nestabilan objekat. ICijentu on deluje konstan-
j**; I I Ispravno: vrednost je promenljiva
tno, ali neki spoljni proces moZe da ga izmeni. Evo primera koji predstavlja
)
klasu povezanu s komunikacionim uredajem:
int main0 { //: COB:Volatile.cpp
const Z zz, // Rezervisana ree volatile
z.fO; ll Zaista se menja!
I tll:- c'l ass Conm {
const volatile unsigned char byte;
Na ovaj nadin, korisnik iz- deklaracije vidi koji se dlanovi mogu menjati u kon-
stantnoj funkci ji dlanici.
volatile unsigned char flag;
{
enum bufsize = 100 };
unsi gned char bufIbufsi ze] ;
i nt i ndex;
266 Misliti na jeziku C++ Poglavlje 8: Konstante 267

publ I c: Iako moZete ignorisati konstante i nastaviti da koristite stare tehnike pro-
Comm0; gramiranja jezika C, zapamtite da su konstante tu da vam pomognu. Od
voi d isr0 vol ati l e; poglavlja 1l pa nadalje, koristiiemo reference, i tu iete lo5 jasnije videti koliko .1e
char read ( i nt i ndex) const; vaZna upotreba konstanti kao argumenata funkcija.
);

Comm::Comn0: index(0), byte(0), flaq(0) {) VeZbe


Relenia ovih veZbi nalazi se u elektronskom dokumentu The Thinking in C++ Annotated Solution Guidekoji
ll 0vo je samo primer; nece raditi moZete preuzeti sa lokacije wwwBruceEckel.com.

// kao preki dna ruti na: I . Napravite tri konstantne celobrojne wednosti i saberite ih u definiciji niza
void Comm::isr0 volatile { da biste dobili vrednost kojom se utvrduje velidina niza. Poku5ajte da
flag = 6' prevedete takav k6d na C i pogledajte 5ta se de5ava (u opStem sludaju,
bufIi ndex++] = bYte; moZete prisiliti prevodioca za C ++ da radi kao prevodilac za C tako Sto
// Povratak na poaetak bafera iete koristiti indikator s komandnog reda.)
i f(i ndex >= bufsi ze) i ndex = 0;
2. DokaZite da prevodioci za C i C++ zaista razlidito rade s konstantama.
I
Napravite globalnu konstantu i koristite je u globalnom konstantnom
izrazu; zatim prevedite program prevodiocima za C i C++.
char Comm::read(int index) const (
if(index.0 1l index >= bufsize) 3. Napravite primere definicija konstanti za sve ugradene tipove i njihove
return 0; varijante. Sada ih koristite u izrazima s drugim konstantama da biste pra-
return bufIi ndex] ; vili nove definicije konstanti. Uverite se da ie se one uspeSno prevesti.
i 4. Napravite konstantu u datoteci zaglavlja, zatim ukljudite datoteku zagla-
vlja u dve .cpp datoteke, i na kraju prevedite te dve datoteke i poveZite ih.
int main0 { Ne bi trebalo da dobijete greSke. Sada probajte isti eksperiment na C-u.
vol ati I e Comm Port; 5. Napravite konstantu dija se wednost ufvrduje na podetku izwSavanja pro-
Port.isr0; ll 0K
grama, tako sto se prodita kada je program podeo da se izvrsava (moraiete
lll Porl.read(0); // Gre5ka, read0 nije nestabjlna funkcija da koristite standardno zaglavlje <ctime>). Kasnije, pokuSajte da uditatr
I lll,- drugu wednost wemena u konstantu i vidite Sta se de5ava.
Kao Sto ste koristili rezervisanu rea const, i volatile moZete koristiti za elanove 6. Napravite konstantan niz znakova, a onda poku5ajte da promenite neki od
podatke, funkcije dlanice isame objekte. Za nestabilne objekte moZete pozivati tih elemenata.
samo nestabilne funkcije.
7. Deklari5ite spoljaSnju konstantu u jednoj datoteci i u toj datoteci napravite
Funkcija isr( ) ne moZe se koristiti kao stvarna prekidna rutina (engl. lnrer-
funkciju main$, koja Stampa vrednost spoljaSnje konstante. Defini5itr
rupt seruice routine) zato Sto se funkciji dlanici tajno prosleduje adresa tekuieg
spoljaSnju konstantu u drugoj datoteci, a onda prevedite i poveZite te dve
objekta (this), a prekidna rutina, u op5tem sludaju, nema argumente. Da biste
datoteke.
reSili ovaj problem, moZete da napravite statiiku funkciju isrO, Sto je obja-
injeno r.r poglavlju 10. 8. Napi5ite dva pokazivada na konstantnu celobrojnu wednost tipa long
Sintaksa za rezervisanu red volatile je ista kao zarezewisanu red const, tako koristeii dva nadina deklarisanja. Neka jedan od njih pokazuje na niz ele,
da se desto razmatraju zajedno. Kombinacija ove dve rezervisane redi naziva se i manata tipa long. PokaZite da moZete poveiati ili umanjiti wednost poka.
c-u kualifikator. zla(a, ali ne moZete promeniti ono na Sta on pokazuje.
9. Napi5ite konstantan pokazivad na broj tipa double i neka on pokazuje na
niz takvih podataka. PokaZite da moZete promeniti ono na Sta pokazivai
Sa2etak pokazuje, ali ne moZete umanjiti ili poveiati wednost pokazivada.
Rezervisana red const omoguiava da definiSete konstantne objekte, argumente, I 0. Napi5ite konstantan pokazivad na konstantan objekat. PokaZite da moZere
rezultate i funkcije dlanice, i da zaobidete pretprocesorsku zamenu wednosti, a samo da proditate wednost na koju pokazuje pokazivad, ali ne moZete
da ne izgubite prednosti takve zamene. Sve ovo obezbeduje znadajnu dodatnu promeniti pokazivad niti ono na Sta on pokazuje.
proveru tipova, kao i dodatnu bezbednost. Prauilna upotreba konstanti, to jesl
upotreba konstanti sluda gde je to moguie, moZe biti znadajna za va5e projekte.
268 Misliti na jeziku C++ Poglavlje 8: Konstante 269

ll U datoteci PointerAssignment.cpp, uklonite oznaku komentara iz reda s 26. Izmenite datoteku Quoter.cpp tako Sto iete funkciju quote( ) udiniti kon-
greSkom da biste videli koju ie greSku priiaviti va5 prevodilac' stantnom, a lastquote promenljivom.
\2 Napravite literal znakow ogniza s pokazivadem na podetak tog niza. Sada 27. Napravite klasu s nestabilnim dlanom. Napravite i obidne i nestabilne
koiistite pokazivad da menlate dlanove niza. Da Ii vas prevodilac priiavljuje funkcije dlanice koje menjaju nestabilan dlan, i pogledajte kako ie prevo-
da je to gre5ka? Da li treba da prijavi greSke? Ako ne prijavljuje, Sta mislite, dilac reagovati. Napravite obidne i nestabilne objekte klase, a onda pozo-
zbog dega? vite obidne i nestabilne funkcije dlanice da biste videli Sta ie se uspe5no
prevesti i kakve greSke ie vam prijaviti prevodilac u sludaju neuspeha.
13. Napravite funkciju kojoj se argument prenosi po wednosti kao konstanta.
Zaiim poku5ajte da promenite taj argument u telu funkcije' 28. Napravite klasu koja se zove ptica i moZe da leti( ) i klasu kamen koja ne
moZe. Napravite objekat klase kamen, uzmite i dodelite njegovu adresu
14. Napravite funkciiu kola po wednosti prenosi broj tipa float' Unutar
pokazivaiu tipa void*. Zatim dodelite pokazivad tipa void* pokazivadu tipa
funkcije veZite reierencu tipa const float& za taj argument, i nadalie kori-
ptlca* (moraCete da ga konvertujte) i pozovite funkciju leti( ) preko tog
stite samo reference da osigurate da se argument ne menja'
jednu' pokazivada. Da lisada razumete zaSto moguinost dodele wednosti poka-
15. Izmenite datoteku ConstReturnValues.cpp uklanjajuii, jednu po zivada tipa void* (bez konverzije) predstavlja ,,rupu" u jeziku C koja se nije
oznake komenrara u redovima koji uzrokuju greske, da biste videli koje ie
mogla dozvoliti i u C++-u?
greSke prijaviti prevodilac.
16. Izmenite datoteku ConstPointer.cpp uklanjajuii, iednu po jednu' oznake
komenrara u redovima koji uzrokuju greske, da biste videli koje ie greske
prijaviti prevodilac.
I 7. Napravite nor,r.r verziju datoteke ConstPointer.cpp koja ie se zvati Const-
Reierence.cpp i koristite reference umesto pokazivada (moZda iete molati
rla pogleclate poglavlie l l da biste to uradili).
I 8. Izmenitc datoteku ConstTemporary.cpp uklaniajuii, jednu po iednu,
oznake komentara u redovima koji uzrokuju greSke, da biste videli koje Ce
greSke prijaviti prevodilac.
19. Napravite klasu koja sadrZi konstantan i obidan ilan tipa float. Inicijali-
zujte ih koriSienjem liste inicijalizatora konstruktora.
20. Napravite k.lasu koja se zove MyString i sadrZi objekat tipa string, kon-
struktor koji inicijalizuje taj objekat i funkciju print( ). Izmenite datoteku
StringStack.cpp tako da se u kontejner smeStaju objekti klase MyString i
izmenite glavni program tako da ispisuje ove objekte.
21 . Napravite klasu s konstantnim dlanom koji se inicijalizuje u konstruktor-
skoj listi inicijalizatora. Klasa treba da ima i neoznadenu nabrojivu listu
koju koristite za utvrdivanje veliiine niza.
22. U datoteci ConstMember.cpp, uklonite specifikator const iz definicije
funkcije dlanice, ali ga ostavite u deklaraciji, da biste videli kakvu ie greSku
prijaviti prevodilac.
2 3. Napravite klasu s konstantnim i obidnim funkcijama. Napravite konstantne
i obidne objekte ove klase, i poku5ajte da pozovete razlidite tipove funkcija
za razlidite tipove objekata.
24. Napravite klasu s konstantnim i obienim funkcijama. Poku5ajte da pozo-
vete obidnu funkciju iz konstantne funkcije i pogledajte kakvu ie gre5ku
prijaviti prevodilac.
2 5. U datoteci Mutable.cpp uklonite oznaku komentara u redu koji uzrokuje
gre5ku i pogledajte kakvu gre5ku ie prijaviti prevodilac.
Efikasnost je jedna odvaZnihkq,rak(e.dptikp-kojujg C++ nasledio od
jezika C. Da C++ nije tako'delowo,ran, rnndgi programeri ne bi ni
koristili taj jezik.
272 Misliti na jeziku C++ Poglavlje 9: Umetnute funkcije
273

Ierlan od naci.a da se poboljsa efikasnost u c-u jeste upotreba makroa(engl. Postoje dva problema. prvi je sto se izrazi mogu umetnuti u mako,
rnacro), koji vam dozvoljavaju da napravite nesto sto izgleda kao obidan poziv dime se
moZe izmeniti redosled izradunavanja. Na primer:
funkcije, ali bez dodatnih troskova. Mako se realizuje u pretprocesoru, umesto
u prevodiocu. Pretprocesor direktno zamenjuje sve makroe njihovim wedno- #defjne FL00R(x,b) x>=b?O:l
stima, tako da se izbegavaiu stavljanje argumenata na stek, procesorska instruk- Ako sada koristimo izrazekao argumente:
cija GALL, waianje argumenata i procesorska instrukciju RETURN. Sav posao
if(FL00R(a&Ox0,r,0x07)) / / ...
radi pretprocesor, a vi dobijate sve pogodnosti i ditljivost poziva funkcije, i to vas
niSta ne koSta. makro fe biti zamenjen u:
Pri koriSienju prerprocesorskih makroa u c++-u, javljaju se dva problema. i f(a&0x0f>=0x07?0:1)
Prvi problem vai,i i za c: makro izgleda kao poziv funkcije, ali se ne ponasa uvek
Prioritet operatora &je niZi od prioriteta operatora >=, tako da ie vas izradu_
tako. ovo moze da izazove greske koje se kasnije tesko pronalaze. Drugi problem navanje makroa iznenarriti. Kada otkrijete ovaj problem, moZete ga reSiti
postoji samo u c++-u: pretprocesor nema dozvolu da pristupi podacima ilano- tako
Sto iete obuhvatiti zagradama argumente u definiciji makroa. (Ovole
vima klase. To znadi da se pretprocesorski makroi ne mogu koristiti kao funkcije dobra teh_
nika pri pravljenju pretprocesorskih makroa.) prema rome:
dlanice,
U C++-u su rrvedene umetnute funkcije (engl.inline function), s ciljem da se #define FL00R(x,b) ((x)>=(b)?0: 1)
zadrZi efikasnosr pretprocesorskih makroa, ali i da se dodaju osobine pravih otkrivanje problema moZe biti tesko i potrajati sve dok ne shvatite da
funkcija, kao 5to su bezbednost i oblasti vaLenja. u ovom poglavlju iemo razmo- pravilnoponasanje makroa ne treba uzeti zdrivo za gotovo. u verziji prikazanog
triti probleme makroa u c++-u, videiemo kako se oni resavaju pomoiu umet- makroa bez zagrada, uecina izraza ce se izradunatitadno zato sto je prioritet
nutih funkcija, i upoznaiemo se s nadinom rada umetnutih funkcija. operatora >= manji od prioriteta operatora kao sto su +,/,--, i dak od prioriteta
operatora za pomeranje bitova. Lako moZete pomisliti da ovo funklionise
u
svim izrazima, ukljudujuii i one s rogidkim operatorima nad bitovima.
Zamke pretprocesora Predstavljeni problem se moZe resiti paZl;'ivim programiranjem: tako
sto iete
osnovni problem u radu s makroima jeste sto vas mogu zavarati tako da pomi- argumente u makrou staviti u zagrad,e. Druga poteskoia je suptiln ija. za razliku
slite da se pretprocesor ponasa isto kao prevodilac. Naravno, namera je i tita aa od normalnih funkcija, svaki put kada koristite irgument u makrou,
on se izradu-
makro izgleda i da se ponasa kao poziv funkcije, tako da je lako upasti u olu nava. Dok pozivate makro samo sa obidnim promenljivama, ovo izradunavanje je
zamku. Problemi podinju kada se pojave fine razlike izmedu makrba i poziva bezazleno, ali ako izradunavanje argumenta ima sporedne efekte, makro
neie
funkcije. imitirati pona5anje funkcije i rezultat moZe biti iznenadujuii
Razmotrite ovaj jednostavan primer: Na primer, ovaj makro utwduje da Ii se njegov argument narazi
u odredenom
#defi ne F (x) (x + 1) opsegu:

Ako sada F pozovemo ovako: #define BAND(x) (((x),s && (x)<10) ? (x) : 0)
F(1) Dok koristite ,,obidni" argument, makro radi kao prava funkcija. AJi, problemi
podinju dim se opustite i podnete da verujete da oi
pretprocesor ie to, pomalo neodekivano, zameniti sa: iestepruua 2.,t.ip. prema
tome:
(x) (x + 1)(1) : :MacroSi deEffects. cpp
/ f C09
Problem nastaje zbog razmaka izmedu slova F i orvorene zagrad.e,u definiciji #include "../require.h,,
makroa. Kada se razmak r,rkloni, mozete pozuatimakro F sa razmakom: #i ncl ude <fstream>
F (1) using namespace std;

i to ie se ipak pravilno zameniti sa: #define BAND(x) (((x),s && (x)<10) ? (x) : 0)
(1 + 1)
int main0 {
Prikazani primer je prilidno trivijalan, jer se problem odmah uodava. prave
ofstream out (,,macro.out,,) ;
teskoie nastajLl kada u pozivu makroa koristite izrazekao argumente. assure(out,',macro.out,,) ;
for(int i = 4; i < 11; i++) {
int a= i;
-
I

274 Misliti na jeziku C++ I

lggEulj. 9: Umetnute funkcije 275

OUt << "a - ".. a << endl.. ,\t,;


putc( ) u datoteci cstdio, moZe dvaput izradunati drugi argument.
out << "BAND(++6)=" .. BAND(++6) << endl; ovo je speci-
Out << "\t a = " << a << endl; fikacija.standardnog jezika c. Takode, nepaZljiva reai"zaci]a funkcije
toupper( )
kao makroa, moze vise p^uta izradunati argument i tako dovesti
I do neoeekivanog
| /ll,- rezultata pri kori5ienju fu nkcij e toupper(*p++). I
obratite paznju na to da se imena makroa piSu velikim slovima. To je korisno
ier saopstava iitaocu da se radi o makrou, a ne o funkciji, to jest sluZi kao pod- Kontrola pristupa u makroima
setnik u sludaju da ste u nedoumici. Nara'rno, c zahtevapaZljivo programiranje i upotrebu pretprocesorskih
F.vo potpuno neodekivanog rezultata programa:
makroa,
a moglo bi se reii da isto vazi i za c++, da n4e jednog p.obl",,u,
makro nema
a=4 oblast vaZenja koja se zahteva za funkcije dlanice. p."eiprocesor prosto
zame-
BAND (++3 ) =6 njuje tekst, pa ne moZete napisati ovako ne5to:
a=5 class X {
a=5 int i;
BAND (++3) =g publ i c:
a=B #defi ne VAL (X: : i ) // Gre5ka
a=6
BAND (++3) niti bilo Sta slidno. ovde se ne
bi znalo ni koji objekat koristite. Nema nadina da
=9
a=9 u makrou izrazite oblast vazenja klase. Bez iternative pretprocesorskim makro_
ima, programeri bi do5ti u isku5enje da neke podatke dlanoue p.oglase.ia,rnim,
BAND(++3)=19 zarad eflkasnosti. To bi otkrilo internu realizaciju i onemoguiilo prJmene
u n]oj,
a= 10 a poniStilo bi i korisne efekte privatnosti.
a=B
BAND (++3) =6
a= 10 Umetnute funkcije
a=9 Resavanjem problema makroa s pristupom privatnim ilanovima
krase u c++-u,
BAND (++6) =6 eliminisani su sui problemi s preiproceJorskim makroima. ovo je uradeno
tako
a = 11 Sto je koncept makroa_stavljen pod kontrolu prevodioca,
gde itreba da bude.
a=10 Umesto makroa, u jeziku C++ se koriste umitnute
BAND(++6) =g funkciie (engl" inline func-
tions), koje su prave funkcije u svakom smisru. svl sto le"tq?t"
a=12 oa ouie.,.
funkcije, dobiiete i od umetnute. Jedina razlika je u tome sto sok6d
umetnute
Kacla a ima vrednost 4, proverava se samo prvi deo uslova, paseizrazizradu- funkcije umeie na mestu primene, dime se zaobirazt poziv funkcije .
zna(i da
nava sarno jcclnorn, i sporedni elekat poziva makroa je to sto a postaje 5. To biste (skoro) nikada ne treba da koristite makroe, vei
samo umernute funicije.
oiekivali i od poziva normalne fi-rnkcije u ovoj situaciji. Medutim, kada je broj u Svaka funkcija koja je deflnisana u dekraraciji krase, automatski
se umeie, ari
zadatom opsegll, proveravaju se oba uslova, a rezultat je da se wednost argu- mozete napraviti i umetnutu funkciju van klase, tako ste iete ispred
nJ" .,u,ri,i
menta clvaput trveiava za jedinictr. Rezultat se dobija pono'rnim izradunavanjem rezervisanu red inline. Da bi ovo imaro efekta, morate ukljuditiielo
funkcije u
argumenta, Sto dovodi do treieg uveiavanja argumenta. Kada broj izad,e iz deklaraciju, inade bi prevodilac smatrao da se radi o deklaraciji obiine
funkcije"
opsega, jos uvek se proveravaju oba uslova, pa wednost opet biva uveiana dva- Prema tome:
put. Sporedni efekti su razliditi, u zavisnosti od argumenta. inline int plus0ne(int x);
je
- Jasno da ovo nije ponasanje kakvo Zelite od makroa koji izgleda kao poziv
ftrnkciie. lI ovom sltrdaju, odigledno resenje je da se napravi prava funkciji, sto, nema drugog efekta, osim dekrarisanja funkcije (koja kasnije rnoZe,
ali ne mora,
naravno, dodaje k6d i smanjuje efikasnost. dobiti definiciju umetnute funkcije). Ispramadeklaracija i definicija
obuhvata i
Nazalost, problem nije uvek tako odigledan, jer moZete dobiti biblioteku koja
telo funkcije:
sadrzi pomesane funkcije i makroe, a da to i ne znate. u ovakvom slueaju mogu inl ine int plus0ne(int x) { return ++x; }
postojati skrivene greske koje se veoma tesko pronalaze. Na primer, mako

I ove teme je detaljnije obradio Andrew Koenig u svojoj knjizi c rraps & pifak (Addison wesrey, I989)
276 Misliti na jeziku C++ Poglavlje 9: Umetnute funkcije 277

Prevodilac ie (kao i uvek) proveriti pravilnost upotrebe liste argumenata Ovde su dva konstruktora i funkcija print( ) podrazumevano umetnuti. prime-
funkcije i rezultat (i primeniie neophodne konverzije), a pretprocesor za to nije tite da u glamom programu ne vidi da se koriste umetnute funkcije. Logidko
se
sposoban. Takode, ako prethodnu funkciju poku5ate da napi5ete kao pretproce- ponaSanje umetnutih i obidnih funkcija mora biti isto (ako to nije sludaj, u prevo-
sorski makro, dobiiete neZeljene sporedne efekte. diocu postoji gre5ka). Razlikuje se jedino izvr5avanje funkcija.
Skoro uvek iete definicije umetnutih funkcija stavljati u datoteku zaglavlja. Nara'rno, biiete u iskuSenju da koristite umetnute funkcije u deklaracijama
Prevodilac stavlja tip (kombinaciju potpisa funkcije i tipa rezultata) i telo umet- svih klasa, jer s njima ne morate da defini5ete spolja5nje funkcije dlanice. Imajte
nute funkcije u tabelu simbola. Kada koristite tu funkciju, prevodilac proverava u vidu da je cilj umetanja da se prevodiocu omoguii napredna optimizacija. Ali,
da li je poziv ispravan i da li se rezultat pravilno koristi, i onda zamenjuje poziv umetanje velikih funkcija proUzrokuje dupliranje koda svuda gde se te funkcije
funkcije telom funkcije, dime elimini5e dodatne troSkove za njen poziv. Umet- pozivaju, a sav taj kOd umanjuje brzinu koju smo posrigli u izw5avanju (jedini
nuti kdd zauz.ima prostor, ali ako je funkcija mala, ona mole zatzeti manje pro- pouzdan nadin kori5denja umetnutih funkcija je da eksperimentisanjem otkri-
stora nego k6d napravljen za njeno pozivanje (stavljanje adrese funkcije na stek jete njihove efekte umetanja).
i izvr5avanje procesorske instrukcije CALL).
lJmetnuta funkcija u datoteci zaglavlja ima poseban status: u svaku datoteku
gde se f-unkcija koristi morate ukljuditi datoteku zaglavlja koja sadrZi funkciju i Pristupne funkcije
njenu definicijtr, ali prevodilac ne prijavljuje gre5ke zbog ponovljenih deflnicija Iedna od najvaZnijih tema o umetanju koda u klasama jesu pristupne funkcije
(medutim, definicija mora biti ista svuda gde je ukljudena umetnuta funkcija). (engl. access function). Ovo su male funkcije koje vam omoguiavaju da ditate ili
izmenite deo stanja objekta - to jest, unutraSnju promenljilu ili promenljive.
Evo primera u kome moZete videti zaSto je umetanje toliko vaZno za pristupne
Umetnute funkcije u klasama funkcije:
Ispred definicije umetnute funkcije treba upisati rezervisanu red inline. Ovo nije
neophodno u definiciji klase. Svaka funkcija koju definiSete u definiciji klase
//: C09:Access.cpp
automatski postaje umetnuta. Na primer:
// Umetnute pristupne funkcije
ll: C09:lnline.cpp class Access {

// Umetnute funkcije u klasama int i;


#include <iostream> publ i c:
#i ncl ude <stri ng> int readQ const { return i; }
usi ng namespace std; void set(int ii) { i = ji; }
l.
class Point {
int i, j, k; int main0 {
public: Access A;
Point0: i(0), j(0), k(0) {} A. set ( 100) ;
Point(int ii, int jj, int kk) int x = A.read0;
: i(ij), j(jj), k(kk) {} ) /// ,-
void print(const string& msg = "") const { Korisnik klase nikada nema direktan kontakt s promenljivama unutar klase, i
i f(msg. si ze0 ! = 0) cout << msg << endl ; one mogu ostati privatne, pod kontrolom autora klase. Pristup privatnim
COUI << i = . << i .. ,,,
,, ,'
podacima dlanovima moZe se kontrolisati kroz interfejs funkciia dlanica. pored
.."i="..i.."," toga, pristup je izuzetno efikasan. Razmotrimo, na primer, funkciju read( ). Ako
<< "k = " << k << endl;
ne koristimo umetanje, k6d koji se generi5e za poziv funkcije read( ) obidno
I
ukljuduje stavljanje pokazivada this na stek, i procesorsku insrrukciju CALL. Na
); veiini raeunara, ovaj k6d bi bio veii od koda dobijenog umetanjem, a i izw-
Savanje bi sigurno duZe trajalo.
int marn0 {
Pornt p, q(1,2,3); Programer koji poku5a da napravi efikasnu klasu bez umetnutih funkcija bio
p.print("vrednost p") ;
bi u iskuSenju da zaobide pozivanje funkcije tako Sto ie dozvoliti korisniku
q.print("vrednost q") direktan pristup dlanu i, koji ie proglasiti za jami. Ovo je katastrofalno reienje
;
zato Sto i postaje deo javnog interfejsa i autor klase vi5e ne moZe da ga promeni.
I lll,-
278 M is liti na jeziku C++ Poglavlje 9: Umetnute funkcije
271 t-

Sada ste se z.aglavili s dlanom i koji je celobrojnog tipa. Ovo je problem, jer . Umesto toga, imenima metoda se aesto dodaju redi ,,get,, i ,,set,, (na englt
kasnije moZete uvideti da je mnogo korisnije predstaviti informacije stanja kao skom uzmii zadaj), da se ukaZe na ditade i menjade:
bro j u formatu pokretnog zareza, nego kao celobrojnu wednost, aii i je sada deo
//: C09:RectangleZ.cpp
javnog interfejsa i ne moZete ga promeniti. IIi, moZda iete Zeleti da ne5to // eil'aei i menjadi s prefi ksima ,,get,,
dodatno izrae unate pri ditanju ili menjanju dlana i, ali to ne moZete ako je i javni
dlan. Ako se uvek koriste funkcije za ditanje i menjanje stanja objekta, moZete c1 ass Rectang) e {
menjati internu predstar.rr objekta do mile volje. i nt wj dth, hei ght;
Osim toga, kad koristite funkcije elanice za kontrolu podataka dlanova, publ i c:
nioZete funkciji dodati kod koji ie utvrdivati kada se podatak menja, Sto je jako Rectangle(int w = 0, int h = 0)
korisno pri otk-lanjanju gre5aka. Ali ako je podatak dlan javni, moZe ga promeniti : wi dth (w) (h) { } , hei ght
hilo ko i bilo kada, a da vi to ne znate. int geil^tidth0 const { return width; }
void setWidth(jnt w) { width = w; }
\- int getHeight0 const { return hejght;
Lrtacr r menJacr void setHeight(int h) { height = h; )
}

Neki dele pristupne funkcije na iitaie (eogl. accessor),za ltanje informacija l.


stanja iz objekta, i menjaie (eogl. mutator), za promenu stanja objekta. Zbog
prekJapanja funkcija, mogu se koristiti ista imena za ditade i menjade; nadin int main0 {
pozivanja funkcije odreduje da li ditate ili menjate podatke. Evo primera: Rectangle r(19, 47);
I I : C09: Rectangl e. cpp // width & height:
Change
// L1 tacr r menJacr r.setHeight(2 * r.getWidth0) ;
r.setWidth(2 * r.getHeight0) ;
c) ass Rectangl e { I / //:-
int wide, high; Naravno da ditadi i menjadi ne moraju samo ditati ili postavljati
publ i c: wednos
unutrasnjih promenljivih-mogu i izradunavari svojstva. 0 sredeiem
Rectangle(int w = 0, 1nt h = 0) primer
koristimo wemensku funkciju Jtandardne bibrioteke jezika c da
: wide(w), hjgh(h) {} bismo napravi
jednostarmu klasu Time:
int width0 const { return wide; } // Citanje
void width(int w) i wide = w; \ ll f"lenjanje //: C09:Cpptime.h
int height0 const { return high; } // Citanje // Jednostavna vremenska klasa
void height(int h) { high = h; I ll Menjanje #ifndef CPPTiME H

); #define CPpTIME H
#incIude <ctimel
int main0 {
#i ncl ude <cstri ng>
Rectangle r(19, 47);
f I Pronena promenljivih width i height: class Time {
r.height(2 * r"width0) ; std::time_t t;
r.width(2 * r.height0) i std: : tm 1 ocal ;
I lll,- char asci i Rep [26] ;
unsigned char 1flag, aflag;
Konstruktor koristi listu inicijalizatora (tema koja je ukratko izloLena u void updatelocal 0 {
poglavlju B, a koju iemo potpuno upoznati u poglavlju 14) da bi inicijalizovao if(!lflas) {
wednosti promenljivih wide i high (koristeii wstu konstruktora za ugradene Iocal = *std: :localtime(&t) ;
tipove). 'I
f 1 ag++;
Imena funkcija ne mogu biti ista kao imena podataka dlanova, pa iete moZda )
doii u iskuSenje da podatke dlanove oznadite podvlakom ispred imena. Identi- )
fikatori koji zapodinju podvlakom rezervisani su za sistemska imena, tako da ih void updateAscii0 {
ne treba koristiti. if(!af1as) {
updateLocal 0;
28r
Poglavlje 9: Umetnute funkcije

std : : stncpy(asci i Rep,std : : asctime(&l ocal ) ) ; )


afl ag++; int second0 {
i updateLocal 0 ;
) return I ocal . tm-sec i
publ i c:
)
Time0 { mark0; } I,
it
void mark0 { #endif I I CPn:]aE-A I I I :-
1f.)ag = aflag = 6' nadina, kao Sto
std::time(&t); Standardna biblioteka jezika c moZe prikazivati vreme na vise
sevidiuklasiTime.NijeneophodnoaZuriratisvezapise'Takosmo'naprimer'
toririifi t tipa time-t kao osn-ovni prikaz' Za lokalno weme tipa tm i tekstualni
)
const char* asci i 0 da Ii su
znakovnog niza, asciiRep, postoje indikatori koji pokazuju
{
updateAsci i 0 ; fritaz u otiitu
updatetocal(
ii prikazi uskladeni sa osnovnim prikazom' Dve privatne funkc!'e'
)
return asci iRep; wednosti'
i updateAscii( ) proveravaju ove indikatore i uslovno aZuriraju
^Konstruktor
poziva funkciju markO (koju moZe pozvati i-korisnik da bi
)

/l Razlika u sekundama: weme i tek-


int delta(Time* dt) const { prikazao tekuce.vleme), a ona brise indikatore, sto znadi da lokalno
koia u
return int(std: :difftime(t, dt->t)) i"J"i prikaz vi5e ne va2e. Funkcija ascii( ) poziva tunkciju updateAscii( )
; (iz standardne biblioteke
) Iokalnu memoriju kopira rezultai funkcije asctime( )
oblast u koju ce biti upisani
i ntdayl i ghtSavi nSS 0 { i"rit" cl, zato st; tunkcija asctime( ) koriiti statidku
tunkcije ascii( ) je adresa
updateLocal ( ) ; irrJ p"J*i kada se funtcija pozove kasnije. Rezultat
return local.tm isdst; teksta u lokalnoj memoriji
I- Sve funkcije, podev od dayltghtSavingsO, koriste
funkciju updatelocalo'
int dayOfYearO { // dan u godini zbog dega se'dotqalu prilidno ielike i rloz".r" umetnute tunkcije. Pravljenje
updateLocal 0; nije wedno truda' posebno kada imate u
,*Jtrrriit, funkcija u ovom sludaju ovo ne znadi da
retunn local.tm_yday; vidu da te funkcije verovatno nedete disto pozivati' Medutim'
) updatelocal(
* treba praviti umetnute funkcije. Neka makar funkcija dime se zao-)
int day0fWeek0 { /l dan u nedelji "G,"
ort.r" umetnuti, tako da Ce se njen k6d kopirati u druge funkcije'
updateLocal O;
bilazi kdd za poziv te fu nkciie'
return local.tm_wday;
Evo malog Probnog Programa:
)
int since1900O { /l Godine od 1900. //: C09:CPPIime.cPP
updateLocal 0; ll Iestiranje jednostavne vremenske klase
return local.tm_year; #include "CPPIime.h"
i #.include <iostream>
int month0 { // nesec using namesPace std;
updateLocal ( ) ;
return I ocal . tm mon; int main0 {

)- Time start;
int day0fMonth0 {
for(int i = 1; i < 1000; i++) {

updatelocal 0 ; cout << i << ' ';


return Iocal.tm_mday; if(i%10 == 0) cout << endl;
) )
int hour0 { l/ 0d ponoci, 24 dasa Time end;
updateLocal 0; cout << endl I
return local . tm hour. cout << "pocetak = " << start'ascii0;
)- cout << "kra; = " << end'ascii0;
int minute0 ( cout << "razlika = " << end'delta(&start);
updateLocal 0; | /l/:-
return locai.tm min;
282 Misliti na jeziku C++ Poglavlje 9: Umetnute funkc'tje 283 t-

Napravljen je objekat klase Time, zatim je program neko weme proveo u odigledno je da male funkcije dobro rade kao umetnute, ali primetite da
petlji, a or.rda je napravljen drugi objekat klase Time. ove objekte smo koristili da nismo umetnuli dve najveie funkcije, po5to time verovatno ne bismo poboliSali
pokaZemo poietno, krajnje i proteklo vreme. performanse koda:
//: C09:Stasha.cpP {0}
U metn ute fu n kcije u d inam idkom nizu i u steku #include "Stash4.h"
#include <iostream>
NaoruZani umetnutim funkcijama, moZemo klase steka i dinamidkog niza
#i ncl ude <cassert>
uiiniti joS efi kasnijim: using namespace std;
I I :C09: Stash4. h const int increment = 100;
// Umetnute funkc ije
#ifndef STASH4 H int Stash::add(void* element) (

#define STASH4 H if(next >= quanti ty) /l Da 1 i je ostalo dovoljno prostora?


rrnclude "../requrre.h', inflate(increment);
// Kopiranje elemenata u skladi5te,
c'l ass Stash { // podev5i od sledeeeg*praznog prostora:
i nt sj ze; I I ueliei na svakog prostora int startBytes = next size;
int quantity; ll Broj skladi5ta unsigned char* e = (unsigned char*)element;
i nt next; // Si edeei prazan prostor for(int i = 0; i < size; i++)
// Ni z baj tova koj i se di nami dki pravi storage[startBYtes + i] = eIi];
unsigned char* storage; next++;
void jnflate(int increase) ; return(next - t); /l Indeksni broi
publ ic: )
Stash(int sz) : size(sz), quantity(0),
next (0) (0) ( )
, storage void Stash: :inflate(int increase) {
Stash(int sz, jnt initQuantity) : size(sz), assert(increase ,= 0);
quantjty(0), next(0), storage(0) {
if(increase == 0) return;
inf 1a te(init Qu an ti ty); int newQuantily = quantity + increase;
) int newBytes = newQuantitY * size;
Stash::-Stash0 { int oldBytes = quantitY * size;
1f(storage != 0) unsigned char* b = new unsigned char[newBytes];
de1 ete [] storage; for(int i = 0; i < oldBYtes; i++)
) b[i] = storagelil; ll Kopira stari element u novi
i nt add (vo i d* e l ement) ; delete [] (storage); // 0slobada staro skladiSte
voi d* fetch ( i nt i ndex) const i storage = O; ll Pokazuie na novi memoriiski blok
require(0 <= index,,,Stash::fetch (-)index,,); quantity = newQuantity; II Tadajte novu veliiinu
if(index >= next) I l//,-
return 0; ff Za oznacavanje kraja Probni program jo5 jednom proverava da li sve dobro radi:
/ I Pravt pokazi vac na el ement:
return &(storageIindex * size] ); //: C09:Stash4Test.cPP
) //{L} stasha
int count0 const { return next; } #i ncl ude "Stash4. h"
I; #include "../requi re'h"
#endtf ll #include <fstream>
STASH4 H ///:- #i ncl ude <i ostream>
#include <string>
using namespace stdi
285
Misliti na jeziku C++ Poglavlje 9: Umetnute funkciJe
244

void* pop0 {
int main0 (
if(head =- 0) return 0;
Stash intStash(sizeof (int)) ; void* result = head->data;
for(int i = 0; i < 100; i++; Link* oldHead = head;
i ntStash. add (&i ) ;
head = head->next;
for(int i = 0; i < intStash'count0; j++)
delete oldHead;
cout << "intStash'fetch(" " j " ") = " return result;
<< * ( i nt*) i ntStash. fetch (i )
)
<< endl;
);
const int
bufsize = B0;
* bufsize' #endtf ll SIA}Ka-H lll:
100);
Stash stringstash(sizeof(char) je u ranijoj verziii
i fstream in("Stash4Test.cPP") ; Primetite da je uklonjen destruktor klase Link' koji postojao
popO, izraz delete oldHead oslobada
assure(in, "Stash4Test.cPP") ; klase Stack, ali le bio pnarun. U funkciji
tipalink.(ine uni5tava njegovo poljedata)'
string line; memorilu toju ie korisiio objekat
u sludaju klase
whi 1e(get1ine(in, I ine) ) Veiina funkcija se umede sasvim lepo i odigledno' posebno
medutim' ako funkcija sadrZi uslovne
stri ngstash. add ( (char* ) I i ne ' c _str0 ) ; Unt. Caf< i runkiija pop( ) izgleda valjano'
iskaze ili lokalne prom;nlji;e, nije sigurno da ie umetanie biti podjednako
int k = 0; tako da umetanje verovatno
korisno. U ovom sltrdaju, funkcija ie dovoljno mala
char* cP;
whi l e ( (cp = (char*) stri ngStash ' fetch(k++)) !=0) ima smisla.
cout << "stri ngstash. fetch (" .. k .. ") = " Ako su sve funkcije umetnute, kori5Cenje biblioteke
postaje wlo jednosta'"'no
<< cP << endl; zatostonijepotrebnopovezivanje,kaoStomozetevidetiusledeiemprimeru
\ I ll,- (primetite da nema datoteke Stack4'cpp):
pa bi njegov rezultat trebalo
Ovo ie probni program koii smo i ranije koristili' //: C09:Stack4Test'cPP
da bude isti. //(T) StackaTest.cPP
Umetanie se io5 bolie koristi u klasi Stack: #include "Stack4.h"
#include "../requi re.h"
//: C09: Stack4. h #i ncl ude <fstrearn>
// Sa umetnutim funkcijama #include <iostream>
#i fndef STACK4-H
#i ncl ude <stri ng>
#defi ne STACK4-H
us i ng namesPace std;
#include "../require.h"

class Stack int main(int argc, char* argvU) {


{
requireArgs(argc, 1) i ll lne datoteke ie argument
struct Link ( j (argv [1] ) ;
voi d* data;
i fstream n

Li nk* next i
assure(in, argv[1]);
Li nk (voi dr dat L'i nk* nxt) : Stack textl i nes;
' string line;
data(dat), next(nxt) {}
)
* head; // eiianje datoteke i smeStanie redova na stek:
c: while(get1 ine(in, Iine))
Publ i
Stack0 : head(0) i) textl ines.push(new string(l ine) ) ;
-Stack0 ( // Uzimanje redova sa steka i ispisivanje:
require(head == 0, "Stek nije prazan"); string* s;
wnilei(s = (5trins*)textlines.pop0) l= 0) {
cout << *s << endl;
)
voi d Push (voi d* dat) (
head = new Link(dat, head); delete s;
)
)
void" Peek0 const { I I / /,-
return head ? head->data:0;
)
286 Misliti na jeziku C++ Poglavlje 9: Umetnute funkcije 287
i
Nekacla se piSu klase u kojima su sve funkcije umetnute, tako da ie cela klasa Da bi program bio jasniji, u nekim primerima u ovoj knjizi prekoradena je
biti tr claroteci zaglavlla (videiete u ovoj knjizi da sam i ja to uradio). Takve klase razumna velidina umetnutih fu nkcija"
se koriste u toku razvoja programa, mada ponekad umetanje svih funkcija moZe Prevodilac takode ne moZe da umetne funkciju ako se njena adresa dita
produZiti prevodenje. Kada se program malo stabilizuje, verovatno iete hteti da posredno ili izridito. Ako prevodilac mora da prodita adresu, onda ie k6d
se vTatite unaz.ad i zamenite neke umetnute funkcije obidnim funkcijama, tamo funkcije smestiti u memoriju i koristiie dobijenu adresu. Medutim, ramo gde se
gdc jc to pogodno. ne zahteva adresa, prevodilac Ce verovatno ipak umetnuti kOd.
vaZno je da razumete da je rezeMsana red inline samo predlog za prevo-
dioca. Dobar prevodilac ie umetati male i jednostavne funkiije, a ianemariie
Umetnute funkcije i prevodilac previ5e komplikovane. ovo ie vam doneti rezultat semantiku pozivafunkcije i
-
Da biste razumeli kada je umetanie efikasno, poZeljno je da znate Sta prevodilac efikasnost makroa.
racli kada naide na umetnutu funkciiu. Kao u sludaju bilo koje druge funkcije,
prevodilac ie smestiti rlp funkcije (tadnije prototip funkcije koji ukljuduje ime,
tipove argumenata i tip rezultata) u svo;'u tabelu simbola. Kada prevodilac vidi lsturene reference
da su tip umernute funkcije i njeno telo isprami, on unosi i telo funkcije u tabelu Ako zamiSljate kako prevodilac realizuje umeranje, mozete se zbuniti misleii da
simbola. Od prevodioca zavisi da li ie kOd duvati u izvornom obliku, kao preve- postoji vi5e ogranidenja nego sto ih stvarno ima. Na primer, moZe vam izgledati
dene asemblerske instrukcije, ili na neki drugi nadin. da prevodilac neie moii da umetne funkciju pristupa drugoj funkciyi tola
los
Kada pozovete umetnutu funkciju, prevodilac prvo proverava ispravnost nije deklarisana u klasi (bilo da je umernura ili nije):
poziva. To znadi da svi tipovi argumenata moraju odgovarati tipovima navede- //: C09:Evaluation0rder.cpp
nim u listi argumenata funkcije, ili ih prevodilac mora konvertovati u te tipove. // Redosled izvrSavanja umetnutih funkcija
I tip rezultata u odredi5nom izrazu mora biti ispravan (ili se mora konvertovati u
ispravan tip). ovo je, nara'uno, isto sto prevodilac proverava za bilo koju funk- class Forward {
ciju, aii se znadajno razlikuje od onog Sto radi pretprocesor, jer on ne moZe da int i;
proverava i da konvertuje. publ i c:
Ako sve informaciie o tipu funkcije odgovaraju kontekstu poziva, onda se Forward0 : i(0) {}
direktno umeie k6d funkcije za taj poziv, dime se zaobllazi stvarno pozivanje i // Poziv nedeklarisane funkcije:
ontoguiava dalja optimizacija. Ako je umetnuta funkcija ilanica klase, adresa int f0 const { return g0 + 1; }
objekta (vrednost pokazivada this) stavlja se na odgovarajuie mesto, Sto pret-
int g0 const { return i; }
procesor takode ne podrT-ava. );
int main0 {

Ogranicenja Forward frwd;


Postoje dve situacije u kojima prevodilac ne moZe da umetne k6d funkcije. U frwd.f0;
tim sludajevima, prevodilac na osnolu definicije umetnute funkcije pravi ) /l/,-
obidnu funkciju. Ako prevodilac ovo mora da uradi u vi5e jedinica za prevodenje U funkciji f( ) poziva se tunkcija g( ), iako tunkcija c( ) jos uvek ni;'e deklari-
(sto bi standardno prouzrokovalo gre5ku zbog vi5estrukog definisanja), program sana. To je moguie zato Sto se po standardu nijedna umetnuta funkcija u ktasi
z.a povezivanje ie dobiti obave5tenje da ignoriSe ponovljene definicije. ne obraduje sve do zatvorene zagrade kojom se zawsava deklaracija klase.
Prevodilac ne moZe da umetne previse komplikovanu funkciju. ovo zavisi od Nara-rno, ako zatim funkcija g( ) pozove funkciju f( ), dobiiete niz rekurzivnih
konkretnog prevodioca, ali ie veiina odustati ako umetanje ne bi doprinelo poziva koji je suvi5e komplikovan da bi prevodilac mogao da ga realizuje umeta-
efikasnosti. Smatra se da je suvi5e sloZeno umetati sve wste petlji. Kada malo njem (jedna od tih funkcija mora nekada da se zawsi, inade ie rekurzija biti
botje razmislite, raspakivanje umetnute petlie zahteva mnogo vi5e wemena beskonadna).
nego izw5avanje koda z,a poziv funkcije. Ako se funkcija sastoji od skupa jed-
nosta,urrih iskaza, prevodilac verovatno neie imati problema s njenim
unretaniem, ali ako iskaza ima puno, onda je bolje izwSiti dodatni k6d za poziv Skrivene aktivnosti u konstruktoru i destruktoru
hrnkcije nego telo funkcije. Svaki put kada pozovete veliku umetnutu funkciju, umetanje konstruktora i destruktora izgleda efikasnije nego sto zapravo jeste.
celo telo te funkcije se umeie na mestu svakog poziva, tako da program moZete Konstruktor i destruktor mogu imati neke skrivene aktivnosti, zato sto klasa
Iako da zatrpate kodom, a da ne postignete primetno poboljSanje performansi. moZe sadrZati podobjekte koji takode imaju konstruktore i destruktore. ovi
288 Misliti na jeziku C++ Poglavlje 9: Umetnute funkcije 289

podobjekti rnogu biti objektni dlanovi, ili mogu postojati zbog nasledivanja interfejs ostao aist. On takode smatra da je optimizacija posebna tema. Ako Zelite
(tema kojom se bavi poglavlje 14). Evo primera klase s objektnima dlanovima: optimizaciju, koristite rezervisanu red inline. Ako se koristi ovaj pristup, datoteka
//: C09: Hi dden. cpp Rectangle.cpp ie izgledati ovako:
I / Skri vene akti vnosti u umetnutim funkcijama //: C09:Noinsitu.cpp
#i ncl ude <i ostream>
// Uklanjanje in situ funkcija
using namespace stdl
class Rectangle {
c) ass l',1ember { int width, height;
int j, j, k; publ i c:
publ r c: Rectangle(int w = 0, int h = 0);
Member(intx=0): i(x), j(x), k(x) {} int getllidth0 const;
-Member0 { cout .. "-Member" .. endI ; ) void setl,lidth(int w) ;
I; int getHeight0 const;
void setHeight(int h);
cl ass l.ii thMembers { t.
l"lember q, r, s; l/ Imaju konstruktore
i nt i ; inline Rectangle::Rectangle(int w, int h)
publ i c: : width(w), heisht(h) {}
l4ithl,lembers(jnt ii) : i(ti) {\ ll Trivijalno?
-l^li thMembers 0 { i nl i ne i nt Rectangl e: : getl,Ji dth 0 const {
cout << "-Withl"lembers" << endl; return width;
) )
);
'inline vojd Rectangle::setWidth(int w) {
int main0 { width = w;
WithMembers wm(1); )
I lll,-
Konstruktor klase Member se jednosta'"no umeie, posto se ne desava nista inl ine jnt Rectangle::getHeight0 const {

speciialno - nema nasledenih objekata niti objektnih dlanova koji bi prouzroko- return height;
vali dodatne skrivene aktivnosti. Ali, u klasi WithMember, de5ava se viSe aktiv- )

nosti nego Sto se vidi na prvi pogled. Za objektne dlanove q, r i s, automatski se


'inline void Rectangle::setHeight(int h)
pozivaju konstruktori i destruktori, a /l konstruktori i destruktori su takode {

umetnuti, tako da postoji znaaajna razlika u odnosu na normalnu funkciju dla- height = h;
)
nictr. Ne znaii da konstruktor i destruktor nikada ne treba da se umeiu; postoje
slucajevi kada to in'ra smisla. Llmetanje je zgodno kada pravite prvu skicu pro-
grama, i kada Zelite da poboljiate efikasnost.
int main0 {
Rectangle r(19, 47);
//Transponovanje vrednosti width i height:
int iHeight = r.getHeight0;
Jasnije pisanje r. setHei ght (r. getwi dth0 ) ;
tJ knlizi kao Sto ie ova, jednostavnost ijezgrovitost stavljanja umetnutih definicija r.setWidth(iHeight);
u klase je veoma korisna, jer vi5e teksta staje na stranice ili na ekran (na semina- | / / /:-
rima). Dan Saks2 je israkao da, u srvarnim projektima, stavljanje definicija u klase
prar,i bespotrebnu zbrku u interfejsu klase i time oteZava njeno korisienje.
Ako Zelite da sagledate efekte umetnute funkcije u odnosu na obidnu,
dovoljno je da uklonite rezervisanu red inline. (Umetnute funkcije treba da budu
Funkcije ilanice definisane u klasama naziva in situ funkcije (po latinskom izrazu
u datoteci zaglavlja, dok obidne funkcije moraju biti u datotekama izvornog
in situ, Sto znadi na mestu) i smatra da sve definicije treba smestiti van klase da bi
koda.) Da biste stavili funkciju u dokumentaciju, iskopirajte je iz izvorne
datoteke. Kopiranje in siru funkcija u dokumentaciji zahteva viSe rada i podloZno
Irr.lltn,llrill]r,( ., llt,tlr,ltlnltX(irtirltlittct. Plrrlt Il.rll. lg9l
290 Misliti na jeziku C++ Poglavlje 9: Umetnute funkcije 29t

]e greskama. Drugi argument u korist ovog pristupa jeste da uvek moZete imati Pobolj5ano otkrivanje g reiaka
konsistenran stil formatiranja za deflnicije funkcija, 5to nije uvek slueaj sa in situ Dosad smo koristili funkcije iz zaglavlja require.h, bez delinisanja (mada smo
Itrnkcijama. koristili i funkciju assert( ) za otkrivanje programerskih greSaka tamo gde je to bilo
zgodno). Sada je weme da defini5emo ovu datoteku zaglavlja. Ovde je pogodno
koristiti umetnute funkcije, jer one dozvoljavaju da se sve smesti u datoteku zagla-
Jo5 neke osobine pretprocesora vlja, Sto pojednostavljuje upotrebu paketa. Samo ukljudite datoteku zaglavlja i ne
Ranije sam rekao cla .skoro uvek treba da koristite umetnute funkcije umesto morate da brinete o povezivanju datoteka.
makroa. Izuzeci su kada treba cla koristite tri posebne osobine C pretprocesora lzuzeci (engl. exceptlons) omogudavaju efikasniju borbu protiv raznih gre-
(kao i C++ pretprocesora): stavljanje znakovnog niza pod navodnike, spajanje i Saka - posebno od onih posle kojih rad moZe da se nastavi. Medutim, zaglavlje
nadovezivanje znakovnih nizova. Znakormi niz se stavlja pod navodnike, kao Sto require.h se koristi u sludajevima kada se spredava nastavljanje programa, na
je objainjeno ranije u knjizi, operatorom #, 5to omoguiava da identifikator primer kada korisnik ne unese dovoljno argumenata ili kada datoteka ne moZe
pretvorite u znako'"mi niz. Znakovni nizovi se spajaju kada izmedu njih nema da se otvori. Zalo je prihvatljivo Sto ove funkcije pozivaju funkciju exit( ) iz stan-
znakova interpunkcije. Ove dve osobine pretplocesola posebno su korisne pri dardne biblioteke jezika C.
pisanju koda z.a uklanjanie gre5aka. Prema tome: Prikazana datoteka zaglavlja sme5tena je u osnovnom direktorijumu u paketu
#define DEBUG(x) cout << #x " = " << x << endl s primerima, pa joj lako mogu pristupiti programi iz svih poglavija:

ispisuje wecingst bilo kojc promer.rljive. Takode moZete ispisivati iskaze dok se //::require.h
izwSavaju: // Ispitivanje gre5aka u programu
defjne TRACE(s) cerr << #s << endl; s l/ Lokalni "using namespace std" za stare prevodioce
#ifndef REQUIRE H
Iskaz #s stavlja navodnikc oko iskaz-a koji se ispisuje, a drugo s ponavlja iskaz #define REQUIRE-H
tako da se on iz."r5ava. Narav'no, ovako ne5to moZe napraviti problem, posebno #i nc l ude <cstdi o>
u petlji for koja se sastoji od jednog reda: # i ncl ude <cstdl i b>

for(int i = 0; i . 100; i++1 #i ncl ude <fstream>


rnncE(f(i)); #i ncl ude <stri ng>

Po5to u rnakrou TRACE( ) postoje dva iskaza, petlja for koja se sastoji od jed- inline void require(boo1 requirement,
nog reda izvrSava samo jedan od njih. Re5enje je da se u makrou taeka i zarez const std::string& msg = rrRequ-rement failed") (
zamene 7-afe7,om. using namespace std;
if (!requirement) {
fputs (msg. c_str0 , stderr)
Nadovezivanje znakovnih nizova fputs ("\n", stderr) ;
;

Znakovni nizovi se nadovezuju operatrom ##. Ova tehnika omoguiuje da zale- exit(1);
pite jedan identifikator za drugi i tako automatski napravite novi identiflkator.
)
Na primer: )
/lcefine FIELD(d) char* a/l/l strlng; int a/i/l-size
clac,s Record { inline void requireArgs(int argc, int args,
i'. [ll.rp]: const std::string& rnsg =
: l i i,-, :
"Morate uneti %d argumenata") {
"wll'
FI[-D(;-hree): using namespace std;
i:
//... if (argc != args + 1) {
fprintf(stderr, msg.c_str0, args) ;
Svaki poziv makroa FIELD( ) pravi dva identifikatora, jedan za sme5tanje fputs ("\n", stderr) ;
z.nakovnog niza, i drugi za sme5tanje duZine tog niza. Ovo olakSava ditanje koda, exit(1);
a moZe sprediti greSke pri njegovom pisanju i pojednostaviti odrZavanje. )
)
Poglavlje 9: Umetnute funkcije 293
292 Misliti na jeziku C++

Evo jednostavnog programa za testiranie funkcija izzaglavlja require.h:


inline void requireMinArgs(int argc' int minArgs'
const std: : stri ng& msg = / r C09l. ErrTest. cPP
I
"Morate uneti najmanje %d argumenata") { //{T) ErrTest. cPP
using namesPace std; // Testiranje funkcije require.h
if(argc. minArgs +
1) { #include "../require.h"
fprintf (stderr, msg.c-str0, minArgs) ; #i ncl ude <fstream>
fPuts("\n", stderr); using namespace std;
exit(1);
) int main(int argc, char* argv[]) {
'i nt i = 1;
)
requ'ire(i, "vrednost ne sme biti nula");
inl ine vojd assure(std: :i fstream& in, requi reArgs (argc, 1) :
const std: : stri ng& fi I ename = " ') ( requi reMi nArgs (argc, 1) ;
using namesPace std; ifstream in(argv[1] );
if(lin) { assure(in, argvIt]); ll Koristj se ime datoteke
fpri ntf(stderr, "Ne mogu da otvorim datoteku %s\n"
' i fstream nofi 1 e( "nofi le.xxx") ;
filename.c-str0); //l assure(nofile); / I Podrazumevanj argument
exit(l); ofstream out( "tmP.txt") ;

) assure (out) ;
) I lll=
Mogli biste doii u iskusenje da odete jos jedan korak dalje u oNaranju
inline void assure(std: :ofstream& out, datoteka i da dodate makro u require.h:
const std: : stri ng& fi I ename = " ) {
us i ng namesPace std; #define IF0PEN(VAR, NAME) \
if(!out) {
ifstream VAR(NAME); \
fprintf(stderr, "Ne mogu da otvorim datoteku %s\n", assure(VAR, NAME);
fiIename.c_str0); Sto bi se onda moglo ovako koristiti:
exit(1);
IF0PEN(in, argv[1])
)

) ovo, na prvi pogled, moZe biti privlaino zato sto treba manje da kucate.
#endif ll nEQUIRE-H ///:- Ovakav nadin niji ba5 mnogo rizilan, ali ga je ipak bolje zaobi6i. Setite se da
Podrazumevane poruke su razumljive, a mogu se menjati, ako
je neophodno' makro izgleda kao funkcija, ali se drugadije ponasa; on pravi objekat (in) dija se
Primetiiete da smo umesto argumenata tipa char* koristili argumente tipa oblast vaZenja Siri i izvan makroa. Vi moZda razumete, ali za novajlije u pro-
const string&. Moguie je koristiti oba tipa argumenata u ovim funkcijama, Sto
je gramiranju i odrZavanju koda, to ie jos jedna zagonetka. C++ je dovoljno kompli-
korisno (moZaa ieie i sami Zeleti da koristite ovaj nadin programiranja)' lovan i bez dodatnog zbunjivanja, pazato pokusajte da se suzdrZite od upotrebe
U definicijama funkcija requireArgs( ) i requireMinArgs( ), potrebnim argu- makroa kada god moZete.
mentima komandnog reda dodali smo j05 jedan, zato Sto se ime programa plo-
sleduie kao nulti argument. ZaIo ie wednost argc uvek za iedan veia od
pravog
broja argumenata komandnog reda. SaZetak
i.okatnu <ieklaraciju using namespace std koristili smo u svakoj funkciii zato VaZno je da sakrijete internu realizaciju klase da biste kasnije mogli da je prome-
sto neki prevodioci, u weme pisanja ove knjige, nisu ukljudivali funkcije stan- nite. Menjaiete je radi eflkasnosti, ili zato Sto iete bolje razumeti problem koji
dardne blblioteke jezika C u imenski prostor std. To je nepravilno, pa_bi izridito re5avate, ili ie vam postati dostupna neka nova klasa, pa iete hteti nju da koristite.
navodenje prouz.rokovalo greSku pri prevodenju. Lokalna deklaraciia dozvoljava Sve Sto ugroZava privatnost interne realizacije, umanjuje fleksibilnost jezika.Zato
funkciiama iz, zaglavl)a require.tr da rade i sa ispra'rnim i s neispravnim bibli- su umetnute funkcije veoma vaZne, jer one praktidno uklanjaju potrebu za ptel'-
otekama bez. otvarania imenskog prostora std. procesorskim makroima i zaobilaze pratede probleme. Umetnute funkcije dlanice
mogu biti podjednako efikasne kao i pretprocesorski makroi'
294 Misliti na jeziku C+r Poglavlje 9: Umetnute funkcije 29s
r
Nararmo da moZete i preterati s kori5ienjem umetnutih funkcija u definici- I 2. Izmenite datoteku Cpptime.cpp tako da meri weme od trenutka poietka
jama klasa. Programeri ie podleii tom isku5enju, zato sto im je lak5e. Medutim, to izw5avanja programa, do trenutka kada korisnik pritisne taster Enter.
nije tako straSno zato Sto kasnije moZete zameniti umetnute funkcije obidnim 13. Napravite klasu s dve umetnute funkcije, tako da funkcija koja je prva
funkcijama bez promene njihove funkcionalnosti. Va5a ideja vodilja pri razvoju definisana u klasi, poziva drugu funkciju, bez isturene deklaracije. Napisite
prograrna treba da bude: ,,Prvo napraviti k6d tako da radi, a onda ga optimizovati". glar,rri program koji pravi objekat klase i poziva pnu funkciju.
14. Napravite klasu A sa umetnutim podrazumevanim konstruktorom, koji
ispisuje poruku. Sada napravite klasu B diji ie dlan biti objekat klase A.
VeZbe Dodajte klasi B umetnuti konstruktor. Napravite niz objekata klase B
Rescniaovihvezbi nalazeseLr elektronskomdokumentu'l'hethinkinginC++AnnotatedSolutionGuidekoii i pogledajte Sta se deSava.
rnozete preuzoti sa lokaci je mvrv. Brt:cel-lckel.cont.

l. I 5. Napravite veliki broj objekata klase iz prethodne veZbe i upotlebite klasu


Napi5ite program koji koristi makro FO, prikazan na poietku ovog
poglavlja, i pokaZite da se on ne zamenjuje pravilno, kao Sto je opisano u Time da biste izmerili razlike u izwsavanju umetnutog i neumetnutog kon-
tekstu. Popravite makro i pokaZite da radi ispra'rno. struktora. Uradite to isto i sa programom za optimizaciju, ako ga imate.)
16. Napi5ite program koji s komandnog reda dita znakovni niz. Napi5ite petlju
2. Napi5ite program koji koristi makro FLOORO, prikazan na poaetku ovog
poglavlja. PokaZite pod kojim uslovim ovaj makro ne radi dobro" for koja pri svakom prolasku uklanja po jedan znak iz znakovnog niza,
i koristite makro DEBUG( ) iz ovog poglavlja za ispisivanje znakovnog niza
3.Izmenite datoteku MacroSideEffects.cpp tako da makro BANDO radi posle svakog prolaska kroz petlju.
ispravno.
1 7. Ispravite makro TRACE( ) na nadin pokazan u ovom poglavlju i dokaZite da
4. Napravite dve identidne funkcije, flO i 12O.FunkciiuflO treba da bude radi ispravno.
umetnuta, a funkcija 12( ) neka ostane obidna. Sada upotrebite funkciju
I 8. Izmenite makro FIELD( ) tako da sadrZi i indeksni broi. Napravite klasu diji
clock( ), koja se nalazi u zaglavlju <ctime>, da biste obeleZili podetnu i ka-
jnju tadku izvriavanja, a onda uporedite ove dve funkcije da vidite koja je su ilanovi sastavljeni od poziva makroa FIELD( ). Dodajte funkciju dlanicu
brZa. Mo2cla iete morati da ponovite pozive funkcija u vremenskoj petlji
koja ispisuje sadrZaj polja koriSienjem indeksnog broja. Napi5ite glavni
program za testiranje ove klase.
da biste dobili korisno poredenie.
5 . l.ksperimenriSite s velidinom i sloZenoSiu koda unutar funkcija iz velbe 4,
I9. Izmenite makro FIELD( ) tako da automatski generi5e pristupne funkcije
za svako polje (medutim, podaci i dalje treba da budu privatni). Naprauite
da biste poku5ali da pronadete tadku u kojoj je vreme izw5avanja umet-
klasu diji su ilanovi sastavljeni od poziva makroa FIELD( )' Napi5ite glavni
nute i obidne funkcije podjednako. Zatim probajte to isto s razlieitim pre-
program za testiranie ove klase.
vodiocima i obratite paZniu na razlike.
6. PokaZite da se na umetnute lunkcije primenjuje unutraSnje povezivanje. 20. Napi5ite program koji dita dva argumenta s komandnog reda: prvi je celo-
brojni, a drugi je ime datoteke. Koristite funkcije iz zaglavlia require.h da
7. Napravite klasu koja sadrZi niz elemenata tipa char. Umetnite konstruktor
biste proverili broj argumenata, utwdili da je celobrojna vrednost izmedu
koji funkcijom memset( ) iz standardne biblioteke jezika C popunjava niz
5 i 10, i da se datoteka moZe uspe5no oworiti.
prosledenom wednosiu (postavite podrazumevanu wednost argumenta
na ' '). Dodajte i umetnutu funkciju print( ) za ispisivanje svih elemenata
2l . Napi5ite program koji koristi makro IFOPEN( ) za otvaranje datoteke kao
ulaznog toka. Obratite paZnju na pravljenje objekta tipa ifstream i prime-
niza.
tite njegovu oblast vaZenja.
8. Zamenite sve funkcije dlanice u datoteci NestFriend.cpp iz poglavlja B
umetnutim funkcijama. Te funkcije ne treba da budu in situ. Zamenite 22. (lzazovno) saznajte opciju prevodioca za prevodenje na asemblerski k6d.
i funkcije initialize( ) konstruktorima.
Napi5ite datoteku koja sadrZi veoma malu funkciju i glavni program koji
poziva tu funkciju. Proverite program na asemblerski k6d kada je funkcija
9. Upotrebite umetnute funkcije u datoteci StringStack.cpp iz poglavlja 8' umetnuta i kada nije umetnuta, i pokaZite da u verziji s umetnutom funk-
10. Napravite listu koja se zove Hue i sadrZi dlanove red, blue i yellow. Sada cijom nema dodatne instrukcije za poziv funkcije.
napravite klasu koja se zove Color, i sadrZi podatak tipa Hue, i konstruktor
koji inicijalizuje taj podatak svojim argumentom. Napi5ite pristupne
funkcije za ditanje i menjanje podatka tipa Hue. Sve ove funkcije treba da
budu umetnute.
I I . Izmenite ve7-bu 10 dodavanjem menjada i ditada.
. ,/jr.1-r "f

.." 'i:..',.'.''',

/ 1;'..

i.:,i:"-. .,
1....r,
; i. i r 1:r i) .r :-t
::..,:i,
-i!:.'**!'rl! 1'
, t'::l.id.*.1"'l:. :.' -
' .; j:' ,"':,, :' ' "
-. I . ;
-
298 Misliti na jeziku C++ Poglavlje I0: UPravljanje imenima 299

(-++ omogr,riava znadajnu kor.rtrolu pravljenja imena i njihove vidljivosti, kao char oneChar(const char* charArray = 0) {

i smcStaja i povezivanja imerra. static const char* s;


Rez-err,.isana red static je preklopljena u C-u pre nego 5to je termin ,,prekla- i f(charArray) {
panje" dobio to znadenje, a C++ joj je dodao joS jednu namenu. Izgleda da je s = charArray;
osnormi koncept u svim upotrebama ove rezervisane reii: ,,neSto Sto ne menja return *s;
svoj polo7.aj" (kao statidki elektricitet), bilo da se misli na fizidki poloZaj u memo- )
el se
riji, ili na vidljivost u datoteci.
require(s, "vrednost s niie iniciial izovana");
[J ovom poglavlju iete nauaiti kako rezervisana red static odreduje smeStanje
i vidljivost, kao i napredni nadin kontrole pristupa imenima preko imenskog if{*s -- 'tO''
return 0;
prostoro (engl. namespace). Takode iete saznati kako da koristite prevedene
return *s++;
lunkcije koje su na;lisane na C-u.
)

char* a = "abcdefghijklmnopqrstuvwxyz";
Staticki elementi iz jezika C
Rezervisana red static, i u C-u i u C++-u, ima dva osnovna znadenja, koja naZalost int majn0 {
cesto smetaju jedno drugom: // oneChar0; // Funkcija require0 ispisuje greSku

l. Dodeljuje fiksnu adresu: to jest, objekat se pravi u statiikoj oblasti poda- oneChar(a); // Iniciialjzuje s na vrednost a
taka (engl. static data area), umeslo da se pravi na steku svaki put kada se char c;
pozove funkcija. Ovo je koncept statiikog skladiita (engl. static storage). while((c = oneCharO) != 0)
cout << c << endl;
2. Objekat dek-larisan kao static je Iokalni u odredenoj jedinici za prevodenje
(kao ioblasti vaienja klase u C++-u, Sto iete videti kasnije). Ovde rezervi- I I I l,-
sana red static odreduje uidljiuost imena, tako da se ime ne moZe videti statidki objekat char* s zadrLava svoju wednost izmedu poziva funkcije
je
van jedinice za prevodenje ili van klase. Takode, opisuje na(.in poueziuanja oneCharO, zato sto se ne nalazi na delu steka dodeljenog funkciji' nego u
statidkoj obtasti. Kada pozovete funkciju onechar( ) sa argumentom tipa chaf*,
i odreduje koja imena ie videti povezivad.
taj argument se dodeljuje promenljivoj s, i waia se prvi znak niza' Svaki sledeii
ll ovom odeljkr.r iemo opisati znadenje reei static koje je nasledeno iz jezika C. pori*izuntcile oneChar( ) bez argumenta, uzrokovaie koriSienje podrazume-
vane wednoiti nula za niz charArray, sto ukazuje funkciji da jos uvek ditate zna-
Staticke promenljive u funkcijama kove iz prethodno inicijalizovane vrednosti promenljive s. Funkcija ce nastaviti
pre-
Svaki put kada pozovete funkciju, prevodilac pravi lokalne promenljive na steku. da waii znakove sve dok ne stigne do oznake za6aj znakovnog niza. Tada
staje da uvecava wednosti pokazivada da ne bi presla preko kraja reda.
Ako postoji poaetna wednost promenljive, ona se dodeljuje pri svakom prolasku
kroz- taj deo programa. Stu e" se desiti ako poiovete oneChar( ) bez argumenata i bez -prethodne
Nekada treba saduvati wednost promenljive izmedu dva poziva funkcije. To inicijalizacije promenljive s? u definiciji promenljive s mogli ste da dodelite
moZete postiii ako promenljivu proglasite za globalnu, ali tada ona neie biti inicijalnu wednost:
samo pod kontrolom iunkcije u kojoj je definisana. C i C++ vam dozvoljavaju da staticchar*s=0;
napravite statidki podatak unutar funkcije; taj podatak se ne pravi na steku, vei ali, ako statidkoj promenljivoj ugradenog tipa ne dodeiite inicijalnu wednost,
u statidkoj rnemoriji tog programa. Statidki podatak se inicijalizuje samo jed- prevodilac ie je na poeeitu p.ogra-a sigurno inicijalizovati wedno5iu nula
nom, i to kada se funkcija pozove prvi put, a zatim zadrLava tu wednost izmedu (konvertovanuu odgovarajueitip podatka). Zato Ce promenljiva s, kada se prvi
poziva funkcije. Na primer, prikazana funkcija waia redom znakove iz niza'.
put pozove funkcija-oneChar( ), imati wednost nula. U ovom slueaju, naredba
II : Cl}:Stati cVari ableslnfunctions. cpp
' prepoznaje tu situaciju.
if(!s)
#include "../require.h" p.itarana inicilaZacili promenljive s je jednostavna, ali podetna wednost
#include <iostream> statidkih objekata (kao i ivih drugih objekata) moze biti i rezultat proizvoljnog
using namespace std; izraza skonstantama i prethodno deklarisanim promenljivama i funkcijama'
zapamtite da je funkcija onechar( ) veoma podlozna problemima koji nastaju
u visenitnom izvrsavanju; setite se toga uvek kada pravite funkcije sa statidkir.n
promenljivama.
300 Misliti na jeziku C++ Poglavlje l0: Upravljanje imenima 30I

inicijalizacije objekata za koje su pozivani konstruktori. Za globalne objekte se


Staticki objekti klasa unutar funkcija uvek poziva konstruktor pre ulaska u glavni program, i oni se uniStavaju kada se
Ista pravila ,ii" rustatidke objekte k1asa, ukljudujuii dinjenicu da treba inicija-
izlazi iz glavnog programa. Ako funkcija koja sadrZi statidki objekat nije nijed-
Iizovati te objekte. Dodeljivanje wednosti nula ima smisla samo za ugradene
nom pozvana, konstruktor za taj objekat se nije izw5io, tako da se neie izw5iti ni
tipove, a tipovi ko;e je dehnisio korisnik inicijalizuju se pczivanjem konstruk-
destruktor. Na primer:
tora. prema tome, ako ne zadate argumente konstruktora kada definisete
sta-
imati podrazumevani konstruktor' Na primer: //: C10:Stati cDestructors. cpp
ti-ki objekat, onda klasa rnora
//: C10:Static0biectslnFunctions'cpp // Destruktori za statidke objekte
#i ncl ude <fstream>
#i nc'l ude <i ostream>
using namespace std;
us i ng namesPace std;
ofstream out("statdest.out"); // Datoteka za praeenje
class X (
class Obj
int i; char
{
c; ll ldentifikator
publ i c:
publ i c:
X(int ii = 0) i(ii) () // Podrazumevana vrednost
Obj(char cc) : c(cc) {
-X0 { cout << "X: :-X0 " << endl ; )
out << "0bj::0bj0 za " << c << endl;
); )

void f0 (
-obi 0 {

statjc x x1(47);
out << "0bj::-0bj0 za " << c << endl;

static X x2; I I Poztva se podrazumevani konstruktor )


);
)

Obj a('a'); // Globalno (statiiko skladiite)


int main0
f0;
i
// Konstruktor i destruktor se uvek pozivaju
I I I l:- void f0 {
ZainicijalizaciiustatiakogobjektatipaX,unutarfunkcijefO'moZesekori- static Obj b('b');
stiti konstruktor s argumentima ili podrazumevani konstruktor. Vrednost se
)
inicijalizuje samo kada se prvi put prolazi kroz definiciju'
void s0 {
stati c Obj c ('c')
Destruktori statiikih objekata ;

Destruktori stariakih objekata ito jest svih objekata u statidkom skladistu, a ne


)

pri izlasku
samo lokalnih statidkih otrl"tutu kao u gornjem primeru) pozivaju se 'i nt main0
i, glu*og programa, ili kada se izriiiio pozove funkcija exit( ) iz standardne {

poziva out << "unutar main0' << endl;


bib"lioteke iezik; C. U veiini realizacija, kada se glami program izw5i,.on t0; ll Poziva statidki konstruktor za b
funkciju exit( ). To znadi da je pozivanje funkcije exit( ) unutar destruktora opa-
objekata se // funkcija g0 nlje pozvana
sno, lei moZe dovesti do beikonadne rekurzije. Destruktori statidkih out << "izlazim iz main0" << endl;
nepozivajuakoizprogramaizadetepozivanjemfunkcijeabort()izstandardne l //1,-
biblioteke iezika C.
U klasi Obj dlan c tipa char se pona5a kao identifikator, tako da konstruktor i
Pomoiufunkcijeatexit()izstandardnebibliotekejezikaC,moZetezadati
akcije koje treba da se izwSe pri izlasku iz glal'nog programa. u tom sludaju,
destruktor mogu da ispi5u informacije o objektu na kome rade. Objekat a je glo-
balni, pa se njegov konstruktor poziva pre ulaska u glavni program, ali konstruk-
fun[cije [o1e su navedene u atexit( ) mogu biti pozvane pre destruktora statidkih
tor statidkog objekta b u funkciji fO i statidkog objekta c u funkciji gO izw5aval'u
objekata, odnosno, pre pozivanja funkcije exit( )'
se samo ako se pozivaju ove funkcije.
Kao i u sludaju obienih objekata, statidki objekti unistavaju se obrnutim redo-
sledom u odno-su na inicijalizaciju. Samo objekti koji su prethodno inicijalizo-
vani konstruktorom mogu da se uniste. Na sreiu, prevodilac pamti redosled
-
302 Misliti na jeziku C+r Poglavlje l0: Upravljanje imenima 303

Pozvali smo samo funkciju f( ) da bismo videli koji ie konstruktori i destruk- se podrazumeva spoljno povezivanje.) Primetite da se nadin povezivanja odnosi
tori biti pozvani. Evo rezultata programa: samo na elemente koji imaju adrese u weme povezivanja, odnosno uditavanja:
Obj : :0b: 0 za a
prema tome, povezivad ne razmatra deklaracije ni lokalne promenljive'
unutar mai n 0
0b; : :Obj 0 za b Zbrka s rezervisanom redi static
izlazim iz main0 Evo primera kako se dva znadenja rezervisane redi static mogu medusobno pre-
0b3::-0b: 0 za U
ptitatl. Svl globalni objekti se sme5taju u statidku oblast, pa ako (u oblasti vaLenia
0b.1 ::-0b;0 za a
datoteke) napi5ete:
Konstruktor objekta a je pokrenut pre ulaska u glarmi program, a konstruktor inta=0;
objekta b je izwSen samo zato Sto je pozvana funkcija fO. Kada smo iza5li iz
glavrrog programa, pokrenuti su destruktori napravljenih objekata, ali obrnutim onda ie podatak a biti smeSten u statidkoj oblasti programa, a njegova wednost
redosledom u odnosu na pozivanje konstruktora. To znadi da redosled kojim se biie inicijalizovana jednom, pre ulaska u glar,ni program. Pored toga, vidljivost
pozivaju destruktori objekata b i c zavisi od toga da li smo prvo pozvali funkciju objekta aje globalna u svim jedinicama za prevodenje. U smislu vidljivosti, sta-
f( ) ili funkciju g( ). tidtoj promenljivoj (koja je vidljiva samo u svojoj jedinici za prevodenje) je
Primetite da je objekat out tipa ofstream takode sratiaki - posto je definisan suprotna spoljasnja promenljiva, tije ime je vidljivo u svim jedinicama za prevo-
van svih funkcija, orr je sme5ten u statieko, oblasti.VaZno je da se njegova defini- denje. Tako je prethodno prikazana definicija isto Sto:
cija (po5to se ne radi o spoljnom objektu) pojavi na poeetku datoteke, dakle pre externinta=0;
njegove moguie upotrebe. U suprotnom, koristili biste objekat pre nego Sto je Ali, ako umesto toga kaZete:
on pravilno inicijalizovan.
U C++-u, konstruktor globalnog statidkog objekta se poziva pre ulaska u glavni staticinta=0;
program, pa omogr-riava jednosta'"no i prenosivo izwSavanje koda pre ulaska u samo ste promenili vidljivost, tako da se na a primenjuje unutrasnje povezi-
glarni program. Sliino tome, destruktor statidkih objekata omoguiava pisanje vanje. ICasa za smeltanje je nepromenjena - podatak se nalazi u statidkoj oblasti
koda koji se izvrSava nakon izlaska iz glar,.nog programa. U C-u ste za takve tri- podataka bez obzira na to da li je promenljiva statidka ili spolja5nja.
kove rrvek nrorali da eksperimentiSete i sami tragate po asemblerskom kodu. Kada se odnosi na lokalne promenljive, rezervisana red static ne menia vidlji-
vost vei klasu za smestanje.
Ako promenljivu koja vam izgleda kao lokalna deklarisete kao spoljasnju, to
U pravljanje povez ivanj em znadi da skladiste postoji na nekom drugom mestu (pa je promenljiva praktidno
[.lop5teno, svako ime u oblasti uaienja datoteke (to jest, koje nije ugneZdeno u globalna za tu funkciju). Na primer:
klasu ili funkciju) vidljivo je u svim jedinicama za prevodenje tog programa. Ovo
se desto naziva spoljno poueziuanje zato Sto je to ime vidljivo programu za pove- I /:
Cl}z Local Extern.cPP
zivanle i van svoje jedinice za prevodenje. Spoljno povezivanje se primenjuje na //{ L}Local Extern2
#include <iostream>
globalne promenljive i obidne funkcije.
Oblast vaZenja nekih imena rreba ograniditi na datoteku. Takvu promenljivu
int main0 {
mogu da koriste sve funkcije iz datoteke, ali ne i funkcije van te datoteke. oblast
extern int i;
vazenja imena se ogranidava i da bi se izbegle dvosmislenosti sa identifikato- std: : cout << i ;
rima iz drugih datoteka.
Ako su objekat ili ime funkcije izridito deklarisani kao statidki u oblasti
I l//:-
/ I : ClltLocalExtern2'cPP
vaircnla datoteke, onda su oni lokalni u svojoj jedinici za prevodenje (u ovoj {0}
knjizi misli se na cpp datoteke). Na ta imena se primenjuj e unutrainje pouezi- 'int i = 5;
uanje, lto znadi da ih moZete koristiti u razliditim jedinicama za prevodenje, a da
pri tome ne nastane dvosmislenost.
Kada se radi o imenima funkcija (za funkcije koje nisu dlanice klasa), rezervi-
Prednost unutrasnjeg povezivanja je to Sto ime mozete smestiti u datoteku
sane redi static i extern mogu samo da promene vidljivost, ako napisete:
zaglavlja, a da pri tome ne brinete da ie u weme povezivanja doii do dvosmisle-
nosti. za imena koja se obidno smeStaju u datoteku zaglata, kao sto su definicije extern void f0;
konstanti i umetnutih funkcija, podrazumeva se unutra5nje povezivanje. (Medu- to je isto kao jednostarma deklaracija:
tim, za konstante se unutraSnje povezivanje podrazumeva samo u C++-u, a u C-u
void f0;
Poglavlje l0: UPravljanje imenima 305
Misliti naieziku C++
304

Ugornjemprimeru,pravisenoviimenskiprostorkojisadrZiobuhvaiene
Ako kaZete: poitoji znadajna razlika u odnosu na klase, strukture, unije
deklar"acije. Medutim,
static void f0; i liste:
znaiidajefrrnkciiaf()viciljivaSamouovojjedinicizaprevodenje-ovosepone- . Imenski prostor moze se definisati samo u globalnoj oblasti vaZenja, ili u
kad naziva statiinost na niuott datoteke' drugom imenskom Prostoru.
. lzazavorene zagrade kojom se zawsava definicija imenskog prostora, niie
neophodno staviti taiku izatez.
Ostale klase za smeitanje koriste' Postoie ios dva speci- . Definicija imenskog prostora moZe obuhvatiti vise datoteka zaglavlja, a
Videiete da se rezervisane redi static i extern desto
Specifikat,or auto se skoro u sludaju klasa takva sintaksa bi izgledala kao redefinisanie:
fikatora klase za ,..liu"i. koja se rede pojavljuju.
Ol tt pro-
nikada ne upotrebllava, ler on'saopStava prevodiocu :1.r-"-'okalnoi
i odnosi //: C10:Headerl.h
(engl' automatic) se
menljivoi. Ree auto'le skraienica od "automatski" lz kon-
#i fndef HEADERI_H

na naiin na koii pr..;oJil". automatski dodelluje skladiste prgTSljiuoj. #defi ne HEADERI-H


moze da utwdi da li je promenljiva
teksta u kome je de{inisana, prevodilac uvek namespace MYLib {

lokalna, tako da ie specifikator auto suvi5an' extern int x;


Registarskapromentliva(dek]arisana'specilikatoromre8ister)Iokalnaie void f0;
(auto), i nagoveStJva pr"roaio." da ie biti puno kori5de"L, lu
i treba da je drZi u
prevodioci
il...
registru, ako moZe. pi;" tome, ovo
je pitinje.optimizaciie. Razliditi )

rnog' i au gu zanemare' Ako ditate adresu


raziidito reaguiu na ovaj specif,kator;
promenljive, prevodilai ie skoro sigurno ianemiriti specifikator register' Treba #end:t // HEADERI-H ///:-
uglavnom bolje opti- //: C10:Header2.h
da izbegavate to.iSC.nit ouog ier prevodilac
'p"tifikatora' #i fndef HEADERZ-H
miz.uie kod od vas. #defi ne HEADER2-H
#i ncl ude "Header1. h"
jej oi u 'imens ki prostor l'lyli b
// Dodavan i mena
lmenski Prostor namespace MyLib { // Ovo nije redefinisanje!
IakoimenamogubitiugneZdenauk]ase,imenaglobalnihfunkcija,globalnih prostoru. extern Y; int
u jedinstvenom globalnom imenskom
fromenliivih i klasa joS tiret su povezivanie na pro- void g0;
Rezervisana ."e o-oguiava da primenite unutra5nje il...
''t"#" na nivou datoteke) ' Ali u velikim
menljive I i,ntci;e ito 1est, d"a ih uainite.statidkim )
globalnog imenskog prostora moZe prouzro-
projektima, n.*ogrinoti kont'ole
klasa, programeri desto prave
kovati proble*.. d" Ui reSili ove pro6l"*", sludaju #endit /l H1ADER?-|1 lll:-
dugadka i komplikovana imeni, koia se verovatno
neie ponoviti na drugim
(eesto se koristi rezeryisana rei
//: C10:Continuation.cPP
mestima, ali ,ato Ceie se vi muiiti dol ih kucate' #include "Heade12.h"
rypedef da bi se ovo
poiednostavilo ) Ovakvo re5enje nije elegantno' rnt main0 ll ///r-
na podesan nadin podeliti na viSe
t.l C++-u, globalni imenski prostor moZete . Imenskom prostoru se moZe dodeliti alternativno ime, tako da ne morate
delovakorisien]emrezervisanereiinalnespace.Rezervisanarednamespace, dakucatenezgrapnaimenakojasuosmisliliautoribiblioteka:
imenasvojih dlanova u pose-
slidno kao i reii ciass, struct, enum i union, stavlja
banprostor.Dokostalerezervisanereiiimajuinekedodatneupotrebe,jedina //:C10:BobsSuperDuperLi brary.cpp
prostora' namespace BobsSuperOuperLibrary {
svrha reti n.unespace jeste pravlienje novog imenskog class Widget I /* ... */ l;
class Poppit { l* ... *l l;
Pravljenje imenskog Prostora //...
Pravlienje imenskog prostora ie slidno pravljenju
klase: )
// Ovo ime je predugaeko za kucanjel Dodeljdu mu alijas;
//: C10:MYLib'cPP namespace Bob = BobsSuperDuperLibrary;
namesPace MYLib { int main0 ll l//r-
I Oe*l aracije e Ne mozete napraviti
I instancu imenskog prostora, zarazliku od klase'
)
int mainO \\ lll:-
-
307
Misliti na jeziku C++ Poglavlje l0: UPravljanje imenima
306

Razre5enje oblasti vazenJa


se izridito zadati koriSieniem operatora
Anonimni imenski Prostor anoniman imenski prostor kome
moZete Svako ime u imenskom prostorJmoze
kao i ime u klasi:
Svaka iedinicu ,-u p"'udtnie
sadrT'i vaLloiana
,u.urt"S.";. oblasti isti nadin
itirviii i."ove navodeci namespace bez identifikatora:
//: C10:ScoPeResolution'cPP
//: C1 0: UnnamedNamesPaces ' cPP namespace X {

namesPace { class Y {
*/
cl ass Arm /
,* ..
*/
/
l.t,
static int i;
t* ... i.t,
ass Leg / t Publ i c:
c1
cl ass Head I "'
*/ I
\.
t' void f0;
cl ass Robot );
Arm arm[4] cl ass Z;
Les [16] ;
1 eq void func0;
nead head[3]; )
il .- int X::Y::i = 9;
) xanthan; class X::Z {
int i, i, k; int u' v' w;
l publ i c:
int mainO \\ lll,- /(lnt'lJ;
su automatski i bezuslovno
dostupna unu- int q0;
lmena iz- ovog imenskog prostora jedinstven za svaku
ie uvek I.
rar te iedinic. ,u p"'oJJn]t' nnonimni Pfostor
imena u anonimni imenski prostor'
X::Z::Z(int i) { u = v = w = i; )
iedinictr za prevodcnit' ;k;';t";;; Iokalna 'i nt X::Z::g0 { return u = v = w = 0; }
povezlvanle'
n" *oru,* izriiito zadavati unutraSnje
statienosti na nivou datoteke kori-
t;;;; ';esto void X::func0 {
LI ieziku t.**, p,.pu"ie;; X::Z a(1);
ste anonimtri imenski Prostorl' a.s0;
)
Prijatelji :-^--r,i hr^cr^r
.-:.- tako (to
prostor t:ko sto iete ga
sa deklari- int main0ll lllr-
Deklaraciiu priiatelia mo7-ete tbacitiu imenski se odnosi na podatak dlan klase
Primetite da bi definicija)G:Y::i lako mogla da
sati unutar iidne obuhvaiene
klase: X, umesto na imenski prostor X' .-...
V tola je ugneZdena u klasi
smo iosad videli' imenski prostori prilidno lide na klase'
I I : CIO:Fri endlnjection'cPP Sudeii po ovome Sto
namesPace Me {
class Us {
Naredba using -:c,-^.^-
ilfri end voi d
..
You (
Postoievamwlobrzopostatidosadnodakucatepuneidentifikatoreulmen.
odmah'uditate ceo
); da
skom prostoru, rezerviiana ree using vam dozvoljava onda se to zove
); i;;;rfuprostor. aro;e toristite uz rez=ervisanu red n.unespace,
da se imena navode bez zadavania
naredbausing. NareJil;i"; ;oguiava
i
int mainO \\ lll:- i*""ttog p.oitoru. PogledajtJ ovaj jednostavan imenski
prostor:
prostora Me'
funkciia you( ) dlan imenskog
ti-ai" u globainom imenskom prostoru'
Sada ie
Ako deklari5.tt p'i1*tii" unutar //: C10:NamespaceInt'h
globalni prostor' #'i fndef NAMESPACEINT-H
onda ie tai prijateli trbaien u
#defi ne NAMESPACEINT-H
namesPace Int {
negative };
Kori iienje imenskog Pl?:-l?.,tf," izriditim navodeniem pomoiu
poziva se na trl nacll
enum sign
class Integer
{ Positive,
{
Ime iz- imenskog prostora imena
naredbe using za uvoZenje svih int i;
operatora razreienia op'"gu' upotrebom. pristup odre-
deklaracije using-za direktan si gn s;
u imenskom prn.,orr, iri r.?ii*!.,1"*
denom imenu.
Misliti na jeziku C++ Poglavlje l0: Upravljanje imenima 309
308

// Sada je neophodno razreSenje opsega


publ 1 c:
ii = 0) // za Math::a :
Integer(int
l"lath: : a. setSi gn (posi ti ve) ;
: i (ii ),
s(i '= 0 ? positive negati ve)
{) Drugi imenski prostor sadrZi neka imena iz imenskog prostora Math:
si gn getS i gn const { return s; }
0
voi d setSi gn (si gn sgn) i s = sgn; )
//: C10:NamespaceOverri di ng2. h
#i f ndef NAI'IESPACEOVERRI DI NG2_H
il ... #def i ne NAMESPACEOVERRIDI NG2_H
); #i ncl ude "Namespacelnt. h"
) namespace Cal cul ati on (
tendtf ll NAMESPACEINT-a lll,- using namespace int;
prostora
Iedna primena naredbe using jeste da uveze sva imena iz imenskog Integer divide(Integer, Integer) ;
Int u drugi imenski prostor, u kome ie ta imena biti ugneZdena: lt ...
)
//: C10: NamesPaceMath ' h
#endif I / NAMESPACEOVERRIDING2_H ///:-
#i fndef NAMESPACEMAIH_H
#def i ne NAMESPACE|4ATH_H Po5to je i ovaj imenski prostor uveden naredbom using, postoji moguinost
#'i ncl ude "NamesPacelnt.h" da se imena sukobe. Medutim, dvosmislenost se pojavljuje na mestu upotrebe
namespace Math { imena, a ne na mestu upotrebe naredbe using:
using namesPace lnt; C10:0verri di ngAmbi gui ty.cpp
I nteger a, b;
//:
#i ncl ude "NamespaceMath. h"
Integer divide(lnteger, Integer) ;
#i ncl ude "NamespaceOverri di ng2. h"
il .. void s0 {
) using namespace Math;
ttendif I I NA|4ESPACEI4ATH-a I I l,- usi ng namespace Cal cu1 ati on;
SVa imena iz irr.renskog prostora Int mozete ugnezditi unutar funkcije: // Sve ie u redu do:
//: C10:Arithmetic.cPP //! divide(1,2); l/ Dvosnislenost
)
#i ncl ude "NamesPacelnt. h"
void arithmetic0 {
int mainO {l ///r-
usi ng namesPace Int; Prema tome, moguie je naredbama using uvesti vi5e imenskih prostora sa
I nteger x; istim imenim a, bez izazivanja dvosmislenosti.
x. setSi gn (Posi ti ve) i
)
int mainOll lll,- Deklaracija using
Kori5denjem deklaracije using, moZete uvoziti jedno po jedno ime u tekudu
Bez naredbe using, morali biste uvek da navodite potpuna imena' oblast vaZenj a. Za razliku od naredbe using, koja predstavlja imena kao da su
pomalo
Iedno svojstvo naredbe using moze vam, na prvi pogled, izgledati deklarisana globalno, deklaracija using se primenjuje unutar tekuie oblasti
nelogiano. Imena koja su uveze;a naredbom using vidljiva su u oblasti vaZenja vaLenla.To znadi da ona moZe redefinisati imena uvezena naredbom using:
u koioj je ta naredba navedena. Ali, ta oblast moZe redefinisati uvezena imena,
kao cla su deklarisana u globalnoj oblasti vaZenjal //: C10:UsingDeclaration.h
#i fndef USINGDECLARATION_H
//: C10: NamesPace0verri di ng1. cPP #defi ne US INGDECLARATION_H
#i ncl ude "NamesPacel'lath. h" namespace U {
int main0 { inline void f0 {}
usi ng namesPace Math; inl'i ne void g0 {}
Integer a; // Skriva Math::a; )
a. setSi gn (negati ve) ;
3to Misliti na jeziku C++ Poglavlje I 0: Upravljanje imenirna 3ll t
namespace V { Pravila za koriSienje imenskih prostora
inline void f0 {} Neka od navedenih pravila mogu vas malo obeshrabriti, pogotovo ako ste stekli
inline void S0 () utisak da iete ih stalno primenjivati. u opstem sludaju, mozete se provuii uz
)
veoma jednostavnu primenu imenskih prostora, ako znate kako oni rade. Kljudna
#endlf / / USINGDECLARATT}N_H / / / :- stvar koju treba da zapamtite jeste da globalna naredba using (izrazom ,,using
nilnespace" van svih oblasti vaZenja) olvara imenski prostor za tu datoteku. Ovo
I I : Cl}: Us i ngDecl arati onl. cpp je uglavnom dobro za datoteku realizacije (,,cpp" datoteka) zato Sto direktiva
#i ncl ude "Usi ngDecl aration. h,, using deluje samo do kraja te datoteke. ona ne utide na druge datoteke, tako da
vold h0 i
zasebno moZete kontrolisati kori5ienje imenskog prostora za svaku datoteku
using namespace U; ll Naredba usinq
realizacije. Na primer, ako otkijete dvosmislenosti zbog prevelikog broja nare-
using V::f; /l Deklaracija using
f O; // Poziva funkci ju V::f 0; daba using u nekoj od datoteci realizacije, promenite tu datoteku koristeii pot-
U::f0; /l U pozivu se moraju koristiti .imena puna imena ili izbegnite dvosmislenosti deklaracijom using, pri demu ne morate
potpuna
da menjate ostale datoteke realizacije.
)
int mainO {l IIl:- Datoteke zaglavliasuveC drugaprida. Sigurno nikada neiete hteti da upotre-
bite globalnu naredbu using u datoteci zaglavlja, jer bi to znadilo da bilo koja
Deklaracija using samo opisuje potpuno ime identifikatora, ali ne daje infor-
druga datoteka, koja ukljuduje tu datoteku zaglavlja, takode otvara imenski
macije o tipu. Ukoliko imenski prostor sadrZi skup preklopljenih funkcija istog prostor (a datoteke zaglavljamogu ukljuditi i druge datoteke zaglavlja).
imena, deklaracija using odnosi se na sve funkcije iz tog skupa.
Dakle, u datotekama zaglavlja treba da koristite puna imena, ili ograniiene
Deklaraciju using mozete pisati svuda gde moZete stavitinormalnu deklara-
naredbe using i deklaracije using. Takav pristup iete naii u ovoj knjizi, i ako se
ciju. Deklaracija using se ponasa kao normalna deklaracija u svakom pogledu,
budete njega pridrZavali neiete ,,zagaditi" globalni imenski prostor i watiti se u
osim u jednom: posto ne navodite listu argumenata, moguie je da deklaracija
svet C++-a kakav je bio pre imenskih prostora.
reci using izazove prekiapan.ie funkci]'a sa istim tipovima argumenata (Sto nije
dozvoljeno pri normalnom preklapanju). Ova dvosmislenosli"," pojaviti kao
greSka na mestu upotrebe imena, a ne na mestu deklarisanja.
Deklaracija using se takode moZe pojaviti u okviru imenskog prostora, i ima
Statifki ilanovi
Kada istu memorijsku lokaciju treba da koriste svi objekti klase, na c-u se ta
isti efekat kao i bilo gde - deklari5e ime koje vaZi u prostoru:
Iokacija deklari5e kao globalna promenljiva, ali to nije bezbedno. Globalni poda-
/ I : Cl0:Usi ngDecl arati on2. cpp tak moZe menjati svako, i njegovo ime moZe izazvatidvosmislenosti ako se kori-
#include "UsingDecl aratjon.h,, sti joSe negde u velikom projektu. Bilo bi idealno kada bismo mogli da smestimo
namespace Q { podatak kao da je globalni, ali da je istowemeno skriven unutar klase i jasno
using U::f; povezan s njom.
using V::g; Za to sluZe statidki dlanovi klase. Statidki podaci ilanovi se uvek nalaze na
/t... istom mestu u memoriji, bez obzira na to koliko iete objekata napraviti u klasi.
)
Svi objekti dele isto statiako skladiSte, Sto im omoguiava da medusobno komuni-
void m0 {
ciraju. Ali, statidki podatak pripada klasi; njegovo ime je vezano za oblast vaZenja
usi ng namespace Q;
klase i on moZe biti jarmi, privatni ili za5tiieni.
t0; / / Pozi va funkciju U: :f0 ;
gO; l l Pozj va funkci:u V: :g 0 ;
i
int
Definisanje skladi5ta za statiike ilanove
majnO {l I//:- Po5to statidki podaci imaju istu adresu bez obzira na broj napravljenih objekata,
Deklaracija using sluzi za pravljenje alternatirnih imena, i omoguiava dekla- moraju negde biti definisani. Prevodilac neie rezeMsati memoriju umesto vas.
risanje iste funkcije u razliiitim imenskim prostorima. Ako budetJredeklarisali Program zapovezivanje ie prijaviti gre5ku ako je statidki podatak deklarisan, a
istu funkciju uvozenjem razliditih imenskih prostora, neiete izazvatidvosmisle_ nije definisan.
nost ni dupliranje koda.
3r2 l0: UPravljanje imenima 3r3
Misliti na jeziku C++ Poglavlje

I)ozvoljena je samo jeclna definicija koja se mora pojaviti van klase (umetanje int l,{i thStati c: : x = 1;
nije dozvoljcno). Prerna torne, defrnicija se uobiiajeno stavlja u datoteku reali- int l^li thStati c: :Y = x + 1;
zacijc klase. Sintaksa ponekad zadaje muke, ali je zapravo sasvint logidna. Na // l,]ithStatic::x a ne ::x
primcr, ako napravitc statiaki clan klase:
int main0 {
class A { WithStati c ws;
stdtrc int i; ws. pri nt 0 ;
publ ic: \ t//,-
Ovde oznakaWithStatiq: definise oblast vaZenja u celoj definiciji, pa se x+l
);
odnosi na alan x.
onda morate definisati skladi5te za taj statidki dlan u datoteci realizacije, ovako:
int A::i = 1; I n icijal izacija statidko g niza
je
Ako biste hteli da definiStc obidnu globalnu promenljilu, rekli biste: U po[lavlju 8 iikorisiena je s-tatidka konstantna wednost u telu klase. Takode
ili obidnih. Sintaksa je
-og,ie" napraviti niz statiakih objekata, bilo
konstantnih
int i = 1;
prilidno konsistentna:
ali, ovde se operator razre5enja opsega i ime klase koriste da biste zadali oblast
vaTenja A::i. //: C10:Stati cArraY.cPP
Neki ljudi te5ko prihvataju ideju da je dlan A::i privatan, a da odigledno postoji // Inicijalizaciia statidkih nizova u klasama
van klase. Zar to nije suprotno mehanizmu za5tite? Medutim, ovo je potpuno class Values {
bezbedno iz dva razloga. Kao prvo, definicija je jedino mesto u kome je ovakva // stat:dke konstante se injciializuju na mestu deklarisanjar

inicijalizacija ispravna. I stvarno, kada bi statidki podatak bio objekat s konstruk-


static const int scSize = 100;
static const long sclong = 100;
toronr, vi biste pozvali konstmktor, umesto Sto koristite operator (=). I kao drugo,
posle definicije, krajnji korisnik ne moZe da napravi drugu definiciju - program // Automatsko broianje se moZe koristiti za statidke
ni
nizove
/l Nizovi, statidki dlanovi koii nisu konstantni celobrojni
za povezivanje bi prijavio greSku. Autor klase mora da defini5e dlanove, ili dolazi
do greSke prilikom povezivanja. To znaei da se promenlfiva defini5e samo jed-
// moraju se iniciializovati spolja:
stati c const i nt sclnts U ;
nom i da je pod kontrolom autora klase. stati c const I ong scLongs [] ;
Ceo izraz. za inicijalizaciju statidkog dlana je u oblasti vaZenja klase. Na static const float scTable[];
primer: static const char scLetters[];
/l: Cl):Statinit.cpp stati c i nt si ze;
// 0blast vaZenja za inicijalizaciju statiakog alana stati c const fl oat scFl oat;
#i ncl ude <i ostream> stati c fl oat tabl e[] ;
us ing namespace std; stati c char I etters [] ;
l.
int x = 100:
i nt Val ues: : si ze = 100;
cl ass l,/i thStati c {
const fl oat Val ues: : scFl oat = 1.1;
static int x;
static int y; const int Values::sclnts[] = {
publ i c: 99, 47, 33, 11, 7
void prr'nt 0 const { );
cout << "WithStatic::x - " << x << endl;
cout << "l^i i thStati c: :y - " .. y <. gndl; const I ong Val ues: : scLongs [] = i
)
99, 47, 33, 11, 7
I,
)r
3r4 Misliti na jezikur C++ Poglavlje 10: Upravljan1e imenima 315 t
const float Values::scTableU - { Stat: : xTabl e2 [] = {
r.1 , 2.2, 3.3, 4 .a x(1), x(2), x(3), x(4)
); );
const char Val ues: : scLetters [] = (
const X Stat::x3(100);
'a','b','c','d','e',
'f','g','h','j','j' const X Stat::xTab'l e3[] = {
); x(1), x(2), x(3), x(4)
);
float Values::table[4] = {
1.t,2.2, 3.3, 4.4 int main0 { Stat v; } ///,-
);
statidki nizovi objekata,bez obzira na to da li su konstantni ili nisu, moraju se
char Values::letterstl0l = {
inicijalizovati na isti nadin, tipidnom sintaksom za deflnisanje statidkih objekata.
'a','b', ,c,, ,d,, ,e,,
'f','g','h','i','3'
);
UgneZdene i lokalne klase
int main0 { Statidke dlanove moZete lako staviti u klase koje su ugneZdene u druge klase.
Vatues u; \ /ll:-
Definicija ovakvih dlanova je intuitivna i odigledna - koristite sledeii nivo oblasti
Statiike konstante celobrojnog tipa moZete definisati unutar k]ase, ali sve va1enja. Medutim, ne moZete definisati statidki podatak unutar lokalne klase
ostalo (ukljudujuii celobrojne nizove, dak i ako su statiake konstante) morate (lokalna klasa je definisana unutar funkcije).
definisati spolja. Na ove definicije se primenjuje unutraSnje povezivanje, tako da
se mogu smestiri u datotekr,r zaglavlja. Sintaksa za inicijalizovanje statidkih //: Cfi:- Local . cpp
nizova ista je kao za bilo koju grupu, ukijudujuii i automarsko brojanje. // Statidki dlanovi i lokalne ktase
#include <iostream>
Takode mozete napraviti statidke konstantne objekte klasa, kao i nizove
using namespace stdl
takvih objckata. Medutim, ne mozere ih inicijalizovati u telu klase, sto je dozvo-
ljeno za statiake konstanre cetobrojnih ugradenih tipova:
// UgneZdena klasa M07E da ima statiiki podatak dianr
//: C10:Stati c0bjectArrays. cpp class Outer {
// Stati cki ni zovj objekata k1 asa class Inner {
class X { static int i; // lvo je u redu
i nt i ; l.
publ 1 c:
X(int ij) : i(ii) {} int 0uter::lnner::i = 47;
l;
// Lokalna klasa ne moZe da ima statiike podatke dlanove:
c1ass Stat { vojd f0 {
I 0vo ne radi , j ako bi ste
I cl ass Local {
ll vi ieleli da radi: publ i c;
//! static const X x(100); //! static int i; // Gre5ka
// 0blekti konstantnih i obidnih statickih klasa l/ (kako biste vi definisali i?)
ll noraju se definisati spolja: ) x;
stati c X x2; )
static X xTable2U;
static const X x3; int main0 { Outer x; f0; I ///:-
static const X xTable3|; odmah moZete uoditi problem sa statidkim dlanom u lokalnoj klasi: kako da
i; opi5ete podatak u oblasti vaLenja datoteke da biste ga definisali? u praksi,
X Stat::x2(100);
lokalne klase se koriste veoma retko.
3r6 Misliti na jeziku C++ Poglavlje l0: Upravljanje imenima 317

Staticke funkcije clanice )


Statiike tunkcije dlanice koje se, kao i statidki podaci, odnose na celu klasu, takode stat'i c int f0 {
rnoZete napraviti. Umesto da pravite globalnu funkciju koja se nalazi u globalnom I lt va1 0; // Greika: statidka funkcija Elanica
ili Iokalnorn inrenskom prostoru i ,,zagaduje ga", unesite funkciju u klasu. ll ne moie da pristupi obidnoj funkciji dlanici
Statieku ftrnkciju nro2ete poz-vati na uobidajeni nadin, tadkom ili strelicom, return incr0; l/ U redu - poziva se statiika funkciia
pornoiu imena nekog objekta. Medutim, statidke funkcije se deSie pozivaju po )

irlrenrr klase, bez z-adatog objekta, koriSienjem operatora za razreSenje osega:


t.

// : C10 : Srmpl eStati cMemberFuncti on. cpp int X::i = 0;


class X {
publ i c:
int main0 {
static void f0{}; X x;
i; X* xP = &x'
x.f0;
int main0 { xp-'f ( );
X::f0; X::f0; /l radi samo sa statidkim elanovima
I I I l:- i /t/:
Kada vidite statieku funkciju dlanicu u klasi, setite se da je namera autora pristu-
Posto statidke funkcije dlanice nemaju pokazivad this' one ne mogu
klase da ta funkcija bude povezana s celom klasom. pati obidnim dlanovima, niti mogu pozivati obidne funkcije'
Statidka funkcija ne moZe da pristupi obidnim elanovima klase, vei samo sta- primetite da se u glamom p-giu*, statiikom dlanu moZe pristupati kori-
tidkim. Ona moZe da pozove samo druge statidke funkcije svoje klase. Kada se S6enjem uobidajene iintakse iu tueto* ili strelicom, povezujuii funkciiu sa

oUl"i o*. Statidkim dlanovima se pristupa, i bez objekta navodenjem


poziva obidna funkcija, skriveno se prenosi adresa tekuieg objekta (pokazivad imena
this), a poSto za statiaki dlan ne postoji pokazivad this, on ne moZe pristupati klase i operatora razresenja opsega (zato sto ie statidki dlan povezan sa klasom, a
obidnom dlanu. Zbog toga su statidke funkcije malo brZe nego obidne, jer se ne ne sa odredenim objektom).
prosleduje pokazivai this. Istowemeno dobijate pogodnosti koje pruZa funkcija Evo jedne zanimilive osobine: zbog nadina na koji se statidki
ilanovi
9.bj:Iti
unutar klase. definisati statidki objekat fe klase. Sledi primer u
inicijalizuju, u klasi moZete
Kada se radi o podacima dlanovima, rezervisana red static ukazuje na to da objekat klase Egg. Po5to smo defini-
to#;" dtzvoljeno da postoji samo iedan
postoji samo jedna memorijska adresa za njih, koja je ista za sve objekte klase.
'fo se slaZe sa upotrebom rezervisane reii static za ,Ji piiru,ri konstruktor, *oz"t" da pristupite tom obiektu, ali ne moZete da
definisanje podataka unutar napravite nijedan nov objekat tipa Egg:
tunkcile i znadi da se koristi samo jedna kopija lokalne promenljive za sve pozive
funkcija. //: C10:Singleton.cPP
Evo primera u kome se statiaki podaci dlanovi i statidke funkcije dlanice // Statieki dlan istog tipa obezbeduje da
// postoii samo jedan obiekat tog tipa'
koriste zajedno: '/
I Ovo se desto naziva i singularan obrazac projektovanja'
//: C10:Stati cMemberFuncti ons.cpp #i ncl ude <i ostream>
class X { using namesPace std;
int i;
static int j; class Egg {
publ i c: static Egg e;
x(int ii = 0) : i (ii) ( int i;
// Nestaticka funkcija elanica moZe da pristupi Egg(int ii) : i (ii) {)
I/ stalickoj funkciji clanici ili podatku: Eggiconst zggil; ll Sprelava pozivanje konstruktora za kopiranje
j = i; publ i c:
) static Egg* instance0 { return &e; )
int val 0 const { return i; } 'int val0 const ( return i; )
static int 1ncr0 { );
l/t t+*; // GreSka: statiika funkcija dlanica
ll ne noie da pristupi obiinom podatku
return ++.i I
318 Misliti na jeziku C++
Poglavlje l0: Upravljanje imenima 319 t-

Egg Egg::e(47);
program moZe da radi, a moZe i da ne radi. Ako programsko okuzenje sklapa
p.og.urn tako da se prva datoteka inicijalizuje pre druge, neie biti problema.
int main0 {
Meautim, ako se druga datoteka inicijalizuje pre prve, konstluktor klase Oof se
lll ESs x(l); ll GreSka - ne moZete daj napravite obiekat tipa Egg
oslanja na postojanje objekta out koji jos uvek nije inicijalizovan, i to ie
I I lloiele da pri stupi te samo :ednoi nstancj :
cout << Egg::lnstance0-'val0 " endl; prouzrokovati probleme.
I lll,- Ovaj problem se desava jedino u sludaju inicijalizovanja statiikih obiekata
koji zauisejedan od drugog. Statidki objekti u jedinici za prevodenje se inicijali-
Objekat E se inicijalizuje posle deklaracije klase, tako da prevodilac ima sve zuju pre prvog poziva funkcije u toj jedinici - ali to moZe biti posle inicijalizacije
p o t reb n e i n fo rm aci j e z-a z,auzimanje me mo ri j e i pozivanj e konstruktora.
glavnog programa. Ne mozete biti sigurni u redosled inicijalizacije statidkih
Da bi se u potpunosti spredilo pravljenje drugog objekta tipa Egg, dodato je
objekata ako su oni u razliditim datotekama.
joS neSto: drugi privatni konstruktor koji se zove konstruktor za kopiranje (engl.
Finiji primer moZete pronaci u priruiniku ARM.1 u globalnoj oblasti vai.eoja
copy constnrctor),Zasad ne moZete znati za5to je ovo neophodno jer ie kon- jedne datoteke nalazi se:
struktor z-a kopiranje biti predstavljen tek u sledeiem poglavlju. AIi, da malo
zavirimo unapred tl tu temu: ako biste uklonili konstruktor za kopiranje, onda extern int y;
biste mogli da napravite objekat tipa Egg na sledeii nadin: intx=y+1;
Egg g = *Egg::instance0; a u globalnoj oblasti vaZenia druge datoteke pi5e:
Egg e2 (*Egg: : i nstance0 ) ; extern int x;
Oba objekta koriste konstruktor za kopiranje. Da bismo otpisali tu mogui- intY=1+l'
nost, deklarisali smo privatni konstruktor za kopiranje (definicija nije neop- Mehanizam zapovezivanje i uditavanje garantuje inicijalizaciju svih statidkih
hodna zato Sto se on nikada ne poziva). Veliki deo narednog poglavlja posveien je podataka nulo*, pre dinamidke inicijalizacije koju zadaje programer- U prethod-
konstruktoru z-a kopiranje, pa ie vam tada ovo biti jasnije. nom primeru, popunjavanje nulama skladista koje zauzima objekat out tipa
fstream nema posebno znadenje, pa je ono nedefinisano do pozivanja konstruk-
tora. U sludaju ugradenih tipova, inicijalizacija nulom ima smisla. Ukoliko se
Zavis nost statiaki h objekata prva datoteka inicijalizuje pre druge, promenljiva y statidki se inicijalizuje nulom,
Statidki objekti unurar odredene jedinice za prevodenje uvek se inicijalizuju po pa wednost promenljive x postaje jedan, i y se dinamidki inicijalizuie na wednost
redosledu definisanja u toi datoteci. Redosled uni5tavanja objekataje uvek obr- hva. Ako se datoteke inicijalizuju obrnutim redosledom, x se statiiki inicijalizuje
nut u odnosu na redosled iniciializacije. nulom, y se dinamidki inicijalizuje na wednost jedan, i x onda postaje dva'
Standardom nije propisan redosled inicijalizacije statidkih objekata koji se Programeri moraju biti svesni ovoga. Program u kome su statidki objekti
nalaze u razliditim jedinicama za prevodenje, a jezik ne omoguiava da sami medusobno zavisni moZe raditi na jednoj platformi, ali kada se prenese na drugu
zadate taj redoslecl. Ovo moZe prouzrokovati ozbiljne probleme. Sledi primer platformu s drugim prevodiocem, iz nekog tajanstvenog razlogavise neie raditi.
rrenutne katastro[e (koja ie blokirati rad primitivnijih operatilmih sistema i iza-
zvati prekidanje procesa u naprednijim operativnim sistemima):
Re5enje problema
I I Prva datoteka Postoje tri pristupa za prevazilaZenje ovog problema:
#i ncl ude <fstream>
std: : ofstream out ( "out. txt" ) ;
I . Nemojte da napravite problem. Najbolje resenje je da izbegnete zavisnost
izmedu statidkih objekata.
Druga datoteka koristi objekat out prilikom inicijalizovanja:
2. Ako je to nemoguie, stavite problematidne definicije statidkih objekata u
I I Druga datoteka jednu datoteku tako da moZete kontrolisati njiholu inicijalizaciju navo-
#i ncl ude <fstream>
deii ih po pravilnom redosledu.
extern std: :ofstream out;
3. Ako ste ubedeni da se ne moLe izbe6 da objekti budu razbacani po jedini-
class 0of {
publ i c: cama zaprevodenje - kao u sludaju biblioteke, gde ne mozete kontrolisati
0of0 { std::out .. "iao"; i
programere koji ih upotrebljavaju - postoie dve programerske tehnike za
reSavanje ovog problema.
) oof;

I B.jme Sroustrup i Margaret Ellis, Tlu Anrcbted C++ Refercnce Manual Addison-lVesley 1990 , strile 20-21
321
320 Misliti na jeziku C++ Poglavlje l0: UPravljanje imenima

posto'ie',ali im ne
Deklaracije za objekte x i y samo najavljuju da ti objekti
Prva tehnika definicija za objekat init tipa Initializer
dodeljuju prostor u memoriji.-Medutim,
Ovu tehniku je gveo )erry Schwarz dok je pravio biblioteku tokova podataka objektu u svakoj datoteci u kojoj je ukljuieno zaglavlje.
(posto su definicije z-a cin, cout i cerr statidke i nalaze se u posebnoj datoteci). aodeluje ,nuaist" tom
i*" statidko (rezervisana ree static ovog puta kontroliSe samo vidliivost
rosto 1"
Nile tat<o efikasna kao druga tehnika, ali vei dugo postoji tako da moZete naiii
na kod u korne se ona koristi; zbog toga je vazno da razumete kako radi.
i-".ru, a ne nadin na koji se dodeljuje memorija; skladi5te se.podrazumevano
Ova tehnika koristi dodatnu klasu u datoteci zaglavlla biblioteke. Ta klasa je
nalaziuoblastivaZenjadatoteke),onojevidljivoSamouokvirutejediniceza
prevodenje, pa povezivad neie prijaviti gre5ku zbog viSestrukog
deflnisania'
z-aduZena z-a clinamidku inicijaliz-aciju statiekih objekata' Evo jednostavnog
Evo auiotlte koja sadrZi deflnicije objekata x,y i initCount:
primera:
ll: C10:lnitializer.h Il: CIO Ini ti al i zerDefs. cPP {0)
ll Iehnika za statiiku inicijalizaciju // Definicije za initializer.h
#ifndef INITIALIZER_H
#include "Initial izer'h"
#defrne INITIALIZER_H // Statiika jniciializaciia de postaviti
// sve ove vrednosti na nulu:
#i nc'l ude <t ostream>
extern i nt x1 I Ovo su deklaracije, a ne definiciie int x;
I int Y;
extern i nt yi
i nt Ini ti al i zer: : i n i tCount;

class Injtia1izer {

static int initCount; (Nararno,instancaobjektainitkojajestatidnananivoudatoteke'takodese


da je kori-
publ i c: pravi u ovoj datoteci zato sto je ukljudeno zaglavlie.) Pretpostavimo
Ini ti al i zer0 { inik biblioteke napravio jo5 dve datoteke:
std::cout << "lnitializer0" << std::endl; :
Cl}zInitializer.cPP {0i
I I
// Inici.lalizuie se samo Prvi Put
// Stati ika i ni ci i al i zaci j a
i f ( i ni tCount+* == 0) {
#.i ncl ude " Initi al i zer.h"
std::cout << "inicijal izujem vrednosti "
<< std::endl;
x - 100; i
y = 2001 I I : Cll: Ini ti al i zer2. cPP
) //{L) InitializerDefs Initializer
i // Statieka iniciializaciia
-lnitjalizer0 { #include "Initial izer.h"
std::cout << "-lnitializer0" << std::endl; using namesPace std;
// 0slobadanie memoriie samo na kraju
if(--jnitCount == 0) { int main0 {
std: :cout memoriju" cout << "unutar mainQ" << endl;
::,::l::ili:m cout << "izlazim iz mainQ" << endl;
I I 1ude se oslobada memorija j //1,-
)
SadanijevaZnokojasejedinicazaprevodenjeprvainicijalizYje:PrViputkada
)
inicijalizuje jedinica koja sadrZi fniiiatizer.tr, dlan initCount
ie imati wednost
se
I;
t,rtu,puCesewednostiinicijalizovati'(Ovoseoslanjanaiinjenicudasestatidka
dinamidka inici-
ll U sledecem redu se pravi po jedan objekat u oblast skladiSta popunjava nulama pre nego Sto zapoine neie
ostal-e j-edinice, wednost objekta initcount
// svakoj datoteci u koioj je ukljuden Initializer'h, ali iJir".u".l Kada sL iniJlaizulu Memorija se oslobada po obrnutom
titi.rrriu i u njima se preskare inicijalizacija.
II svakt obiekat ie vidl:jv samo u svojoj datoteci:
ie se pobrinuti da se to desi samo jednom'
static Initializer init; redosledu, i destruktor -Initialize;( )
tendtf ll INITIALIZER-H ///:-
Misliti na jeziku
Poglavlje I0: Upravljanje imenrma 323
322 C++

Konstruktor takode ispisuje poruku, a pozivanjem funkcije print mozete


U ovom primerr.t su korisieni globalni statieki podaci ugradenih tipova. Ova saznati da li je objekat inicijalizovan.
tehnika radi i sa klasama, ali objekti onda moraiu da budu dinamidki inicijalizo'
Druga klasa se inicijalizuje na osnovu objekta prve klase, a izazivazavisnost:
vani klasom Initializer. Iedan nadin da se ovo uradi jeste da napravite klase bez
konstruktora i destruktora, ali s funkcijama dlanicama za inicijalizaci;'u i osloba- //: Ci0:Dependency2.h
danje memoriie, ko)e koriste razlieita imena. Medutim, deSie se koriste pokazivadi #ifndef DEPENDENCyZ H

na objekte, koje iete napraviti kori$ieniem operatora new unutal konstruktora #define DEPENDENCy2 H
# i ncl ude "Dependencyl. h"
Initializer( ).

class Dependency2 {
Druga tehnika Dependencyl d1;
Nakon Sto je prva tehnika vei dugo primenjivana, neko je (ne znam ko) predsta- publ i c:
vio tehniku koju iemo objasniti u ovom odeljku, a koja je mnogo jednostavnija i Dependency2(const Dependencyl& depl) : d1(depl) {
distija od prve. Zbog sloZenosti jezika C++, proslo je neko weme do otkrivanja dve std: :cout << ',Konstruktor klase Dependency2,,;
druge tehnike. print0;
Ova tehnika se zasniva na dinjenici da se statidki objekti unutar funkcije inici- )
jalizuju (samo) pri prvom pozivu funkcije. Imajte na umu da mi ovde ne resa- void print0 const { dl.print0; )
vamo problem kada ie se statidki objekti inicijalizovati (to se moze posebno );
kontrolisati), vei pokuSavamo da obezbedimo da se inicijalizuju po pravilnom #endif // DEPENDENCy2_H ///:-
redosledu.
Ova tehnika je vrlo uredna ive5ta. Kada postoji medusobna zavisnost objekata
. Konstruktor ispisuje poruku, azatrmi stanje objekta dr, tako da moZete videti
da li je-taj objekat inicijalizovan do trenutka pozivanlakonstruktora.
pri inicijalizaciji, stavite statiiki objekat u funkciju koja waia referencu na taj Da bismo pokazali Sta moze dovesti do gieSke, u sledeioj datoteci naveli
smo
ob jekat. U ovom sludaju, jedini nadin da pristupite statidkom objektu je pozivanje definicije statidkih objekata pogresnim redosledom, onako kako bi stajale
kada
funkcije, a ako objekat mora da pristupi drugim statiikim objektima od kojih bi program za povezivanje inicijarizovao objekat kiase Dependency2 pre
objekta
z-avisi, oncia on mora pozivati njihoue funkcije. Kada se funkcija prvi put pozove' klase Dependencyl. Zatim smo obrnuli redosred da bismo poturaiia
sve radi
vrednosr se inicijalizuje. Redosled statiake inicijalizacije je garantovano ispravan tadno kad je redosled pravilan. Na kraju je prikazana druga tehnika.
zbog nadina na koji je osmiSljen k6d, i na njega ne utide redosled povezivanja. Da bismo obezbedili ditljiviji rezultat, napravili smJfunkciju separatoro.
Napisali smo dve medusobno zavisne klase. Prva sadrZi objekat tipa bool koji Po5to pre pokretanja glavn-og programa funkiila moZe da ,. porou.
samo prili_
se inicijalizuje u konstruktoru, tako da moZete znati da li je konstruktor pozvan kom inicijalizacije promenljivih, funkcija separator( waia liZnu wednost
) koja
z-a statiaku instancu klase (statidka oblast se popunjava nulama pri pokretanju se koristi za inicijalizacij u nekoliko glob alnih promenlj ivih.
programa, 5to znadi da promenljiva ima wednost false ako konstruktor nije bio
pozvan): //: C10:Technique2.cpp
#incl ude "DependencyZ. h,,
I l: C10 Dependencyl. h us i ng namespace std;
#i fndef DEPENDENCYl-H
#defi ne DEPTNDENCY I_H i/ Uraea vrednost tako da se moZe pozvati za
#include <iostream> // globalnu inicijalnu vrednost:
int separator0 {
class Dependencyl { cout << rr---------------------, << endl ;
bool i ni t; return 1;
publ i c: )
Dependencyl0 : init(true) i
std::cout << "Konstruktor klase Dependencyl" // Simul i ra prob l em zavi snosti :
<< std: :end1 ; extern Dependencyl depl;
) Dependency2 dep2 (dep1) ;
voi d pri nt ( ) const { Dependencyl depl;
std: : cout << "Vrednost cl ana i n'i t kl ase Dependencyl: " 'i
nt x1 = separator0 ;
<< jnit << std::endl;
I
i:
l0: UPravljanje imenima 325
324 Misliti na jeziku C++ Poglavlje

inicijal izuju ovim redosledom, sve dobro radi: u datoteci realizacije, gde biste ranije stavili definicije statidkih obiekata'
// Ako se vrednosti
navedite definicije funkcija:
Dependencyl dePlb;
Dependency2 deP2b (dePlb) ; //: C10:DependencylstatFun.cpp {0}
int x2 = separator0; #i ncl ude "DependencylStatFun.h"
Dependencyl& d10 {

// statiakjh obiekata u funkciie je


Ubacivanje uspelo static DePendencYl depl;
Dependencyl& d10 { return dePl;
stati c DePendencYl dePl; I I ll,-
return depl; Pretpostavimo da se i drugi k6d moze staviti u ove datoteke. Evo druge
)
datoteke:
Dependency2& d20 i //: C10:Dependency2StatFun.cpp (0)
stati c DePendencY2 deP2 (d1 0 )I #incl ude "DependencylStatFun.h"
return deP2; #i ncl ude "Dependency2StatFun.h"
)
DependencY2& d20 {
static DependencY2 dePz(d10) ;
int main0 return deP2;
Dependency2& deP2
{
= d20; j /l/,-
\ lll,- Sadapostojedvedatotekekojesemogupovezatipobilokomredosledu,paSe
Funkcije dl ( ) i d2( ) omotavaju statidke instance objekata tipa Dependencyl
i i njihovistatlS6 otletti mogu inicijalizovati po bilo kom redosledu. Po5to ove
inicijalizacije:
Dependenry2. Iedini naain na koji mozete doii do statidkih objekata jeste pozi- daioteke sadr7e omotadke tuntcile, nema opasnosti od nepravilne
uanle f.rntcila, a to ie obezbediti inicijalizaciju pri prvom pozivu funkcije'
Ovo Kadazapodneizw5avanjeo,ogp.og,u*a,videietedasestatidkiobjekattipa
Takode
guru.,,r;" tainu inicijalizaciju u Sta iete se uveriti kada izvr5ite program i pogie- Dependencyl uvek inicijaltu;" pie rtuilekog objekta tipa Dependencyz.
*oZ"t" Ua"ii da je ovaj pristup mnogo jednostarrniji od prve tehnike'
date rezultat.
Evo kako biste konkretno organizovali k6d i upotrebili ovu tehniku.
obidno bi
(zato sto ste iz nekog razloga //: C10:Technique2b.cPP
se sratiaki objekti definisali u zaiebnim datotekama //{L} DependencylstatFun Dependency2StatFun
prisiljeni cla rako uradite; setite se da upravo definisanje statiakih _objekata u #i ncl ude "Dependency2StatFun. h"
zasebnim datotekama izazivaprobleme). umesto toga, u zasebnim datotekama int main0 { d20; i lll,-
zaglavlja:
definiSite omotaeke funkcije. 1L funkcije morate deklarisati u datoteci MoZete doii u isku5enje da napi5ete funkcije dl ( ) i d2( ) kao umetnute
unutar
Umetnuta
//: C10:DePendencYlStatFun.h njihovih datoteka zaglailia, ali io definitivno.ne smete da uradite'
datoteci u kojoj se pojavljuje'.a to kopiranje
#i f ndef DEPENDENCYlSTATFUN-H funkcija se moZe topi.ati u svakoj
#def i ne DEPENDENCYlSTATFUN-H itatiikih objetata. posto se na umetnute funkcije podrazu-
ukljuiujeidefinicije
kopija statidkih
#i ncl ude "DePendencYl . h" *.ruto primenjuje unutrainje povezivanje, pojavilo bi se vi5e probleme.
extern DePendencYl& d10; oi;"tu,u ,-.,i- l"ai.r lcami zi prevodenje, sto bi sigurno izazvalo
#endtf I I DEPENDENCYISTAtFUN-H II lt- " Za svaku omotadku funkciju treba da postoji Samo jedna definicija,
Prema tome,
druge
7,apravo, rezervisana rea extern je suvi5na u deklaraciji funkcije. E'vo a to znafi da ih ne umeiete.
datoteke zaglavlia:
: CIO DependencY2StatFun. h
I
#i
I
fndef DEPENDENCY2STATFUN-H
Alte rnativno Povez lvanJ e biblioteku pre-
#def i ne DEPENDENCY2STATFUN-H sta se desava kada pisete prog.uln.ru c++-u, ai.elite da koristite
vedenu sa jezika C? Ako deklari5ete funkciju jezika C:
#'i ncl ude "DependencY2'h"
extern DependencY2& d20; float f(int a, char b);
rendif I I DEPENDENCY2STATFUN-H ///:-
F
I

Misliti na jeziku C# Poglavlje l0: Upravljanje imenima 327


326

c++ prevodilac ie dopuniti ovo ime, na primer, ovako -f-int,char, da bi podr- VeZbe
Zao prellapanje funkcija (i bezbedno povezivanje tipova). Medutim, u preve- Re5enja ovih veZbi nalaze se u elektronskom dokumentuThe thinking in C++ Annotated Solution Guklekoii
denom oUiiku Uibtioteke napisane na jeziku C, sigurno nrTe dopunjeno ime moZete preuzeti s lokacije ww.BruceEckel.com

funkcije, pa ie njeno interno ime biti _f. Prema tome, povezivad neie moci da l. Napravite funkciju sa statidkom promenljivom koja je pokazivad i argu-
razreSi C++ poziv funkcije f( ). mentom podrazumevane wednosti nula. Kada je u pozivu zadata vrednost
Za prevazrlaLenje ovog problema, u C++-u je obezbeden mehanizam alterna' za ovai argument, to je podetak niza elemenata celobrojnog tipa' Ako
tiuno[ poueziuanja (engl. alternate linkage specification), koji ie ostvaren prekla- pozovete funkciju sa argumentom koji ima wednost nula (koristeii podra-
panjem rezervisine ,.3i e*t".r. Iza rezervisane redi extern sledi znakowi niz zumevanu wednost argumenta), funkcija waia sledeiu wednost u nizu,
tojim se zadaje tip povezivanja za deklaraciju, a zatim sledi deklaracija: dok ne vidi wednost ,,-1" (koja se ponasa kao indikator kraja niza). Ispro-
bajte ovu funkciju u glavnom programu.
extern "C" float f(int a, char b);
2. Napravite funkciju koja svaki put waia sledeiu wednost Fibonadijevog
ovo govori prevodiocu da na funkciju f( ) primeni c povezivanje i ne dopu- nizi. Dodalte argument logidkog tipa s podrazumevanom wednosiu false.
njuie im-ena. Iedine dve wste povezivanja koje podrZava standard su "C" i"C++", Kada argument ima wednost true, funkcija waia podetak Fibonadijevog
aii proizvodadi prevodilaca mogu podrZavati i druge jezike na isti nadin. niza. Isprobajte ovu funkciju u glavnom programu.
Grup., deklaiacija sa alternalir.nim povezivanjem stavite u vitidaste zagrade,
3. Napravite klasu koja sadrzi niz elemenata celobrojnog tipa. Zadajte veli-
ovako:
dinu niza koristedi statidku konstantu celobrojnog tipa unutar klase.
extern "C" { Dodajte konstantnu promenljivu celobrojnog tipa i inicijalizujte je u kon-
float f(int a, char b); strukiorskoj listi inicijalizatora; umetnite konstruktor. Dodajte statidku
double d(int a, char b); promenljivu dlanicu celobrojnog tipa i inicijalizujte je. Dodajte statidku
) funkcilu flanicu koja ispisuje statieki podatak. Dodajte umetnutu funkciju
Slieno se deflniSe i alternatilmo povezivanje za sve funkcije iz datoteke dlanicu print( ) koja ispisuje sve vrednosti u nizu i poziva statidku funkciju
zaglavlja: dlanicu. Isprobajte ovu klasu u glavnom programu.
extern "C" { 4. Napravite klasu Monitor koja prati broj pozivanja svoje funkcije dlanice
#include "Myheader.h" incident( ). Dodajte funkciju dlanicu print( ) koja ispisuje broj pozivanja.
) Sada napravite globalnu funkciju (ne funkciju dlanicu) koja sadrZi statidki
Veiina proizvodada prevodilaca dodaje specifikacije za alternati\Tlo povezi- objekat tipa Monitor. Ta funkcija treba da pozove prvo incident( ), a zatim
vanje u datoteke zaglavlla koje se koriste i u programima na jeziku C i u pro-
print( ). Isprobajte ovu funkciju u gla'rnom programu.
gramima na jeziku C++, tako da ne morate da brinete o tome' 5. Izmenite klasu Monitor iz veabe 4 tako da moZete pozvati funkciju
decremento za umanjivanje broja pozivanja. Napravite klasu Monitor2
diji konstruktor ima argument tipa Monitorl*. Konstruktor treba da saiuva
SaZetak taj pokazivad i pozove funkcije incidento i printo. U destruktoru klase
Rezervisana rad static moZe biti zbunjujuia zato sto u nekim situacijama odre- Monitor2 pozovite funkcije decremento i printo. Sada, unutar funkcije
duje dodellivanje skladi5ta, a u dlugim odreduje vidljivost i nadin povezivanja napravite statieki objekat klase Monitor2. Eksperimenti5ite pozivajuii i ne
imena. poiivajuii funkcije u glar.nom programu da vidite Sta ie se desiti s destruk-
Imenski prostor u c++ omoguiavaju naprednije i fleksibilnije upravljanje ime- torom klase Monitor2.
nima u velikim projektima. 6. Napravite globalni objekat klase Monitor2 i pogledajte Sta se desava.
KoriSienje rezervisane redi static unutar klasa jeste jo5 jedan naiin za upra- 7. Napravite klasu s destruktorom koji ispisuje poruku i poziva funkciju exit( ).
vljanje imenima u programu. Statidka imena se ne mesaiu s globalnim imenima, Napravite globalni objekat ove klase i pogledajte Sta se deSava.
a vidilivost i pristup zadrLavajt se unutar programa, omoguiavajuii vam bolju 8. U datoteci StaticDestructors.cpp eksperimentisite s redosledom pozivanja
kontrolu pri odrT-avanju koda. konstruktora i destruktora, pozivajuci radiditim redom funkcije f( ) i g( ) u
glarmom programu. Da li je to vaS prevodilac shvatio?
328 Misliti na jeziku C++ Poglavlje 10: Upravljanje imenima 329

9. LJ datoteci StaticDestructors.cpp, testirajte podrazumevani nadin obrade 21. Otklonite problem u datoteci OverridingAmbiguity.cpp, najpre pomoiu
greSaka pretvarajuii originalnu definiciju objekta out u spolja5nju dekla- razreienja opsega, a zatim ponovo pomoiu naredbe using koja primorava
raciju i pomeranjem njegove definiciie iza definicije objekta a (diji kon- prevodioca da izabere jedno od identidnih imena funkcija.
srruktor Obj Salje informaciju objektu out). Pokrenite ovaj program dok se 22. U dve datoteke zaglavlja smestite dva imenska prostora tako da svaki sadrZi
niSta va7.no ne izwSava na radunaru. klasu (sa umetnutim definicijama). I(ase u oba imenska prostora treba da
t0 DokaT-ite da istoimene promenljive koje su statiane na nivou datoteke ne imaju isto ime. Napravite cpp datoteku koja ukljuduje obe datoteke zagla-
iz,az,ivait dvosmislenost kada su ukliudene u vi5e cpp datoteka, vlja. Napravite funkciju i unutar nje upotrebite naredbe using da biste uve-
tl Napravite jeclnostavnu klastr koia sadrZi celobrojnu promenljivu, konstruk- zli oba imenska prostora. Probajte da napravite objekat klase i pogledajte
Sta se de5ava. Premestite naredbe using u globalni prostor (van funkcije) i
tor koji svojim argumentom iniciializuie tu wednost, funkciju dlanicu koja
pogledajte da Ii to ne5to menja. Otklonite problem koristeii razre5enje
dlanr-r dodeljuje wednost argumenta, i funkciju printO koja ispisuje wed-
opsega i napravite objekte obe klase.
nost alana. Stavite klasu u datoteku zaglavljai ukljudite datoteku zaglavljau
dve cpp datoteke. U ;ednoj cpp datoteci napravite instancu klase, a u dru- 23. Otklonite problem u veZbi 22 upotrebom naredbe using koja primorava
go; deklari5ite taj identifikator kao spoljni i testirajte ga u glavnom pro- prevodioca da izabere jedno od identidnih imena funkcija.
gramu. Zapamtite da morate da poveZete dve datoteke u kojima se nalazi 24. lzdvojite deklaracije imenskih prostora iz datoteka BobsSuperDuperli-
objekat, inade povezivad neie pronaii objekat. brary.cpp i UnnamedNamespaces.cpp u odvojene datoteke zaglavlja i
12. Promer.rite program tako da instanca objekta bude statidka i uverite se da dajte anonimnom imenskim prostorima imena. U treioj datoteci zaglavlja
povezivac sada ne moZe da pronade objekat. napravite nov imenski prostor koji kombinuje elemente prva dva imenska
13. DeklariSite funkciju u datoteci zaglavlja. Defini5ite funkciju u jednol cpp
prostora naredbom using. U glar,ni program uvezite novi imenski prostor
datoteci i pozovite ie u glavnom programu druge cpp datoteke. Prevedite naredbom using, i pristupite svim njegovim dlanovima.
program i uverite se da radi. Sada promenite definiciju funkcije tako da 25. Napravite datoteku zaglavlja koja ukljuduje zaglavlja <string> i <iostream>,
postane statiaka i uverite se da povezivad ne moZe da je pronade' ali ne koristi naredbe using ni deklaracije using. Za5titite zaglavlje od pono-
I 4. Izmenite datoteku Volatile::isr( ) iz poglavlja 8 tako da comm::isr( ) moZe
vljenog ukljutivanja. Napravite klasu u kojoj su sve funkcije umetnute, i
da radi kao prekidna rutina. Savet: prekidna rutina nema argumente.
koja sadrZi dlan tipa string, konstruktor koji svojim argumentom inicijali-
zujetaj znako'rni niz i funkciju print( ) koja ga ispisuje. Napravite cpp dato-
I 5. NapiSite i prevedite iednostavan program koji koristi rezervisane redi auto
teku i isprobajte svoju klasu u glalmom programu.
i register.
26. Napravite klasu koja sadrZi statidke podatke tipa double i long. Napi5ite
16. Napravite datoteku zaglavlja koja sadrZi imenski prostor. U imenskom
statidku funkciju dlanicu koja ispisuje njihove wednosti.
prostoru deklari5ite nekoliko funkcija. Napravite drugu datoteku zaglavlja
kola ukljuiuie prvu i pro5iruje imenski prostor dodajuii jo5 nekoliko dek- 27. Napravite klasu koja sadrZi celobrojnu wednost, konstruktor koji svojim
laracija funkcija. Napravite cpp datoteku koja ukljuduje drugu datoteku argumentom inicijalizuje tu wednost i funkciju print( ) koja je prikazuje.
z-aglavlja. Dodelite imenskom prostoru alternativno (kraie) ime. Napi5ite Sada napravite drugu klasu koja sadrZi statiEki objekat prve klase. Dodajte
funkciju koja poziva druge funkcije koristeii operator za razreienje statieku funkciju dlanicu koja poziva funkciju print( ) statiikog objekta.
opsega. tJ definiciji drtrge funkcije, naredbom using uvezite imena iz Isprobajte klasu u glavnom programu.
imcnskog prostora, i pokaZite da niie potrebno razre5enje opsega da biste 28. Napravite klasu koja sadrZi statidki i obidan niz celobrojnih wednosti.
pozvali funkcije iz imenskog prostora. Napi5ite statidku metodu za ispisivanje nizova. Isprobajte klasu u glavnom
I 7. Napravite datoteku zaglavlja sa anonimnim imenskim prostorom. Uklju-
programu.
dite zaglavlje u dve odvojene cpp datoteke i pokaZite da je anoniman pro- 29. NapraviteklasukojasadrZiobjekattipastring,konstruktorkojiinicijalizuje
stor jedinstven za svaku jedinicu za prevodenje. taj niz svojim argumentom i funkciju print( ) za ispisivanje tog niza. Napra-
I 8. Koristeii datoteku zaglavliaizveZbe 17, pokaZite da su imena iz anonim-
vite novu klasu koja sadrZi konstantne i obidne statiike nizove diji su ele-
nog prostora automatski i bezuslo'rno dostupna u jedinici za prevodenje. menti objekti prve klase, kao i statidke metode za ispisivanje ovih nizova.
Isprobajte drugu klasu u glavnom programu.
19. Izmenitc datotekr.r Friendlnjection.cpp dodajuii definiciju priiateljske
fturkcije i pozivajrrii tr.r [unkciiu iz glavnog programa. 30. Napravite strukturu koja sadrZi celobrojnu wednost i podrazumevani kon-
struktor koji inicijalizuje tu wednost na nulu. Neka ova struktura bude
20. tJ datoteci Arithmetic.cpp, pokaZite da naredba using ne deluje van
Iokalna za funkciju. U toj funkciji napravite niz objekata strukture i poka-
okvira firnkcijc u kojoj ie napravliena.
Zite da je svaka celobrojna wednost u nizu automatski inicijalizovana na
nulu.
330 Misliti na jeziku C++ t
3I . Naprarrite klasu koja predstavlia vezu sa Stampadem i koja dozvoljava da
imate santo iedan StamPad.
3 2. U datoteci zaglavlja, napravite klasu Mirror ko!a sadrzi dva
podatka dlana:
pokazivad na objekat klase Mirror i dlan tipa bool. Dodaite i dva konstruk-
iora, podrazumevani konstruktor koji inicijalizuje logidki dlan wednosiu
*,
true, a pokazivad nulom. Drugi konstruktor ima argument tipa Mirror
koji dodeljuje internom pokazivaeu, a dlanu tipa bool dodeljuje wednost
false. Dodajte funkciju dlanicu testo. Kada pokazivad na objekat nema
wednost nula onda waia wednost funkciie test( ) koja je pozvana preko
pokazivada. Ako pokazivad ima wednost nula, na vrednost dlana tipa bool.
bada napravire per cpp datoteka tako da svaka ukljuduie zaglavlje klase
Mirror. Prva cpp datoteka deflnise globalni objekat klase Mirror upotre-
bom podrazumevanog konstruktora. Druga datoteka deklarise objekat u
prvoj datoteci kao spoljni i deflnise globalni objekat klase Mirror upotle-
Lom-drugog konstruktora, s pokazivaeem na prvi objekat. Nastavite ovako
dok ne riign"t. do poslednje datoteke koja ie takode sadrZati definiciju
globalnog objekta. U toj datoteci, glavni program treba da pozove funkciju
Iest( ) i ispise rezultat. Ako je rezultat true, menjajte redosled povezivanja
sve dok ne dobijete rezultat false.
33. Otklonite problem u veZbi 32 koristeii prvu tehniku prikazanu u ovoi
knjizi.
34. Otklonite problem u veZbi 32 koristeii drugu tehniku prikazanu u ovoj
knjizi.
35. Ne ukljuduiuii datoteku zaglavlja, deklarisite funkciju putso iz stan-
dardne biblioteke jezika c. Pozovite or,u funkciju iz glavnog programa.

Reference su,kao konstantni pokazivadi koje,prevodilac automat


r
-
ski dereferencira.
I: Reference i konstruktor za kopiranje 333
332 Misliti na jeziku C++ Poglavlje I

// f4edutim, moZete napi sati 'i ovo:


Iako reference takode postoje u Pascalu, verziia koia se koristi u c++-u
pre-
gzna(aiaza pre-klapanje operatora const int& q = 12; ll O)
uzeta je iz- jezika Aigol. Reference su od kljudno
(videti poglavlje I2i, ali su takode pogodne za kontrolu prosledivanja argumenata // Reference se vezuju za skladiSte koie pripada drugoj promen'liivoi:
int x = 0; ll Q)
rr funkciie i iz funkcija. int& a = x;
U ovom poglavliu iemo se ukratko oswnuti na razlike izmedu pokazivaia u
ll Q\
posveien int main0 {
C-u i C++-u, a onda iemo predstaviti reference. Najveii deo poglavlja COUt << ',1 = << X ((
,, ,,, a = " << a << endl ;
je temi koja prilidno zbtrniuje novailije u c++-u - konstruktorimaza kopiranje a++;
(engl. cop,v-constructor).1b iu speciialni konstruktori za pravljenje novih obje- COUI << rX = rr << X << ", a = " << a << endl ;
kati od po.tnl"Cln objekata nekog tipa, i u niima se koriste reference. Prevodilac I lll,-
koristi konstruktore za kopiranie da bi funkcijama prosledivao i vraiao objekte
U redu (1) prevodilac zauz\mamemoriju, inicijalizuje je wedno5iu 12 i
vezuje
po urednosti. referenca mora da se veZe za deo memorije
jezika referencu za adresu tog bloka. Svaka
Na kraju ienio rasvetl iti poka,ziuai na ilan, pomalo nejasan element
koji pripada nekoj promenljivoj. Kada pristupate referenci, pristupate i tom delu
C++.
memorije. Prema tome, ako napisete redove kao Sto su (2) i (3), uveianje wednosti
u ,uprulro uveiava',Tednost i, kao sto je pokazano u gla'u'nom programu' Da
porrSri*o, najjednostavnije je da o referenci razmi5ljate kao o elegantnom poka-
Pokazivati u jeziku C++ jeste strozi odnos prema zivaau. Prednost ovog,,pokazivaia' jeste to sto ne morate da se
pitate da li ie inici-
NajvaZnija razlika izmedu pokazivada u c-u i u c++-u jalizovan i kako da ga dereferencirate (to radi prevodilac)'
tipovima u c++-u. ovo se isride kada je u pitanju pokazivae tipa void*.
iosebno Postoje odredena pravila za kori5ienje referenci:
U jeziku C niie dozvoljeno da dodelite pokazivad
jednog tipa pokazivaiu drugog
tome: . Referenca se mora inicijalizovati kada se napravi (pokazivae se moze
inici-
tipa, ako koristite pokazivad tipa void*' Prema I
jalizovati bilo kad).
bi rd* b; moZe se
rock* r; 2. Kada je referenca inicijalizovana adresom odredenog objekta, ne
void* v; promeniti tako da pokazule na d'rugi objekat' (Uvek moZete promeniti
adresu na koju pokazuje pokazivad).
b = v; 3.ReferencanemoZeimatiwednostNULL,veijeuvekpovezanasnekim
Ova ,,moguinosti" jezika C doz-voljava da s jednim tipom
podataka-radite kao s delom memorije'
jeziku.c. U.C++-u ovo
nekim drugi"m tipom, i stvara probleme u sistemu tipova u
zaista Zelite da s jednim
nije dozvoijeno; prevodilac ie vam prijaviti gre5ku. Ako
Reference u funkcuama
nekim drugim tipom, morate upotrebiti konverziiu
tipom podataka radite kao s
Reference iete najde5ie vidail u ulozi argumenata i rezultata funkcija.
Kada se
izridito naglasiti i prevodiocu i ditaocu vaseg koda. (U poglavlju 3 je
aa Uiste to referenca koristi kao argument funkcije, bilo kakve izmene te reference
unutal
predstavliena pobol jSana sintaksa za izriditu konverziju') biste istr
funkcije prouzrokovaie promene argumenta uanfrnkclle. Nararryto-da
ali pomoiu refrenci dobili
mogli da uradite i pros^ledivanjem pokazivada, se
(O referenci moZete razmi5ljati kao o sintaksnoj pogodnosti.)
Reference u jeziku C++ dereferencira'
' etotOa.
lasiili
funkcija waia referencu, mo.ai" voditi raduna kao i kada waia
poka
Referenca (&) ie kao konstantni pokazivad koji se automalgki- zivad. podata[ na koji se odnosi referenca ne sme da nestane nakon izw5enji
i rezultate funkcije. Mozete napraviti i
obidno se koristi z-a liste argumenata funkcije, inade bi referenca pokazivala na nepoznati deo memorije'
proizvolinu referencu. Na Primer: Evo primera:
II : Cll: FreeStandi ngReferences ' cpp
#i ncl ude <i ostream>
//: C11:Reference.cPP u
us i ng namesPace std;
// Jednostavne reference C++-u

'i nt* f(int* x) {


// 0bicna samostalna referenca: (*x1 ++ t
int y; return x; // Ovo je bezbedno, x postoji van ove oblastj vaZenja
int& r = Y;
ll Kada napravite referencu' morate je inicijalizovati
)

// adresom nekog postojeceg obiekta'


334 Misliti na jeziku C++ Poglavlje I l: Reference i konstruktor za kopiranje 335
t
int& g(jnt& x) i
Poziv funkcij e f.(L) izaziva gresku u prevodenju zato Sto prevodilac mora
x++; ll Isti funkciji f0
efekat kao i u najpre da napravi referencu. On to radi zauzimanjem memorije za podatak tipa
return x; // Ovo je bezbedno jer x postoji izvan ove obl ast i vaZenja ini, inicijalizovanjem wedno5iu 1 i pravljenjem adrese za referencu koju ie
)
vezati. Vrednost podataka morabiti konstantna. Ne bi imalo smisla da se ona
menja - vise nikid ne biste mogli da mu pristupite. Za sve priwemene objekte
int& h0 { mori vaZiti ista pretpostavka: da im se kasnije ne moZe pristupiti. Prevodilac vas
j nt q; obavestava o gre$ci kada menjate ove podatke, zato Sto bi to prouzrokovalo
I ll reLurn q; // Greika gubitak informaciia.
static int x;
return x; // Eezbedno, x se nalazi van ove oblasti vaZenia
Reference na pokazivate
Ako u C-u Zelite da promenite urednost pokaziva(.a, umesto vrednosti podatka
)

na koji pokazuje, deklaracija funkcije izgleda ovako:


rnt main0 {

inta=0; voi d f (i nt**) ;


f(ea); l/ Ovo ie ruZno (a1 i i zri ci to) i morali biste da ditate adresu pokazivada kada ga prosledujete:
g(a); I I Ovo je dista sintaksa (ali ie skriveno)
I I I l:- int i = 47;
int* iP = g1 '
Poziv funkcije f( ) nema tako pogodnu i distu sintaksu kao sto imaju reference, f(&i p) ;
ali je jasno da je prosledena adresa. u pozivu funkcije go, prosledena ie adresa
(preko reference), ali vi to ne vidite. u c++-u sintaksa je distija, zbog korisienja referenci. Algument funkcije
postaje referenca pokazivad i vi5e ne morate da ditate adlesu pokazivada. Prema
tome:
Reference na konstante
Prosledivanje reference argumenta u datoteci Reference.cpp radi samo kada //: C11 : ReferenceToPoi nter' cPP
#i ncl ude <i ostream>
argument niie konstantan. Funkcijag( ) neie prihvatiti konstantan argument, Sto
je dobro, zato Sto funkcija menja spoljni argument. Ako funkcija ne menja wed- using namespace std;
nost argumenta, defini5ite argument kao referencu na konstantu. Tada iete funk-
void increment(int*& i) { i++;
ciju moii da koristite u svim situacijama. Ovo znadi da funkcija neie menjati
)

argumente ugradenih tipova i da ie pozivati samo konstantne funkcije dlanice, i


int main0 {
neie menjati jar.me podatke dlanove objektnih argumenata. int* i = 0;
Upotreba referenci na konstante u argumentima funkcija je posebno zna- cout<<'i="<<i << endl;
aajna zato Sto funkciji moZe biti prosleden priwemeni objekat. Takav obiekat increment(i);
moZe biti rezultat neke druge funkcije, ili neki drugi priwemeni objekat koji je cout << rri = r' << i << endl;
izridito napravljen. Priwemeni objekti su uvek konstantni, pa prevodilac neie \ lll.-
prihvatiti taj argument ako ne koristite referencu na konstantu. Evo veoma jed-
nostavnog primera:
I I : Cll: ConstReferenceArguments. cpp
Saveti za prosledivanje argumenata
Prosledivanje reference na konstantu Argumente bi trebalo da, kad god ie moguie, prosledujete funkcijama kao refe-
I I rerr"e na konstante. Ovaj savet vam na prvi pogled moZe izgledati kao savet za
void f(int&) {} poboljsanje
-stlurui" efikasnosti (a time ne Zelite da se bavite u trenutku kada tek osmi-
void g(const int&) {} svoj program). Iza njega se krije nesto mnogo vaZnije: da bi se objekat
piosledio po wednosti, potreban je konstruktor za kopiranje, a takav konstruk-
int main0 { tor nije uvek dostupan.
III f (t); // Gres ka Poveianje efikasnosti koje postiZete ovako jednosta'"nom navikom moZe biti
s(1); veoma znadajno: prosledivanje argumenta po wednosti prouzrokuje pozivanje
I l/1,- konstruktora i deJtruktora. Ako neiete menjati wednost argumenta, prosledite
ga kao referencu na konstantu, sto zahteva samo smestanje adrese na stek.
Misliti na jeziku C++ Poglavlje I I : Reference i konstruktor za kopiranle 337
336

ga moZe watiti tako sto ie ga smestiti u registar. U sludaju prostih tipova poda-
Prosledivar-rieadreserlryepreporudljivokaclfunkcijamenjaobjekatpajejedini taka u jeziku C, jednostavno kopiranje bitova wednosti objekta jednako 1e kopi-
(To ie bolie neg-o da meniate spoljni
siguran nuein prn.i.Jiran;e'po'v'ednosti' ranju tog objekta.
Ovo je tema sledeieg
objekat, jer to korisnici frinkcije uglavnom ne odekuiu)'
odeljka.
Prosledivanje i vraianje velikih objekata
Razmotrimo sada tipove koje defini5u korisnici. Ako napravite klasu iZelite da
Konstruktor za koPi ranje prosledite po wednosti objekat te klase, kako ie prevodilac znati sta da radi? Ovo
posto razumere osnove referenci, spremni ste da proudite jednu od najozbilj- nije tip koji je ugraden u prevodioca - vi ste ga napravili.
nijihtemauC++-tt:konstruktorzakopiranje,kojiseiestooznadavasaX(X&) Da biste ovo ispitali, moZete podeti s jednostavnom strukturom, koja je
prosledi-
konstruktoi je veoma bitan za upravljanje odigledno suvi5e velika da bi stala u registar:
(X oci reference na X). Ovaj
vanjemiwaean;empovrednostiobjektnihtipova.Videietedajekonstruktorza
ga vi / / : CLl: Passi ngBi gStructures.cpp
kopiranje tntitc, ,,az.in da ie ga prevodilac automatski sam
napraviti, ako struct Blg {
ne napi5ete. char buf[100] ;
int i;
ong d;
Prosledivanje i vraianje po vrednosti
1

razmotriiemo nadin ) B, 82;


Da bismo ,urrn-,,.ii potrebu za koristruktorom za kopiranje,
po wednosti' u toku poziva
na koji se u C-u prosleduju i vraiaju promenljive Bis bisfun(Bis b) {
Ako deklariSete funkciju i pozovete je:
funkciie. b.'i = 100; // Radi ne5to s argumentom

int f(int x, char c); return b;


int g = f(a' b) ; )

kakoieprcvodilacznatikakodaproslediivratiovepromenljive'onjedno- jnt main0 {


stavnoznall3rojtipovaskojimaonmoradaradijetakomali-char,int,float, s2 = bi sfun (B) ;
doubleirljillor,er,arijacije'.okodusuteinformacijeugradeneuprevodioca.' fo
je poziv funkcije I //1,-
Ako prevedet" f.ogru. u asemblerski k6d' victeiete da
Ovde je dekodiranje asemblerskog rezultata malo komplikovanije, zato Sto
preveclen tt nesto nalik na sledeie redove:
veiina prevodilaca koristi ,,pomoine" funkcije umesto umetanja celog koda. U
push b glavnom programu, poziv funkcije bigfun( ) podinje na odekivan nadin - celoku-
Push a pan sadrZaj objekta B stavlja se na stek. (U ovom sludaju, videiete da neki prevo-
call f0 dioci upisuju u registre podatke o adresi i velidini objekta tipa Big, a zatim
add sP'4 pozivaju pomoine funkcije za stavljanje objekta tipa Big na stek.)
mov g, register a
Pre pozivanja funkcije, neophodno je da se argumenti stave na stek. Medutim,
Ovajkodjezr-racajnopromen,)endabibioopStiji;izrazizabiaieserazlikovati u asemblerskoj verziji datoteke PassingBigStructures.cpp primetiiete i dodatnu
prema iome'da li su promenljive globalne (u tom sludaju bi se
koristile oznake -b radnju pre pozivanja funkcije: adresa objekta 82 se stavlja na stek, i ako je odi-
i-a) ili lokalne {prevodilac biim plistupao pomoiu steka)' Ovo vaZiizaizrazpro- gledno da ona nije argument. Da biste razumeli Sta se ovde de5ava, morate znati
poziva funkcije ft I zavisl od vase Seme za obeleZavanje imena,
nienljive g. Izgled koja ogranidenja postoje u prevodiocu kada poziva funkciju.
imenovani u vasem
a ,,register a,, z.a,,.isi od naiina na koji su procesorski registri
n..,oll"r.,. Logika koja stoji iza ovog koda ostaje ista'
Okvir steka za pozivanje funkcija
tIC-uiC.++-tt,argtlmenti'"pt'istavliajunastek'zdesnanalevo'aondase Kada prevodilac generi5e k6d za poziv funkcije, on prvo stavlja sve argumente
l.roziva funkciia. Kocl z-a
pozivanje tunkcije odgovoran je i za brisanie argume-
prosleduje argumente na stek, a onda poziva funkciju. Unutar funkcije postoji kOd za pomeranje poka-
nata sa steka (5to objaSaniava liniju add sp,4)' Prevodilac zivada steka nadole, da bi se obezbedilo skladiSte za lokalne promenljive
vrednosti ni stek - on zna koliki su ti argumenti i
po vrednosti, tako Sio kopira funkcija (,,nadole" je u ovom sludaju relativan pojam, jer vaS radunar moZe uma-
da se niihovim stavlianjem na stek prave tadne kopije' njivati ili povedavati wednost pokazivada tokom stavljanl'a podatataka na stek).
Rezr.rltat iunkcije f( j smesta se u registar. Da ponovimo,
prevodilac ima pot-
Ali, procesorska instrukcija CALL, stavlja na stek adresu programske naredbe
puneinformacijeotipurezultata,zatoStojetajtipugradenujezikiprevodilac
338
Misliti na jeziku C++ Poglavlje I 1 : Refererrce i konstruktor za koptranje
339
t
Moglobivampastinapametdarezultatsnimiteunekuglobalnuoblast
koristi instrukciia RETURN za waianie
na
pozivaniafunkciie
koia ie poz-vala funkciitr' Tu adresu funkcio- podataka, ali ni ovo ne bi bilo dobro' Moguinost ponovnog
meniati, ier program bez nie neie
mesro poziva. ow adresu n. ,*.,. bilo koju drugu funkciju, pa
postJinstrukciie CALL i dodele znaii da svaka funkcija moZe biti prekidnirutina za
nisati isprarmo. gro ttutl l'glt;" "ktit
steta ako siavite rezultat u globalnu-obl.utt' biste se
i za sebe samu. Prema tome, Tggli
funkciii: vaZi i u sludaju
skladiSta lokalnoi promenliivoi u *u,i,i, istu funkciju, Sto bi obrisalo upisani rezultat. Ista logika
rekurzije.
Argumenti funkcije JedinosigurnomestoukojemoZeteupisatirezultatjesteresistar,takodase
veliki za pri-
Sta da se radi kida registri nisu dovoljno
op"i *ueutJna problem:
Povratna adresa rezultata na stek' kao
f,iruturrl" rezultata. Re5enje ie da stavite adresu odredi5ta
i onda dozvolite funkciji da kopira powatnu
Lokalne Promenljive ledan od argumenata funkcije probleme, i to efikasniie. Zbog
informaciju [irektno u odrediSte. Ovo re5ava sve
pozove funkciju bigfun( ) u glamom programu
oiekuie da memoriia bude raspore- togu pr"rldilac, pre nego Sto
K6d koii se generiSe za ostatak funkcije objekta 82. lI asem-
paZljivo d.a bira izmedu argumenata
funkcije i auiot"t" lassingiligstrictures^.cpp, stavlja nastek adresu
skriveni
dena ba5 ovako, da bi mogao memorije' koji ut".rt o* rezultituia funkciiu bigfun( ), videiete da ona oiekuie ovaj
ne dira rezultat' ovaj blok
lokalnih promenliivih " Ji piri"# nazva(emo okuir argument i pravi kopiju na odrediStu, u funkciji'
sve sto iunkciji koristi procesu pozivania,
u
oredstavrja
'fitnkciie
@ngl. function frame\ '
Mo2etepomisliriauit'u"*nodapokuSatedastaviterezultatnastek'Pre-
Kopiranje bitova ili inicijalizacija
bi mogla da vrati pomerai koji bi Zasad nam dobro ide. Prona5ll smo .raein za prosledivanje
i waianje velikih'
vodilac bi mogao d" ih J;"; ; titk'
funkcija
^ rezultat' paZnju na to da znate samo naein za l(oplran]e
p"t"r""t"fit" daleko u steku podinje [Jnortarr.rif, sfiuktura. Obratite radi u C-u gde se promenliive
bitova s jednog mesta na drugo, Sio sifurn-o dobro
U objekti mogu biti.mnogo sloZe-
pot*uti";" na"tako primitivin nadin' C++-u
Ponovno Pozivanje fu nkci-1e u C-u i C++-u podrZavaju prekide; to nijiodjednostarmegomilebitova;oniimajuznadenje'Kopiranjebitovaobjekta
Problem se iavlia zbog toga Sto funkciie moZe IoSe uticati na znadenje objekta'
r"r,rtlla' Takode se podrzavaju i rekur-
iest, jez.ik omogucuie o";";;;;;;i'""i" moZe poiaviti bilo gde u toku izw- Razmotritelearortu.'a.r'primer:klasakojausvakomtrenutkuznakoliko
ziwi pozivi funkcija. r" )t"fl da se piekid
prekidnu objekata postoji. u poglavllu to ste videii da se ovakve
kiase prave ukljudivaniem
programa' Naravno' onaj ko pi5e
Savanja programa, bez naru5avanja wednosti u svim regi- statidkog Podatka dlana:
uspostavlianje
rutinu odgovoran je za duvanie i ponormo tiebi da koristi memoriiu jo.
strima ko ji se korisre , "f "il"ii "tt
prekidna rutina //: C11:HowManY.cPP
dublje u steku, to ," ;;;; 'uaiti ue'ueano'
(Prekidnu rutinu mozete zamisliti
// Klasa koia broii svoie obiekte
tipa void koja e uva i obnavlja #i ncl ude <fstream>
kao obiinu funkciiu ;;;;;;u1u
i
' ""'ttutom
nekim hardverskim dogadajem' a ne #include <string>
stanje procesora. prekidnalurine se poziva using namesPace std;
runkcija pokusala da wati wed- ofstream out ("HowManY.out") ;
'"';:t;..;:H,1il;;l] ., se des,o kada bi obidna
steka kojile iznad povratne adrese,
da dirate deo
nosti na stek. PoSto class
*ta"osti ispod powatne adrese' Kada se izlrsi adresu
".^."2"" proce- HowManY {
funkcija bi morala Ou
'tu' potu'i'ue mora pokazivati na powatnu static int objectCount;
sorska instrukciia nerUiN' publ i c:
'teka Neposredno pre izwSavanja
(ili ispod nie, Sto ,*iti oa vaSeg radunara)'
steka nagore' iime ie
pokazivad
HowManY0 { obiectCount++; )
nn)
instrukciie REIURN, funf<ci;a rno'u"a1-Ro1'eri static void print(const string& msg = (
Viednostiispod povratne adrese na steku' if(msg.sizeo l= 0) out " msg " "' "'
obrisati sve svoie f ,)rtuil1" p'l''enljive' bi pomerila
l,ostaitr ttgrozene " ;i;;;^;;
;;; J; p"kida Prekidna rutinai lokalne pro- out << "obiectCount = "
na stel svoiu povratnu adresu
r.rokaz.ivai .t.tu no,iot. Jlui .tuvltu << obiectCount << endl;
menliive, iime bi izbrisala va5 rezultat' da i
ovai problern bi t;;;';; tt1"sl ot" Sto-bi korisnik funkcije bio zaduZenc ne -HowManY0 {
zarezullatna steku. Medutim, lezik
prethodno zanzmedod-atnu memoriju u kratkim
objectCount--;
s jezikom c. Kao sto iemo
racli tako, u c** .nro',ilul.,a" r.o-putibilan Print("-HowManY0");
.;;. opisati' C++ koristi eflkasniie re5enie' )
);
340 Misliti na jeziku C++ Poglavlje I l: Reference i konstruktor za kopiranje 34t

int HowMany::objectCount = Q; Konstruktor za kopiranje


Problem nastaje zbog toga Sto prevodilac sam pretpostavlja kako da napravi
ll Prosleduje i vraca P0 VREDN0STl: noui objekat od postojedeg. Kada prosledujete objekat po wednosti, vi pravite
HowMany f(Howl,lany x) i novi objekat (prosledeni objekat u okviru funkcije), od postojeieg objekta (od
x.print("argument x f 0 ") ;
originalnog objekta koji se nalazi van funkcije). ovo je desto sludaj i kada waiate
return x;
objekat iz funkcije. \J izrazu:
)

HowMany h2 = f(h);
int main0 {
objekat h2 se ne inicijalizuje pozivanjem konstruktora, vei je napravl;'en od
HowMany h; rezultata funkcije f( ). I u tom slueaju novi objekat je napravljen od postojeieg.
Howl,lany: :print("pos1e inicijalizovanja vrednosti h") ; Pretpostavka prevodioca je da Zelite da napravite novi objekat kopiranjem
Howl"lany h2 = f (h);
bitova. U mnogim sludajevima ovo moZe dobro da radi, ali ne u sludaju klase
HowMany: :print("pos1e pozivanja funkcije f0") ;
HowMany. Inicijalizacija podataka ove klase predstavlja nesto vise od jedno-
I I ll:- stavnog kopiranja. Slidan primer je i klasa koja sadrZi pokazivade - razmislite da
Klasa HowMany sadrZi statiaki podatak celobrojnog tipa objectCount i Ii treba da kopirate adrese na koje oni pokazuju.
statiaku fr,rnkciju dlanicu print( ) koja ispisuje vrednost podatka objectCount, Sreiom, mozete sperediti prevodioca da kopira bitove. To iete uraditi tako sto
z-ajedno sa opcionim argumentima poruke. Svaki put kada se napravi objekat, iete sami definisati funkciju koju ie prevodilac koristiti svaki put kad god treba
konstruktor uveiava objectcount, i tako broji napravljene objekte. Kada se da napravi nov objekat od postojeieg. PoSto pravite nov objekat, logidno je da
uni5ti objekat, destruktor umanjuje tu wednost. ova funkcija bude konstruktor, kao i da njegov jedini argument ima veze s objek-
Medutim, rezultat programa ni,e ono sto biste odekivali: tom pomoiu koga se inicijalizuje wednost. Ali, objekat se ne moZe proslediti
posle inicijal izovanja vrednosti h: objectCount = 1 konstruktoru po wednosti, jer vi tek definiiete funkciju koja opisuje prosledi-
argument xu f0:
objectCount = 1 vanje po vrednosti, a sintaksnoi nema smisla da prosledujete pokazivad zato sto
-Howl,lany0: ob3ectCount = 0 pravite nov objekat na osnovu postojeceg. zato se koriste reference, pa je argu-
posle pozivanja funkcije f0: objectCount = 0 ment referenca na izvorni objekat. ova funkcija se naziva konstruktor za kopi-
-Howl4any0: objectCount = -1 ranje, a desto se obeleZava sa X[x&), Sto predstavlja opis konstruktora za
-HowMany0: objectcount = -2 kopiranje u klasi X.
Nakon Sto je napravljen objekat h, podatak objectCount ima wednost jedan, Ako napravite konstruktor za kopiranje, prevodilac neie praviti nov objekat iz
Sto je u redu. Ali, posle poziva funkcije f( ), odekujete da objectCount ima wed- postojeieg kopiranjem bitova. uvek ie pozvati konstruktor za kopiranje. Ako ne
nost dva, zato Sto se i objekat h2 takode nalazi u tekuioj oblasti vaLenla. Umesto napravite konstruktor za kopiranje, prevodilac ie uraditi nesto razumno, ali vi
toga, obiectCount ima vrednost nula, sto vam ukazije da se desila neka stra5na moZete potpuno da kontroli5ete ceo proces.
greSka. Ovo potvrduje i dinjenica da pozivanje dva destruktora na kraju pro- Sada je moguie otkloniti problem u datoteci HowMany.cpp:
grama daie negatir,rru wednost broja objekata, a to nikada ne bi trebalo da se //: C11:HowMany2.cpp
dogodi. // Konstruktor za kopiranje
Pogledajte Sta se de5ava u funkciji fO, nakon Sto je argument prosleden po #'i ncl ude <fstream>
wednosti. Originalni objekat h postoji van funkcije, a unutar funkcije se nalazi #i ncl ude <stri ng>
dodatni objekat koji je kopija prosledena po wednosti. Argument je prosleden using namespace std;
primitir,mim kopiranjem bitova u jeziku C. Da bi se odrZala celovitost podataka ofstream out ("HowMany2. out") ;
klase HowMany, neophodno je da oni budu pravilno inicijalizovani, Sto se
dohija jcdnostavnim kopiranjem bitova. class HowMany2 {
Kada se izade v. oblasti vaZenja na kraju poziva funkcije f( ), poziva se destruk- string name; // Identifikator objekta
tor lokalnog objekta x koji vrednost objekta objectCount umanjuje za jedan, tako static int objectCount;
publ i c:
da je van ftrnkcije vrednost ovog objekta nula. Objekat h2 se takode pravi kopira-
njem bitova, pa se ni tada ne poziva konstruktor, i kada se izade iz oblasti vaZenja
HowMany2(const string& id = '") : name(id) {
++obj ectCount;
h i h2, njihovi destruktori uzrokuju negativnu wednost objekta objectCount.
pri nt ( " HowMan y2 O ") ;
)
342 Misliti na jeziku C++ Poglavlje I I : Reference i konstruktor za kopiranle 343 t
-Howt4any2 0 1 name(h.name) u listi za inicijalizaciju konstruktora poziva konstruktor za kopi-
- -obj ectCount I ranje klase string.
print("-HowMany20"); U konstruktoru za kopiranje, brojad se uveiava za jedan, kao i u obidnom
) konstruktoru. To znadi da iete od sada dobijati tadnu wednost u brojaia, kada
// Konstruktor za kopi ranje: prosledujete ili waiate po wednosti.
Howl,lany2(const HowMany2& h) : name(h.name) { Funkcija print( ) je izmenjena tako da ispisuje poruku, identifikator objekta i
nare -= "kopija"; wednost brojada. Posto ta funkcija sada mora pristupati podatku name odrede-
++obj ectCount ;
nog objekta, ona vi5e ne moZe biti statidka funkcija dlanica.
print("Howl4any2(const Howl4any2&) ") ;
U glavnom programu dodali smo joS jedan poziv funkcije f( ). U ovom pozivu
)
se koristi uobidajeni pristup jezika C i zanemaruje se rezultat. Po5to znate kako se
voi d pri nt (const stri ng& msg = " " ) const {
if(msg.size0 l= 0) wednost vraia (to jest, k6d u funkciji obraduje powatni proces, stavljajuii rezul-
out << msg " endl; tatuodredi5tedijaseadresaprosledujekaoskriveniargument), zapitajteseStase
out << '\t' .. name << rr . 'r deSava kada se rezultat zanemari. Rezultat programa ie malo rasvetliti ovu temu.
<< "objectCount = " Pre nego Sto pokaZemo rezultat programa, evo jednog malog programa koji
<< objectcount << endl; koristi klase tokova za dodavanje brojeva redova datoteci:
) //: Cll:Linenum.cpp
); //(T) Li nenum. cpp
// Dodavanje brojeva redova
i nt Howl4any2 : : obj ectCount = 0; #incl ude " . . /requi re. h "
#incl ude <vector>
ll Prosledivanje i vracanje P0 VREDN0STI: #incl ude <stri ng>
HowMany2 f(Howl4any2 x) { #incl ude <fstream>
x.print("argument x unutar funkcije f0"); #incl ude <i ostream>
out << "Vracanje iz funkciJe f0 << endl; #incl ude <cmath>
return x i usi ng namespace std;

int main(int argc, char* argv[]) {


int main0 { requireArgs(argc, 1, "Upotreba: linenum datoteka\n"
HowMany2 h( h"); "Dodaje brojeve redova u datoteku");
out << "Ulazak u f0" << endl; i fstream i n (argv [1] ) ;
HowMany2 h2 = f(h); assure (in, argv [1] ) ;
h2.print("h2 nakon pozivanja funkcjje f0"); string line;
out << "Pozivanje funkcije f0 bez rezu'ltata" << endl; vector<string> lines;
f (h); while(getl ine(in, line)) // eita celu datoteku
out << "Nakon pozivanja funkcije f0" << end1. 1i nes. push_back (l i ne) ;
\ I I l,- if(lines.size0 == 0) return 0;
Ovde je ubadeno dosta novih redova da biste bolje shvatili Sta se deSava. Kao int num = 0;
prvo, podatak name se pona5a kao identiflkator objekta. Konstruktor moZe pro- // Broj redova u datoteci odreduje maksimalnu 5jrinu
slediti identifikator tipa znako\.nog niza (obidno je to ime objekta) koji se kopira u // potrebnu za ispisivanje brojeva redova:
podatak name koriSienjem konstruktora klase string. Podrazumevana wednost const int width = int(log10(lines.size0)) + 1;
je definisana kao ="", Sto daje prazan znako'v,ni niz. Konstruktor uveiava wednost for(int i = 0; i < lines.size0; i++1 1

podatka objectCount za jedan, a destruktor je umanjuje za jedan.


cout,setf (ios: :right, ios: :adjustfield) ;
cout.width(width);
Sledeii je konstruktor za kopiranje HowMany2 (const HowMany2&). Kon-
struktor za kopiranje moZe praviti nove objekte samo od postojeiih objekata,
cout << ++num << ") " << 1ines[i] << end'l;
)
Sto se ime postojeieg objekta kopira u podatak name, zatim sledi red ,,kopija'
tako da biste videli odakle to ime dolazi. Ako bolje pogledate, videiete da ime
) ///,-
345
Misliti na jeziku C++
Poglavlje I l, R"f"t"n." i kontt'ukt'
344
h poziva obidni konstruktor' koii
Kao Sto biste i odekivali, prvo se za objekat
(.ela datoteka ic uiitana u objekat tipa vector<string> tehnikom.koiu ste Ali, kada se ude u funkciiu f ( ), prevodi-
uveiava wednost obiectiotint na ledan.
virleli ranije Lr ovoi knjizi. Pri ispisivaniu brojeva redova' voleli
bismo da redovi prilikom prosledivanja po wed-
Iac posredno poziva tonsiruttor za kopiranje
znadi da Sirina polia za broieve redova mora biti
ti je obiekta h (odatle ime "h kopiia')
Srrclrr r.cclrrs.5ro a nosti. Napravljen ie novi oU;ttut, koji ko.pija
wednost obiect-
'ora'.ati,utvrditi llro j reclova koriSieniemiskaza vector::sizeo,
srtrgdc ista. t.itko tn07-crrro unutar funkcije tt). Zahvalul'ji tn"tt'uttoru za kopiranie'
ali irlt.,, je 6a z..a.r. rla li i.ra vi5e oci l0 redova, ili viSc
od I00, ili vi5e od 1000
Count Postaje dva'
u datoteci, zao- f( )' Pre nego Sto se
rr.rlova, itd. Akrt uznlctc logantanr sa osTlovom 10 broia redovas
potrebnu za
u redu osam nagoveStava se podetak waianja iz funkcije oblasti vazerl ja na
Sirinu (kada rzade
k^rlire g. na ceo br.1 i cliilate jedan, clobiiete maksimalnu se iz'
totatna promenljivi ,,f, topi;a" moZe uniStiti h2' koii
je h2' Objekat
kraju funkcije), mora ,. tlpituti u rezultat'
rspisir,anie bro jeva redova. a to objekat
pnmctiiete nekoliko dudnih poziva unutar petl,e for: setf( ) i width( )' ovo su po'i'ut'jem. ko.nstruktora' pravi se od postoieieg
zadate porav- ;r"ah;;; .,i;" iri.i;urlro,-it unltal iynkc]je f( ) - pa se u redu ponovo
pozivi izlaznih funkcija iz klase ostream koje omoguiavaju da objekta - Iokalne promenljive $e^vet
postaie
'nu.i. I Sirinu podataka koji se ispisuju. ove funkcije se moraju pozvati svaki put objekta h2
koristi konstrukror za k;i;";j; iada ime identifikalora ,,h
U drugom tomu' celo pogla- jest lotalnog oblekta unutar
t uao ." red ispisuie i z.boi toga ,u ot't u petlji for' kopije'
kopiranjem to
kopija kopija', jer je on
podataka o izlaznim funkci- "ut,uo tunkciie' obiectCount
vlje objaSnia,a klase tokova.'i., e"tt pronaii vi5e funkcije fO. Posle waianja oblekta, a pre zaw5etka lokalni objekat "h
unistava
iama, [ao i o drugim nadinima
za kontrolu k-lasa toka' priwemeno doUi;a wed.toJt tri, ai odmah zatim se
HowMany2' dobija samo dva objekta' h i h2'
Prinrenom programa Linenum.cpp na rezultat programa kopija'. Po5to je funtcija f( ) zawsena u redu I3' postoie
SE: p"'iJii" aa leoUletath2 zaista zawsio kao "h kopija kopija''
1) HowManY2 0
Z) h: objectCount = 1
Privremeni objekti
3) Ulazak u f0 se rezultat ignoriSe' Obratite
Red 15 podinie pozivom funkcije f(h)' pri demu
poziva da bi prosledio
4) HowMany2 (const Howl"lanY2&)
paZnju na to da se u redu 16 konstruktor za kopiranje
5) h koPija: obiectCount = 2 argument,kaoiranile.uredu2lsevididasekonstruktorzakopiranjepozivaza
6)argumentxuf0 mora imati
ranije' Ali' konstruktor za kopiranje
rezultat, sto je takode
7) h koPija: objectCount = 2 "U;"!"f """ (poiazivad this). odakle ta adresa dolazr?
ioi" preastavtlazai.iis,.
B) Vracanie iz funkcije f0 "a-."*
prevodilac moZe aa ;;p;;; pii*e*e.ti objekat kad god mu je.potreban
za
9 ) HowManY2 ( const HowManY2&)
'U. pravi priwemeni
prevodilac
isprarmo izradunava#'i;;" oror. sludiju,
10) h koPija koPjia: objectCount = 3 objekat, koji mi i n" ,|ai*o, i u niega smesta
ianemareni rezultat funkciie f( )'
11) da memorija ne bi bila
Zivotni vek tog p.i*";;;;; ou;"tti;t najkraii moguii
-HowManY20
12) h koPija: obiectCount = 2 Nekada se privremeni obiekat
L3) h2 nakon pozivanja funkciie f0 zatrpana nepotrebnim-piir,i.-l"i- objeitima.
pozivanja funkcije on postaje nepo-
I4) h koPlja koPija: obiectCount = 2 *oi, oa-uf, proslediti'funkciji, pa nakon pozivanjem destruktora za lokalni
15) Pozivanje funkcije f0 bez rezultata treban. U tom ,f"eu;u, fin-""'f"ttti;u izwsi
16) Howl4any2 (const Howt"lany2&) objekat (redovi 23i24),uniStava se priwerneni objeJcat 1*9"-: ??,:?'
a za njim i objekat h'
17) h koPiia: objectCount = 3 Konadno, u redovima 28-31, objekat h2 se uniStava'
wada na nulu' kao Sto treba'
1B) argument x unutar f0 otl"ttu objectCount
i *"arrort se

19) h koPija: objectCount = 3


20) Vracanie iz funkciJe f0
21) HowManY2(const Howl'4anY2&) Podrazumevani konstruklor za kopiranje
?2) h koPi j a koPi j a: obj ectCount = 4 Postosekonstruktorzakopiranjekoristiprilikomprosledivanjaiwaianjapo
vas u sludaju jednostavnih
23) -HowManY2 ( ) wednosti, vaZno je d" g" il;;Jilac napravi umesto
?4\ h kopiia: objectCount = 3 struktura, kao Sto radi i u C-u'
kopiranje bitova'
25) -HowManY2 ( ) Dosad ste videli samo podrazumevano prosto
Kada se radi o sloZenijim tipovima, C+i prevodilac ie i tada automatski pra-
?6) h koPija koPija: objectCount = 2
27) Nakon Pozivanja funkciie f0 vitikonstruktorzatopiranle,akogavinenapravite'Uovomsludaju'kopiranje
2B) -HowManY2 0 -
bitova desto nema smisla'
Recimo da pravite nolu
29) h koPi j a koPi j a: obj ectCount = 1
E ; primera inteiigentnijeg pristupa prevodioca
30) -Howl'4anY2 0 klasu koja se sastoji netotito postojeiih klasa. Ovoj klasi je dodeljen
3i) h: objectCount = 0 "i"Ui"(",""
odgovarajuii .,uriv Co-fo sils (kompoziila),
i onu predstavlia jedan od nadina
Misliti na jeziku C# Poglavlje I l, R"fut"n." i kontttukt 347 r
i
346

jednostavno obiavljuje da je
KIasaWithCC sadr2i konstruktor za kopiranje, koji
na koji mozete napraviti klasu od postoieiih klasa. Sada preuzmite ulogu
pitanje'.U klasi Composite' objekatklaseWithCC
pozvan - to pokeie zanimljivo
nai,,,nog korisnika krtji pokuSava brzo da reSi problem praveii novu klasu na ovaj konstruktora' Kada u klasiWithCC uopSte
ie pravl koriSienjem podrazumevanog
nacin. t)oSto ne znate z-a konstruktor za kopiranje, vi ga i ne pravite. Ovaj primer napravio podrazumevani kon-
ne bi bilo konstruktora, prevodilac bi"automatski
prikaztrje 5ta radi prevodilac dok pravi podrazumevani konstruktor za kopiranje Ako vi dodate konstruktor za kopi-
nove klasc:
,ii"t,"i koji u ovom sluiaiu ni5ta ne bi radio. konstruktore, tako da on vise
ranje, saopstili ste prevodiocu da Ste Sami napravili
I I : C1.1:Defaul tCopyConstructor.cpp ne treba da ih pravi. Prevodilac ie se buniti ukoliko
izriiito ne napravite podra-
// Automatsko pravl jenje konstruktora za kopi ranje ,u*"ru.ti konsiruktor, kao Sto je uradeno za klasuWithCC'
#i ncl ude <i ostrearTl>
KlasaWoCCnemakonstr.,kto.,ukopiranje,alinjenkonstruktorieSmestiti
#i ncl ude <stri ng> funkciiom
porrrf" u unutra5nju promenljivu tipaitring koja se moZe ispisati
usi ng namespace std; konsirukto. ," izridito poziva u listi inicijalizatora konstruktora
;;i*ij. Ovaj
'nur"'Co*posite (Sto je ukratko predstavljeno u poglavlju B, a biie detalino
class WilhCC \ ll Sa konstruktorom za kopiranje kasnije'
Ltrua".ro u poglavlju I4). Razlog za ovo postaie odigledan
publ i c:
Klasa composite sadiZi objeite ttase wittrcc i klase
wocc (primetite da je
I I lzri ai to se navodi podrazumevani konstruktor: kao Sto i
l,ijthcc0 {} ugradeni objekatwocc i.rl.llato,rurl u listi inicijalizatorakonstruktora,
konstruktor za kopiranje' U glavnom
i^li thCC (const i^]i thCC&) mora da bude), i nema izrieito definisan
{
kopiranie u definiciji:
cout << "l^li thCC (l^li thCC&) " << endl ; programu, objekat se pravi kori5ienjem konstruktora za
) Composite cZ = c;
)r Prevodilac automatski pravi konstruktor za kopiranje
klase.Composite' a

cl ass l^loCC { I I Bez konstruktora za kopi ranje


."rrlo, programa otkriva nadin na koji je taj konstruktor napravlien:
stri ng i d; SadrZai objekta c: Composite0
publ i c: Pozivanje konstruktora za kopiranje klase Composite
l4oCC(const string& ident = "") : id(ident) {} r,li thcc (t.li thcc&)
voi d pni nt (const stri ng& msg = 'r " ) const { SadrZai obiekta c2: Composite0
if(msg.size0 != 0) cout << tlrsg << ": "; je kompozicija obiekata
cout << id << endl; Da bi napravio konstruktor za kopiranje klase koja
u poglavlju
)
p"""jJih klasa (ili koiisti nasledivanie, koje ie biti predstavljeno
svih objekata dla-
iai p."uoaifac rekurzilrro poziva konitruktore za kopiranje
); neki drugi objekat' kon-
nova i osno'u'ne klase. fo jeit, ako objekat dlan sadrZi
sluiaju' prevodilac
c1 ass Composi te i struktor za kopiranje tog'objekta se iakode poziva' U tom da je pokazuie
VJithCC withcc; ll Ugradeni objekti p"ri"" tr"t"rtto. ,u toilranle klase,Witlr^Cc' Rezultat programa
za kopiranje pre-
WoCC wocc; ir4 to"to"f.tor pozivan. Po.fo klasaWoCC nema konstruktor' i po-zvl|e ga u kon-
publ i c: vodilac (e za nfit.rup.*iti konstruktor koji kopira bitove'
u glavnom
Composite0 : wocc("Composite0') () struktoru za kopiranle klase composite. Poziv composite::print( )
identidan
nt (const stri ng& msg = ) const p"kazuje du r" to de.ava zato Sto je sadrZaj objekta c2.wocc
rr
voi d pri " {
;;;r;;
wocc . pri nt (msg ) ; pravljenja ovakvog konstruktora zove se
iualzulu objekta c.wocc. Postupak
I iniciializacija ilan po ilan (engl' memberwise initialization) '
umesto da to radi
i; Uvek je bolje da'sami nup.Jvit" konstruktora za kopiranje'
prevodilac. To garantuje da ie konstruktor biti pod va5om kontrolom'
jnt main0 {

Composite c;
c.print("SadrZaJ obiekta c") ; ZaobilaZenje ko n stru i sanja kopi rani gm.
klasa koja ra.di, bez kon-
cout << "Poziva se konstruktor za kopiranje klase Composite" Sada se mozdadudite kako se uopste inoZe napraviti
<< endl; zupu*tlt",^tonstruktor za kopiranje vam treba samo ako
struktora za kopiranje.
vam
Composite c2 = ci ll
Poziva konstruktor za kopiranje
;;;i"d"l;" ouj.tui klase po urednosti' Ako se to nikada ne desava' onda
c2.print("Sadriaj obiekta c2") ; konstruktor za kopiranje i ne treba'
) I ll,-
Poglavlje I l: Reference i konstruktor za kop 349
Misliti na leziku C++
348

Iz ovoga sledi da je, sa stanovista odrZavanja koda, bolje koristiti pokazivade


Spreiite prosledivanje po vrednosti ie ga kada proiledujete airesu argumenta koji ie se meniati. Ako uuek prosleduiete
kons.truktor za kopiranje' prevodilac
nt-nlr"i"'"
,,Ali", kaT.ete vi, ',ako neie pro- adresu kao referencu na konstantu (oslm kada nameravate da meniate spoljni
da znam da se obiekat nikada
naprar,iti rrnrcsto nrentt t)ai<le' kako ia objekat preko te adrese, pa prosledujete obiian pokazivae), iitalac ie mnogo
sledivati Po wednosti?" po lakSe pratiti vaS kOd.
spredavate prosledivanie objekta
Postoji jednostavan posttrpak koiinr da ga
toi z'a kopiranie',Ne.1grate,dak
vrertnosri: cteklarisite ori';;,;;i;".ir,,t da pro-
defir.risete, osim ako ,-,"tu'i.,nt.i1u
dlanica iri prijateriska funkciia treba Pokazivaii na ilanove
pokuSa da vrati ili prosledi
slecitrje obickat ,ng tipo'|n'"ttfit"tti f]<o.fgr,lsnit Pokazivadjepromenljivaukojojseduvaadresanekememorijskelokacije.Vi
objekat po vreclnosti, p''"'odilac ie
prijaviti gre5ku zato Sto ie konstruktor za
podraz-umevani kon- mozete promeniti o.o .,u Sta pokazivad pokazuje za weme iz-wSavania, a odre-
kopiranic privatall. f""""aif"l 'iSe ne mo7-e da napravi di5te potazivada moZe biti podatak ili funkcija. Pokaziuai na il.an u C++-u radi
da vi preuzimate tai posao.
.ir',.,t,,ri ziito sto ste iz.ritito rekli slidno kao i obiian pokazivad, ali on pokazuje na lokaciju unutar k]ase. Problem
je
pokazivanje na
L,vo Primera: u tome Sto pokazividu treba adresa, a unutar klase nema,,adrese";
I I : Cll: NoCoPYConstructi on ' cPP dlana klase znadi radunanje pomeraja u odnosu na podetak objekta. Ne mozete
konstruktor za kopiranje napraviti pravu adresu bez kombinovanja tog pomeraja sa podetnom adresom
// Spreeavamo ptuuod'ioca da napravi
odiedenog objekta. Sintaksa za korisienje pokazivada na elanove zahreva da se
class NoCC i navede objekat.
poka-
i nt i ; Da biste razumeli ovu sintaksu, razmotrite jednostavnu Strukturu sa
NoCC(const NoCC&); // Nema definicije zivadem sp i objektom so. Na ilanove mozete pokazivati koriSieniem prikazane
publ i c: sintakse:
NoCC(int ri - 0) : i(1i) {}
: Cll:SimpleStructure.cPP
I I
i; struct SimPle { int a; };
int main0 {
vord f(NoCC); Simple so, *sP = &so;
sp->a I
int maln0 {
so. a;
NoCC n;
/ lt f(n\: // Gre5ka: pozvan je
konstruktor za kopiranje I lll,-
konstruktor za kopiranje
))'oitit'u' po"un je,konstruktor pretpostavite da imate obidan pokazivad, ip, na celobrojnu promenljivu.
iii ;:;i' ^lr' =
n3(n);
^,ll ct"ilu' pozvan ie za kopiranje
Sada
Da biste pristupili onome na Sta ip pokazuje, treba da dereferencirate
pokazivad
//l NoCC
*:
\ I I t,- operatorom
Primetite uopSteniii oblik deklaracije:
*iP = 4i
i pokazuje
NoCC(const NoCC&) ; Na kraju, razmotrite pokazivad koji predstavlja pomeraj u objektu
na pokazivad poka-
na nesto unutar objekta klase. Da biste pristupili onome Sta
s rezervisanom redju const' *' AIi, to je pomeraj u objektu' pa
,"j" -o.u," ga deieferencirati operatorom
* dereferencira-
morate pristupiti tom objektu. Zito se operator kombinuje s
Funkcije koje menjaju spoljne ob-jekte njemobjekta.Prematorn",.touusintaksazapokazivadnaobjekatie->*'aza
SirltaksareferencijelepSa<'rdsintakse.pokaztvada,alionaobmanjujeditaoca.Na
verziia funkcije get( ) menja wednost objekat ili referencu je .*. Evo primera:
primer, r-r biblioteci ioiLt' preklopliena ow funkciju, niie vam an =
koii koristi 47 ;
arg'men,, ,ipu-.nu.g.'iuau ei,u," k.d
pokazivacNa0bjekat->*pokazivacNaCl
svog
cla se spolini obiekat menja: objekat.*pokazivacNaClan = 47;
naiuf-l?elgf.dno
Kakosadaizgledasintaksazadefinisanjepokazivadanadlan?Kaoizasvaki
char c;
pokazivai, *orit" odrediti tip podataka na koji se pokazuje' i koristiiete
opera-
cin'get(c); klasu objekata uz
po vrednosti' Sto nagove5tava da se tor * u definiciji. Iedina razlikale u tome sto molate definisati
Poziv fr.rnkciie iz'gleda kao prosledivanie i;j" ;" koristi ovaj pokazivad. Klasa se, naravro, definise koriSienjem imena
spolini ohiekat ne menia' klase i operatora razre5enja opsega. Prema tome, iskaz:
i nt Kl asa: : *Pokaz i vacNaC'l an;
350 I
I

Misliri na jeziku C++ Poglavlje I I : Reference i konstruktor za kopiranje 35r I

clefini5e pokazi,a- na cran koji se zove pointerToMember


i pokazuje na celo. Zagrade takode igraju vaZnu ulogu kada definiSete i koristite pokazivade na
brojnu prorre,ljivu .nLrtar klasc objecttlass. pokazivad
na dlan mozete iinici. funkcije dlanice. Pokazivad na funkciju u klasi definiSete tako Sto umeiete ime
jalizor.,ati kada ga clefiniSere (ili u
bilo koje vreme):
klase i operator razreSenja opsega u definiciju pokazivada na obidnu funkciju:
int Klasa::*pokazivacNaClan = &Klasa::a;
ovde reraa ,,adrest:" oblekta Klasa::a, zato sto se pozivate /I : Clll.PmemFunDefini tion.cpp
na krasu, a ne na class Simple2 {
objekat re klase. Prcnra rome, &Klasa::a se moZe koristiti samo kao sintatsa poka_ publ i c:
z.ivaia na clan. int f(f1oat) const { return 1; }
Evo primera pravljenja i upotrebe pokazivada );
na podatke dlanove:
/ :
I Cll: Po i nterTot4emberData. cp int (Simp1e2::*fp) (float) const;
#i ncl ude <i ostneam> int (Simple2::*fp2) (f1oat) const = &Simple2::f;
using namespace std; int main0 {
fp = &Simp1 e2: : f;
c1 ass Data ( l //t:
pub) i c: U definiciji za fo2 vidite da se pokazivad na funkciju dlanicu takode moZe ini-
int a, b, c; cijalizovati kada je napravl;'en, ili u nekom drugom trenutku. Za raz\ktt od obid-
voi d pri nt 0 const { nih funkcija, operator & je obauezanpri ditanju adrese funkcije dlanice. Medutim,
cout << "a = ".. a.. ", b =', << b identifikator funkcije moZete navesti bez liste argumenata, zato sto se prekla-
.. ", C - ,, .. C .. gndl; panje razre5ava na osnovu tipa pokazivada na dlan.
l
);
Primer
int main0 { Pokazivadi su znadajni zato sto tokom izw5avanja programa moZete promeniti
Data d, *dp = &d; ono na Sta on pokazuju. Pokazivadi omoguiavaju fleksibilnije programiranje, jer
int Data::*pmlnt = &Data::a; moZete menjati ponaSanje u toku izvr5avanja programa. Isto je i s pokazivadem
dp->*pmlnt = 47; na dlan; on vam dozvoljava da pokazujete na dlan za vreme izwSavanja. Klase
pmlnt = &Data::b; najdeiie imaju samo javne funkcije dlanice (podaci dlanovi se uglar.nom sma-
d.*pmlnt = 48; traju delom interne realizacije), tako da u sledeiem primeru pokazivad pokazuje
pmlnt = &Data::c; na funkcije dlanice tokom izw5avanja programa:
dp->*pmlnt = 4g;
dp-'pri nt 0 ;
/ I : Cll: Poi nterToMemberFuncti on. cpp
j /l I ,-
#'i ncl ude <i ostream>
using namespace std;
oiigledno
da je ovo previse nezgodan nadin da biste ga koristili
ma gde sem u
specijalnim slucajevima (kojima su ovi pokazivadi i nam"enjeni). class hlidget {
Pokazivadi na dlanove su takode
u.o,.u ogranideni: o.ri ,.og, biti dodeljeni publ i c:
samo prosebnim lokacijama unutar klase. Ne moZete,
nu pii-"., uveiavati void f(jnt) const cout << "Wi dget: : f0 \n";
njihove vrednosti, ili ih uporediti, kao sto moZete sa
obidnim pokazivadima. voi d g (i nt) const cout << "l,lidget: :90\n";
void h(int) const cout << "Wi dget: : h 0 \n";
void i (int) const cout << "liidget::i ()\n";
Fu n kc ije );
slidnim postupkom iemo dodi do.sintakse pokazivada
na runkciju dranicu. poka-
zivae na funkciju (koji je predsravrjen na krilu poglavrja 3) deflnise ," oruto, int main0 {

int (*fp) (ftoat); Widget w;


Widget* wP = &w;
zagrade oko (+fp) su neophodne da bi prevodilac pravilno voi d (Wi dget: : *pmem) (i nt) const dget: : h;
razumeo definiciju. &Wi
Beznjih, bi to oznadavalo funkciju koja waia pokazivad tipa (w.*pmem) (1);
int*.
(wp->*pmem) (2) ;
) // l:-
Misliti na jeziku C++ Poglavlje I I : Reference i konstruktor za kopiranje 353
352

proseian korisnik pravi ovako kom- po5to se ime g pojavljuje u funkciji dlanici, 5to automatski znadi da je u oblasti
NaraVr.r() cla rrije r.lzulnno ocekivati cla
plrkovalrc iz.raz.e. Ako korisnik mora direktno da radi s pokazivadem na ilan' vaZenja klase? Problem je Sto se ovo ne slaZe sa sintaksom za pokazivad na dlan,
a moralo bi, da bi svi, posebno prevodilac, shvatili Sta se de5ava.
onciabitrebalodadehniSeteitipiskazomtypedef.DabisteStvarnorasdistili
realiza- Sintaksa za dereferenciranje pokazivada na dlan izgleda suvi5e specifidno:
interne
itunri, puturivac na ilarl moZete^koristiti kao deo mehanizma
cijc. I:r'o prethoclnog pritnera rt kome sada koristimg notar*u: n3 d\an unutar (this->*fptrlil)(j);
klasc.Korisrtiksamotrebadaprosledibrojkoiimieizabratifunkciju:' Izgleda kao da je pokazivai this suvi5an. Da ponovimo, sintaksa zahteva da
I I : CII: Poi nlerTol'4emberFuncti on2 ' cpp pokazivad na ilan uvek bude vezan za objekat kada se dereferencira.
<iostream>
'include
us r ng namesPace std;
Sa2etak
cl ass l/i dget { Dobro je Sto su pokazivadi u C++-u skoro identidni pokazivaiima u C-u. U
vojd f (int) const cout << "Widget: :f0\n"; suprotnom bi C++ prevodilac nepravilno preveo mnogo koda sa jezika C. Gre5ke
void g(int) const cout << "l^li dget: : S 0 \n" ; u prevodenju nastaju pri rizidnim dodelama wednosti pokazivaia; otklanjaju se
void h(int) const cout << "l^li dget: : h 0 \n" ; jednostavnom (i izriditom!) konverzijom.
void i (int) const cout << "l,,li dqet: : i 0 \n" ; C++ takode dodaje referenceizjezika Algol i Pascal, koje su kao konstantni
enum { cnt = a ); pokazivadi koje prevodilac automatski dereferencira. Referenca sadrZi adresu,
voi d (Wi dget :*fptrIcnt] ) (int) const; ali vi s njom radite kao s objektom. Reference su najznadajnije za distu sintaksu
publ i c: preklapanja operatora (Sto je tema sledeieg poglavlja), ali takode dodaju i sin-
l^lidget 0 { taksna pravila za prosledivanje i wadanje objekata u sludaju obidnih funkcija.
fptr [0] dget: // Zahteva se puna sPecifikact.la
= &Wi
Argument konstruktora za kopiranje je referenca na postojeii objekat, i koristi
fptr[1] = &VJidget:
se za pravljenje novog objekta od postojeieg. Prevodilac automatski poziva kon-
fptr[2] = &l^/1dget:
struktor za kopiranje kada prosledite ili watite objekat po wednosti. Iako ie pre-
fptr[3] = &Wl dget:
vodilac automatski napraviti konstruktor za kopiranje, bolje je da ga sami
) napravite, jer Cete tako obezbediti njegovo pravilno ponasanje. Ako ne Zelite da
void select(int i' int i) { r" obl"kut p.osleduje ili vraCa po vrednosti, treba da napravitc privatan kotrstrttk-
if(i 0 <
ll i'= cnt) return; tor za kopiranje.
(thi s-'"fptrIl] ) (i) ; pokazivadi na dlanove imaju istu funkcionalnost kao i obidni pokazivadi.
) odredeni deo memorije (podatak ili funkciju) mozete izabrati za weme izwsa-
i nt count ( ) { return cnt; }
vanja programa. Jedini razlika je u tome 5to pokazivadi na dlanove rade sa ila-
); novima klasa, a ne sa globalnim podacima ili funkcijama. Korisienjem ovakvih
pokazivada moZete menjati pona5anje u toku izw5avanja programa'
int main0 (

!li dget w;
fo.iint i = 0; i < w'countl;t i++)
VeZbe
w.select(i' a7); ReSenjaovihveZbinalazeseuoblikuelektronskogdokumentaThe,t.hi*inginC++AllllototedsolutioilGuidt,
\ !ll,- da le celokuPna realizacila'
m BruceEckel com'
koii moZete preuzeti sa lokacije

interfcisu klasc i u glavnom programu^v d te I . Od dela koda u odeliku ,,Pokazivadi u jeziku c++", na
podetku ovog pogla-
I.J
count( ) eiti se broi funkcija u inter- jeziku C (koristeii strukture za tipove poda-
,,ol;,,;.,;;;ii i.,"rtii"' skrivena Funkciiom da ,rqa, napravii" progiu* na
autor klase moZe da promeni broi funkcija, a prevodi' pokuSajte da ga prevedete
noi realiz-aciji. Na oval na'in taka), i potaZite aaie on uspesno Sada
koristi'
,,;;; na kod tikn*" se ta klasa
""i"i.ii"iir".iia u konstruktoru moZe izgledati suvi5e sPeci-
prevodiocem zaC++ i pogledajte Sta se deSava'
";;; pokazivada na dlan
2'Delovekodakojisenalazenapodetkuodeljka,,ReferenceujezikuC++..
n.;;.';; ;; i.,iste mogli iednostavno da kazcte: stavite u glavni irog.u*. Dodajie iskaze zaispisivanje rezultata
koji
da biste se
automatski derefe-
uverili da ," ."rir"ri"" ponasaju kao pokazivaii su
fptr[1] = &s;
rencirani.

I Zahvalirrient s0 O\\'enLr N'lortcnsentl za ovitj prlmer


355
r
avlje I l: Reference i kontttrkto, =" kopi"nje
I

354 Misliti na jeziku C+r

16. Napi5ite klasu sa konstruktorom za kopiranie koji ispisuie.poruku


u tok
3. Napiiite prograrn u kome iete poku5ati: (l) da napravite referencu koja te.klase'
nije inicijalizovana kada je napravljena, (2) da izmenite referencu tako da Sudu napravite funkciju koja prosleduje po lrednosti objekat
se nakon inicijaliz.acije odr.rosi na drugi objekat, (3) da napravite referencu i drugu zuntiilu koja pravi lokalni objekat klase iwaia ga po wednosti'
"orrt.
pozoite ove funkcije ai blste se uverili da se konstruktor za kopiranje zaista
weclnosti N(l[.1..
neprimetno pozivapri prosiedivanju i waianju objekata po wednosti'
4. NapiSite funkcijrr ciji je argr.rrnent pokazivad, koja menja ono na Sta argu- inicijali-
ment pokazuje, i vraia odrediSte pokazivada kao referencu. 17. Napravite klasu koja sadrZi pokazivad tipa double*. Konstruktor
zulL tal pokazivad pozivanjem funkcije new double i dobijenom skladistu
5. Napravite klasu s nekoliko funkcija dlanica. Prepravite program izveLbe4 poka-
dodeljuie wednosi argumenta. Destruktor ispisuj e wednost na koju.
tako cla argllment pokazuje na objekat nove klase. Pokazivad treba da bude joj wednost -1, poziva operator delete' i onda
zivae pokazuje, dodellule
konstantan i pojecline lunkcije dlanice treba da budu konstantne i doka- Sada napravite funkciju kojoj se prosleduie
postavlja po(azivae
2ite da u funkciji moZete pozvati samo konstantne funkcije dlanice. Neka "i ""iu.
oUlukaft" t t"se po wednosti, i pozovite ovu funkciju u glarmom programu'
argument iunkcije bude referenca umesto pokazivada.
Sta se de5ava? iJklonite probiem tako Sto iete napisati konstruktor
za
6. Napravite program od delova koda koji se nalaze na podetku odeljka,,Refe- kopiranje.
rence na pokazivade".
l8'Napravitek]asuskonstruktoromkojiizgledakaokonstruktorzakopiranje,
7. Napravite funkciju diji je argument referenca na pokazivad na pokazivad, aliloji ima dodatni argument podrazumevanom wednoSiu' PokaZite da
s
koja menja taj argument. Pozovite tu funkciju u glarmom programu. se ipak koristi kao konstruktor za kopiranje"
8. Napravite tirnkciju iiji argument je referenca tipa char&, koja menja taj 1 9. Napravite klasu s konstruktorom za kopiranje
kojiispisuje poruku' Napra-
argunrcnt. IJ glavnorn programu ispisite promenljir,u znakovnog tipa, pro- vite drugu klasu koja sadrZi objekat prve klase, ali nemojte da napravite
sleclite tu promenljilr-r funkciji, i ponovo je ispi5ite da biste se uverili da se konstruftor za kopiranje. FokaZite da konstruktor za kopiranje iz druge
promenila. Kako ovo utide na aitl,ivost programa? klase, koji ie napraviti prevodilac, automatski poziva konstruktor
za kopi-
9. Napravite klasu koja ima jednu konstantnu i jednu obidnu funkciju dlanicu. ranle iz prve klase.
NapiSite tri furnkcije diji je argument objekat te klase: prvoj se prosleduje po 20. Napravite veoma iednosta\Tlu klasu i funkciju koja waia po wednosti obje-
wednosti, drugoj po referenci, a treioj po referenci konstante. Poku5ajte da kaf te k1ase. Napravite drugu funkciju eiji je argument referenclnl objekat
tu funkcijama pozovete obe funkcije dlanice vaSe klase i objasnite dobijene
te klase. Kao argument druge funkcije, pozovite prvu funkciju' Pokaiite
da
rezultate. druga funkcija mora koristiti referencu na konstantu kao argument'
10. (Malo teZi zadatak) Napi5ite jednostavnu funkciju diji je argument celo- 21 . Napravite jednostavnu klasu bez konstruktora za kopiranje, i
jednostarmu
bro jna vred nost, koja uveiava tu vrednost za jedan i waia je. Pozovite funk- tuntcilu tolol se prosleduje objekat te klase po wednosti Sada promenite
ciju u glal,norn programu. Sada otkrijte kako prevodilac pravi asemblerski klasu iako Sto iete dodati privatnu deklaraciju (samo1 za konstruktor
za
kOd i pregledajte iskaze tog koda da biste razumeli kako se argumenti pro- kopiranje. Objasnite Sta se de5ava kada se funkcija prevede"
sleduju i r,raiaju, i kako se lokalne promenljive smeStaju van steka.
22.UovojveZbipravimoalternativukori5ienjukonstruktorazakopiranje.
I I . Napi5ite flnkciju s argumentima tipa char, int, float i double. U asembler- Napravite klaru x i d"k]*isite (ali nemojte da definisete) privatan konstruk-
skom kodu koji je napravio prevodilac pronadite iskaze kojima se argu- toiza kopiranje. Napravite javnu funkciju clone( ) kao konstantnu funkciju
menti stavljaju na stek pre poz-iva funkcije. dlanicu koja waia kopiju objekta napravljenog operatorom new' Sada napi-
12. Napi5ite firnkciju koja vraia broj tipa double. Prevedite je na asemblerski Site funkciju diji je argumLnt referenca na konstantu tipa X& i klonira
kod i utvrdite kako se vrednost waia. Iokalnu topilu [oja moie da se menja' U ovom pristupu je nezgodno 5to vi
r3 Napravite asemblerski kdd za datoteku PassingBigStructures.cpp. Pre- morate izrieito uni5titi klonirani objekat (operatorom delete) kada sa njim
gledajte k6d i otkrijte nadin na koji prevodilac pravi k6d za waianje i pro- zavrSite rad.
sledivanje velikih struktura. 23. Objasnite nije u redu u datotekama Mem'cpp i MemTest'cpp' iz pogla-
Sta
t4 NapiSite jeclnostavnu rekurzi'u.nu funkciju koja umanjuje svoj argument za vlja 7. Uklonite Problem.
jedan i waia nr.rlu kada vrednost argumenta postane nula, a u suprotnom 24. Napravite klasu koja sadrzi broj tipa double i funkciju print( ) koja ispisuje
poda-
se sama ponovo poziva. GeneriSite asemblerski k6d za ovu funkciju i obja- taj troj. U glamom programu napravite pokazivade na dlanove i za
snitc kako nadin na koji prevodilac pravi kdd podrZava rekurziju. tak dlan i za funkciju 6linicu. Napravite objekat i pokazivad na taj objekat,
t5 NapiSite kod kojim iete dokazati da prevodilac automatski pravi konstruk- i radite sa oba elementa klase preko pokazivaia na dlanove, koristeii i
tor za kopiranje, ako ga vi sami ne napravite. DokaZite da taj konstruktor objekat i pokazivad na objekat.
z.a kopiranje kopira hitove prostih tipova i poziva konstruktor za kopiranje
klasa ko je je clefinisao korisnik.
356 Misliti na jeziku C++

25 NapraviteklasukojasadrTinizcelobrojnihvrednosti.DalimoZetedadode.
liteindeksnebroieveilanovimanizaupotrebompokazivaeanadlanove?
preklopljene
26 Iz-menite clatoteku PmemFunDefinition'cpp dodavanjem
ftrnkcije elanice f( ) (moZete da utwdite listu argumenata
toja Ce \zazvati
pokazivai na dlan' dodelite ga preklo-
freklapanie). Sada napravite drugi tog pokazivada' Kako
funkciie f( ), i pozovitl tunkciiu preko
i,ii.r"ir.iriri
se ovde razre5ava PreklaPanje?
koia
2 7. Poinite s datotekom FunctionTable'cpp iz poglavlja 3' Napravitetlasu
sadrZivektorpokazivadanafunkcije.I{asatakodetrebadasadrZifunkcije
dlaniceadd()iremove()kojesluZezadodavanjeiuklanjanjepokazivada
na funkciie. Dodajte i funkiiju run( ) koia se kreie kroz vektor
i redom
poziva sve funkciie'
28.IzmenitereSenjevelbe2Ttakodaradispokazivadimanafunkcijedlanice.

l,r
l,:,

iit,
$t.
i-.,
j-.
i ','
it ..
I,
l:
II
t'.
L.
["
i i".'
i'
i"
;r
I

Ii
tt.,

,I2: PREKLAPANJE oPERAToRA


l\

:'
i Preklapanje operatora je samo ,,sintaksna poslastica', Sto znadi da
i
I
je to joS jedan nadin zapoz.walje funkcije.
I
I
Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 3s9
l-
358

Postoje dve razlike izmedu upotrebe operatora i obidnog pozivanja funkcije. 2. definisan kao globalna funkcija (s jednim argumentom za unarnu funk-
Sintaksa je drugadija; operator se eesto poziva tako Sto ga stavljate izmedu argu- ciju, odnosno dva argumenta za binarnu funkciju), ili kao funkcija dlanica
menata, ili ponekad iza argumenata. Druga razlika je u tome Sto prevodilac (bez argumenata za unarnu funkciju, odnosno s jednim argumentom za
odredr,rje koju ,,funkciju" ie pozvati. Na primer, ako koristite operator sabiranja binarnu funkciju - objekat postaje levi argument).
za argumente u formatu pokretnog zareza, prevodilac ie ,,pozvati" funkciju koja Evo male klase koja prikazuje sintaksu za preklapanje operatora:
ie sabrati brojeve u formatu pokretnog zareza (ova),,poziv" tipiino predstavlja
umetanje koda ili procesorske instrukcije za rad s pokretnim zarezom)' Ako / /: Cl?:lperatorOverl oadl ngSyntax.cpp
#i ncl ude <i ostream>
koristite operator + za sabiranje u format pokletnog zareza i celog broja, pre- using namespace std;
vodilac ie ,,pozvati" specijalnu funkciju koja celobrojnu wednost konvertuje u
broj u formatu pokretnog zareza, a onda ,,poziva" k6d koji sabira brojeve u fol- class Integer {
matu pokretogzarcza. int i;
Ll c++-u je moguie definisati novo znaienje operatora koji rade s klasama. publ i c:
ova definicija je ista kao definicija obidne funkcije, samo sto se ime funkcije Integer(int ii) : i(ii) {}
sastoji od rezervisane reii operator, iza koje sledi operator. Operator posta;'e const Integer
obidna funkcija koju prevodilac poziva kada vidi odgovarajuii obrazac. operator+(const Integer& rv) const {
cout << "operator+" << endl;
return Integer(i + rv.i);
Na 5ta treba obratiti paZnj u )
MoZete doii u iskuSenje da preterate s preklapanjem operatora. u podetkuje to I nteger&
zabavna igradka. Zapamtite, ro je samo ,,sintaksidka poslastica", jo5 jedan nadin operator+=(const Integer& rv) {
z,a poz,ivanje funkcije. Gledajte na to ovako: nema razloga da preklapate opera- cout << "operator+='' << endl ;
rore osim kada to olaksava pisanje, a posebno iitanjekodau kome se pojavljuje i +- rv.i;
klasa. (Setite se da se k6d vise puta dita nego Sto se pise.) Ako ovo neiete postiii, return *thi s;
nemojte se muditi sa preklapanjem. )
I.
Iedna od uobiiajenih reakcija na preklapanje operatorajeste i panika: odjed-
nom operatori u c-u nemaju uobidaieno znadenje. ,,Sve se promenilo, i sav moj
k6d na jeziku C ie raditi neSto sasvim drugo!" To nije istina. Znadenje operatora
int main0 {

u izrazima koji sadrZe samo ugradene tipove podataka ne moZe se promeniti.


cout << "ugradjeni tipovi:" << endl;
inti=1,j=2,k=3.
Nikada ne moZete preklopiti operator tako da se izraz:
k += i + j;
1 << L. cout << "objektni tipovi:" << endl;
ponaSa drugatije r.rego Sto se oiekuje, ilidaizraz: Inteser i i (1), jj (2), kk(3);
kk += 'i i + ji;
1.414 << 2;
| ///,-
ima smisla. Preklopljeni operatori se koriste samo u izrazimakoji sadrZe objektne Dva preklopljena operatora su definisana kao umetnute funkcije dlanice koje
til.love podataka. ispisuju poruke. Funkcije binarnih operatora u klasi imaju samo jedan argument
- desni operand. Unarni operatori nemaju argumente kada su definisani kao
funkcije elanice. Funkcija dlanica se poziva za objekat sa leve strane operatora.
Sintaksa Operatori koji nisu uslovni (uslormi operatori uvek vraiaju logidku wednost),
Definisan je preklopljenih operatola slidno je definisanju funkcila, pri demu je ime skoro uvek waCaju objekat ili referencu istog tipa kao Sto su operandi, ako su
te funkcije operator@, gde simbol @ predstavlja operator. Broj argumenata u listi oba argumenta istog tipa. (Ukoliko argumenti nisu istog tipa, na vama je da
argumenata preklopljenog oparatora zavisi od toga da li je operator: odludite Sta ie se waiati.) Na ovaj nadin se mogu napraviti komplikovani tzrazi:
I . unarni (s jednim argumentom) ili binarni (s dva argumenta); kk += i.i + jj;
Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 36r

Operaror sabiranja (+) proizvodi nov (priwemen) objekat klase Integer, koji // Sufi ks:
se koristi kao desni operand argument rv za operator dodele uz sabiranje (+=).
friend const Integer
Ovaj priwemeni obiekat ie biti uni5ten dim vi5e ne bude potreban.
operator++(Integer& a, i nt) ;
// Prefi ks:
friend const Integer&
Operatori koje moZete PreklaPati //
operator-- ( Integer& a) ;
Sufiks:
lako moZete definisati novo znaienie skoro svih operatora jezika C, preklapanje friend const Integer
operatora je prilieno ogranideno. Na primer, ne mozete koristiti kombinacije operator--(Integer& a, int) ;
**
operatora koje trenutno nemaju znae enje na C-u (ne moZete koristiti operator l.
stepenovanje), ne moZete menjati prioritete pri izraeunavanju operatora, i ne
moZete menjati broj argumenata operatora. Ovo ima smisla - sve ove aktivnosti // G1 obal ni operatori :
bi proizvele operatore koji bi vi5e zbunjivali nego Sto bi pomagali. const Integer& operator+(const Integer& a) {
U sledeia dva odeljka, prikazani su primeri svih,,regularnih'operatora koji cout << "+Integer\n'';
su prekloplieni na nadin koji iete najverovatnije i vi koristiti. return a; // Unarni operator + ne proizvodi njkakav efekat
)
const Integer operator-(const Integer& a) {
Unarni operatori cout << " - I nteger\n '' ;
Sledeii primer prikazuje sintaksu za preklapanje svih unarnih operatora, u return Integer(-a.i );
obliku globalnih funkcija (prijateljskih funkcija koje nisu dlanice klasa) i u obliku )
funkcija dlanica. operatore prikazujemo pomoiu opisane klase Integer i nove const Integer operator-(const Integer& a) {
klase Byte. Znaeenje preklopljenih operatora zavisiie od naeina na koji Zelite da cout << "-Integer\n";
ih koristite, ali razmotrite kako ie vaSe odluke uticati na programera klijenta. return Integer(-a.i);
Evo kataloga svih unarnih funkcija: )

: Clz:0verl oadi ngUnaryOperators.cpp Integer* operator&(Integer& a) {


I I
#i nc'l ude <i ostream>
cout << "&Integer\n";
usi ng namespace std;
return a.ThisO; // &a je rekurzivna!
)

Funkcije koje nisu ilanice: int operator!(const Integer& a)


// cout << "!Integer\n'';
{

class Integer {
long i; return !a.i;
Integer* This0 { return this; }
)

publ i c: // Pretiksna verzija vra6a uveeanu vrednost


Integer(1ong ll = 0) : j(.l1) {}
const Integer& operator++(Integer& a) {

je argument referenca konstante, ne dolazi do sporednih efekata: cout << "++Integer\n";


I I Kada
a.i++;
friend const Integer&
operator+(const Integer& a) ; return a;
friend const Integer )

operator- (const Integer& a) ; // Sutiksna verzija vraea vrednost pre uveeavanja:


friend const Integer const Integer operator++(lnteger& a, jnt) (

operator-(const Integer& a) ;
cout << "Integer++\n";
fri end I nteger* Integer before(a.j);
operator&(lnteger& a) ; a.i++i
fri end i nt return before;
operator! (const Integer& a); )

funkcije koja ima sporedne efekte je referenca promenljive: // Prefiksna verzija vraea umanjenu vrednost
// Argument
const Integer& operator--(Integer& a) {
// Prefi ks:
cout << "--lnteger\n";
fri end const Integer&
openator++( Integer& a) ;
a. i --;
362 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 363
I
return a; // Funkcije dlanice nisu konstantne, pa mogu imati sporedne efekte:
) const Byte& operator++0 | // pretiksna verzija
II Suft ksna verzija vraca vrednost pre umanienia: cout << "++Byte\n,,;
const Integer operator--(lnteger& a, int) ( b++;
cout << " lnteger--\n"; return *this;
Integer before(a.i); )
a.i--; const Byte operator++(intl I l/ Suf.iksna verzija
return before; cout << "Byte++\n";
I Byte before(b);
b++;
// Pokazacemo da preklopljeni operatori rade: return before;
void f(lnteger a) { )
+a; const Byte& operator--0 { /l prefiksna verzija
-o; cout << "--Byte\n";
-a; --b;
Integer* ip = &a; return *thi s;
la; )
++d i const Byte operator--(int)
cout << "Byte--\n";
I /l Sufiksna verzija
a++;
Byte before(b);
- -b;
) return before;
)

// Funkci3e clan'ice (podrazumeva se argument "this"): );


class Byte {
unsigned char b; void g(Byte b) {
publ i c: +b;
Byte(unsigned char bb = 0) : b(bb) {) -b;
// Nema sporednih efekata: konstantne funkciie ilanice: -b;
const Byte& operator+0 const { BYte* bP = 96'
cout << "+Byte\n"; !b;
return *thi s; ++b;
) b++;
const Byte operator-0 const ( - -b;
cout << "-Byte\n" I b--;
return Byte(-b); )
i
const Byte operator-0 const { int mainfl {
cout << "-Byte\n"; Integer a;
return Byte(-b) ; f(a);
i Byte b;
Byte operator! 0 const { g(b);
cout << "!Byte\n"; \ ///:-
return Byte ( ! b) ;
ove funkcije su grupisane na osnovu nadina prosledivanja
)
,Kasnije cemo navesti
argumenata.
smernice za prosledivanje i waianje argrr-e.rit". uglur-
Byte* operator&0 {
nom iete koristiti tehnike iz prethodnog primera (kao i one koji iete videti u sle-
cout << "&Byte\n";
decem odeljku). Neka vam one posluZe kao sablon kada preklapate operatore.
return thi s;
)
364 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 36s

friend const Integer


Uveianje i umanjenje vrednosti (--)' unose operator%(const Integer& l eft,
preklopljenl operatori uue!a.,li i umanienja wednosti zaiedan, (++) i const Integer& right);
poivati razli8ite funkcije u zavisnosti._g9 tog.u da Ii se
nedoumice zato 5ro treba friend const Integer
(kao prefiks), ili iza objekta na
operatori pojavljuju ispred objekta na koji deluju operator^(const Integer& I eft,
mada neke na prvi pogled zbu-
tili ,1.t,.,1,.i (tcao's,fit<si. Reienle ie iednostavno,(pref,ksnouv-eiavanje vrednosti)' const Integer& ri 9ht) ;
n1ui". roau prevodilac vidi, na p,i-tt, izraz ++.a friend const Integer
,rn g.n"riS.'poz-iv f.nkcije opeiator++(a); ali, kada
vidi izraza++, on poziva funk- operator&(const Integer& I eft,
ciju'operator++(a, int). Datle, prevodilac.pravi razliku izmedu ova dva izraza const Integer& ri ght) ;
piri"qrCi raz-lidite preklopljene iunkcije' Ako prevodilac' u datoteci Overloadin- friend const Integer
,-uuirziie funkcila dlanica' vidrrzraz++b' on poziva funk- operatorl (const Integer& I eft,
gUnary'Operators.cpp
ci ju B::operator+ + (int). const Integer& ri sht) ;
Korisniksamovididasepoziva|urazliditefunkcijezaprefiksnu.isufiksnu friend const Integer
verz-iiu.Dabir.rapravioarugaeilipotpiszasufiksnuverziju'prevodilacprosle- operator<<(const Integer& I eft,
(koia nikada ne dobiia const Integer& ri sht) ;
duje la2nu konstantnu *"a".,osi za celobrojni argument
identifikator zato 5to se nikada i ne koristi)' frjend const Integer
operator>>(const Integer& l eft,
const Integer& ri sht) ;
Binarni operatori // }peratori dodele menjaju i vracaj u I vrednost :

Sledeii primei predstavlia verziju programa OverloadingUnaryoperators'cpp


za fri end Integer&
primer svih operatora koje iete preklapati' operator+= (Integer& eft,
binor.," op.ratore , tako da sada imate 1

Ponovosuprikazaneverzijez-aglobalnefunkcijeizafunkciiedlanice. const Integer& right);


friend Integer&
I l: Clz: Integer.h operator-= (Integer& 1 eft,
I I Preklapanje operatora koji nisu dlanovi
const Integer& ri sht) ;
#i fndef INTEGER-H friend Integer&
#define INTEGER H
operator*= (integer& 1 eft,
#i ncl ude <i ost ream> const Integer& ri ght) ;
friend Integer&
// Funkci3e koie nisu ilanjce: operator/=(lnteger& I eft,
c1 ass Integer {
const Integer& ri ght)
long i; fri end Integer&
;

publ i c: operator%= (lnteger& 1 eft,


Integer(1ong1l = 0) : i(ll) {) const Integer& right);
// Operatori koji prave nove, izmenjene vrednosti: fri end Integer&
fri end const Integer operator^=(lnteger& left,
operator+(const Integer& 1eft, const Integer& ri ght)
const I nteger& ri ght) ; friend Integer&
;

friend const Integer operator&= (Integer& eft,


oPerator-(const Integer& left'
1

const Integer& ri ght)


const Integer& ri ght) ; fri end Integer&
;

friend const integer operatorl =(Integer& 1 eft,


oPerator* (const Integer& 1 eft ' const Integer&
const Integer& right) ;
right);
fri end Integer&
friend const Integer operator>>= (lnteger& 1 eft,
operator/(con:i
l::il::t lill;,, friend Integer&
const Integer& right);

operator<<= (Integer& 1 eft,


const Integer& right);
366 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora !6V t
// Uslovni operatori vracaiu vrednosti true ili false: const Integer
frr end i nt operator*(const Integer& 1eft,
operator== (const I nteger& I eft, const Integer& right) {

const Integer& ri ght) ;


return Integer(1eft.i * right.i);
fri end i nt )

operator!=(const Integer& 1eft, const Integer


const Integer& right); operator/(const Integer& 1eft,
f ri end 'i nt const Integer& right) {
operator<(const Integer& 1eft, require(right.i != 0, ."deljenje s nu1om,,);
const Integer& right); return Integer(1eft.i / rlght.i);
friend int )

operator> (const Integer& eft, 1


const Integer
const Integer& right); operator%(const Integer& left,
fri end i nt const Integer& right) {
operaton<=(const Integer& left, require(right,i != 0, "ostatak pri deljenju s nu1om,,);
const- Integer& right) ;
return Integer(1 eft. i % r1 ght. i ) ;
fri end I nt i
operator>= (const I nteger& i eft, const Integer
const Integer& right) ;
operator^(const Integer& 1eft,
fri end i nt const Integer& right) (

operator&&(const Integer& 1eft, return Integer(1eft.i ^ right.i);


const I nteger& ri ght) ; )

fri end i nt const Integer


operatorl I (const Integer& 1eft, operator&(const Integer& 1eft,
const Integer& right); const Integer& right) {
return Integer(1eft.i & right.i);
II lsptsuje sadrZaj u iz1azni tok:
void print(std::ostream& os) const { os '< i; ) )
const Integer
);
operatorl (const Integer& left,
#endif ll INTEGER_H ///:-
const Integer& rlght) (
: CI?:lnteger.cPP {0i return Integer(1eft.i I right.i);
I I
I I Realizaci ja preklopl jenih operatora )

#include "Integer.h" const Integer


#include ". ./require.h" operator<<(const Integer& 1eft,
const Integer& right) {
const Integer return Integer(1eft.i << right"i) ;
operator+(const Integer& left, )

const Integer& right) { const Integer


return Integer(left.i + right.i); operator>>(const Integer& 1eft,
)
const Integer& right) {

const I nteger return Integer(1eft.i >> right.i) ;


operator- (const I nteger& I eft, ]
right) {
const Integer& // Operatori dodele menjaju i vracaju lvrednost:
return Integer(left.i - right.i); Integer& operator+=(lnteger& 1 eft,
)
const Integer& rjght) {
if(&left == &right) {/* dodela vrednosti istom objektu */)
I eft.'i += ri ght. i ;
return left;
)
Poglavlje I 2: Preklapanje operatora 369
Misliti na jeziku C++
358

return I eft;
I nteser& o,erator-=,
::::?.i:,[::i ri qht) (
*/)
)
Integer& operator<<= ( integer& 1 eft,
if(&left == &right) {/* dodela vrednosti i stom objektu
const I nteger& ri ght ) {
left.i -= right.i; if(&1eft == &riSht) {/* dodela vrednosti istom obiektu */}
return eft; 1
I eft. i <<= ri ght. i ;
i return 1 eft;
Inteqer& operator*=(lnteger& left'
)
const lnteger& ri sht) (
*/) Uslovni operatori vracaju vrednost true ili false:
i f (&left == &ri ght) { /* dodel a vrednosti i stom objektu //
*= ri ght. i ; i nt operator== (const Integer& left,
I eft. i const Integer& right) {
return eft;
1
return Ieft.i == ri ght. i ;
I )
rnteser& operator/=,::::?.;:,[:li i nt operator! (const Integer& 1eft,
.,ni,l r
=
cons t Integer& right) {
require(right.i l= 0, "deljenie s nulom"); */) return Ieft.i != ri ght. j ;
liiar.ri == a.isl,t) {7. ooo.ta vrednosti istom obiektu I
1 eft. i /= ri ght. i ;
i nt operator< (const I nteger& I eft,
return eft; 1
const Integer& right) i
) return left.1 < right.j;
Inteser& operator%=,::::?.;:.[:li
.,nn,,, )
j nt operator>(const Integer& I eft,
require(right.i l= 0, "ostatak pri delieniu s nulom");
const Integer& right)
I riAl.fi == f.lsl,t) {/" dodela vrednosti
istom objektu */) i
return Ieft.i > right.i;
I eft. i %= ri ght. i ;
)
return 1 eft; i nt operator<= (const Integer& 1eft,
) const Integer& right) {
rnteser& operator^=,:::::.;:,[:li return I eft. i <= ri ght. i ;
.,nn,,,
if(&left == &right) {/* dodela vrednosti istom objektu "/} )
j nt operator>= (const Integer& 1eft,
left.i ^= right'i; const Integer& rlght) {
return I eft; return left.i >= right.i;
)
)
I nteger& operator&= nteger& I eft '
(I 'int operator&&(const Integer& left,
const I nteger& ri ght) { right)
f(&left -= &right) {/* dodela vrednosti i stom objektu */) const Integer& {
i return I eft. i && ri ght. i ;
left.i &= right'i; )
return I eft; int operatorl I (const Integer& 1eft,
) const Integer& right) {
Integer& operator] =(lnteger& left' return left.i ll right.i;
const I nteger& risht) {
*/]
dodela vrednosti istom objektu ) // /,-
if(&left == &right) {/*
1eft.i l= right.i; / I z CLZIIntegerTest.cpp
return eft;
//{ L} Inteser
1

) #include "lnteger.h"
rnteser& operator>>=(rllii.ilrlill; #i ncl ude <fstream>
right) {
*
l\ using namespace std;
if(&left == &rjght) i/* dodela vrednosti istom objektu
ofstream out("lntegerTest.out") ;
I eft. i >>= ri ght. i ;
t70 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 371 I
const Byte
void h(lnteqer& c1, lnteger& c2) {

// S1 oZen i zraz:
operator-(const Byte& right) const {

cI+=cl*c2+c2%cl; return Byte(b - ri ght. b) ;


#defr ne TRY (0P) \ )

out <<,,C1 =,,; cl.print(OUt); \ const Byte


out << " , cZ = "; c2.Print(out); \ operator*(const Byte& right) const {
return Byte(b * right.b);
out << "; c1 " #OP " c2 daie "; \
(ct 0P c2).Print(out); \ i
out << endl; const Byte
TRY(+) TRY(-) TRY(.) TRY(/)
operator/(const Byte& right) const {

TRY (%) TRY (^) TRY (&) TRY ( | )


require(right.b l= 0, ,,deljenje s nulom");
TRY(<<) TRY(>,) IRY(+=) TRY(-=)
return Byte(b / right.b);
TRY(*=) rRY(/=) TRY(%=) TRY(^=) )
const Byte
TRy(&=) TRY( | =) TRY(>>=) TRY(<<=)
//Uslovni oPeratorj: operator%(const Byte& right) const {

#define TRYC(0P) \ require(right.b l= 0, ,,ostatak pri deljenju s nu1om,,);


out << ,,c1 = ',; cl.print(out); \ return Byte(b % right.b);
out << ,, , cZ = "; c2.print(out); \ )

out << "; c1 " #0P " c2 daie "; \ const Byte
oul << (c1 0P c2); \ operator.'(const Byte& right) const {
out << endl; return Byte(b ^ rjght.b);
TRYC(<) TRYC(>) TRYc(==) TRYc( l=) rRYC(<=) )

TRYC(>=) TRYC(&&) rRYC( I I )


const Byte
operator&(const Byte& right) const {
)
return Byte(b & right.b);
int majn0 {
)

cout << "funkcije priiatelJi "" endl; const Byte


Integer cl(a7), c2(9); operatorl (const Byte& right) const i
h(c1, c2); return Byte(b I right"b);
\ I ll,- )
const Byte
operator<<(const Byte& right) const
II: C12: Byte. h {

Preklopljeni operatori ilanovi return Byte(b << right.b);


I I
# i fndef BYTE_H
)

#defi ne BYTE_H
const Byte
#include ". ./requrre.h" operator>>(const Byte& right) const {

#i ncl ude <i ostream>


return Byte(b >> right.b);
// Funkcije alanice (podrazumeva se arqument "this"): )

class Byte { // i vraeaju lvrednost.


0peratori dodele menjaju
uns i gned char b; ff operator dodele moZe biti samo funkcija dlanica:
publ i c: Byte& operator=(const Byte& r.ight) i
Byte(unsigned char bb = 0) : b(bb) {} // Proveravamo dodeljivanje vrednosti istom objektu:
// Nema sporedni h efekata: konstantne funkci j e dl ani ce: if(this == &riSht) return *th.is;
const Byte b = right.b;
operator+ (const Byte& ri ght) const { return *thi s;
return BYte(b + right.b); )

)
Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 373
372

Byte& operator<<=(const Byte& right)


Byte& operatop+= (6onst Byte& ri ght)
( {
"',ii,iis istom objektu */} if(this ==&right) {/* dodela vrednosti istom objektu */)
== &righl) dodela {/.
vrednosti
b <<= right.b.
b += rioht.b; return *thi s;
return "thi s i )

S\ie-\ Lrperator-=(const Byte& rrght)


// Uslovni operatori vracaju vrednost true ili false:
1
*/) int operator==(const Byte& right) const {
if(this == &risht) i/. dodela vrednosti istom objektu return b == right.b;
b -= ri ght. b;
return *thi s;
)
int operator!=(const Byte& right) const {
)
return b != right.b;
Byte& operato,'"= (const Byte& ri ght) { */}
if(th;s == &right) {/* dodela vrednosti istom obiektu )
int operator<(const Byte& right) const
b -= right.b;
{
return b < right.b;
return -this;
)
i int operator>(const Byte& right) const {
Byte& operatorl= (const Byte& ri ght) {
return b > right.b;
require(right.b l= 0, "delienie s nu1om"); */)
== &rrght) i/* dodela vrednosti istom objektu
)
rf(this int operator<=(const Byte& right) const {
b /= right.b; return b <= right.b;
return *thi s; )
)
int operator>=(const Byte& r'ight) const {
Byte& operatop2= (const Byte& ri ght) { return b >= right.b;
require(right.b l= 0, "ostatak pri delieniu s nulom") i */)
ifitnis == &right) {/* dodela vrednosti istom objektu )
int operator&&(const Byte& right) const (
b %= right.b; return b && right.b;
return *thi s; )
I int operatorl | (const Byte& right) const (
Byte& operatop^= (const Byte& ri ght) (

if(thjs == &right) {/* dodela vrednosti istom obiektu


-
ll return b ll right.b;
)
b ^= rj ght. b; Ispisuje sadrZai u jzlazni tok:
return *thi s; //
void print(std::ostream& os) const {
)
os << "0x" << std::hex << int(b) << std::dec;
Byte& operatopg= (const Byte& ri ght) (
if(thls == &right) {/* dodela vrednosti istom obiektu
-
ll )
);
b &= right.b;
return *thi s;
#endit /l B\TE_H ///:-
l
Byte& operator]=(const Byte& right) {
//: Cl?tBytelest.cpp
if(this == &riSht) (/- dodela vrednosti istom objektu
-
ll #include "Byte.h"
#i ncl ude <fstream>
b l= right.b; using namespace std;
return *thi s; ofstream out ("ByteTest.out" );
)
void k(Byte& bl, Byte& b2) (
Byte& operatop>>=(const Byte& right) {
if(this == &right) {/* dodela vrednosti istom objektu
*
lJ b1=bl*b2+b2%bll
b >>= ri ght . b' #define TRY2(0P) \
return *thi s; out <<,,b1 =,,; bl.print(out); \
I
out << ", b2 = ''; b2.Print(out) I \
374 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 375 I
"; " " b2 daJe "; \ Svi operatori koji su prikazani u prethodna dva primera preklopijeni su tako
out << b1 #0P
da rade samo s jednim tipom podataka. Operator moZete preklopiti tako da radi s
(b1 0P b2) 'Print(out); \
out .< endl; vi5e razliditih tipova, pa moZete, na primer, sabirati babe i Zabe. Pre nego Sto
zapodnete iscrpljujuie preklapanje operatora, trebalo bi da pogiedate odeljak o
bl=9;b2=41; automatskoj konverziji tipova u ovom poglavlju. eesto moZete izbeii preklapanje
TRY2(+) TRY2(-) TRY2(*) TRY2(/) velikog broja operatora ako na pravom mestu upotrebite konverziju tipova.
TRY2 (%) TRY2 (^) rRY2 (&) TRY2 ( I )

TRY2(<<) TRY2(>>) TRY2(+=) TRY2(-=)


TRY2(*=) TRY2(/=) TRY2(%=) rRY2(^=)
Argumenti i rezultati
rRY2(&=) TRY2( l=) TRY2(>>=) TRY2(<<=) Na prvi pogled moZe vas zbuniti Sto se u datotekama OverloadingUnaryOpera-
TRY2 ( = ) // OPerator dodel e tors.cpp, tnteger.h i Byte.h na razlidite nadine prosleduju i waiaju argumenti.
Iako argumente moheteprosledivati i waiati na razne nadine, izbor tih nadina u
//Uslovni oPeratori: ovom primeru nije sludajan. Oni prate Iogidan Sablon, isti koji iete u veiini
#define TRYC2(0P) \ sludajeva i vi Zeleti da koristite.
out <. ,,bl = "; b1. pri nt (out) ; \ I . Kao i u sludaju bilo kog argumenta funkcije, ako treba samo da proiitate
out << ", b2 = "; b2.Print(out); \ argument, a ne i da ga menjate, prosledujte po referencu konstante. Obidne
out << "; bi " #0P " b2 daie "; \ aritmetidke operacije (kao Sto su sabiranje (+) i oduzimanje (-), itd.) i
out << (b1 0P b2); \ logiike operacije, nede promeniti svoje argumente, tako da Cete preteZno
out '< endl; prosledivati reference konstanti. Ovo ie se na funkciju dlanicu klase odra-
ziti tako Sto ie ona postati konstantna funkcija dlanica. Samo u sludaju ope-
b1 =9; bZ = 47:.
ratora koji menjaju levi argument (kao sto su operator dodele uz sabiranje,
rRYC2(<) TRYC2(>) TRYC2(==) TRYC2(!=) rRYC2(<=)
rRYC2(>=) TRYC2(&&) TRYC2( | I )
+= ili operatora dodele =), argument s leve strane ru 4e konstanta, ali se ipak
prosleduje po adresi, zato sto ie se menjati.
// Laniana dodela: 2. Tip rezultata zavisi od odekivanog znadenja operatora. (Da ponovimo, sa
Byte b3 = 92; argumentima i rezultatima moZete raditi Sta god Zelite.) Ako operator pro-
b1=b2=b3l izvodi nor,u wednost, moraiete da napravite nov objekat kao rezultat. Na
) primer, iskaz Integer::operator+ mora proizvesti objekat klase Integer koji
je zbir operanada. Ovaj objekat se waia po wednosti kao konstanta, pa se
int main0 { rezultat ne moZe menjati kao lwednost.
out << "funkcija clanica:" << endl; 3. Svi operatori dodele menjaju lwednost. Da biste omoguiili da se rezultat
Byte (a7) b2 (9)
b1
' ;
dodele koristi u landanim izrazima, na primer uizrazu a=b=c, odekuje se
k(b1, b2); da iete watiti referencu na lwednost koja je upravo promenjena. Ali,
\ lll,- treba Ii ova referenca da ukazuje na konstantu ili ne treba? Iako izraz
Viclitedaoperatorclodele(-)moradabudefunkcijadlanica'ovoiemo a=b=c aitate sleva na desno, prevodilac ga raSdlanjuje zdesna nalevo, tako
objasniti kasniie. da ne morate waiati referencu promenljive da biste podrZali ulandavanje
powatnu dodelu (engl'
Za sve opeiatore dodele postoii k6d koji proverava dodela. Ponekad se odekuje da se operacija moZe izvr5iti nad argumen-
je op-sta smer-
utflit"iCrir,?r) sto je dodeliivanje wednosti istom objektu; ovo veiini sluda- tom kome je upravo dodeljena wednost, na primer, t izrazu
nica. erJgram iz primera ne iadi t'iStu au spre'i
powatnu dodelu u
(a=b).func( ); za argument a se poziva funkcija func( ) nakon Sto mu je
da biste to izmenili). Provera powatne
leva taoiisite k6d umesto komentara dodele uz sabiran e
dodeljena wednost argumenta b. Prema tome, rezultat za sve operatore
Joo.i" ilsto nije neophodna; na primer, u sluaaiu operatora
dodele treba da bude obidna referenca na lwednost.
promenljive A uveiate za
i*=t eerto hoiete da kazete A+=A i da time wednost 4. Kada se radi o logidkim operatorima, u najgorem sludaju odekuje se celo-
je da dodeljivanje istom. obiektu proverite
njenu trenutnu wednost. NajvaZnije brojni rezultat, a u najboljem sludaju - logidka .,rednost. (Biblioteke koje
(=), u komplikovanim izrazima
pritit o- preklapania opu.utoru aoaete iel se
su napravljene u weme kada vedina prevodilaca joS uvek nije podrZavala
katastrofalni rezultati' (Llglavnom ie sve u redu' ali treba da paZljivo
,'r,rg,, AnUiti ugradeni logidki tip jezika C++, koristiie celobrojne vrednosti ili wednosti
koristite operator dodele =.) ekvivalentnih tipova definisanih rezervisanom redju typedef.)
Misliti na jeziku C++ Poglavlje I 2: preklapanje operatora
376 377

prefiksnih desile bi se rri stvari. Kao.prvo, bio bi napravljen


op(r ratori rrvcian ja i urnanienia, (++) i (- -), ttnose nedoumice zbog objekat tmp, i pozvan njegov
pa ne moZe doradivati kao konstrukto.r. Kao drugo, konstruktor za Lopiranje
i srfiisnih LI obc vt:rz.ije objckat se menja, se bi kopirao objekat rmp na
'erzii.. .,,erzija vraia wedtlost objekta nakon sto je on promen jen, mesto spoljnog rezurtata. I kao treie, na kiaju
obrasti uuz.nlu, tir,,'rri pnrrun
koltstanta. t)reftksna
desrruktor objekta tmp.
pa ocekujete cia clobiiete promenjen objekat. Plema tome, u sludaiu prefiksne
+this kao referencu. Sufiksna verzija bi trebalo da Pristup.,,waian.ia priwemenog objekta,, funkcioniSe
verzije', rrioTcte vratiti vrc(lnost ,., sasvim drugaiije. prevo-
dilac zna da ob;'ekat koji sluZi trelba samo zavracanie.
vraia r,rednost pr? nego Sto se ona promeni, pa morate da napravite poseban zato cenapraviti objekat
rezultat direktno na mestu spolja.njeg rezurtata. To
objekat koji ie predstai,liati tu vrednost i vratitetaj objekat. Prema tome, zahteva samo jedan poziv obidnog
waiati po vrednosti ako Zelite da saduvate odekivano konstruktora (konstruktor-zi kopiranje .rij"
..,i,krn. verzije morate n"optrodan),
destruktor se ne
poziva zato Sto uopste neiere ni napraviti
znacenje. (Naiii iete nu op"ruroi" uveianja i umanjenja koji waiaju celobrojnu totatnr oul.tut. o"; ;;;;" je zna-
dajno efikasnija, a zahteva samo paZlyivo pogramiranje;
ili logiiiu we.1.rost, koia, na primer, ukazuje na to da se objekat nalazi na kraju zacija rezultata.
desto se naziva optimi-
ili
lisrc.) Sacla se postavlja pitaniL: da li ove wednosti treba waiati kao konstantne
(++a).fun^co funk-
kao prornenljive? Ako dozvoiite da se objekat menja, uizrazu
(a++)'funcg, funkcija funcO ie
ci;a iuncO ie raditi sa obiektom a, ali u izrazu
sufiksni operator uveianja. Pri-
Neobitni operatori
radiri s privreme.inr obieitom koii ie napravio Sintaksa za preklapanje, nekoliko operatora je
pomalo drugadija.
,r.*.ni objekti su automatski konstantni i to ie prevodilac oznaditi. Da bi se pristupa elementu niia ([)
saiuvala konsistentnost, bolie je da u oba sludaia imamo konstantne objekte,
kao . .Operator
jedan -o.u titi funkciia eia.,i.a i ima samo
argument. Posto ovaj operator ukazule
u prefiksnoj verziji budu pro- nu ,o ou se objekat ponasa kao
5ro smo ovde uradili. IIi, mozete izabrati da oblekti desto iete waiati referencu, iato niz,
opera- da
-oz" r" zgodno koristiti
r.nenljivi, a da u suhksnoi verziii budu konstantni. Zbog razliaitih znadenja jednakosti. Ovaj operator se desto preklapa; s reve strane znaka
rora z,a rrveian je i uman jen je, ir)ih iete posebno razmatrati od sludaja do sludaja' p.i*"." iete videti u knjizi.
operatori new i delete upravljaju ainamietom
memorijom i mogu se prekra-
pati na vi5e razliditih nadina. Ovi t-ema je
obradena u poglavlju 13.
Vraianje konstante Po vrednosti
Vraianje konsrante po wednosti moze u podetku malo zbunjivati, pa zasluzuje Operator zarez
(+). Ako ga kori-
dodatno objasn]enje. Razmotrimo binarni operator sabiranja Operator zarez se poziva kada. se pojavi pored
je
stite u izrazu kao Sto f(a+b), rezultat izrazaa+b postaje priwemeni objekat objekta odgovarajuieg tipa. Medu_
tim, ,,operator ," se ne odnosi ,.i rir". rlisti
funkciie fO. Po5to u pitanju priwemeni objekat' on je argumenata funkcije, vei samo na
koji se koristi u poz.ivu ie objekte koji su ,,na otvorenom,,, razdvojeni ,irZrnu.
ar.rromarski konstantan, tako da niie bitno da Ii iz-ridito waiate konstantnu
wed- fz4eJa il;r;iLp.ru,o.
nema mnogo praktidnih_primena; on je dodat jezik
u rUJg to.,rirr"nt-nlsti. E o
nost ili Ile. primera pozivanja funkcije zareza, kada
poruku. se zarez pojavlju je ispredobjekta, kao i
[Jmesto da rezrrltar i.raza a+b prosleditc funkciji, moZete ioj poslati kada se pojavljuje iza objekta:
primer, moZete reii (a+b).g( ), pri demu it g( ) ovom sludaju neka funkcija
Na
'
clanica klase Integer. Time Sto ste rezultat udinili konstantnim, rekli
ste da se / /.: ClZ:0ver1 oadi ng0peratorComma. cpp
pozivati tu wednost. ovo je ispravno #include <iostream>
sarno konstantne tlnkcije dlanice mogu za
smestite informacije u objekat usi ng namespace std;
sa stanovista konstantnosti ier vas spredava da
koji ie najverovatnije biti iz-gubljen. ciass After {
publ i c:
Opti m izacija rezultata const After& operator, (const After&) const
Obratite paTnfu na oblik koli se koristi kada se prave novi objekti za waianje
po cout << "After::operator,0,, .. endl
{
;
wednosti. U funkciji operatora sabiranja, na primer, piSe: return *thi s;
return Integer(left.i + right.i); )

je
);
ovo samo na prvi pogled izgleda kao ,,poziv konstluktora'. sintaksa ista kao
za priwemeni obletit;lskaz iaZe ,,napravi priwemeni objekat klase Integer i cl ass Before { } ;
,.uii gu". Mozete pomisliti da je rezultat isti kao da pravite imenovani lokalni
objekit i waiate ga. Medutim, rezultat je znadaino razlidit' U dva reda:

Integer tmP(left.i + right'i);


return tmP;
-
378 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 379

Before& operator, ( j nt, Before& b) { // Definicije statidkih dlanova:


cout << "Before: :operator, 0 " " endl ; int Obj::i = 47;
return b; int Obj::j = 11'
)
// Kontejner:
int main0 i class ObjContainer (

After a, b; vector<Obj*> a;
a, b; ll Poziva se operator zarez publ i c:
void add(Obj* obj) { a.push_back(obj); }
Before c; fri end cl ass SmartPoi nter;
I, c; I I Poziva se operator zarez );
\ I I l,-
class SmartPointer
Kacla je funkcija opcratora globalna, mo7-e se promeniti znaaenie zaleza ispred {
ObjContainer& oc;
posntatranog objekta. Prikaz.ana upotreba zareza priliano ie neiasna i disku- i nt i ndex;
tabilna. Verovatno biste mogli da koristite liste u koiima su objekti razdvojeni publ i c:
zaret.\nta kao delove sloZenijih izraza, ali se operator zarez obiino ne preklapa. SmartPoi nter(ObjContai ner& objc) : oc(objc) {
index = 0;
Operator pristupanja tlanu (->) ]
Operator za dereferenciranje pokazivada (->) obidno se koristi kada Zelite da // Rezulta't ukazuje na kraj liste:
objekat iz-gleda kao pokazivae. Posto je u ovakav objekat ugradeno vise funkcija bool operator++O I // Prefiksna verzija
nego u obidni pokazivad, on se desto naziva pametni pokaziuai (engl. smart if(index >= oc.a.size0) return false;
jf(oc.a[++index] == 9; return false;
pointer). Pametni pokazivadi su posebno korisni ako Zelite da ,,omotate" klasu
oko pokazivada da biste taj pokazivad udinili bezbednim. eesto se koriste kao return true;
iterotori, to jest objekti koji se kreiu kroz zbirku (kontejner) drugih objekata, i
pokazujuii na jedan po ledan objekat, nezavisno od realizacije kontejnera. bool operator++(int) { l/ Suftksna verzija
(Kontejnere i iteratore iete naii u bibliotekama klasa, kao Sto je standardna return operator++0 . // Kori sti prefi ksnu verzi3u
)
biblioteka jezika C++, koja je opisana u drugom tomu.)
Obj* operator->0 const
Operator za dereferenciranje pokazivada mora biti funkcija dlanica i na njega {
require(oc.aIindex] != 0,',vrednost nula,,
se primenjuju dodatna, netipifna ogranidenja: on mora waiati objekat (ili refe-
"vraca SmartPoj nter: : operator-> 0 ,') ;
rencu na objekat) koii takode ima operator za dereferenciranje pokazivaea, ili return oc. a Ii ndex] ;
mora vraiati pokazivai na koji se moZe primeniti taj operator. Evo jednostavnog )
primera: );
II : ClZ: SmartPoi nter. cpP.
#i ncl ude <i ostream> int main0 (
#r ncl ude <vector> const int sz = 10;
#i nclude ". ./requi re.h" Obj oIsz];
usi ng namespace std; Obj Contai ner oc;
for(inti=0;i<sz;i++)
cl ass Ob: { oc.add(&oIi] ) ; / I Popuni
static jnt j, j; SmartPoi nter sp (oc) ; // Pravl jenje i teratora
public: do{
void f0 const { cout << i++ .. endl ; ) sp-rf0; // Poziv operatora za dereferenciranje pokazivada
void g0 const { cout << i++ << endl; ) sP->9 0 ;
I; ) whi 1 e(sp++) ;
380
Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 38r

obi de{rrri5e 0ltiekte s koiirtra se radi u ovom programu. Funkcije fo l/ Detinicije statidkih
i objekata:
Klasa
g( ) jerlnosta'.. isl.lisrr j. z.a.intliivc vrednosti kori5ienjem statidkih dlanova int Obj::i = 47;
su dodati u konteinere tipa objcontainer' int Obj::j = 11;
lrn,tnrot o. Pokaz-ivaci ltit ovc obiekte kao niz
i<uriic,cnjcrn njegovc {'unkcije addg. Konteiner ObiContainer,izgled-a
riicr,' ,," postrrli nacin da proi'itate pokazivaee iz ovog // Kontejner:
1.'r,k;tzir.irca, ali Prirrre
,1,,
kao prijateljska klasa' c1 ass ObjContai ner
in,,tcinera. N{eilutirn, klasa SmartPointer je definisana
{
vector<obj*> a;
takodaonaviclittr.rtttra5njostkontejnera.ovaklasaVeomalidinapametnipoka. pub'l i c:
zivac. - objcktc te klase rnozetc ponlerati unapred
korisienjem operatora uve-
--)' pri demu.se nikada ne void add(Obj* obj) i a.push back(obj); I
ianja (++)'(rttclT.ete clefir.risati ioperator umanienja' c1 ass SmartPoi nter;
ir.lat.i i,t.gratrica kotrtejnera. Klasi takode omoguiava
pristup wednosti na koju
pokazivaia'
friend SmartPointer;
pokazuie, koriSienjem operatora za dereferenciranje class SmartPointer
' primetite da je iclasa bmartpointer prilagodena konreineru za koji je napra- ObjContainer& oc;
{

pametnog poka-
\rljena; za razlikti od obidnog pokazivada, ne postoji opSta swha unsigned int index;
iteratori naueiiete vise u sledeiem
z.ivada. o pamctnirn pot<azivae ima koji se zolu publ i c:
poglavlju ove knjige, i u drugom tomu' SmartPointer(ObjContajner& objc) : oc(objc)
' pokazivai SmaitPointeitp nu.tuj" kada se u gla\"nom programu konteiner oc index = 0;
{

izrazima:
napulti ottjektirna klase Obi. Panletni pokazivadi se pozivaju u )

Poziv pametnog pokazivaia // Rezultat ukazuje na kraj liste:


sp-'f0; ll bool operator++O { // Prefiksna verzija
sp-'g ) ; (
if(index >= oc.a,size0) return false;
lako pokaz-iva. Sp llelna funkcije dlarrice f() ic(), operator za dereferencir- 'if(oc.a[++index] == 0) return false;
anjcpokaziva.aautollatskipozivaovefunkcijezapokaziva(tipaobj*kojije return true;
vraierr it.iz,raz-aSmartPointer::operator-r. Prevodilac ie
proveriti da li ie poziv
)
funkciie ispravan. bool operator++(int) | // Sufiksna verzija
IakosuinternimehanizmioperatorazadereferenciranjepokazivadasloZeniji return operator++0; /l Koristi se prefiksna verzija
nego k6d drugih operatora, cilj iome se teZi ie potpuno isti:
obezbediti pogodnu )

sintakstr z.a korisr.rike klasa. Obj* operator->0 const {


require(oc.a[1ndex] l= 0, "vrednost nula "
"vraca SmartPoi nter: :operator->() ") ;
Ugne2deni iterator return oc.aIindex];
ugnezdene u
Cesto iete videti klasu ,,pametnog pokazivada' ili klasu ,,iteratora'
prepraviti tako da se klasa Smart- )
klasu kojol sluze. prethodni primei se mo7.e );
Pointer r,rgnezdi u klasu OblContainer, ovako:
// Pravi pametan pokazjvad koji
II :Clz: NestedSmartPoi nter'cPP //pokazuje na po?etak klase ObjContainer:
# i nc I ude <i os t ream> SmartPointer begin0 {
#i nc'l ude <vector> return SmartPo'i nter(*thi s) ;
#include "../require.h" )
usi ng namesPace std; \.

cl ass 0bj { int main0 {


static int i, j; const int sz = 10;
publ i c: Obj olszl;
void f0 { cout " j++ .. endl ; ) ObjContai ner oc;
void g0 { cout " ;++ .. endl ; ) for(inti=0;j<sz;i++)
); oc.add(&oIi] ) ; / / Popuni
0bjConta'iner: :SmartPointer sp = oc.begin0 ;
r
I

382 Misliti na jeziku C++ Poglavlje I 2: Preklapan1e operatora 383

do { / /: ClZtPoi nterToMember0perator. cpp


sp-,f ( ) ; II Pozi v operatora za dereferenci ranje pokazi vada #i ncl ude <i ostream>
sp-,9 ( ) ; using namespace std;
i wni 1e(++5P) '
I I I l:- class Dog {
publ i c:
Porecl toga 5to smo Lrgnezdili klasu, ovde postoie samo dve razlike u odnosu 'i
nt run (i nt i ) const {
na originalni primer. Prva razlika je u tome Sto je klasa deklarisana tako da moZe
cout << "run\n";
biti prijateljska: return i;
c1 ass SmartPoi nter; )
fri end SmartPoi nter; int eat(int i) const {

Prevodilac mora z-nati da klasa postoji pre nego Sto mu saop5timo da je ta cout << "eat\n";
klasa prijateljska.
return i;
Dnrga raz-lika je u funkciji dlanici begin( ) klase ObiContainer koja pravi )

pametni pokazivai na podetak sekvence u kontejneru. Ovo je pogodnost wedna


i ntsl eep (i nt i ) const {
cout << "ZZZ\n";
za programerc, jer je napravljena po uzoru na tehniku koja se koristi u standard-
return i ;
rro j hibliotcr:i jczikl (. r-*.
)
typedef i nt (Dog: : *pMF) (i nt) const;
Operator ->" // operator ->* mora vratiti objekat
Operator ->* je binarni operator koji se pona5a kao i svi drugi binarni operatori. l/ koji ima operator poziva funkcije,0:
On postoji zbog situacija u kojima Zelite da imitirate pona5anje ugradene sin- class Function0bject {
takse pokaziuaia na ilan,kolaje prikazana u prethodnom poglavlju. Dog* ptr;
Kao i operator za dereferenciranje pokazivada (->), operator za dereferenci- PMF pmem;
publ i c:
ranje pokazivada na dlan se u op5tem sluiaju koristi uz objekat koji predstavlja
,,pametni pokazivad". Prikazaiemo jednostalrriji primer, pa ie ovo biti jasnije, // Cuvanje pokazivada na objekat i na funkciju dlanicu
Pri clcfinisanju operatora ->*, trik je u tome da on mora vraiati objekat za koji se
Function0bject(Dog* wp, pMF pmf)

lno7.e p'rozvati operator pozivanja lunkcije, O, sa argumentima za funkciju dla-


: ptr(wp), pmem(pmf) (
nicu koju pozivate.
cout << " konstruktor FunctionObject \n,';
)
Operator poziua funkcije, ( ), mora biti funkcija dlanica. Jedinstven je po tome
Sto moTe inrati proizvollan broj argumenata. Kada se taj operator preklopi, // Pozivanje kori5eenjem saduvanjh
objekat se mo7-e pona5ati kao funkcija. Iako biste mogli da defini5ete viSe pre-
// pokazivada na objekat i na ilanicu
int operator0(int i) const (
klopljenih tirnkcija operatora poziva funkcije s razlieitim argumentima, to se cout << "Function0bject: :operator0\n,';
e esto koristi z-a tipove nad kojima se primenjuje samo jedna operacija, ili kada se
return (ptr->*pmem) (i) 3 // poziv
neka opcracija posebno istide. tl drugom tomu iete videti da se u standardnoj )
bibliotcci jczika (.++ operator poziva funkcije koristi da bi se napravili l.
,,funkcijski objekti". Function0bject operator->*(pMF pmf) {
I)a biste preklopili operator ->*, prethodno morate napraviti klasu sa opera- cout << "operator->*" << endl ;
toronr pozivanja funkcije. Opcrator ->* ie waiati objekte te klase. Ova klasa return Function0bject(thjs, pmf) ;
rnora prikrrpiti neophodne informacije. Tako ie, kada se pozove operator pozi- )
vanja funkcije (5to se deSava automatski), za objekat biti dereferenciran poka- );
z.ivad na dlan. tl primenr koli sledi, konstruktor klase FunctionObiect prikuplja i
e uva pokaz-ivae na ob jekat i pokazivad na lunkciju dlanicu, a zatim te pokazivade int main0 {
koristi operator poziva funkcije. Dog w;
Dog::PMF pmf = &Dog::run;
cout << (w->*pmf) (1) .. s.61 .
pmf = &Dog::s1eep;
Misliti na jeziku C++ Poglavlje I 2 : Preklapanje operatora 38s
384

cout << (w-'*Pmf) (2) " endl'


. Korisnici ne mogu definisati nove operatore. Io znaei da ne mo7-ete napra-
pinf - &Dog: :eat; viti nove operatore od kombinacija znakova koje se trenutno ne koristc
cout << (w-'*Pmf) (3) " .n6'' ' kao operatori. Iedan razlog je odredivanja prioriteta pri izraiunavanju
l ll l:- novih operatora, a drugi je to Sto potreba za novim operatorima niie tolika
da biste se mudili da ih naPravite.
Klasa Dog inta tri funkcije dlanice. Sve imaju celohrojni argument i vraiaju
celobrojni aigtrmeltt. Za PMF se koristi rezervisana rea typedef da bi se pojed-
. Ne moZete promeniti prioritete pri izradunavanju operatora. Njih ]e
nostaviio deftnisanje pokazivada na dlan koji pokazuje na funkcije dianice klase dovoljno tesko zapamtiti i takve kakvi su, kada se niko ne igra s njima.
Dog.
i)p.,rutu,. ->* pra'i i *.aia objekat klase Functionobiect. Ovai operator ima i
pokazivai'na oltjekar (this) i pokaT-ivai na dlan, i prosleduje ih konstruktoru klase Operatori koji nisu funkcije tlanice
irunctionobiect ko ji duva te vrecinosti. Kacla se na objekat primeni pokazivad na U nekim od preihodnih primera operatori su mogli biti funkcije dlanice ili funk-
ilan, prevodilac proslecluje argumente opelatoru ( ) rezultata te funkcije. Ope- cije koje nisu dlanice, i izgledalo je kao da tu nema velike razlike. ovo dovodi do
rator iunctionObiect::operator( ) uz-ima te algumente i dereferencira ,,pravi" pitu.,ji, ,,Kakve funkcije izabrati?" U opstem sludaju, ako vam je svejedno da li su
pokaz.ivad na alan koristeii saiuvane pokazivaae' etanlie ili ne, bolje je da izaberete da funkcije budu dlanice da biste naglasili
Primetite da se, kao i u sludaiu operatora ->, zapravo umeiete u poziv opera- povezanost operuioiu i klase. Ovo ie dobro raditi sve dokje levi operand objekat
tora ->*. Po potrebi, pre poziva moT.ete da obavite neke dodatne operacije. tekuie klase.
IVehanizam pokazivaia na dlan koji ie prikazan u primeru, radi samo za Nekada iete hteti da Ievi operand bude objekat neke druge klase, kao kada su
fr.rnkcije clartice koie irnaitr celobrojne argumente i celobrojne rezultate' Ovo ie operatori toka (<< i >>) preklopljeni za ulazno-tzlazne tokove. Poito su ulazno-
veliko ogranidenje, ali ako pokusate da prekiopite operator za razlidite tipove -ilazoi tokovi deo os.rolme biblioteke C++-a, verovatno iete iesto preklapati
argume;ata, udiniie ,u.., ." da ie to suvi5e zahtevan posao. Na sreiu, mehani- ove operatore, pa se isplati zapamtiti kako se to radi:
,u-.n Sobluno u C++-u (koji je opisan u poslednjem poglavlju ove knjige
i u dru- : Clz:IostreamOperatorOverloading.cpp
I /
gom tomtr) napravljen ie baS za resavanie ovakvih problema' // erimer preklopljenih operatora koii nisu ilanovi
#include "../require.h"
#i ncl ude <i ostream>
Operatori koje ne moZete preklapati je
#include <sstream> ff "Iokovi znakovnih nizova"
noitole ioperatori kt;e ne moT.ete preklapati. Glami razlogzaovo ogranidenje #i ncl ude <cstri ng>
bezbednost. Ako bi ovi operatori mogli da se prek-lapaiu, to bi na neki nadin
using namesPace std;
ugrozilo ili unistilo bezbednosne mehanizme, otezalo bi programiranje, ili bi
unelo zabunu. class IntArray {
. enum ( sz = 5 );
Operator dlan (.). Operator tadka ima znadenje za sve dlanove klase' ali
kada biste dozvolili d'a se ta; operator preklopi, ne biste mogli normalno da
int i [sz] ;
publ i c:
pristtrpate ilanovima.
IntArray0 { memset(i,0, sz* sizeof(*i)); )
. Pokaz.ivad na dlan (.*) - iz. istog razloga kao i operator O' int& operator[] (int x) {
. je
Ne posto ji operator eksponenta. Najpopularnije re5enje za ovo.bio opera- require(x>=0&&x<sz'
tor **, iz Fortrana, ali je to pokrenulo pitanje otezane sintaksne analize. " lntArray: :operator[]
jzvan opsega") ;
[] (l-u nema opcratora eksponenta, pa je iz-gledalo da on nije potreban ni u return i [x] ;
C++-u, ili se smatralo da umesto toga uvek mozete pozvati funkciju. Posto- )
jan je ovog operatora bi dodalo pogodnu notaci;'u, ali ne bi dovoljno unaple- friend ostream&
clilo funkcionalnost jezika da bi se opravdala dodatna sloZenost prevodioca' operator<<(ostream& os, const IntArray& ia);
fri end i stream&
operator>>(i stream& i s, IntArray& i a) ;
);
ost ream&
operator<<(ostream& os, const IntArray& ia) {
-
386 Misliti na jeziku C+r Poglavlje I 2: Preklapanje operatora 387

for(int J = 0; J < ia.sz; i++) { Osnovne smernice


os << ia.i [i];
if(3 != ia.sz -1) llurlayl je predloZio da pratite ove smernice kada odludujete da li ie operator
nc <<
biti tunkcija dlanica ili ne:
"

i
os .. endl; Preporufena upotreba
return os; Svi unarni operatori Funkcije ilanice
I
Momju Dltl funkcije ilanice
istream& operator>>(istream& js, IntArray& ia)( a= -= /= *= n= &= l= ft: yy= 1q= Funkcije tlanice
for(int i = 0; i < ia.sz; j++) Svi ostali binarni operatori Nisu funkcije ilanice
is >> ia.i[i];
return i s;
) Preklapanje dodele
Dodele desto zbunjuju novajlije u c++-u. Znak jednakosti predstavlja tako funda-
int main0 { mentahu operaciju u programiranju, kao sto je kopiranjeiegistra na maSinskom
stringstream lnput("47 34 56 92 103"); nivou. Pored toga, korisienje znaka jednakosti ponekadu po-riuu i konstruktor za
IntArray l; kopiranje (koji je opisan u poglavlju 1 I):
'1
nput >> l;
; I I Koristi se preklopljeni operator [] Tip b;
I t4l = -1
Tipa=b;
cout << I;
a = b;
I I I l,- u drugom redu se definiie objekat a. pravi se novi objekat na mestu gde ga
Klasa takode sadrZi preklopljeni operator pristupa dlanu niza, []' koji ranije nije bilo. Vei ste videli kakav odbrambeni stav ,urui^u c++ prevodilac
referencu na vazeiu wednost u nizu. Posto se waia referenca,izrazi prema inicijalizaciji objekata, tako d.aznateda se konstruktor
uvek mora pozvati
i[a] = -1; na mestu definisanja objekta. Koji konstruktor se poziva? objekat
a se pravi od
postojeieg objekta tipaTip (to je objekat b, s desne strane znaka jednakosti),
menja vrednost elementa niza, a izgleda mnogo bolje od izraza u kome se

ste pokazivadi. lqo q" postoji samo jedan izbor: konstruktor za kopiranje. Iako se Loristi znak
jednakosti,
VaZno ie da znate da argumenti preklopljenim operatorima pomeranla
ipak se poziva konstruktor za kopiranje.
sleduju po referenci, tako da mogu izazvati sporedne efekte' U defin
u treiem redu, stvari stol'e drugadije. Na levoj strani znaka jednakosti narazi
se prethodno inicijalizovan objekat. Iasno je da neiete pazvati
funkcija, izraz.ikao Sto ie ovai: konstruktor za
objekat koji je vei napravljen. u ovom sludaju, za objekat a se poziva rip:,opera-
os << ia.i [:]; tor=, a plisls6uje mu se desna strana znaka jednakosti. (MoZeie imati vise
(to jest, funk-
r.rz.rokujtr cla se poz.ivaj u postoieie preklopljene funkciie operatola cija operatora dodele koje rade s razliditim tipovima desnih
operanada.)
biblioteci <iostream>). U ovom sludaju, pozvana je fun
ko je su clefinisane tr
. ovakvo ponasanje se ne ogranidava samo na konstruktor ia kopiranje. Kada
osiream& operator<<(ostream&, int), zato Sto ia.i[i] waia celobrojnu inicijalizujete objekat korisienjem znaka jednakosti, umesto'uobiealenog
nost. poziva konstruktora, prevodilac ie potraiiti konstruktor
koji prihvata wednost
Kada zawsi rad s objektom klase istream ili ostream, funkcija operatoftI koja se nalazi s desne strane:
referencu tog objekta tako da se moze koristiti u sloZenijim izrazima. : :CopyingVs Ini ti
je / / C12 a1 i zati on. cpp
U glavnom programu, koristi se novi tip klase iostream, a to class Fi {
(dekla'risan je u za[lavlju <sstream>). Ova klasa pretvara objekat tipa sfing
publ i c:
odniza kao je ovde pokazano) u ulazno-izlazni
moze napraviti znakova, Sto
testirati
Fi0 {}
tJ prethodnorn primeru, ovo znaei da se operatori pomeranja mogu l.
otvaranja datoteke ili r.rpisivanja podataka s komandnog reda'
Uovomprimerujeprikazanstandardninaiinkori5ienjaoperatora
Da biste preklopili ove operatore' kopirajte potpis funkcije, watite objekte I Rob Mu.ray, C++ Strategies & Iacaics, Addison-Wesley,
1993, strana 47
5to je redeno i napravite sliino telo funkciie.
Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 389
388

a = rv.a;
61 355 Fee {
b = rv.b;
publ i c: c = rv,c;
Fee(rnt) {) return *thi s;
Fee(const Fl &) { )
)
); friend ostream&
operator<<(ostream& os, const Value& rv) {
int main0 (
return os << "a =,'<< rv.a ((,,, b=,
Fee fee = t; ll Fee(int) << fv.b (( ", C " << fv.c;
F] f i ; =
)
Fee fum = ft; ll Fee(Fi) )r
\ I I t,-
KadaraditeSaZ-nakomIednakosti,trebadaimatenaumuSledeie:iniciializa- int main0 {
koristi se ope'
ako obiekai joS uvek niie napravljen; u suprotnom'
.iiu..-ruir,.ra Value a, b(1, 2, 3.3);
rator dodele (=). cout << "a: " << a << endl;
se znak jednakosti koristi za cout << "b: " << b << endl;
loi ie bolie da izbegnete pisanie koda u.ko.me konstruktor' Dve iniciializa-
inicilaliz.aciiu; umesto ,"g", It"t pozivaite izriiito a= b;
lii. ,r toiirnu kori5ien z-nak jednakosti' sada postaiu: cout << "a posle dodele: ,,<< a << endl;
ie
I ///:-
Fee fee(i);
Fee fum(fi ); ovde objekat s leve strane znaka jednakosti kopira sve elemente objekta s
desne strane, onda waia referencu na sebe koja omoguiuje pravljenje sloienijih
'fako neiete zbuniivati ditaoce vaSeg koda'
izraza.
ovaj primer sadrzi uobidajenu gresku. prilikom dodele wednosti objekra istog
Ponaianje oPeratora dodele (:) tipa, uvek treba da proverite da li se objekat dodeljuje samom sebi. U nekim
sludajevima, kao Sto je ovaj, moZete bez problema dodeliti wednost, ali ako se
Lldatotekamalnteger.hiByte'hvidelisteda-operatordodelemoZebitisamo
nalazi.s leve strane
irnt.i;u dlanica. tln je tesnt povezan s objektom koii se dodele' onda biste izmeni realizacija klase, onda to moze postati znaiajno. Ako nemate naviku da
operator
znaka =. Kacla bi Uifo .oguCt'globalno definisati
proveravate powatno dodeljivanje, moZete napraviti greske koje se kasnije
tesko
pronalaze.
mogli pokuSati cla redefiniSete ugradeni znak =:
int operator=(int, Tip) ; ll Ovo:e globalno = nije dozvoljeno!
vas da operator dodele (=) Pokazivati u klasama
Prevodilac reSava ovaj probiem primoravajuii sta. se desava kada objekat nije ovako jednostavan? sta ako, na primer, objekat
napravite kao funkciiu dlanicu' sadrZi pokazivade na druge objekte? Ako kopirate wednost pokaiivada, imaiete
Kada napravite operatol dodeie (-), molate
kopirati sve potrebne informacije
dva pokazivada na istu memorijsku lokaciju. o pokazivadima u objektima sami
iz-desnogoperandautekuiiobjekat(tojest,.uobjekatzakojijepozvanoperator morate voditi raduna.
dodele).7a iednostavne obiekte, ovo ie odigledno: Postoje dva pristupa ovom problemu. Najjednostar,niji nadin jeste da kopi-
I I : C12: SimPl eAssi gnrnent ' cPP rate,ono na sta se pokazivad odnosi kada dodeljujete wednost ili koristite kon-
// Jednostavan oPerator =0 struktor za kopiranje. Ovo je jasno:
#include <iostream>
us i ng namesPace std;
/ / : ClZzCopyingWi thpoi nters. cpp
// Re5avanje problema postojanja alijasa pokazivada
c1 ass Va1 ue // kopiranjem onoga na Sta pokazuju u toku
dodele i koriieenja konstruktora za kopiranje.
{

int a, b; //
#incl ude ". ./require.h,,
float c; #include <string>
public:
float cc = 0.0) #i ncl ude <i ostream>
Value(int aa = 0, int bb = 0'
using namespace std;
: a(aa), b(bb), c(cc) {)
Va1 ue& oPerator= (const Val ue& rv) {
Misliti na jeziku C+t Poglavlje I 2: Preklapanje operatora 391 t-
390

cl ass Dog {
Dog* getDog0 const { return p; i
stri ng nm;
-DogHouse0 { delete p; }
pub l i c :
friend ostream&
Dog (const stri ng& name) : nm(name) {
operator<<(ostream& os, const DogHouse& dh) {

cout << "Pravi se obiekat tiPa Dog: << *this << endl; return os .."[" .. dh.houseName
<< "] sadrZi " *Oh.Ot
) "
// ieni konstruktor za kopi ranje i
Napravl
l.
)

//operator dodel e su 1 spravni .


IIPravljenje objekta tipa Dog iz pokazivaca na Dog:
Dog(const Dog* dp, const string& msg) int main0 {

: nm(dp->nm + msg) {
DogHouse fidos (new Do9("Fi do") , " Fi doHouse") ;

cout << "Kopi ram objekat ti Pa Dog << *this << " from cout << fjdos << endl;
DogHouse fidos2 = fidos; // Pozivanje konstruktora za kopiranJe
'< "dP << endl; cout << fidos2 << endl;
)
fi dos2. getDog () ->rename ( " Spot" ) ;
-Dos 0 {
<< *thjs << endl; f i dos2. renameHouse ( "SpotHouse" ) ;
cout << "Bri sem obiekat ti Pa Dog:
cout << fidos2 << endl;
)
voi d rename(const stri ng& newName) { fidos = fidos2; /l Dodela
nm = newName; cout << fidos << endl;
cout << "Preimenujem obiekat tipa Dog u: .< *thjS.. endl; f j dos. getDog ( ) -rrename ( "1'1ax" ) ;
f i dos2. renameHouse ( "MaxHouse" ) ;
I l/l:-
)
fri end ostream&
operator<< (ostream& os, const Dog& d) { Dog je jednostavna klasa koja sadrZi samo znakovni niz u kome se duva ime
return oS .. "[" .. d.nm << "l ". psa. U op5tem sludaju, znaiete kada se ne5to desi u klasi Dog zato Sto konstruk-
I tori i destruktori ispisuju poruke. Obratite paZnju na to da je drugi konstruktor
); pomalo slidan konstruktoru za kopiranje, osim sto je argument pokazivaa a ne
referenca, i ima drugi argument koji predstavlja poruku koja se nadovezuje na
cl ass DoqHouse { ime psa. Ovo pomaZe pri praienju ponaianja programa.
Dog" p; Funkcije dlanice ne ispisuju opis objekta, vei Salju wednost *this u tok cout.
stri ng houseName; Time se, u stvari, poziva operator toka (<<) klase ostream. Ovaj nadin je dobar,
publ i c:
jer ako poZelite da promenite format informacija o klasi Dog (kao Sto sam ja ura-
DogHouse(Dog* dog, const string& house)
dio dodajuii 't' i '1 '), treba da ga promenite samo na jednom mestu.
:
p(dog) , houseName(house) ( i
Klasa DogHouse sadrzi pokazivad tipa Dog* i prikazuje detiri funkciie koje
DogHouse(const DogHouse& dh)
: p (new Dog (dh. P, " kopi rano" ) ) ,
iete uvek morati da defini5ete kada klasa sadrZi pokazivaie, a to su: obidan kon-
houseName (dh. houseName
struktor, konstruktor za kopiranje, operator dodele 1=) (ili ga definiSite, ili ga
+ " kopirano") () onesposobite) i destruktor. Operator dodele proverava powatno dodeljivanje,
DogHouse& operator= (const DogHouse& dh) { iako to ovde nije obavezno. U ovom sludaju, powatna dodela se proverava samo
j da biste se setili te moguinosti, ako kasnije promenite k6d.
I I Provera povratnog dodel i vanj a:
if (&dh l= this) {
p = new Doq(dh.P, " dodelieno"); Brojanje referenci
houseName = dh. houseName + " dodel jeno" ;
U prethodnom primeru, konstruktor za kopiranje i operator dodele (=) prave
) novu kopiju objekta vezanog za pokaziva(, a destruktor je briSe. MoZda iete
return *thi s;
Zeleti da izbegnete ovo kopiranje ukoliko objekat zahteva puno memorije ili
I troSi puno resursa pri inicijalizaciji. Ovaj problem se obidno reiava broianjem
void renameHouse(const string& newName) (
referenci.Treba da napravite pametan objekat, koji zna koliko objekata pokazuje
houseName = newName;
)
393
Poglavlje I 2: Preklapanje
operatora
Misliti na jeziku C+$
392
void detach0 t
konstruktorom za kopiranje require(refcount != 0) ; *this << endl;
na njega. Prilikom dodeliivanja ili iniciializa^ciie tipa Dog: '<<
treba napraviti jo5 jednan pokazivad
na postojeci obiekat i uvecati broj
referenci' cout << "Prekidam "tl"'u objektom koristi:
,*;fi ffii;i"rJJ
i obiekat kada broj referenci ii-unlstava obiekat ako ga niko ne
Desrruktor treba da ""isti it(--retcount == 0) delete this;
dostigne nulu.
Jiil *ri e a m ate ob ekat (Doq iz.p letlr-ojl" cl::T::l' Yi i, iy'i;
',ilii: t d e nj j )
77 Urtorno kopira
ovai objekat klase Dog'
."#L:;J;""ffi ,;";'#;6;;.;;Gn-'i"n"li':ll::1lS:':l:::"til":i: 'l'l ioziua se pre menjania obiekta tipa Dog'.a
::TJt"##;ffi ffi ; ;i17"o'i.'o u u i i " ." io ovaj rob em ali asa'
E
ko risti se
p I j

// rezultujuei poru..,yu"C ,"-ioO.f:riL pokazivadu


tipa Dog*'

H::ffi"rf',Jff ii.:'iil;;;'ipiiii'nriunisu'!z1e,t.:!.11!:!,";?^i?;I1i 'ots* 0 *this


;illll?l,""i;,;;;#"';A::*,::t*::I::'Jtti:[:#1:
llXX'fi lru ururu
DISanla '^'"";i"':';;t"t" lidnu kopiju tog blokapre nego Sto
unal i as t
cout << "Ukidam alijas za objekat
tipa Dog: '<<
postoje alijasi:
<< endl;

troj referenci veii od jed . r ""p*'iti )l-H. prauit. kopiie ako ne


,:;; ;" I!:i: f T:f i: :TSe
L:^+^ -^-^mariri rrrte no.atke. Evo ied-
atke Evo
ffiffi referenci
;'""Ji:i:'::";[ffi[-i""ia
^ ,-
-l: pri upisu'
pod j ed-
i'f(retcount == 1) return this;
ffiffi;H.""i" i kopiranja
--refcount;
za kopiranje:
//: C12:ReferenceCounti ng' cPP //' ioristi konstruktor
'"Ltr"n n.* Dog(*this) :
// Broianie referenci i kopiranje pre uplsa
*inctuoe "../require'h" ) (
#i ncl ude <stri ng> ioid rename(const string& newName)
#i ncl ude <i ostream> u: " <( *this << endl;
::r;::-lliT:imenujem objekat tipa
Dos
using namesPace std;
)
cl ass Dog friend ostream&
{
Dog& d) {
stri ng nm; ooerator<<(ostream& os' const u1'
return os << "[" << d'nm << rc = "
int refcount;
Dog(const string& name) << d.refcount;
:'nm(name), refcount(1) t
Dog:'<< *this
)
<< endl;
cout <<,,prav.im oUjetai tipa );
)
// Soretavamo dodelu: class DogHouse {
bog&' operator= (const Dog& rv) ; Dog* P;'
publ i c: string houseName;
' il ou:.t,i klase Dog se mogu napraviti samo u dinamidkoi memoriii: publ i c:
't',uii. oos- make(const stri
ng& name) { '-iogiorru(oo9* dog, const string&
-,"pio.nj,
house)
(
return new Dog(name);
,.- !:
1. houseName(house)
,,ttapravtiela DogHouse: '<<
*this << endl;
) cout << i.-i.rut.
--t'nrtO.n*Dog& d)
Dog(const )
dh)
i " kopiia"),
refcount(1)-( DogHouse(const DogHouse&
Dog: " : P(dh.P)
cout << "Konstruktor za kopiranje klase '
'houseName("koPirano
<< *thi s << endl ; " +

dh.houseName) t
i
-Dos0
-;;ri:. t P->attach0;
"Bpisem objekat tipa Dog: '<< *this << endl;
cout << "Konstruktor' za kopiranje
klase DogHouse: "
<< *this << end'li
)
void attach0 ( )
DogHouse& dh) {
++refcount; DogHouse& operator=(const
cout << "Povezujem objekat tipa Dog: '<< *this << endl;
// Proverite povratno dodeliivanie:
irtaon r= this)
"norrallarna
(

= dh.houseName + " dodelieno";


)
394 Misliti na jeziku C++ Poglavlje I 2 : Preklapanje operatora 395 l-

te ono 5to ste naipre kori sti I i cout << "bobs:" << bobs << endl;
I I ObriSi :

cout << "Unos spots = fidos,, <. endl;


p-,detach ( ) ;
p = dh.p; Kao konstruktor za kopiranje spots = fidos;
// cout << "Pos1e spots = fidos" .< endl;
p->attach ( ) ;
cout << "spots:" .. spots << endl;
: cout << "Dode'ljivanje .istom objektu,' << endl;
cout << "DogHouse oPerator= "
<< *tht s t< endl bobs = bobs;
;
return *thi sI
cout << "Pos1e dodeljivanja istom objektu,, << endl;
cout << "bobs:" << bobs << end];
I
// Umani i vanje broja referenci , usl ovno uni Stavanje objekta // Sledede redove oznaiite kao komentare:
cout << "rename(\,,Bob\,,),, << endl .
-DogHouse ( ) (

cout << "DogHouse destruktor: " 0 ->rename ( ,,Bob,,) ;


bobs . getDog
<< *this << endl; cout << "Posle rename(\,,Bob\,,),, << endl ;
p->detach ( ) ; \ / // :-
I klase DogHouse pokazuje na objekat klase Dog. ICasa DogHouse broji
(const stri ng& newName) ( -objekat
voi d renameHouse reference i sadrZi funkcije za upravljanje referenci. Na raspolaganju je i konstruk-
houseName = newName; tor za kopiranje, tako da moZeie napraviti nov objekat tipu oo! oa postoyeceg.
I Funkcija attach( ) uveiava broj referenci objekta ripa Dog iaiedan, dime uka-
vojd unaliasO { P = P->una1ias0; } zuje na to da jos neko koristi taj objekar. Funkcija detach( ) umanjuje broj refe-
I I Kopiranje pre upi sa. Svaki
put kada meni ate
renci za jedan. Ako broj referenci postane nula, znadi da vise niko ne korisii ovaj
sadriaj pokazivada, prethodno morate
II objekat, pa se on uniStava iskazom delete this.
// ukloniti alijase: Pre nego Sto promenite objekat (na primer, preimenujete ga), uverite se da ga
void renameDog(const string& newName) {
niko drugi ne koristi. To iete uraditi pozivanjem funkcije DogHouse:unaliasi),
unalias0; koja poziva funtciju Dog::unalias( ). ova druga funkcija ie watiti postojeii poka-
p-,rename ( newName) ;
ziva( na Dog ukoliko je broj referenci jedan (sto znadi da niko drugi nepokazuje
)
na taj objekat), ili ie kopirati objekat tipa Dog ako je broj referenci veci oa
ll ...ili kada nekome dozvolite pristup: leaan.
Konstruktor za kopiranje klase DogHouse ne zauzima prostor u memoriji, vei
Dog* getDog0 {
dodeljuje pokazivadu adresu izvornog objekta tipa Dog. Fo5to jos jedan objekat
unalias0;
return P; koristi taj blok u memoriji, broj referenci se poveiiva pozivanjem funicije
Dog::attach( ).
I
fri end ostream& operator dodele (=) radi sa objektom koji je vei napravljen na levoj strani
operator<< (ostream& os const DogHouse& dh) i znaka jednakosti, tako da ga mora obrisati pozivanjem funkiiye detach( ona
' ).
return os " "[" " dh.houseName ie uni5titi stari objekat tipa Dog, ako ga niko vise ne koristi. operator dodele radi
<< "] sadrzi " *dh'P, slidno kao konstruktor za kopiranje. primetite da on prvo proverava da li dode-
"
i ljujete objekat samom sebi.
); Destruktor poziva funkciju detacho za uslo',no uniStavanje objekta tipa
Dog.
int main0 { Da biste realizovali kopiranje pri upisu, morate kontrolisati sve radnje koje
DogHouse piSu po bloku memorije. Na primer, funkcija dlanica renameDog( menja wed-
)
ilOos(oos: :make("Fido"), "FidoHouse"), nost u bloku memorije. Ali, ona najpre koristi funkciju unaliasd da bi spredila
spots(Dog: :make("Spot"), "SpotHouse") ; izmene objekta tipa Dog na koji pokazuje vise objekata klase DogHouse. Ako
cout << "KoPiranje" << endl; treba da napravite pokazivad na objekat tipa Dog iz objekta tipa D-ogHouse, za
DogHouse bobs(fidos); taj pokazivad prethodno pozovite funkciju unalias( ).
cout << "Posle kopiranja bobs" << endl;
cout << " fi dos: " << fi dos << endl ;
cout << "sPots:" " spots << endl;
396 Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 397

tlglar.nonr programu se testiraju razne funkcije koje moraju isprarmo raditi Da biste bolje razumeli ovu tehniku, razmotrite prikazane rezultate pro-
da bi se realiz-ovalo brojanje referenci: konstruktor, konstruktor za kopiranje, grama, proudite izvorni kdd i eksperimentisite s programom.
operator dodele i destruktor. Takode se testira i kopiranje pre upisa, pozivanjem
funkcije renameDog( ). Automatsko pravljenie operatora dodele
F.vo rezultata programa (s malo promenjenim formatiranjem): Veiina ljudi odekuje da je moguie dodeliti jedan objekat drugom objektu isrog
Pravlm objekat tipa Dog: [Fido], rc = 1 tipa, paie prevodilac automatski napraviti operator tip::operator=(tip), ako $a
Napravljena je klasa DogHouse: IFidoHouse] sami ne napravite. Ovaj operator opona5a automatski konstruktor za kopiranje;
sadrzi IFido], rc = I ako klasa sadrZi objekte'(ili je nasledena od druge klase), rekurzi'.rno se poziva
Pravim objekat tipa Dog: [Spot], rc = I operator dodele za ove objekte. Ovo se naziva dodela ilan po ilan.
Napravljena je klasa DogHouse: ISpotHouse] Na primer:
sadrzi ISpot], rc = I
Kopi ranj e II : C12: Autonatj cOperatorEqual s.cpp
#include <iostream>
Povezujem objekat Dog: Ifido], rc = 2 using namespace std;
Konstruktor za kopi ranje k1 ase DogHouse:
INapravljena je k1asa FidoHouse] class Cargo
sadrzi IFido], rc = 2 publ i c:
{

Posl e kopi ranja bobs


Cargo& operat6p=(sonst Cargo&) {
fi dos: IFi doHouse] sadrii IFi do] , rc = ? " << endl;
cout << "unutar Cargo: :operat6p=0
spots: ISpotHouse] sadrZi ISpot], rc = 1
return *thi s;
bobs: INapravljena je klasa FidoHouse]
sadrzi IFido] , rc = ? L
t,
)

spots = fidos
Prekidam vezu tipa Dog: [Spot], rc = 1
class Truck
Briie se objekat tipa Dog: [Spot], rc = 0 {
Cargo b;
Povezujem objekat tipa 0og: IFido], rc = l l.tt
DogHouse operator= ; IFi doHouse dodelJeno]
sadrzi IFido], rc = 3
jnt main0 {
Posle spots = fidos
Truck a, b;
spots: IFidoHouse dodeljeno] sadrZi IFido],rc = 3 a = b; ll Ispisuje: "unutar Cargo::operator=0"
Dodel jivanje istom objektu
DogHouse operator= :
[napravljena ie klasa FidoHouse]
I I //,-
sadrzi IFido], rc = J Automatski operator dodele za klasu Tluck poziva operator CarSo::operator=.
Posle dodeljivanja istom objektu U opstem sluiaju, neiete hteti da prevodilac ovo radi umesto vas. Za malo
bobs : I napravl j ena j e k1 asa Fi doHouse] sloZenije klase (narodito ako sadrZe pokazivadel) treba sami da napravite opera-
sadrzi IFido], rc = l tor dodele. Ako zaista neiete da se klasa koristi u izrazu dodele, deklari5ite ope-
rename("Bob") rator dodele kao privatnu funkciju. (Ne morate da ga definisete osim ako iete 8a
Posle rename("Bob") koristiti unutar klase.)
DogHouse destruktor: Inapravljena je klasa FldoHouse]
sadrzi IFido] , rc = 3
Prekidam vezu sa objektom tipa Dog: IFido],
DogHouse destruktor: IFidoHouse dodelieno]
rc = 3 Automatska konverzija ti Pova
Kada u jezicima C i C++ prevodilac vidi neodgovarajuii tip podataka u izrazu ili
sadrzi IFido], rc = 2
pozivu funkcije desto moze automatski da konvertuie tipove wednosti. U C++-u
Prekidam vezu sa objektom tipa Dog: IFido], rc = 2 isti efekat moZete postidi i za klase, tako Sto iete definisati funkciju za automat-
DogHouse destruktor: IFidoHouse]
sku konverziju tipova. Postoje dve verzije ove funkcije: odredeni tip konstruk-
sadrzi IFido] , rc = 1
tora i preklopljeni oPerator.
Prekidam vezu sa objektom tipa Dog: IFido], rc = 1
Brisem objekat tipa Dog: [Fido], rc = 0
Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 399
t-
398

class Two {
Konverzija kon stru ktorom publ i c:
Ako definiSete konstruktor koji ima samo jedan argument - objekat (ili refe- expiicit Two(const One&) {}
rencu) drugog tipa - taj konstruktor ie dozvoliti prevodiocu da automatski kon- );
vertuje tipove. Na primer:
I I : ClZ:Automati cTypeConversion.cpp void f(Two) {}
// Konstruktor za konverziju ti pova
class 0ne { int main0 {
publ i c: One one;
One0 () //l f(one); // niie dozvoijena automatska konverzija
)r f(Two(one)); // U redu -- konverziju izvodi korisn.ik
\ ///,-
class Two { Konstruktor objekta T\ryo smo udinili izriditim, dime smo rekli prevodiocu da
publ i c:
ne koristi taj konstruktor za automatsku konverziju (ostali konstruktori te k]ase,
Two (const 0ne&) i )
koji nisu izriditi, i dalje se mogu koristiti za automatsku konverziju). Korisnik
); mora rudno da konvertuje tip. u prethodnom primeru, funkcija f(TWo(one)) pravi
priwemeni objekat tipaTivo od objekta tipa one, bas kao sto je to radio prevodilac
void f(Two) {i
u prethodnoj verziji ovog primera.
rnt main0 {

0ne one;
i obiekat tjpa Two, a dobiia obiekat tipa
Konverzija operatorom
f(one); // Funkcija 2el One
Automatska konverzija tipova se izvodi i na drugi nadin: pozivanjem prekloplje-
I I I l,- nog operatora. Mozete napraviti funkciju dlanicu koja konvertuje tip podatka. Ime
Kada prevodilac vidi da je funkcija fo pozvana sa objektom klase one, on te funkcije sastoji se od rezervisane redi operator i imena ciljnog tipa. ovakav
pogleda deklaraciju funkcije fo i vidi da je njoj potreban objekat klase T\ryo. nadin preklapanja operatora je jedinswen jer izgleda kao da ne zadajete tip rezul-
2aiim traZi nadin da od objekta klase One dobije objekat klase Tlvo i pronalazi tata - tip rezultata je ime operatora. Evo primera:
konsrruktor TWo::TWo(One) koga tiho poziva. Rezultat tog poziva je objekat : C12:}peratorOverloadingConversion.cpp
/ /
klase TWo koji se prosleduje funkciji f( ). class Three {
lJ ovom sludaju, automatska konverzija tipova vas je spasila muke oko deflni- int i;
sanja dve preklopljene verzije funkcije f( ). Medutim, dolazi do skrivenog poziva publ i c:
konstruktora za objekat klase T\aro, Sto moZe biti znadajno ako razmatrate efika- Three(int ii = 0, int = 0) : i(ii) ()
snost poziva funkcije f( ). I;

Kako spreciti konverziju konstruktorom ciass Four {

t) nekim ,situacijama, automatska konverzija tipova pomoiu konstruktora moZe int x;


izazvati probleme. Da biste onemoguiili olu konverziju, izmenite konstruktor
public:
stavljajuii ispred njegove dekiaracije rezervisanu red explicit (koja se koristi Four(int xx) : x(xx) {)
operator Three0 const { return Three(x);
samo za konstruktore). Na taj nadin smo izmenili konstruktor klase TWo iz pret- )

hodnog primera: ];
I I : ClZ: Expi i ci tKeYword. cPP void g(Three) {)
I I Kori 5cenj e rezervi sane redi expl i ci t
class 0ne { int main0 {
publ i c: Four four(1);
One0 {} g ( four) ;
); S/1r); // Poziva operator Three(1,0)
Misliti naieziku C++ Poglavlje I 2: Preklapanje operatora 40t
400

Klasa Number ima i operator sabiranja (+), koji je dlan klase, i operator odu-
Konverzijr-rkonstrtlktoromizvodiodrediSnaklasa,akonverzijuoperatorom
Sto pri pravlienju zimanja (-), koji je prijatelj klase. Po5to postoji konstrukror koji ima samo jedan
radi izvorna klasa. Znae aj metocle s konstluktorom ie u tome
nolrr putanju konverz-ije. Medu. celobrojni argument, ceo broj se moZe automatski konvertovati u tip Number,
nove klase, postojeiem .i,...nu moZete dodati
jec.lnim argumentom rruek definise automatsku konverziju ali samo pod odredenim uslovima. U glawrom programu sabiranje dva objekta
tim, krlrrstrirktor s klase Number dobro funkcioni5e zato sto ro potpuno odgovara preklopljenom
jednog podrazume-
iifoua feak i ako postoji vise argumenata, ali su svi osim operatoru. Takode, kada prevodilac vidi objekat klase Number iza koga slede
uanil, sio moZda ne Zelite (u tom sluiaju, onemoguiite konverziju.koriSienjem
moZe koristiti da bi se operator sabiranja i neka celobrojna wednost, to odgovara funkciji dlanici
rezervisane redi explicit). Pored toga, konstruktor se ne
konvertovao u ugradeni tip; to je jedino moguie uii- Number::operator+, a celobrojni argument se konvertuje u tip Number kori-
tip kojije definisaoiorisnik
Sienjem konstruktora. Ali, kada prevodilac vidi celobrojnu wednost, operator
niti preklapanienl oPeratora.
sabiranja i objekat klase Number, on ne zna sta da radi, jer ima samo funkciju
Number::operator+, koja zahteva da levi operand bude objekat klase Number.
Refleksivnost Prema tome, prevodilac prijavljuje gre5ku.
preklopljenih operatora
ledan od najva2nijih razJoga za upotrebu giobalnih Prijateljski operator oduzimanja se ponasa drugadije. prevodilac moZe da
jeste to Sto se automatska fonverzila tipova moZe primeniti na bilo. koii ope-
tipa' popuni oba argumenta kako god zna; pri tome levi argument ne mora biti tipa
rand, dok kod operatora u klasama levi argument mora biti odgovarajuieg Number. Dakle, u izrazu:
Akozelitedasekonvertu,juobaoperanda,globalnaverz\javasmoZepostedeti 1-a
pisanja velikog koda. llvo malog primera:
prvi argument se konvertuje u tip Number, kori5ienjem konstruktora.
I I : Clz: Ref I exi vi tylnOverl oadi ng'cpp
Nekada iete hteti da ogranidite upotrebu operatora tako sto iete ih udiniti
c1 ass Number {
dlanovima klase. Na primer, kada mnozite matricu vektorom, vektor mora biti s
int i;
publ j c: desne strane. Ali, ako zelite da oba operanda mogu da se konvertuju, napravite
Number(int ii = 0) : i(ii) {} operator kao prijateljsku funkciju.
const Number Na sredu, uizrazu l-1, prevodilac neie konvertovati oba argumenta u objekte
operator+(const Number& n) const { klase Number, pa onda pozvati operator oduzimanja. To bi znadilo da bi posto-
return Number(i + n.i); jeii kod napisan na jeziku c mogao da radi drugadije. prevodilac prvo proverava
i najjednostavniju moguinost, a to je ugradeni operator zaizrazl-1.
friend const Number
operator- (const Number&, const Number&) ;

);
Primer konverzije tipova
Automatska konverzija tipova je veoma korisna u klasama koje kapsuliraju zna-
const Number kor.'ne nizove (u narednom primeru koristiiemo klasu string iz standardne
operator- (const Number& n1, biblioteke jezika c++, jer je jednostavna). Kada se tipovi ne bi automatski kon-
const Number& n2) { vertovali, morali biste da napravite funkciju dlanicu za svaku od funkcija iz sran-
return Number(n1.j - n2.i)i dardne biblioteke jezika C, koje rade sa znakormim nizovima:
I
int main0
//: ClZ:Stringsl.cpp
Number
{
a(47), b(11);
// Bez automatske konverzije tipova
#i ncl ude " . . /requi re. h "
a+b;//Uredu #i ncl ude <cstri ng>
a + l; ll drugi argument je konvertovan u tip Number #include <cstdlib>
I ll t + a; // Pogreino!
Prvi argument niie tipa Number
#i ncl ude <stri ng>
a-b;//Uredu using namespace std;
a - t; ll drugi argument je konvertovan u tip Number
t - a; ll prvi argument je konvertovan u tip Number class Stringc {
\ I I l'- stri ng s;
402 Misliti na jeziku C++ Poglavlje I 2: Prekiapanje operatora 403
i

publ i c: konstruktor s jednim


argumentom tipa X, to omoguiava istu konverziju tipova.
Stringc(const string& str = "") : s(str) {} Prevodilac sada moze na dva nadina preii sa X nay, tako da ie prijaviti greSku:
i nt strcmp (const Stri ngc& 5) const {
/ / : ClZ :IypeConvers.i onAmbi gui ty. cpp
return : :strcmp(s.c-str0, S.s.c-str0) ;
class Orange;
)
// Deklaracija klase
ll ...itd., za svaku funkciju iz string.h class Apple {
); publ i c:
operator Orange0 const; // Konvertuje Apple u Orange
int main0 {
);
Stringc s1("zdravo"), s2("svima") ;
sl.strcmp(s2); class 0range {
\ I I l,- publ i c;
Ovde je napravljena sarno funkcija strcmp( ), ali vi biste morali da napravite 0range(App1e); ff Konvertuje Apple u 0range
odgovarajuiu funkciju dlanicu za svaku funkciju iz klase <cstring>-koja vam l.
zatieba. Sreiom, kada omoguiite automatsku konverziju tipova, sve funkcije iz
z-aglavlja <cstring> postaiu dostupne: void f(0range) {}
I I : CIZ: St ri ngs2 . cPP jnt majn0 {
// S automatskom konverzijom tipova
Apple a;
#incl ude ". ./requi re.h"
#j ncl ude <cstri ng>
//l f(a); // Greika: dvosmislena konverzija
#i nc'l ude <cstdl i b>
| ///:-
# inc'l ude <stri ng> odigledno resenje ovakvog probrema jeste da ga ne napravite. Napravite jedin-
usrng narnespace std; stuenu putanju za automatsku konverziju iz jednog tipa u drugi.
Problem koji je teZe uoditi nastaje kada ornoguiite autom-atsku konverziju u
c1 ass Stri ngc { viSe tipova. Ovo se ponekada naziva uiie izlaza(engl.
fan_out):
stri ng s; : C12:lypeConversi onFanout. cpp
publ i c:
/ /
cl ass 0range { ) ;
Stringc(const string& str = "") : s(str) {) cl ass Pear { } ;
operator const char"0 const {
return s.c_str0; class Apple {
i publ i c:
I; operator Orange0 const;
operator Pear0 const;
int main0 {
);
Strjngc ("zdravo"), s2("svima") ;
s1
strcmp(s1, s?); ll Standardna funkcija iezika C
strspn(s1 , sZ); I I Bilo koia funkcija nad znakovnim nizovima!
// Preklopljena funkcija eat0:
voj d eat (0ran9e) ;
\ I ll,- voj d eat (Pear) ;
Sacla svakoj ftrnkciji ciii ie argurnent tipa char*, moZete proslediti i argument
ripa Stringc, z-ato Sto prevodilac z.na kako da od tipa Stringc napravi tip char'. int maln0 i
Apple c;
//t eat(c);
Zamke automatske konverzije tipova // Greika: konverzija Apple -> Orange ili Apple _> pear ?
Kacla prevo<lilac mora da iz-abere nadin pretvaranja tipova, moZe upasti u pote- I lll:-
Skoie ako niste dobro osmislili konverzije. Jednostavan i oiigledan primer je klasa
X koja moZe da se konvertuje u objekat klase Y operatorom Y( ). Ako klasaY ima
404 Misliti na jeziku C# Poglavlje I 2: Preklapanje operatora 405

i,la;a Apple rnrtlc konverloYati i u klasu orange i u klasu Pear'


se aurr-rmatskr SaZetak
verzije
/arnka 1e u rtmr: str.r sve radi dobro dok neko ne napravi dl'e preklopljene Preklapanje operatora postoji zbog onih situacija rr kojirna vanr olaklava 2ivot.
(.\krtposroii samo jedna t'erz,i)aovefunkcije,glavni programradi Tu nema nikakve tajne: prekloplieni operatori su funkcije sa duclnirn irnenirna
fitnkrtji eat()
isprarno.I koje prevodilac poziva kada prirneti odgovarajrrCi obrazac. Ali, ako preklapanje
l)z yt,tr:rrtrn(). rt ,'enje probleme - i opita smernica za automatsku
z'a ett'akte operatora ne donosi velike olak5ice (kao autonr klase) ili korisniktr klast', ontla ie
y()t)'i(:rt))u ltp()',a - psrc r)a naprat'iie jedinstvenu putanju a-utomatske konver- bolje da ne pravite zbrktr njegovonr ttpotrcbotrt.
u druge tipove' ali ne
,i1,, ,, 1,,',)n,,7 t;pa u drugi Klasa se moZe konvertovati
molete napraviti posebne funkcije'
rnats ki. prett'aranja
7a takt a
r.t u Io
VeZbe
ReSenja ovih veZbi nalze se u elektronskom dokumentu fr,p 7)lirrl-irl8
in c++ Atnokttul.sohrtiur ('rtir'ie' koji
moZeie preuzeti sa lokaci.ie m.BruceEckel com'
Skrivene aktivnosti pratiti n-ek-e interne neodekivane aktivnosti
(++)'
l. Napravite jednostavnu klasu s preklopljenim opelatorom uveianja
Automatsku konverziju iipouu togu
Pozovite ovaj operator u prefikinoj i sufiksnoj verziji i
pogledajte kakvo
;;;;;;i. ;ru izmenienu datoteku copvingVslnitialization'cpp: upozorenje iete dobiti od prevodioca'
: ClZ:Copyi ngVslni tj al i zation2'cpp
I I 2.Napravitejednosta,rnuklasukojasadrZicelobrojnuwednostipreklopite
class Fi {);
operatorsaui,anla(+)kaofunkcijudlanicu.Napi5ite.funkcijudlanicu
print()Salgumentomtipaostream&kojaispisujevrednostutajizlazni
cl ass Fee
iok' tsprobaite svoiu klasu da biste videli da Ii ispravno radi'
{

publ t c:
ree(int) {} 3'Uprogramizvelbe2dodajtebinarnioperatoroduzimanja(.),kaofunk-
Fee(const lr&) if cijudlanicu.lokaZitedasvojeobjektemoz"tekoristitiusloZenimizrazima
); kao Sto je a+b-c.
4.UprogramizveLbe2,dodajteiprefiksneisuflksneverz|ieoperatorauve-
odno-
cl ass Fo tako da waial^u objekte dija wednost je uveiana'
{ ianja i
int i ;
"-u";u"i",
,.ro .r-urrl"rr'u. Prot'erite da Ii suhksne verziie waiaju tadne wednosti'
publ i c:
I (x) {i 5.IzmeniteoperatoreuveianjaiumanjenjaizveZbe4takodaprefiksnever-
vraiaju konstantan
Fo(jnt x = 0)
zije waealu rlierencu prolrlenljive'.a da sufiksne
verzije
qperalor Fee0 const { return Fee(i); i bi se ovo primenjivalo
objekat. p"#i; e" sve dobroradi i objasnite zasto
u Praksi.
toka (<<)' kao
6. Preworite funkciju print( ) izveZbe2u prek-lopljeni operator
int majn0 I
u datoteci IostreamOperatoroverloading'cpp'
Fo fo:
lee = fo; 7'IzmeniteplogramizveLbe3takodaoperatorisabiranja'(+)ioduzimanja rade'
Fee da ovi operatori i dalje ispravno
t-l .,u u,,a" i'6t'rt'1"1i*'*' i pokaZite da
'otuzitt
(-) u program izveLbe 2
8' Dodajte unarni operator negacue
:l:^"1"T'J::*:l;ilt;it;:."$J-:K:T I l;;
r b
i'J,,,,,, i, ko nstru kto
n I " I: II isPrarmo radi'
Fo r, ovo ie operatore
Fo. Medutim, klasa eee oToujekta tipa Fee,-ali oodatak tipa char' Preklopite
k()nstrttktor za koPiranlr
koii pravi objekat tipa 9' Napravite klasu koja sadrZi privatan i testi-
toka (<< i >>) (kao u datoteci-Io'olu'"Op"tutorOverloading'cpp)
[;;';i:;;ii.r"'r'i'"'r'1"#5?:"'"','o,""$#-tf ;*n'-',:l;]9r,,,1*"1;::
iskaz: rajteih.r'l"2"...iii."'tiratisak]asa*ut,t,uu*istringstreamisaobjektima
reratir, ro bezopasan cin i cout'
::t1)X',T.or:i X:::ffi[]],i;tJ""lu'r'a"ii' wednost koju ce YuS'p':Y9dt'luc
proslediti za
10. Utvrdite laZnu konstantnu (++) i (--)'
sufiksne #;j;^;;;;ra uveiania i umanienia'
s.adrZi broj tipa double'
i pr-eklopite operatore
,,,,i*,,,1i.,,,,1,11,, t,,nu"",1: :lp'lLil.:,1r,lil]::il:Hrii,,?.uff-,?lil.ilL?,r,r, I I . Napi5ite ttut" Nt'rnUur koia
;;;;;;Jete' izauerit; tiil;
^n tako da
"i'"- r ll"l']' i'""i (o d a' ari ni e
j
-,*, ti
:;fi [* .firurni."iYlti:i
ili] i' J
" +, ^-:1'-tunkciie
Napisite operaror double( )
za
lll,l
i

,,,,i l uii:$ ;l ["i s" irruri ffii|ffiJu-u;ifi;J"


tiPa'
rrvt'k isPlatrvtt koristttt 1c' automatsku konverziju
I
I

Misliti na jeziku C++ Poglavlje I 2: Preklapanje operatora 407


406

24. Napravite klasu koja sadrZi podatak dlan tipa string. Inicijalizujte taj zna-
l2.I.JVeZbi lliskoristrtc optimizociiltrezultata,akotoveinisteuiinili.
kovni niz u konstruktoru, ali nemojte praviti konstruktor za kopiranje ni
I 3. Napravite klasu koja sadrT.i pokaz-ivai i pokaT-ite da ie, ukoliko dozvolite
da
tog operator dodele. Napravite drugu klasu s dlanom koji je objekat prve klase;
pre;voclilac napravi opcrator dodele (=), rezultat koriSienja operatora
ni za ovu klasu nemojte praviti konstruktor za kopiranje ni operator dodele.
titi pokazivael toli poA razliditim imenima pokazuju na isto skladiSte. PokaZite da ie prevodilac ispravno napraviti konstruktor za kopiranje i
Sada resite ovaj problem definisanjem sopstvenog operatola dodele i operator dodele.
pokaT.ite da sre time ispravili problem aliiasa. Proverite dodeljivanje istom
2 5. Kombinujte klase u datotekama OverloadingUnaryOperators.cpp i Inte-
objektu i reSite i taj Problem.
vrednost' ger.cpp.
I 4. NapiSite klasu Bird kola sadrZi z-nako'"'ni niz i statidku celobrojnu
podrazumevanom konstruktoru koristite celobrojnu wednost 26. Izmenite datoteku PointerToMemberOperator.cpp tako Sto iete klasi Dog
LI za
dodati dve nove funkcije dlanice bez argumenata, aiji tip rezultata je void.
automatsko generisanje identifikatora koli ugradujete u znakovni niz,
Napravite i testirajte preklopljeni operator ->* koji radi s va5e dve nove
z_ajedno sa imenom klase (Bird #1, Bird #2, itd.). Dodajte operator toka
(<'<) z.a iz-lazne tokove da biste ispisali obiekte klase Bird. Napisite operator tunkcije.
dodele(=)ikonstruktorzakopilanje.Uglal,rromprogramuproveritedali 2 7. Dodajte operator ->* u datoteku NestedSmartoperator.cpp.
sve ispravno racli. 2 8. Napravite dve klase, Apple i Orange. U klasi Apple napravite konstruktor s

15. NapiSite klasu BirdHouse koja sadrzi objekat, pokazivae i referencu na argumentom tipa Orange. Napravite funkciju s argumentom tipa Apple i
klasu Bird iz. vei,be 14. Argumenti konstruktora su tri objekta klase Bird. pozovite tu funkciju za objekat klase Orange. Zatim oznadite konstruktor
Dodajte operator toka <<, za klasu BirdHouse. onemoguiite operator klase Apple kao izridit i pokaZite da je time spredena automatska konver-
dodele i konstruktor za kopiranje. U glavnom programu proverite da li sve zija. Izmenite poziv funkcije dodavanjem izridite konverzije.
isprarmo radi. Proverite da li mozete ulandavati dodele za objekte klase 29. Dodajte globalni operator * u datoteku ReflexivitylnOverloading.cpp i

BirdHouse i graditi izraze sa vi5e operatora' pokaZite da je refleksivan.


16. Dodajte celobrojni podatak dlan klasama Bird i BirdHouse u programu iz 30. Napravite dve klase i operator sabiranja (+) i funkcije konverzije, tako da
veZbe i5. Dodaite operatore dlanove +, -,* \ l ' Uverite se da ovo radi' sabiranje bude refleksivno za te dve klase.
I 7. I)onovite ve7bu 16 koristeii operatore koji nisu dlanovi' 3I . U datoteku TlpeConversionFanout.cpp dodajte izriditu funkciju koju iete
18. Dodajte operator umanienja (--) u datoteke SmartPointer.cpp i Nested- pozvati da biste konvertovali tipove, umesto operatora za automatsku
SmartPointer.cPP. konverziju tipova.
t9 Izmenite datoteku CopyingVslnitialization.cpp tako da svi konstruktori 32. Napi5itejednostavank6dkojikoristioperatore+,-,*ilzabrojevetipadou-
ispisuju ponrke kojima vas obavestavaiu Sta se deSava. Sada pokaZite da su ble. Prevedite program u asemblerski k6d i pogledajte Sta se de5ava prili-
dva nadina pozivanja konstruktora za kopiranje (pozivanje dodelom i pozi- kom upotrebe operatora.
van je zagrad ama) ekvivalentni.
20 pokusajte da napravire operator dodele koji nije dlan klase i pogledajte
kakvu poruktr iete dobiti od prevodioca.
2\ Napravite klasu sa operatorom dodele koji ima drugi argument, znakovni
nizs podrazumevanom wednosiu. Napravite funkciju koia dodeljuje obje-
kat vase klase clrugom obiektu i pokaZite da ie operator dodele isprarmo
pozvan.
22. Ll datoteci copyingwithPointers.cpp uklonite operator dodele iz klase
DogHouse i pokaZlte da operator dodele koji ie napravio prevodilac
ispiavno kopira znakor,,i niz, ali jednostar.no pravi alijas za pokazivad'
2 3. Klasama Dog i DogHouse, u datoteci Referencecounting.cpp, dodajte sta-
tit'ku ctlobrojn,,.-r"d.rost i obiinu celobroinu wednost. U svim konstrukto-
ll
I

i: '
i
i,'
\..
\';.
l!

l'r ..-

1"r..
t
1(i ;

lf.:
t.\ '
I ri.
t-
I\I
L'
lt
i-

i'
{

ir E:
I
Drrunrtnero STvARANJE
OBJEKATA
Nekad tadno znate kolidinu, tip i rok trajanja objekata u svom pro-
gramu. Ali ne uvek...
Misliti na jeziku C++ Poglavlje l3: Dinamiiko stvaranje objekata 4lI
4lo
2. Objekat moZe biti napravljen na steku (engl. stack) po dostizanju odre-
Skolikor,az,drthoplovatlroTcr-rpravljatisistemzakontroluleta?Kolikooblika denih izw5nih tadaka (otvorena vitidasta zagrada). Taj prostor se automat-
ntoT.ekoristitisisten't,u'ot:t'nu"koprojektovanje?Kolikodvorovaiebitiunekoi ski oslobada posle komplementarnih izw5nih tadaka (zatvorena vitidasta
rnreT.i? zagrada). Ovakve operacije zauzimanja memorije na steku ugradene su u
neolhodno omoguiiti
I)a iti se reiavali opSti problemi pri programiranju' ie
skup instrukcija procesora i wlo su efikasne. Da bi prevodilac mogao da
stvaranjc i trniStavan'je ntitku'u tnttorn 'udu'
U leziku C postoie funkcije za
(s variiantama) i free( ) koie tokom generi5e ispravan k6d, mora znati koliko vam promenjivih treba dok pi5ete
dirtarttiiko ,n,,ri,rrn-,i'1n rne'ntoriie,mallocO program.
rrcap, poznata kao free srore)' Ipak,
racla z.arrrzir,alu oinamret<tr nremoriju @ngr.
3. Objekat moZe biti napr.avljen i u dinamidkoj memoriji. To se naziva dina-
tefunkcijenirrao,oflntzasvepotrebtp'ogtu.nunaieziku.C++'Nepostoji midko zauzimanje memorije. Dinamidka memorija se zauzima poziva-
nadindarudnozadatememorijskuadresuobiektakojikonstruktortrebadaini.
vam rudno zadavanie bilo dozvo- njem funkcije; to znadi da u bilo kom trenutku moZete odluditi koliko vam
ciializuje' o ,-u,n po.io;t JoUti iu'lo'i' Kada bi
memorije treba. Isto tako, morate odluditi kada treba da oslobodite
ljeno, ntogli biste napraviti nekoliko greSaka:
memoriju, Sto znadi da vi odredujete Zivotni vek objekta, koji ne zavisi od
l'ZaboravilistedaupiSeteadresu.Tadagarantovanainicijaiizacijanebibila opsega vaZenja promenjive.
garantovana.
inicijalizaciie, odekujuii Cesto su ove tri oblasti sme5tene u jedan neprekidan deo flzidke memorije:
2. Sl.r.alro stc rrraciili nesto sa objektom pre niegove statidki deo, stek i dinamiika memorija (po redu koji odreduje prevodilac). Ipak,
cla se stvari odvilaju valjano
to nije strogo pravilo. Stek moZe biti na posebnom mestu, a dinamidka memo-
3. Prosleciili ste objekat pogreSnih dirnenz-ija' rija moZe se zauzimati posredstvom operati'rnog sistema. Kao programeru, te
ko bude menjao vas pro. stvari su vam uglarmom skrivene, tako da je dovoljno znati da ie memoriia biti
I nara\.lto, Cak i akrl StC SVe ispravno uradili, svako
granr, moze punuriii iste greSke Veiinu problema u progra.miranju izaziva dostupna kada vam zatreba.
veoma vaZno da se konstruktor uvek poziva
nepropisna iniciializacija, tiko da ie
z-a obiekte stvorene u dinamidkol
memoriji'
Kako c++ g"t.;;i;-it;ramu incilaliiaciju i brisanje' a omoguiava dina- C-ov pristup dinamickoj memorui
Za rad s dinamidkom memorijom na jeziku C, koriste se funkcije iz standardne
miiko stvaranie obiekata u memoriii? ,. biblioteke: mallocO i njene varijante callocO i reallocO radi zauzimanja
se u samol srzl programskog
Problern stvaranja dinamidkih objekata reSava
free( nisu pod kontrolom prevodioca' Ako dinamidke memorije, i free( ) za oslobadanje dinamiike memorije. Ove funkcije
jezika. Bibliot"e te f.lntlije malloc( 1i )
ftrnkcije dinamidkog zauzimanja-prostora i ini- su korisne, ali su primiti'rne. Da bi ih upotrebio, programer mora da bude
imate operato," k;;l;;i'*'iu
di5ienje i oslobadanie zavzetog upuien u naiin rada memorije i mora biti veoma paLljiv. Da biste napravili
cijalizacije, i io5 iedan operator koji kombinuie
garantovati pozivanje konstruktora g:::tl[:ii instancu klase u dinamidkoj memoriji koristeii C-ove funkcije, trebalo bi da ura-
prostora, prevodilac vam moZe I
ovom poglavlju' nauiiiete kako se pomoiu oparatora newl dite neSto na.lik na ovo:
za svaki objekat. U
pravljenjem objekata u dina' :
delete eleganrnn ,"suru orul"p.obt.-, bezbednim / / CL3:t4a11 ocC1 ass.cpp
rnickoj rnenloriii. // i objekti klase
Funkcija Malloc
// 1vako bjste morali da radite da nema operatora new
#incl ude ". ./require.h"
Pravljenje objekata #include <cstdlib> l/ na11oc) i free0
faze: #include <cstring> // memset0
X-a 1ez.i[u O++, objekti se stvaraju u dve
#i ncl ude <'i ostream>
I . Oslobada se rnemorija za sme5tai obiekta' using namespace std;
2. Pozivase konstruktor da inicijalizuje obiekat'
class Obj {
DosaclbiveitrcLlalodaveru)etekakojedrugikorakizvestan.C++namece
int i, j, k;
cirugikrtrak,i.r.,.,'n"*,.iializ-ovaniobjektijedan"odglavnihuzrokaprogramskih enum { sz = 100 };
greiaka. Nije bitrxr gd. i
(uto se obickat stvara - konstruktor se uvek poziva.
raz.lidite nadine i u razliditim trenucima. char bufIsz] ;
prvi korak ,. nr#" obaviti r.ra
public:
I . Memorija rnoZe biti zatzelapre podetka izwsavanja programa u stati'kom void initialize0 { // Ne noiete iskoristjtj konstruktor
trale
skladiStu. Ovai objekat postoii sve dok program cout << "inicija'lizujem Obj" << endl;
i = j = k = o;
memset(buf, 0, sz);
412 Misliti na jeziku C++ Poglavlje l3: Dinamiiko stvaranje objekata 413

)
tokom rada se poziva ekvivalent funkcije malloc (sizeof(MyTlpe)) (desto,
void destroy0 const { ll Ne moZete iskoristiti destruktor podrazumeva poziv funkcije malloc( ) ), poziva se konstruktoi
to
cout << 'uk1 anjam Obj " << endl ' itur. MyT\rpe,
prosleduje mu se adresa u memoriji putem pokazivada this,
)
iprosrediju-se
argumenti (1,2). Kada promenrjivoj fp bude dodeljena wednost, objekat
); 1e ini-
cijalizovan, pre toga ga ne mozete ni prstom taknuil. Automatski, istovremeno
rnt main0 { je
i tip wednosti pretvoren u MyTlrpe, pa je konverzija nepotrebna.
0bj* ob: - (0bj*)mal loc(sizeof (0b.t)) ;
requrre(obj != 0); Standardni operator.new-proverava da li je
-.,,ori]u uspe.no zauzeta prc
nego. Sto adresu prosledi konstruktoru, pa ne morate posebno
obj->initial ize0; ispitivati
uspesnost operacije. Kasnije u poglavlju saznaiete sta se desava
1/... kasnlje: kada ostanete
ob3-'destroY0' bez slobodne memorije.
free (obj ) ; lzraz new mozete napraviti koristeii bilo koji konstruktor dostupan
za tu
I lll,- klasu. Ako konstruktor nema argumenata, napi5ite izraznewbezkonstruktorske
liste argumenata:
[-,r,o kako se pornoiu funkcije malloc( ) zauzima prostor za sme3tanje objekta:
MYTYpe *fp = new MyType;
0bj* obj - (0bj.)malloc(sizeof(0bj)) ;

Korisnik mora odrediti velidinu objekta (jedan od moguiih uzroka gre5ke). . .Primetiiete kako proces.stvaranja objekata u dinamidkoj memoriji postaje
jednostavan. Svodi se na jedan izraz, saugradenim
Funkcija malloc( ) vraia wednost tipa void* jer je zauzet samo prazan memo- dimenzionisan.iem, konrer-
zijom i proverom. stvaranje objekata u dinamidkoj memoriji;.ar"ri"
rijski blok, ali nije stvoren objekat. C++ ne dozvoljava da wednost tipa voidr i. rako kao
i na steku.
bude clocleljena bilo kom pokazivaau, tako da je prvo morate konvertovati.
Irrrnkcija malloc( ) r.noZda neie pronaii clovoljno velik blok rnemorije (rezul-
tat je u tonr sludaju nula), pa rnorate proveriti dobijenu vrednost da biste bili Operator delete
srgrrrrii cia .je rnernorija zatuT.eta. Na izraz new nadovezuje se izraz delete, koji prvo poziva
Najgori problem je r-r redtr: destruktor, a zarim
oslobada memoriju (desto pozivom funkcije free(
)). BaS kao Sto izraz new vraia
Obj->initjalize0; p okazivad n a objekat, izr az delete zahtev
a ud."su obj ekta :
Ako korisnik dotad ne napravi greSku, ne sme zaboraviti da inicijalizuje obje- delete fp;
kat pre nego Sto poane da ga koristi. Konstruktor se ne koristi zato sto ne moZe ovo_uni5tava objekat, a zatim oslobada prostor koji je
biti iz-ridito pozvan.l [Jmesto vas, poziva ga prevodilac po pravljenju objekta. on zauzimao.
operator delete moZe se primeniti samo na o61"tt. stvorene
Problem ie Ll tome 5to korisnik sada moZe da zaboravi na inicijalizaciju pre nego operatorom
new. (Ponasanje operatora delete u odnosu ,u obj.kt" napravrjenl
Sto iskoristi objekat, i cla tako napravi jednu od najde5iih gre5aka. pomoiu
funkcije malloc( ), calloc( ) ili reailoc( ), nije definisino. rako veiina
Isparla da veiini programcra iunkcije za tad s dinamidkom memorijom standard-
nih realizacija operatora new i delete poziva i funkcije malroc( i
rlr.lrrjrr zbrrnjrrjrrcc ikontplikovano. Neki programerina jeziku Ckoristevirtuelne I rreer ), vero-
vatno iete osloboditi memoriju bez pozivanjadestruktora.)
rnaSinc, z-ar.rzinrajrrcr ogrornne nizove promenljivih unutar statiakog skiadi5nog
prostora, ne bi li izbcgli rrpotrebu dinantidke raspodele memorije. Kako C++ . Ako pokazivad koji briSete ima wednost nura, nista se neie desiti. Zbog toga
je preporudljivo pokazivadu dodeliti wednosr
pokrriava da programcrirna olakSa koriSienje biblioteka, C-ov pristup dinami- nula odmah nakon brisanja, radi
spreiavanja dvostrukog brisanja. Brisanje objekta vise od jednom,
i'ko j rncrloriji jc neprihvatljiv rigr.no ;.
greSka i izazva1e probleme.

Operator new Jednostavan primer


Ilcienje u (l++-rr jeste povez-ivanje svil.r aktivnosti potrebnih za stvaranje objekta
Ovaj primer prikazuje inicijalizaciju:
u jedan opcrator, nazv.rn new. Objekat koji se pravi pomoiu operatora new zau-
z.irla dovoljno prostora u dinamidkoj memoriji i poziva konstruktor za inicijal- //: C13:Tree.h
izaciju. Tako, kada napiSete: #i fndef TREE H

*fP = #define TREE H


MYTYPe new li'lyTYPe(1,2); #i ncl ude .i oitream,
I\)\loli l)osei)rn P0slttpak. ltlrtttnertt rtrrrt koji onrogrr(ava pozivanje konstnrktora z-a inicijalizaciiu pEt. class Tree {
lro(jll) /ilr/(,tog l)trrk;r nrt.nrorijt,, ito ic ol)litSnieno kasnije tr poglavljrr j nt hei qht;
Misliti na jeziku C++ Poglavlje l3: Dinamitko stvaranje objekata 415
414

publ ic: Dorada ranijih primera


Tree(rnt treeHeight) : height(treeHeight) {} Upotrebom operatora new i delete, moZete preraditi primer Stash kori5ienjem
-Iree0 i std::cout << "*'; I svih dosad obradenih moguinosti. Kada proudite nove primere, moii iete da
fri end std: : ostream& preradujete primere iz prethodnih poglavlja.
operator<<(std::ostream& os, const Tree* t) {
Zasad iemo smatrati da ni klasa Stash ni klasa Stack neie ,,posedovati"
return os << 'Visina stabla je: " objekte na koje upuiuju. Kada prestane opseg vaz.enja objekata tipa Stash ili
<< t->hei ght << std: : endl ;
Stack, sadrZani objekat neie biti unisten. Razlog zbog iega unistavanje nije
i moguie jeste to, sto u pokusaju da budu opste, ove klase rade s pokazivadima na
I; void. Ako na pokazivadu tipavoid* primenite operator delete, samo se oslobada
,end\f ll tafi_H lll:-
memorija jer prevodilac ne zna koju funkciju destruktora da pozove.
I I :
Cl3: NewAndDel ete. cPP
// Jednostavan primer oepratora new i delete
#i ncl ude "Tree. h" Delete void* je verovatno greSka
us i ng namesPace std;
VaZno je naglasiti da je primena operatora delete na pokazivadu tipa void*, skoro
sigurno gre5ka u programu, osim ako je namena tog pokazivaia wlo jednostavrra;
ini main0 {
pre svega, objekat na koji se pokazuje ne bi trebalo da poseduje destruktor.
I .ee' t new -rPe (40) ;
cout << t; //: C13:BadVoidPoi nterDel etj on.cpp
del ete t; // Brisanje pokaziva-a na void moZe uzrokovati curenje memorije
't ,'l l,- #i ncl ude <i ostream>
wednosti objekta using namespace std;
MoT.enro clokazati da je konstrllktor pozvan ispisivanjem
Tree*. obratite pazniu
tipa Tree ponloiu preklopljenog operatora<< za ostrezun i class Obiect
kao prijateljska, ali je i umetnuta.To 5t0 {
,ra to da je hlnkcija operatora acnnisana void* data; Odvojite skladi5ni prostor
je ftrnkcija umetnuta ne utiee na priiateljski status, niti na dinjenicu da se radi
o //
const i nt si ze;
globalnoj ttrnkciii, a ne o ilanici klase
const char id;
publ i c:

u Pravljanja memorijom
Object(int sz, char c) : size(sz), id(c) (
Nedostaci data = new char[size];
Kacia napravite autornarslii obiekat na steku, velidina objekta i niegovo trajanje
tip, dimenziie i cout << "Pravim objekat " << id
direktno se ugraduju u generiiani kod, jer prevodilac tadno zna << ", velicina = " << size << endl;
domen. eravlienje obielata u dinamidkoi memoriji ukljuduje dodatne resurse'
prosrorne. tlz dinjenicu da malloc( ) mozete zameniti sa calloc( ) ili )
vremenske i -0biect0 {
realloc( ), pogledajte uobidajen scenario: cout << "Brisem obiekat " << id << endl;
(Ovaj k6d moZe
Pozivate malloc( ), koia zahteva memoriiski blok sa zaliha' delete []data; // U redu ie, oslobada skladiSni prostor,
biti deo funkciie.) // pozivanje destruktora nije neophodno
ZalihesepretraZujudoksenepronadedovoljnovelikblokmemorije.ovose )
radi tako stri se proveri mapa ili katalog koii prikazuje slobodne
i zauzete blo-
biti neo-
);
nekoliko pokuSaja' pa moZe
kove.'lir je brz- proces, ali ieito ie potrebno
dreden - ne ocekujte cla ie funkcija malloc( ) uvek raditi isto weme. 'i nt main0 {
pre nego sro d.,6ijemo pokazivai za dati blok, velidina i lokacija bloka moraju 0bject* a = new 0biect(40, 'a');
a i da pri
biri oSelcze.c iz. clva raz-liga: da ih funkciia mallocO ne bi koristila, delete a;
poz-ivu funkcije free( ) sistcm unapred zna koliko memorije da oslobodi' void* b = new Object(a0, 'b');
Nadin reilizovar.rla ovih lunkcija moZe se razlikovati. Na
primer, ni5ta ne del ete b;
ometa r.rgraclivanie osnovnih funkciia za rad sa memorijom u procesor' Ako ste | / I /,-
raduznali, napisite program za testiranie da biste otkrili kako ie
realizovana
ICasa Object sadrZi pokazivad tipa void* koji dobija adresu ,,sirovih" podataka
fu.kcija malloc( )., rii"n., prevodiocu. Isto tako mo7ete ditati izvorni k6d (ne upuiuje na objekat koji ima destruktor). U destruktoru klase Object, delete
biblioreke, ako ga imate (GNLI C kOd je uvek dostupan)'
416 Misliti na jeziku C++ Poglavlje l3: Dinamitko stvaranje objekata 417

jtrie na p<tkaziva- tipa void* bez rrezelienih efekata, ier samo treba da new i delete, jednostamo i sigurno iete pridruziti pokazivade objektima srvore-
se prinren
nim u dinamidkoj memoriji.
se oslobodi prostor za sklacliStenje podataka'
Evo datoteke zaglavlja za dinamidki niz pokazivada Stash.
t)ltrnkcijimain()v.ideietedajeneophodnodadeleteznasakakvimtipom
ob jekta radi. llvo rez.rtltata: // : Cl3 PStash. h
Pravim objekat a, vel i cj na = 40 // sadrii pokazivade umesto objekata
Brisem obiekat a
#i fndef PSTASH H

b, ci na = 40 #defi ne PSTASH-H
Pravim objekat ve1 i

zato sto delete a zna daa ukazuje na obiect, poziva se destluktor i oslobada class PStash {
se zauz_eti prostor. Ako radite s objektom pomoiu pokazivada
tipa void* kao u
je obiect, ali se
int quantity; // Broj skladi5ta
sluiajr.r sa delete b, samo ie se osloboditi prostor koji zauzimao int next; // Sledeee prazno skladi5te
nepozivadestrr'rktor,takodaseneoslobadamemorijanakojuukazujedata. // Skladi5te za pokazivade:
'l'okom prevocienja programa, verovatno neiete dobiti upozorenje; prevodilac void** storage;
pretposiavlja cla znate 5ia radite. Curenje memorije biie vrlo neupadljivo' void inflate(int increase)
' ;
drotito se pojavi curenje memorije u programu, prodite kroz sve iskaze publ i c:
delete i proverite'tipove pokazivaea koje bri5ete. Ukoliko pronadete
pokazivad PStash0: quantlty(0), storage(0), next(0) {}
prona5li jedan od uzroka curenja memorije (medutim, -PStash 0
tipa void* verovatno ste ;
(-++ prtrT.a obilie moguinosti za curenje memorije)' int add(void* element) ;
void* operator[] (int index) const; l/ Pristup dlanu
// Uklanja reference iz pokazivada PStash:
Obavezno ii5ienje pomoiu pokaziva'a void* remove(int index) ;
Da bi kontejneri Stash i Stucl bili fleksibilniji (mogli da sadrZe bilo koji tip // Broj elemenata u kontejneru:
pokazivad od int count0 const { return next; }
obje kata), .o,lii. , pokazivacima tipa void. Dakle, kada dobijemo
oblekta tipa Stash ili stack, najpre ga moramo konvertovati u odgovarajuii tip. )i
Kao Sto je prethocino prikazano, morate ga konvertovati u ispravan tip i pre nego #endif // PSTASH_H ///:-
ga obriSete, inade nastaje curenie men-rorije' osno'rni elementi podataka su slidni, ali sada je skladiSte niz pokazivada na
zaista pozivaza
Kacla se prirneti da memorija curi, valja proveriti da Ii se delete tip void, a memorija se zauzima operatorom new umesto funkcijom malloc( ).
poka-
svaki pokaiivae na clbjekat u konteineru. Kontejner ne moZe ,,posedovati" U izrazt:
zivad jer radi s tipom void+ i ne mo7-e propisno obrisati objekte' Korisnik mora
na objekte napravljene void** st = new void*[quantity + jncrease];
biti oigovoran zi brisanle obiekata. Ukoliko pokazivade
problemi, jer
na stekrr i u clinamidkoj memoriii smestite u isti konteiner, nastaie tip objekta koji se pravi jeste void*, tako da izraz zauzima memoriju za niz poka-
primenjuie samo za pokazivaee koii se odno.se. na. dinamidku zivada na void.
se \zraz. delete
(A kada pro3itut" pokazivad iz kontejnera, ne znate kako. je ta memo- Destruktor bri5e skladi5te u kom su smeiteni pokazivadi a ne ono na sta poka-
memoriju.
rila zatr).eta.r Zbog toga .oiut. biti sigurni da su pokazivadi koji se
koriste s zivadi upuiuju (5to ie, kao ito je prethodno napomenuto, osloboditi memoriju
narednim verzijama Siack ili Stash stvoreni u dinamidkoj memoriji. To moZete koju je zauzimao kontejner, bez poziva destruktora, jer pokazivad na void ne
postiii pa7ljivim programiraniem ili pisanjem klasa diii se objekti prave samo u sadrZi informaciju o tipu).
clinarnidkoj rnernori ji. Druga promena je zamena funkcije fetch( ) operatorom [], Sto sintaksno ima
lsro tako, programer kliient mora da obrise sve pokazivade iz kontejnera.
u v15esmisla. Tip rezultata opet je void*, tako da korisnik mora da brine o tipo-
primerr.r videli ste kako destruktor klase Stack proverava da Ii su svi vima podataka koje drZi u kontejneru i da konvertuje pokazivade prilikom kori-
prethoclnom
objektitipaLinkizvadeniizkontejnera.ZaklasuStashpotrebanjedrugadiji Sienja (problem koji ie biti re5en u narednim poglavljima).
pristup. Evo i definicije funkcija dlanica:

//: C13:PStash.cpp {0}


Pokazivaii i klasa Stash // Oefinici5a dinamidkog niza pokazivaea
pokaziuaie #include "PStash.h"
Napravili smo novu verziju klase Stash, nazvanu PStash. ona sadrZi #include ". ./require.h"
dinamidkoj memoriji, zaraz|iku od verzije klase Stash iz
na ob jekte ko|i postoje u #include <iostream>
prethodnih poglavlja u kojoi su se obiekti kopirali po wednostima' Operatorima
4I8 Mlsliti na jeziku C++ Poglavlje l3: Dinamiiko stvaranje objekata 419

#include <cstrrng> // funkcije'mem' Funkcija inflate( ) je izmenjena tako da radi sa nizovima pokazivada na tip
usi ng namespace std; void, umesto sa sirovim bajtovima. umesto kopiranja pomoiu indeksiranji
nizova, funkcija memset( ) iz standardne c biblioteke prvo popunlava novi blok
int PStash::add(void* element) { memorije nulama (ovo nije neophodno, poSto se pretpostavlja di pstash ispravno
const i nt i nfl ateSi ze = 10; upravlja ditavom memorijom - ali nikad nije na odmet obezbediti se). Nakon toga
i f(next ,- quanti ty) funkcija memcpy( ) premeSta postoieie podatke sa srare rokacije nu no*,. e .rio
i nfl dle ( i nfl ateSr ze) ; su funkcije poput memset( ) i memcpy( ) oprimizovane, pa rade brZe od prikaza-
storage Inext++] = el ement; nih_ petlji. Ali sa funkcijom.kao sto je inflate( to se neie desavati, pa
) verovatno
return (next - t); I I Indeksni broj neiete primetiti razliku u performansama. Cinjenica da je pozivanje iunkcija kon-
I ciznije od petlji, moZe pomoii u spredavanju programerskih gre5aica.
Da biste odgovornost za brisanje objekata svalili na p-rogru.ne.u klijenta,
I I Bez v) asni Stva: postoje dva nadina pristupa pokazivadima u kontejneru tipa pslash: operator[],
PStash::-PStash0 { koji waia pokazivai ali ga zadri,ava u kontejneru i funkiija dlanica remove(
for(int i = 0; 1 < next; i++) koja waia pokazivad ali ga istowemeno uklanja iz kontejnera. Destruktor klase
),
requi re(storageIi] == O,
PStash proverava da li su svi pokazivadi uklonjeni. U sludaju da nisu, biiete
"PStash nije Prazan");
obavesteni, pa iete moii da spredite curenje memorije leiegantniya reSenja
del ete [] storage;
slede u narednim poglavljima).
)

Preklopljeni operator je zamena za funkcjiu fetch


I
I
voi d* PStash: : operator [] (i nt i ndex) const {
Jedan test
Evo izmenjeneverzije starog programa testiranje klase Stash:
require(1ndex >= 0,
"PStash: :operator[] negativan indeks") ; //: C13:PStashTest.cpp
if(index >= next) //{L) PStash
return 0; ll Ukazule na kraj f/ Provera dinamidkog niza pokazivada
I I Pravi pokazi vaa na traZenj el ement: #include "PStash.h,,
return storageIi ndex] ; #include "../require.h,,
)
#include <iostream>
#i ncl ude <fstream>
void* PStash::remove(int jndex) { #i ncl ude <stri ng>
void* v = operator[] (index) I usi ng namespace std;
// Ukl oni te pokazi vai:
i f(v I - 0) storageIi ndex] = 0; int main0 {
return v; PStash i ntStash;
I // 'new' takode radi sa ugradenim tipovima. primet.ite
// "pseudokonstruktorsku,, sintaksu:
void PStash: : jnflate(int increase) ( for(int i =0; j <25;1++)
const int psz = sizeof(void*); intStash.add (new i nt(i ) ) ;
void"* st = new void*[Quantity + increase]; for(int j = 0; j < intStash.count0; j++)
memset (st, 0, ty + i ncrease) * psz) ;
(quanti cout << "intStash[" .. i .. "] = "
memcpy(st, storage, quantitY * Psz); << * (i nt*) i ntStash [j] << endi ;
qtiant i ty += I ncrease; // u1 scenJ e:
dclotc []stor',tLrr'l' Staro skladiite for(int k = 0; k < intStash.count0; k++)
storage = st; I I Pokazuje na novo skl adi 5te dei ete i ntStash. remove(k) ;
\ lll'- i fstream in ("pStashTest.cpp,,) ;

Funkcija add0 je ista kao i ranije, osim sto sada skladi5ti samo pokazivad assure(in, "PStashTest.cpp,,) ;
PStash stri ngStash;
Lrmesto kopijc ditavog objekta.
string line;
Misliti na jeziku C++ Poglavlje l3: Dinamitko stvaranje obiekata 421
420

whi le(getl ine(in, I ine) ) Operatori new i delete za nizove


stringstash.add(new stri ng (l i ne) ); U jeziku C++, nizovi objekata na steku ili u dinamidkoj memoriji lako se prave, a
lsPisuje sadrZaj niza: konstruktor se (nararryro) poziva za svaki objekat u nizu. Ipak postoji jedna
I I zadkoljica: mora postojati podrazumevani konstruktor, osim u slueaju grupne
fo.(.rnt u = 0; stringstashIu]; u++)
cout << "stringstash[" << u << 'r] = inicijalizacije na steku (videti poglavlje 6), jer se za svaki objekat posebno mora
rl

<< * (stri ng*) stri ngstash [u] " endl ; pozivati konstruktor bez argumenata.
// Bri sanj e: Tokom stvarania nizova objekata u dinamidkoj memoriji pomoiu operatora
for(int v = 0; v < stringstash'count0; v++) new, jo5 ne5to morate uraditi. Na primer, niz:
d.l.t. (rtring*)stringstash'remove(v) ; MyType* fp = new t4yType[100];
\ I I l,- zauzima dovoljno prostora u dinamidkoj memoriji za 100 obiekata tipa Mfllpe
Kao i ranije, obiekti tipa Stash prave se
i pune' ali ovog puta se koriste poka-
red: ipoziva konstruktor za svaki od njih. Vrednost fp je samo pokazivai tipa
zivatidobiieiri iz.raz-om new Obratite paZniu na M/flpe*, Sto se dobija iizrazorn:
i ntStash. add (new i nt ( i ) )
MyType* fp2 = new MyType;
lormu' tako da se u dinamidkoj
lzlaznewint(i) koristi pser'rdokonstruktorsku koji pravi samo jedan objekat. Po5to ste vi napisali k6d, znate da je fp podetna
novog objekta tipa int' a po'etna wednost
z,avzimapr"t;i;; 't;;staj
n-remoriii adresa niza, tako da ima smisla pristupiti elementu niza koristeii izraz poput
tog broia jednaka ie vrednosti i' Ali Sta se de5ava kada uniStite niz? Iskazi:
PStash::operatorll mora fp
l)a bi bila ispravno i;pi;;"", vreclnost koju waia
t31 .

tip, 5to v,aZi i za preostale objekte u programu' To delete fp2; ll U redu


biti pretvorenu u nagouu,ll'Z'
je ne2elieni efet at t
biie ispravljen u sledeiim
o,isZeilu po[u'iuueu na tip void i delete fp; // Ne traZimo tai efekat
poglavliirna. izgledaju potpuno isto, a i njihov efekat ie biti isti. Destruktor se poziva za
Drr.rgi test otvara datoteku sa izvornim
kodom i uditava je red po red u drugi otletai tipa M/Type na datoj adresi i oslobada se zavzeta memorija. Sto se tide
niz funkcijom getlineo, a zatim se
kontejner. Svaki red ,. uli,uu"r.uo znakolryri pokazivada fp2 to je u redu, ali kod pokazivada fp to znadi da za ostalih 99 obje-
se dobila nezavisna kopija tog
pravi nov znakovni ,i;;;;;;;"m.new' da bi kata destruktor neie biti pozvan. Odredeni deo memorije ipak ie biti oslobo-
reda.Dasmosvakipr'rtsamoditaliadresepromenljiveline,dobjli'bismogomilu den, jer je ceo blok zauzel u jednom velikom komadu, a velidina ditavog bloka
ona ie'sadrzati samo poslednji red uditan
iz
pokazivaea nu pro..nii*il;;; upisana je prilikom zauzimanja.
datoteke. Resenje je da prevodiocu kaZete da se pokazivad odnosi na niz, sledeiim
izraz:
Prilikom r.rzimania pokazivada' videiete sledeii lzrazom',
* ( st r i ng" ) s t ri ngstash Iv] delete Ufp;
Pokazivadkojisedobijaoperatorom[lmorasekonvertovatiustring*,radi Prazne zagrad.e govore prevodiocu da zahvati odredeni broj objekata iznizai
dereferencira' pa je wednost celog
dodele odgovarajuieg;p" i;;" se string* pozove destruktor za sve te objekte. Ovo je unapredeni oblik ranije naredbe,
irror.o oL1"'l^t. pievoJitac vidi objekat tipa
string i Salie ga u.tof cgut' . koju moZete powemeno sresti u starijim programima:
Oblekat napravlien u dinamidioj memoriji riorate uni5titi koristeii funkcilu
d;biti poruku niste' p:^tl::"-1t] del ete [100] fp;
remove( ) ili iete pri pJr.iffiu pi6g*tnu
d.a
Raniji oblik primorava programera da upise broj objekata u nizu. Posto pro-
obrisaliobiekteutonttint"''fodpokazivadanatipintnikakvokonvertovan]e
z-a taj tip' pi tuto treba da se gramer moZda gresi, a prevodilac ne moZe uvek da prepozna gresku, bolie je
oslobodi
nije potrebno i", n" pniinii J"ti*it'o'
naznaditi broj objekata na jednom mestu nego na dva.
ntctnorija:
delete intStash. remove(k) ;
i\koz-aboravitedakonvertuietepokazivainatipstring,dolazidocurenja Pravljenje pokazivada nalik na niz
pomoiu
menrorije. Neka od ;";;'h pita"la (ali ne i sva) moZete reSiti sa strane gledano, wednost pokazivada fp iz prethodnog primera moze biti u
";lh- potpunosti promenjena u bilo sta, Sto ne mora da odgovara poeetnoj adresi
Sablona (obja5nieni su poglavlju l6)'
niza. Vise smisla ima deflnisati ga kao konstantu, tako da ie pokusaj izmene
vrednosti pokazivada znaditi gre5ku. Ukoliko napi5ete:
int const* q = new int[10];
422 Misliti na jeziku C++ Poglavlje l3: Dinamidko srvaranje objekata 423

ili Pona5anje funkcije new-handler vezano je za operator new. Ako preklopite


1nt const" q = new i nt [10] ; operator new (objasnjen je u sledeiem delu), funkcija new-handler neie biti
automatski pozvana. Moraiete posebno da je pozivate u funkciji svog operatora.
rei const ie biti vez-ana za red int, odnosno za ono na Sta se ukazuje, umesto za
Nara'rno, moZete napisati sofisticiraniju funkciju new-handler, iak i onu koja
sam pokaz.ivad. Prave rezultate donosi iskaz:
ie pokusati da oslobodi memoriju (opste poznatakao sakupljai smeia). To nije
i nt* const q = new i nt [10] ; posao za programere podetnike.
Sada elementi niza q mogu biti izmenjeni, ali ie bilo koja promena vrednosti
q (kao q++) nedoz-voljena, kao i kod obidnog identifikatora niza.
Preklapanje oparatora new i delete
lzraz new sastoji se od dva koraka. operator new u prvom koraku zauzima
Nedostatak memorije memoriju, a u drugom se poziva konstruktor. IJ izrazu delete, poziva se destruk-
Ako operator new ne mo7-e da pronade dovoljno velik neprekidan blok memorije, tor, a memorija se oslobada pomodu operatora delete. Pozivanje konstruktora i
za smeStaj traTenog obiekta, poziva se specijalna funkcija, zvananew-handler. destruktora nikad nije pod va5om kontrolom (kad ne bi bilo tako, moZda biste
Podrazumevana iunkcija new-handler generiSe izuzetak (obradeno u tomu zaboravili na njih), ali moZete menjati operatore za rad s memorijom new i delete.
2). Kako god bilo, ako koristite dinamidku memoriju, mudro je da u radno;'ver- sistem zauzimanja memorije koji koriste operatori new i delete, sadinjen je za
ziji podraz-umevanu funkciju zamenite svojom funkcijom, koja ispisuje poruku op5tu upotrebu. u posebnim situacijama, medutim, on ne mora da zadovoljava
da vi5e nema slobodne memorije, a zatim prekida program. Na ovaj nadin zna- vase potrebe. uobidajeni razlog za promenu tog sistema jeste efikasnost: mogli
iete Sta se desilo. Za konadnu verziju programa, ipak napravite robustniju biste swarati i uni5tavati mnogo objekata odredene klase, Sto bi izazvalo usko
funkciju koja pokuSava da oslobodi memoriju. grlo, i odrazilo se na brzinu izwsavanja. Da bi se re5io taj problem, C++ vam
Funkciju ne'"v-handler moZete da zamenite tako Sto iete ukljuditi zaglavlje dozvoljava preklapanje operatora new i delete, kako biste mogli da napravite
new. h, i ftrnkciji set,new_handler( ) proslediti adresu nove funkcije. sopstvene 5eme zauzimanja skladi5nog prostora.
Fragmentacija dinamidke memorije je posebna tema. Zbog zauzimanja blo-
I I :
Cl3: NewHand l er. cpp
kova razliditih velidina postoji moguinost da se dinamidka memorija toliko
f Pronena funkcije new-handl er
f
#include <iostream> razdeli da ostanete bez skladi5nog prostora. Slobodan skladiSni prostor moZda i
#i ncl ude <cstdl i b>
postoji, ali zbog fragmentacije nijedan deo nije dovoljno velik za vase potrebe.
# i nc I ude <new> Da biste bili sigurni da do toga neie doci, napravite sopstvenu tehniku zauzi-
us i ng namespace std; manja memorije za odredene klase.
Kod ugradenih sistema i sistema za rad u realnom wemenu, program moZe
int count = 0; jako dugo raditi sa ogranidenirn resursima. Takav sistem mole zahtevati da se
memorija uvek dodeljuje u istom wemenskom roku, i da ne dode do iscrplji-
void out_of_memory0 { vanja dinamidke memorije i fragmentacije. Najbolje resenje je da se preklope
cerr << "nema slobodne memorije nakon " << count operatori new i delete tako da programeri mogu koristiti sve prednosti c++-a.
.. " zauzimanja ! " << endl ; Kada preklopite operatore new i delete, valno je da upamtite da samo
exrt(l); menjate nadin na koji se zauzima sirou skladiini prostor. Prevodilac ie pozvati
) vaS operator new umesto standardne verzile, radi zauzimanja skladisnog pro-
stora, i zatim pozvati konstruktor. Tako, mada prevodilac zauzima skladisni
jnt main0 { prostor i poziva konstruktor prilikom prevodenja izraza new, prekiapanjem
set_new_hand I er (out_of_memory) ; mozete promeniti operator new samo zauzimanjem skladisnog prostora. (Na
while(1) { operator delete primenjuju se slidna ogranidenja.)
count++; Preklapanjem operatora new menjate i njegovo ponaSanje u sludaju da osta-
new jnt[1000]; // Iscrpljen je memorijski prostor nete bez memorije. Morate odluditi sta operator new treba da uradi: vrati nulu, u
) petlji poziva funkciju new handler i ponovo pokusava da zarzme memoriju ili
I I I l,- (Sto je uobidajeno) da izazove izuzetak tipa bad_alloc. (rzuzeci su obradeni u
llLrnkcija nerv-handler nema argumente, a njen powatni tip je void. Petija tomu 2.)
while ie nastaviti cla zatrzima memoriju z-a promenjive tipa int (i zanemariie
aciresu) sve dok sc sav slobodan prostor ne popuni. Prvi put kad operator newne
brrdt, nrogarl rla zarrzrne traTeni prostor, poziva se fr,rnkcija new-handler.
Poglavlje l3: Dinamiiko stvaranje objekata 425
Misliti na jeziku C++
424
S0 {puts("S::S0'); )
kao i bilo koii drugi operator'
Operatori new i delete preklapaiu tt.j:]o -S0 { puts("S::-S0"); )

N4o7_ete cta preklopite g;;;il;


ili koristite razlidite tunkcije z-a rad s );
";;ratore
menrorijonl za odredenrr klasu'
int main0 {
puts("Pravim i unjstavam broi tipa int");
Preklapanje globalnih operatqra new i delete int*P=newint(47);
verzije operatora.new i delete
Ovo ic drastidun prl.tuf^ tt'eu; tuau
globalne delete p;
globalne.verzije tih-operatora'
ne odgovaraiu celom .ititrn'' nLo ptettopite ih ne moZete ni pozvati
puts("Pravim i unistavam objekat tipa S");
dak
podrazumevani op.,utotl't'lCt potpu'"to nedostuini' S* s = new S;
u rtovim fr'rnkciiama. del ete s;
biti tipa size-t (standardni tip puts("Pravim i unjstavam niz tipa S[3]");
fugument preklopijenog operatora new.mora pred-
gen.e:ls: r prosleduje prevodilac' a on S* sa = new S[3];
za veiidine u jeziku C). Ovaj argument wati ili pokazivad
treba da delete Usa;
stavtja velidinu obietta'kJiiiftiu nupiur,rti. runkciia (u
na obiekat te velieine (ili';i ;;;;tiebi) ili nulu ako
":*i 1::91^Tmemorije | / I /,-
ponestane memorije mogli biste
tom sluiaju ," konrtrrrktot- ni pi:ziuul 'nko Y1T Ovde moZete videti opsti oblik preklapanja operatola new i delete. Koriste se
Mozia poziv funkcile new-handler ili standardne C funkcije malloc( ) i free( ) za rad s memorijom (koje verovatno
uraditi nesto ito e . p.rziu ris.'informacila.
da postoji p'9bl:m: . koriste i standardni operatori new i delete). Medutim, novi operatori ispisuju i
i,-,"uni"izuzetka viSe odgovara, kao sigrr'al
void*' a ne neki odredeni tip pokazivada' poruke o onome Sto se dogada. Funkcije printf( ) i puts( ) koriste se umesto
Tip rezultata op",uto'u"'"* ieste
prostor' ali ne i da napravi
Njegova namena je samo dazauzme memoriiski tokova podataka, zato Sto se prilikom stvarania objekta toka (poput opStih cin,
objekat. objekat ," p';;iitk kua-"
po'ou" konstruktor' Izwsenje konstruktora cout i cerr), poziva operator new. Prilikom pravljenja printf( ), neiete dospeti u
g"i".tri. pi.vodilai, a vi to ne moZete kontrolisati'
tipa void*' On pokazuje na blok
Skripac, jer ona ne poziva operator new.
Funkciia operatora delete ima argument zato Sto operator
U funkciji main( ) srvaraju se objekti ugradenih tipova da bi se videlo pozi-
-t.t ""*lTip pokazivada ie void*
memorije dodeliene opt'uiotorn koii sluZi da ukloni
vanje preklopljenih oparatora new i delete. Zatim se pravi jedan objekat tipa S,
nakonpozivinla destruktora, pa niz tog tipa. Po kolidini memorije koja se zahteva za niz, ide(ete da se rezer-
delete dobija poturiule rog primera
void.
obiekat iz memoriie. ;;';;il funkcije le Evo iednostarT vise prostor i za dodatne informacije o broju objekata u nizu. U svim slueajevima,
i;i;;. prekolopitL globalne operatore new i delete: koriste se globalne preklopljene verzije operatora new i delete.

'l'lI : Preklopite
I C13:Global0PeratorNew'cPP
globalne operatore new/delete
Preklapanje operatora new i delete u klasama
#include <cstdio> Mada ne morate izridito naglasiti status static, prilikom preklapanja operatora
#i ncl ude <cstdl i b>
new i delete u klasama, stvarate statidku funkciju dlanicu. Sintaksa je ista kao i za
usi ng namesPace std;
preklapanje bilo kog drugog operatora. Kada prevodilac vidi da koristite operator
new za stvaranje objekta klase, poziva dlanicu operator new( ) umesto globalne
voi d* oPerator new(si ze-t sz) (
printf("operator new: %d baitova\n"' sz); verzije operatora. Globalne verzlje operatora new i delete koriste se prilikom
void* m = malloc(sz); pravljenja svih ostalih tipova objekata (osim ako i oni nemaju sopstvene opera-
i f( lm) puts("nema slobodne memorije"); tore new i delete).
return rn; U slededem primeru pravi se primitivan sistem za upravljanje memorijom u
)
klasi Framis. Deo memorije zauzima se u statienom skladiltu podataka prilikom
pokretanja programa i ta memorija se koristi za objekte tipa Framis. Za eiden-
void oPerator delete(void* m) (
ciju o zauzimanju blokova, koristi se jednostavan niz ba;'tova:
Puts("oPerator delete") ;
I I : Cl3:. Frami s. cpp
free (m) ;
// Lokalni prekloplieni operatori new i delete
i #include <cstddef> ll Size-t
#i ncl ude <fstream>
class S { #include <iostream>
int i [100];
Publ i c:
426 Misliti na jeziku C++ Poglavlje l3: Dinamicko stvaranje objekata 427

ri ncl ude <new> f[i] = new Framis;


us i ng narnespace std; new Framis; // }staee bez slobodne memorije
ofstrearn out ("Frani s.out") ; ) catch (bad_al I oc) {
cerr << "Nema slobodne memorije!,, << endl ;
rlass lramrs 1 )
enum { sz = 10 ); de1 ete f[10] ;
char c Isz] ; I/ Zauzina prostor, ne kori stj se stvarn0 f[10] = 0;
statrc unsigned char Pool U; // Koristi oslobodenu memoriju:
stat r c bool a1 I oc_maP [] ; Framjs*x=newFramjs;
publ ic: de1 ete x;
enum psize = 100 \; I I dozuolien broi objekata
{ for(int j = 0; j < Framis::psize; j++)
Framis0 { out .. "Framis0\n' ; I delete f[j]; // }brisati f[10] 0K
-Framis0 { out << "-Framjs0 ... '; } I ll/,-
voi d* operator new(si ze-t) throw(bad-al I oc) ; Zaliha memorije za objekte klase Framis stvorena je pravljenjem niza bajtova
voi d operator del ete (voi d*) ; pool, dovoljno velikog da primi psize objekata. Niz alloc*map koristi se za evi-
I; denciju zatzimanja blokova, pa sadrzi psize wednosti tipa bool. Svi elementi
unsigned char Framis::pool Ipsize sizeof(Framis)]; *
tog niza na podetku imaju vrednost false - posto je zadata samo vrednost prvog
bool Framis: :al1oc_map[psize] = {false}; elementa, prevodilac sve ostale elemente inicijalizuje njihovom podrazumeva-
obiekat tipa nom wedno5iu (koja je false u sludaju tipa bool).
ll velicina se zanemaruie -- pretpostavlja se da ie Framis
Lokalni operator new( ) ima istu sintaksu kao i globalni. on u mapi raspodele
voi d*
trazi wednost false, zatim toj lokaciji dodeljuje wednost true, ukazujuii time da
Frami s : : operator new(si ze_t) throw(bad-al I oc) {

= 0; j < PSjze; i++)


je blok zauzet, pa waia adresu odgovarajuieg memorijskog bloka. Ako su svi
for(int i
if(!alloc_map[]l) { blokovi zauzeti, ispisuje obaveStenje i izaziva izuzetaktipa bad_alloc.
out << "koristim blok broj " << i << ovo je prvi primer izt;zetka koji sreiete u knjizi. Kako je detaljnija rasprava o
a1 1oc_mapIi] = true; I I )znail ga kao iskoriSeenog izuzecima ostavljena za drugi tom, ovde navodimo pojednostavljenu verziju
return pool + (i * sizeof(Framis)); njihove upotrebe. operator new na dva mesta koristi izuzetke. Nakon liste argu-
)
menata funkcije sledi opis throw(bad_alloc), koji prevodiocu i aitadu govori da
out << "nema slobodne memorije" << endl; funkcija moLe izazvati izuzetak tipa bad_alloc. U sludaju da nema vise memo-
throw bad_a1 1 oc 0 ; rije, funkcija zaista generi5e izuzetak iskazom throw bad_alloc. Kada nastane
) izuzetak, izwsavanje funkcije prestaje, a kontrola se prosleduje bloku za obrad.u
izuzetaka, koji je izraZen odredbom catch.
void Framis::operator delete(void* m) { U funkciji main( ) vrdite drugu stranu novdiia - btok try-catch. Blok try ogra-
if(!m) return; // Proverava da li je pokazivac nula niden je vitidastirn zagradama i sadrzi sve naredbe u kojima moZe nastati
// Pretpostavlia da je stvoren blok izuzetak. u ovom sludaju, to je operator new koji se tide objekta tipa Framis.
// Racuna broj tog bloka: odmah nakon bloka try sledi jedna ili vi5e odredaba catch s tipom izuzetka koji
unsigned long b1061 = (unsigned long)m obraduju. U ovom sludaju, catch(bad-alloc) govori da se obraduje izuzetak.
- (unsigned long)pool; odredena odredba catch izwsava se tek po nastanku intzetka tipa bad_alloc, a
block /= sizeof(Framis) ; izw5avan;'e se nastavlja nakon poslednje odredbe catch u toj grupi (ovde postoji
out << "oslobadjam blok broi " <' block << endl; samo jedna ali ih moZe biti vi5e).
I I }znaii ga kao slobodnog:
U prethodnom primeru mogu da se koriste tokovi podataka, zato Sto se ne
a11oc_mapIb1ock] = false;
koriste globalni operatori new i delete.
)
operator delete pretpostavlja da se Framis nalazi u memorijskorr bloku koji
je zato predviden. ova pretpostavka je tadna, jer se lokalni operator new poziva
int marn0 {
Framis* f IFrami s: :psize] I
svaki put prilikom pravljenja objekata tipa Framis u dinamidkoj memoriji.
trY {
Zapamtite da se lokalni operator ne poziva kada se pravi niz tih objekata: za
for(int i = 0;< Framis::Psize; i++) nizove se koristi op5ti operator new Ukoliko korisnik sludajno pozove operator
delete, bez upotrebe uglastih zagrada da bi unistio niz, prouzrokovaie problem.
428 Misliti na jeziku C++ Poglavlje I 3: Dinamiiko stvaranje objekata 429

Na isti nadir.r, korisnik bi mogao obrisati pokazivad koji ukazuje na


objekat trace << "Widget::new[]: ,,
funkciji operatora delete pro- << sz << " bajtova" << endl;
stvoren na steku. I)a biste rpr"iili ovakve gre5ke u
verite da li je adresa , p..d..id.nom bloku (vei vidite moguinost da prekla- return : : new charIsz] ;

panjent np"intnro new i delete ispitate cureniememorije)' )


' op.roio, delete pronalazi orlgovarajuii blok u memorijskim zalihama i void operator delete[] (void* p) {
znak da je trace << "Wi dget: : del ete [] ', << endl
indikatortr za taj blok u nizu alloc_map dodeljuje wednost false, kao ;
: : de1 ete [] p;
blok slobodan.
t.l funkciji mainO pravi se dovoljan broj objekata Framis da.ponestane l.
)

memorijskog prostora; na ovai nadin se proverava ponasanje u slutajulestanka


*.*orij". rida se jedan objekat brise, a drugi se pravi da bi se pokazalo kako je int main0 {
oslobodena memoriia nanovo iskoriSiena' trace << "new Widget,,<< endl;
PoStojeSemadodelememorijeobjektimatipaFramisspecifldna,prilidnoje Widget*w=neyrWidget;
verovatno da je znatno brza od opste Seme dodele standardnih oparatora
newi
ukoliko
trace << "\ndelete l,jidget', << endl;
delete. Meduiim, rreba zapamtiti da ovo neie funkcionisati automatski
del ete w;
se koristi nasledivanie. (Nasledivanje je obradeno u
poglavlju l4') trace << "\nnew Widget[25]".. s.61.
Widget* wa = new l,lidget[25];
trace << "\ndelete []t^lidget" << endl;
Preklapanje operatora new i delete za nizove delete []wa;
odgo-
Prekloplieni op-"ruto.i new i delete pozivaju se kad god napravite-obje.kat I ///,-
uural,,ie klase. Medutim, ako sNorite niz objekata, poziva se globalni operator
poziva se Preklopljeni operatori pozivaju globalne verzije operatora new i delete, i
new da zauzme prostor z,a (iIav niz odjednom, a opsti operator delete
prostora. zauzimanlemi oslobadanjem memorije zaoizove ispisuju podatke u tok trace. Nara'rno, moZete koristiti bilo koju semu za
racli osobadanja tog
preklapaniem specijalnih verzlla operatora new[] i pravljenje memorije u preklopljenim operatorima new i delete.
objekata mozete upravljati
verzije operatora: Sintaksa operatora new i delete za nizove ista je kao za verzije koje rade sa
deietell. lJ ovom primeru pozivaiu se dve razlidite
objektima, ali se na imena dodaju uglaste zagrad,e. u oba sludaja prosleduje se
I I : Cl3: ArraYOPeratorNew. cPP
kolidina memorije koju treba zauzeti.verzljizanizse prosleduje velidina ditavog
// OPerator new za nizove niza.Yazno je imati na umu da je jedina uloga preklopljenog operatora new da
#i ncl ude .new, f f defi ni sanj e Si ze-t wati pokazivad na dovoljno veliki memorijski blok. Mada moZete inicijalizovati
#i ncl ude <fstream>
taj memorijski blok, obidno je to posao konstruktora koji prevodilac automatski
usi ng namesPace std;
poziva. Konstruktor i destruktor ispisuju poruke, tako da moZete videti njihovo
ofstream trace("Array0peratorNew.out") ;
pozivanje. Evo kako izgleda datoteka toka trace zajedanprevodilac:
class Widget ( new Wi dget
enum { sz = 10 ); Widget : : new : 40 baj tova
int i [sz];
publ i c: del ete l,l idget
l,/idget0 { trace " "*"; } -Wl dget: : del ete
-l^lidget0 { trace " "-"; }
void* oPerator new(size-t sz) { new Wi dget [25]
trace << "l,Ji dget: : new [] : "
<< sz << " bajtova" " endl; Yl1l:H:::i1;. 13:1.:iil:"
return : :new charIsz] ;

)
::l:::_ll:t::::_____ -----l,ji dget: : de1 ete []
void oPerator deleteU (void* P) { Stvaranje pojedinadnog objekta, kao Sto i odekujere, zahteva40 bajtova. (Moj
trace << "Widget::delete[] " << endl; radunar koristi 4 bajtaza tip int.) Poziva se operator new a tada i konstruktor
::delete []P; (prikazan kao *). Na komplementaran nadin, iskaz delete poziva destruktor, pa
)
operator delete.
voi d* oPerator new[] (si ze-t sz) {
430 Misliti na jeziku C++ Poglavlje Dinamidko stvaranje objekata
43r
Kada se pravi rriz objekata tipa Widget, koristi se verzija operatora new za Promenrjivoi nm je.na.poeetku
nizove. Obratite paZnlu na to da je traZena veliiina za detiri bajta veia od odeki- doderjena vrednost nura. pokazivade
rreba
vane. lJ ta detiri bajta sistem snima informacije o nizu, tainije, o broju objekata
u nizu. lJ i:az.rt:
;T.:i:1Xili|,,1 I:;: k;iffi
?L1,:il:l^
:"^
p o g,. s n o p,o tu ,,
ueii i .r.o d o d e d o

gly"1i;?;3"ffi ,- :l[""J:T:'::"m;i:*i;
de1 ete [] Wi dget; ii^,{#iTj"Ji":""',ilffi
memorije.ili da se prekine ,ud p.o!ru.nu.
,

uglaste zagrade govore prevodiocu da se briSe niz objekata. Prevodilac pravi kOd u ranijim verzijama-c+*-u^poi.urr-evalo
ako zauzimanje memorije,nir" se da operator new waia nulu
koji traZi broj objekata u nizu i toliko pura poziva destruktor. MoZete videti da se
Ako poku.ate da warite
;rp;t. i;'1" ,p..euuuto pozivanje konstrukrora.
operatori new i delete, pozivaju samo jednom za ditav ntz, a podrazumevani iz opl.ua* ri"n,,_prevodirac
reci ie vam da je trebalo"rtu koji poStuje standarde
konstruktor i destruktor za svaki objekat u nizu. ,ru^"ti'iri)i;i;;; bad_arroc.

Pozivanje konstru ktora O p e rato r,


n. *_i,-d:- p e cU a I n s m e S ta nj e o
tJpamtite da: Postoje i dve druge, manje znane t:_+,s
l: upotrebe preklopljenog
operatora new.
Tip* f = new Tlp; l ' Hteli biste da smestite objekat
na odredeno mesto u memoriji.
narodito vaZno kod.hardveiski ovo je
poziva operator new da zauzme dovoljno veliki blok memorije za sme5taj orijenlisanih rg.ua"ritr riri.-"u, ga"
kat moZe odgovarati por"i"o,, ouj.-
objekta tipa Tip, a zatim poziva konstruktor Tip za taj skladiSni prostor. Sta se ""to- razliditih a"ru hardvera.
2' zereribiste da birate izmedu
dogada ako operator new ne uspe da zauzme memoriju? U tom sludaju se kon- tehnika zauzimanjememorije.
Obe situacije r" r"'3]lllpg irlg*
struktor ne poziva. Evo primera koji to dokazuje: .rmati vi.e od jednog argumenta. Kao
principu: prektopljeni operaror
new moZe
//: C13:NoMemory.cpp velidina objekata, kojule talno
Eto ste ranije videri, prvi argument
je uvek
// Konstruktor se ne pozi va ako zauzimanje memorije ne uspe sraeun"o i"p-ri"ai" pr"i"ail".lf.a".rgi
ment moZe biti bilo Sta., Na prime, u.gr_
# i nc l ude <i os t ream>
gde Zetite da smestite
op"ruiJ* moZete proslediti adresu mesra
#jnclude.new, II definisanje bad alIoc objekat,
;;;;""."ur;; nadin upravrjanja memori.iom ,i
usi ng narnespace std; bilo Sta drugo Sto ,nam
," di"i;"g;;;;;. i,iei., .,u koji prosledujete
argumente operatoru newO, dodatne
isprva se ,,oz" ei.,iii e;Hff.
ass NoMemory ubacite (bez argumenta tipa size_t, ilil,1ilr,,"nu,u
c1 { ,u ni"nr-.r, prevod ilac) posl e
publ i c: sane redi new i
[re ;;;;;'fi ;r;;#ff '
l,:t;# :nne
r ezeri -

NoMemory ( ) { X" xP = new(a) X;


cout << "NoMemory::Nol'4emory0 " .. endl; proslediie a kao drugi arSument
operatoru new. Narayno , do togaie
doii sarno
\.-' :' t::-a.::* -':\ .:-::_: ::' :--tr .:::_:- - ,-':) r n ew d e ki arisan. Evo p ri m e ra rrr.o i,n
ff :l?a1ffi i:?;"';
'

;,0 ".u,o r. t, ti o bj e ka t
cout << "NoMenory::operator nex' << en61',
throw bad_al)ocO; I I "Nema slobodne memorije" /,/,: C73 : p1
acementOperatorNew. cpp
) // sme5tanje na namensku tot<aciju
sa operatorom new
); #include <cstddef> // Size t
#include <iostream>
int main0 {
using namespace std;
NoMenorr,* nm = 0l
:'\ , class X

,:.. ....\ \\Uaa....\.. int i;


pubi ic:
X(int 0) : i(ij) {
cou t "this = ,'<< this << end.l ;
)
-x0 t
<1 jr......, l,: . ./ .A .. ,2 ..a/,

&
432 Misliti na jeziku C++ Poglavlje l3: Dinamiiko stvaranje objekata 433

void* operator new(size t, void* 1oc) ( pravila C++-a. UnoSenjem dinamidkog pravljenja objekata u srZ jezika pomoiu
retu rn I oc; operatora new i delete, omoguieno je lako pravljenje objekata u dinamidkoj
I memoriji kao da se radi o steku. Uz to, upravljan;'e memorijom postalo je fleksi-
); bilnije, poSto operatore new i delete moZete menjati, naroiito ako nisu dovoljno
eflkasni. Thkode moZete odrediti sled dogadaja u sludaju nestanka skladisnog
int rnain0 { prostora.
int I [10];
cout << rr I = 'r << I << endl;
X* xp = new(l) x(a7); ll x na lokaciji I VeZ be
xp-'X::-X0', I I lzriiit poziv destruktora ReSenja izabranih zadatala nalaze se u elektronskom dokumentu 'the Thinking in C++ Annotated Solution
I I Kortstl se samo ako
je objekat smeiten namenski Guide, koji moLete preuzeti sa lokacije m. BruceEckel.com.

\ I ll,- . Napravite klasu Counted koja sadrZi int id i static int count. Podrazume-
I
Primetite cla operator new samo waia prosledeni pokazivaa. Tako, pozivalac vani konstruktor bi trebalo da podinje: Counted( ) :id(count++){. Takode
odluduje gde ie objekar srojati, a konstruktor se poziva da inicijalizuje namenski bi trebalo da ispiSe wednost id i poruku da je pozvan. Destruktor bi trebalo
blok rnernorije kao deo izrazanew. da ispisuje informaciju da je pozvan i wednost id. Testirajte va5u klasu.
lako ovaj primer obraduje samo jedan dodatni argument, nista vas ne 2. DokaZite da new i delete uvek pozivaju konstruktor i destruktor stvarajuii
spreeava da dodate jo5 koji. objekat klase Counted (izveLbe 1) pomoiu operatora new i uni5tavajuii ga
Kada se objekat unistava, nastaje problem. Postoji samo jedna verzija opera- operatorom delete. Takode, napravite niz ovakvih objekata u dinamidkoj
tora delete, tako da se ne moZe reii: ,, Iskoristi posebnu funkciju da oslobodiS memoriji.
memorijr.r". Zeleiete da pozovete destruktor ali neiete da se memorija oslobodi 3. Napravite objekat tipa Pstash i napunite ga objektima izveLbe 1. Posma-
jer objekat i nije napravlien u dinamidkoj memoriji' trajte Sta se dogada kada se izadeiz oblasti vaLenja objekata tipa PStash i
MoZete pozvati samo destruktor: kada se pozove njegov destruktor.
xp->X::-xO; ll Izricit poziv destruktora. 4. Napravite vector<Counted*> i napunite ga pokazivatima na objekte tipa
Or,de slec'li vaZno upozorcnje. Neki programeri pozivaju destruktor izridito da Counted (izveibe 1). Ispi5ite sve objekte iz vektora, a zatim prodite kroz
bi trniStili objekat pre kraja oblasti vaZenja, umesto da izmene oblast vaZenja ili vektor opet i obriSite objekte.
cla objekte prave clinamidki (ispravnije). Imaiete velikih ploblema ako ovako 5. Ponovite veZbu4, ali dodajte funkciju dlanicu fO u klasu Counted, koja
pozovete dcstruktor za obidan obiekat na steku, jer ie destruktor ponovo biti ispisuje poruku. Prilikom prolaska kroz vektor, f( ) pozivajte funkciju f( ).
pozvan po z.avrsetku oblasti vaienja. Ako na ovaj nadin pozovete destruktor za 6. Ponovite veZbu 5 koristeii PStash.
objekat napravljen u dinamidkoj memoriii, destruktor ie biti izvr5en, ali memo- 7. Ponovite veZbu 5 koristeii Stack4.h iz poglavlja 9.
rija neie biti oslobodena, Sto verovatno ne Zelite. Iedini razlog Sto destruktor 8. Dinamidki napravite niz objekata klase Counted (iz veZbe l). Uni5tite niz
rnoZe biti pozvan i na ovai nadin jeste podrSka za namenski smeStaj objekata operatorom delete, bez uglastih zagrada. Objasnite rezultate.
operatorom new.
9. Napravite objekat klase Counted. (izveLbe I) koristeii operator new kon-
Postoji operator delete za namenski smestaj objekta, koji moze biti pozvan
vertujte rezultujuii pokazivad u tip void*, i obriSite ga. Objasnite rezultare.
samo ako konstruktor t?.a7,ove izuzetak prilikom namenskog smeStanja (tako da
se ntemorija automatski prazni). Argumenti namenskog operatola delete odgo- 10. Pokrenite program NewHandler.cpp. Izradunajte koliko dinamidke memo-
varaju argur-pentinta namenskog operatora new, koji je bio pozvan pre nego stO rije je ostalo slobodno.
jr. konstrrrkto y izat.vao izr.rzetak. Ova tema ie podrobnije istraZena u poglavlju o ll. Napravite klasu sa preklopljenim operatorima new i delete, za ledan
izrrzecitna r.t tlrttgont tomu. objekat i niz objekata. PokaZite da obe verzije rade.
,l2.
Smislite test za Framis kako biste pokazali koliko su optimizovani opera-
tori new i delete brZi od globalnih new i delete.
SaZetak I3. Preradite program NoMemory.cpp: u klasu dodajte niz ripa int a operator
I,ravljenje autornatskih objekata u steku zgodno je i efikasno, ali da biste re5ili new treba da zauzima memoriju umesto da izaziva izuzetak tipa bad_alloc.
op5te programerske probleme morate praviti i uni5tavati objekte u bilo kom tre- U funkciji main( ) napravite petlju while kao u primeru NewHandler.cpp da
nprkl rokom rada programa, narodito da biste obradili spoljne informaciie. biste zauzeli memoriju, a zatim posmatrajte Sta ie se deSavati ako operator
I;rrnkcije za rrpravljan je memorijom iz standardne biblioteke jezlka C ne koriste new ne bude proveravao uspe5nost dodele memorije. Tada dodajte i pro-
sc ;eclnostavno, a lre garantu ju ni ispravnu inicijalizaciju, 5to je jedno od osnorrnih veru ikada nestane slobodne memorije izazivajte izrrzetak tipa bad -alloc.
434 Misliti na jeziku C++

l4 Napravite klasu sa namenskim oparatorom new, diji ie argument tipa


,tri.rg. Klasa bi trebalo da sadrZi static vector<string>, gde se smesta drugi
argument operatora new. U funkciii main( ) pozovite namenski operator
new sa argumentima koii opisuiu taj poziv (mogli biste da iskoristite pret-
procesorske makroe FIt-E iLINE)'
t5 Prc racii t e progra ltt ArrayOperatorNew.cpp dodavani em stati'kog vektora,
pokaz.ivaia tipa widge*. operator new treba da u tai vektor upise adresu
irovog objekti, u ,',p.rutnI. delete treba da obrise adresu obiekta iz vektora
(vise informacija o vektorima potraZite u dokumentaciji biblioteke ili u
clrugom tomtr knjige). Napravite i drugu klasu MemoryChecker, iiji
desii.ktor prikazuje broi pokazivada u vektoru. Napravite program sajed-
norn globainom instancom klase MemoryChecker i u funkciji maing,
dinariiaki napravite i uni5tite nekoliko objekata i nizova tipa widget.
PokaT-ite cla MemoryChecker otkriva curenje memorije'

I 4= NnsLrDlVANle,'l SLAGANJE
Pono\mo koriScenje kod3 je jedna od najnapredni.lih rnoguinosri
C++-a, ali ako zaista Zelite da postanete programer, moriiete da
naudite mnogo vi5e od jednostivnog kopiianja i menjanja.
r36 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 437

Kopiranje i menjanie predstavlja zastareo pristup problemu


ponovne upo- Y0{i=o;}
rrebe koda i ne funkcioniie dobro. Na C++-u se veiina problema reSava upotre- void f(int ii) { i = ii; )
bom klasa. Kod mozete ponovo iskoristiti tako Sto iete napraviti novu klasu, na int g0 const { return i; )
postojeiih klasa, a koie rade ispra'uno i vei su testirane' );
osnovu
NalveCi problem je kako upotrebiti klase bez menjanja
postojeieg koda' U
int main0 {
ovorn,poglavljr'robradiiemodvanadinaZapostizanjetogcilja.Prvijeprilidno Y y;
naziva slaganje
direktan: objekti postojeie klase prave se u novoj k'Iasi. To se v .'t (a7) ;
(engl. compo.slrlon) jer i. no'u klasa sastoji od objekata postojeie klase' y.x.set(37): pristup
firugi pristup je ne5to suptilniji' Novu klasu napravite kao rip postojeie
klase' // ugradenom objektu
l /// ,-
Dakle,doslovceuzmetepostoieiuklasuidodajtejojnovikOd.ovajmagidnitin
prevodilac' Funkciji dlanici ugradenog objekta (podobjekta) direktno
naziva se naslediuanje ie..,gl. irtl'teritance), a veiinu posla obavlja se pristupa dvo_
orijentisanog programi- strukim izborom dlanova.
Nasledivanje je jedan od klmena temeijaca objektno
(obradena u poglavlju 15)' obidno se objekti ugraduju kao privatni, tako da postaju
ranja i ima dodatnu primenu .. deo osno,rne reariza-
(Sto je i cije (Sto znadi da realizaciju moZete menjati po rotji).
ispostavlja se da .u ponasanje i sintaksa nasledivanja i slaganja slidni laime funtciye nove klase
koriste ugradene objekte, ali ne moraju da opona.aju
logitnojerseuobaprocesapravenovitipovi,apritomesekoristestari)'uovom inrerfejs tih objekata:
priglavllu nauiiiete tehnike za ponovnu upotrebu koda' / / : Cl4:Composi tion2.cpp
/l Ugradent privatni objekti
#i ncl ude ,,Useful . h,,

Sintaksa slaganja class y


prilikom pravljenja kiasa sue weme ste koristili slaganje, samo Sto ste uglavnom {

pravili objekt. oi ,grud"nih tipova (a ponekad i od objekata tipa string).


Sla- int i;
guni. proir-rol;nih tipova je jednostavno kao i slaganje prostih tipova: X x; // Ugradeni objekat
publ i c:
//: CI4:Usefu1.h Y0{i=0;)
// Klasa za Ponovnu uPotrebu void f(int ji) { i = ii; x.set(ii); }
#i fndef USEFUL-H int g0 const { return i * x.read0; }
#defi ne USEFUT H
void permute0 { x.permute0; }
);
class X {
i nt i ; 'i nt main0 {
publ i c: Yy;
x0 { i = 0; }
v .f (47);
vojd set(int ii) { i = ii; } y. permute 0 ;
int read0 const { return i; *} I // /,-
int Permute0 { return i = i 47; }
Ovde se funkcija permuteo javlja i u interfejsu nove klase, a.li se
); ostale
///:- funkcije elanice klase X koriste u dlanicama klase y.
#endif ll USEFUL-H

Clan i ie privatan u ovoj klasi, tako da je apsolutno-bezbedno koristiti


objekat
pojednostavljuie interfejs:
tipa X kao iivni dlan u novoj klasi, 5to
Sintaksa nas ledivanja
//: C14:ComPosi ti on. cPP Sintaksa slaganja je jasna sama po sebi, a sintaksa nasledivanja je sasvim
nova i
// Ponovna upotreba koda pomocu slaganja drugadija.
#i ncl ude "Useful . h" Kada koristite nasledivanje kazete: ,,ova nova klasa je ista kao i stara,,. ovaj
iskaz navodite u kodu uobidajenim imenovanjem klase, ili pre orvorene vitidaste
class Y { zagtade tela umeiete dvotadku i ime osnoune klase (ili osnor4ih klasa, odvojenih
int i; zarezima prilikom viSestrukog nasledivanja). Nova klasa automatski dobija sve
publ i c: podatke dlanove i funkcije dlanice osnovnih klasa. Evo primera:
x x; ll Ugradeni obiekat
438 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 439 t
Najde5ie takvo nasledivanje nije odgovarajuie.l Hteli bismo da svi jami dla-
I I : Cla: I nherj tance. cPP
novi osnovne klase ostanu javni i u izvedenoj klasi. To moZemo izvesti upotre-
// Jednostavno nasl edi vanje
bom rezervisane reai public prilikom nasledivanja.
#i ncl ude "Useful . h"
li ncl ude <i ostream> U funkciji change( ) pozivamo funkciju permute( ) osnovne klase. Izvedena
klasa ima direktan pristup svim javnim funkcijama osnovne klase.
usrng namesPace std;
Funkcija set( ) izvedene klase redefiniie (eogl. ouerride) funkciju set( ) osnovne
c1 ass Y : Public X i klase. Odnosno, ako pozovete funkcije read( ) i permute( ) objekta tipaY dobiiete
inl i', ll Razlikuje se od alana klase X' verziju tih funkcija iz osno'rne klase (to moZete videti u funkciji main( )). Ali, ako
publ i c: pozovete funkciju set( ) za rinlekt tipa Y, dobiiete redefinisanu verziju. Kada
Y0{i=0;i niste zadovoljni verzijom funkcije koju je klasa nasledila, moZete je promeniti ili
i nt change ( ) i dodati potpuno nove funkcije, poput change( ).
1 = pgrmute0; II Poziva funkciju drugaiijeg imena Prilikom redefinisanja funkcije, moZda Cete ipak hteti da pozovete verzljuiz
return i ; osnovne klase. U funkciji set( ), ime set odnosi se na lokalnu verziju te funkcije.
i Da biste pozvali verziju iz osnorme klase, morate zadati ime osnome klase
void set(int ii) { koristeii operator razre5avanja opsega.
i = ii;
X::set(i i); I I ?oztvanie jstoimene funkciie
i Lista za anicijalizaciju u konstruktoru
I; Videli ste da je u C++-u vaZna ispravna inicij alizacija, pa se to odraZava i na nasle-
divanje i na siaganje. Pri pravljenju objekata, prevodilac garantuje pozivanje kon-
int main0 {
struktora za sve njegove podobjekte. U prethodnim primerima, svi podobjekti su
cout << "sr zeof(X) = " << si zeof(X) << endl l
" '< si zeof (Y) << endl ;
imali podrazumevane konstruktore, a njih prevodilac automatski poziva. Sta se
cout << "sizeof(Y) =
zbiva ako podobjekat nema podrazumevani konstruktor ili ako Zelite da kon-
Y D;
struktoru prosledite argumente? Ovo predstavlja problem jer konstruktor nove
D. change 0 ;
klase nema dozvolu za pristup privatnim podacima tog podobjekta, tako da ih ne
// Interfejs funkcije X:
moZe isprarmo inicij alizovati.
D. read 0 ;
D. permute 0 ; Re5enje je jednostarmo: pozovite konstruktor za podobjekat. U jeziku C++ za
// Redefi ni sana funkci; a krije osnovnu verziju: tu swhu postoji posebna sintaksa, a to je lista za inicijalizaciju u konstruktoru.
D. set ( 12) ; Ona lidi na listu za nasledivanje. Prilikom nasledivanja, osnovnu klasu stavljate
\ I ll,- nakon dvotaike, a ispred podetne vitiiaste zagrade za telo klase. U listi za inici-
jalizaciju, konstruktor podobjekata poziva se nakon liste argumenata konstruk-
VidisedaYnasledu|eklasuX,stoznadidaieYSadrzatiSvepodatkeklase)L
tip-a X' ba5 kao da tora i dvotadke, ali ispred podetne vitidaste zagrade tela funkcije. Za klasu tipa
kao i sve njene funkciie alanice. Zapravo, Y sadrZi podobjekat
Termin se odnosi i Tip nasledenu iz tipa Bar, to bi trebalo da bude nalik na:
,i. nuprurili objekat dlan tipa X unutar klase Y'
"podobjekat"
na obiekte dlanove i na podatke iz osnovne klase' Tio::Tip(int i): Bar(i) { //...
izvodenjem
Svi privatni elementi klase X i dalje su privatni u k-lasi Y odnosno ako klasa Bar ima konstruktor s jednim argumentom tipa int.
y iz- klase X ne moTe se naruSiti mehanizam zastite klase. Privatni elementi klase
memorijski prostor - ali im ne mozete direktno pri'
X jo5 uvek su tu i zauzimaiu
strr p it i. ln icij alizacija obje kata dlanova
Ufunkcijimain()vidirnodasupodaciizk]aseYzdruZeniSpodacimaizklase Ista sintaksa se koristi i zainicijalizaciju obl'ekata dlanova prilikom upotrebe sla-
X, ier je sizeof(Y) dvaput veee od sizeoffX)'
klase'
. gania. Umesto imena klasa zadajete imena objekata. Ako u listi za inicijalizaciju
Obratite paZnju na rezervisanu rei public ispred imena osnovne. pozivate viSe od jednog konstruktora, odvojite ih zarezima:
postaju privatni.
Iikom nasledivanla, podrazumeva se di dlanovi osnowe
klase
imena klase, svi ilanovi osnovne kla$e
Tip2::Tip2(int i) : Bar(i), m(i+t) | // ...
Da red public nije navedena ispred ial'ni
postali bi Privatni
I U Javi je pristup drugaCiji. Prilikom nasledivanja, prevodilac neie dopustiri snizavanic nivoa prisrrrpa
dlanovima.
Misliti na jeziku C++ Poglavlje 14: Nasledivanje i slaganje 441
440

ovakoizgledapoeetakkonstruktorazak]asuTip2,nasledenuodk]aseBar, Kombinovanje slaganja i nasledivanja


klase i
koia sadrZi objekat m' I u Iisti z-a iniciializaciju moZete videti i tip osnorme Slaganje i nasledivanje uvek moZete kombinovati. U sledeiem primeru kon-
iclentifikator ilatla stimo obe tehnike da bismo napravili sloZen oblik klase.
//: C14:Combined.cpp
// nasledivanje i slaganje
Ugradeni tipovi i liste za inicijalizaciju
da izriiito pozovete konstruk-
[.ista za inicijaliz_acijLr u konstrukroru on.,og.r-uru class A (
na koji biste to izveli Cili
t.re za o'jcktn" ala,.,ur". tl stvari, ne postoii drugi nadin 'i nt i;
vci btrdu pozvani pre nego Sto konstruktor nove klase
,ro,, ;t: d:r st'i kotrstrtLktori publ i c:
poziv funkcija dlanica podobjekata
zapodne rad. Iedino to garantuie da iL se svaki kada se A(int ii) : i (ii) {)
oi'lnositi na vei inicijalizovan obiekat' Ne postoji
nadin.da' u trenutku -A0
podobjekta vei nije {}
konstruktor f0
c1oc1e do otvorene \,ltiaaste zagrad,ekonstruktora, void const {}
konstruk-
pozvan, dak i ako pr.roJilu. irora skiveno da pozove podrazumevani l.t)
tor.lbjejo5jedanodnadinanakojiC++sprovodipravilodanijedanobjekat(ili
ne mo7.e biti koriSien bez pozivanja njegovog
konstruktora' class B {
"i.g*i*f
cinjenica da su svi dlanovi vei iniciiaiizovani.do podetka konstruk- 'i nt i;
"ui.r.,i publ i c:
tora,cl<lstapolnaT-ep,ogram"rima.Mozetepretpostavitidasusvipodobiekti
kon-
propisno inicijalizovaniiu,'eas"aiti se na ziriatke
koje Zelite da ostvarite B(int ii) : i(ii) {)
struktorom. Medutim, potioii zadkoliical Sta se dogada s dlanovima ugradenih -80 {}
tipova, koji n ent ai u konstruktore?
void f0 const {}
ugradenim tipovima
Da bi sintaksa bila konsistentna, rnoZete se prema );
oanositikaodaposedujukonstruktorsajednimargumentom:promenljivom classC:publicB{
napisati:
iriog tipu kao i ona koju inicijalizujete' Tako' moZete A a;
II t Clal.PseudoConstructor'cPP publ i c:
c'l ass X { C(int ii) : B(1i), a(ji) {)
i nt i ; -c0 {} // Poziva -A0 i -80
fl oat f; void f0 const { // Redefinisanje
char c; a.f0;
char* si B::f 0;
Publ i c: )
x0 ' i(7), f(1.a), c('x'), s("howdv") {}
);
); int main0 {
C c(a7);
int main0 | ///,-
{X x;
int i (IOO); ll pseudokonstruktor u obidnoi iniciializaciii ICasa C nasleduje klasu B i poseduje objekat dlan (,,sastavljena je od,,) tipa A.
'i nt* iP = new int(47); Vidite kako se u listi zainicljalizaciju pozivaju konstruktor osnovne klase i kon-
struktor objektnog dlana.
\ lll,- i Funkcija c::f( ) redefini5e funkciju B::f( ), koju i nasleduje, ali isto rako poziva
je tehnika' a
I.ipotreba pseudokonstruktora je iednostawa' To uobidajena verziju osnovne k]ase. Pored toga, poziva i funkciju a.fO. Dosad ste primetili da
clobar Iradin pisan ja programa, tako da iete
ga desto koristiti'
promenliivih ugra- samo prilikom nasledivanja mozete govoriti o redefinisanju funkcija: moZere
pseuclokonstrtrktori s'e mogu koristiti prilikom stvaranja
raditi samo s jamim funkcijama objekata dlanova, ali ih ne moZete i redefinisati.
dctlil.t tiPova; Da ponovimo, pozvana funkcija f( ) klase c ne bi pozvala funkciju a.f( ) ako
int i(100); funkcija c::f( ) nije prethodno definisana, inade bi se izuriilafunkcija B::f( ).
int* iP = new int(47);
Zbog pseudokonstruktora, ugradcni tipovi se pona5aju
sliino obiektima'
nisu pravi konstruktori, pa ako izridito ne
upo*tit.l cla pseudokonstruktori
pur,r.,",,, psetrclokonstruktor' vrednost se ne iniciializuie'
T
l4: Nasledivanje i slaEanje 443
442 Misliti na jeziku C++ Poglavlje I

class Derived2: public Derivedl {


Automats ko pozivanje destruktora Member3 m3;
Iako Vanr se u listi z.a inicijilizaciju desto nameie obaveza da izriiito
pozovete
Member4 m4;
pozivate destruktore, postoji samo
konsrrr.tktor, neietc n,,,ruii da iz-ridito ier publ i c:
klasu, on nema argumente' Medutim' prevodilac ie
jeclan clestrtrktor za svakll a Derived20 : m3(1), Derivedi(2), ma(3) {
destruktore, hijerarhijski gledano podevsi od posled-
se postarati da poz-ove sve out << "konstruktor Derived2\n";
njcg izvecienog pa clo destruktora osnovne klase'
' Va2no 1e lsiiei poscbnost konstruktora i destruktorajer se mora
pozvati svaki
)
-Derjved20 {
. hijerarliiji. Kod normalnih funkcija dlanica, poziva se samo ta funkcija, ali ne i out << "destruktor: Derived2\n";
u.rrii. iz osnovne klase. Kada hoiete da poz-ovete i verziju funkcije iz osnor'ryte
)
klase. rnoraiete to iT.riaito uraditi. );
int main0
Redosled poziva konstruktora i destruktora
{
Deri ved2 d2;
Dobro je poznavati poziva konstruktora i destruktora u sludaju da
i redosled ) II /'-
objekat poseduie znatan broi podobjekata Sledeii primer jasno pokazuje prin-
Prvo se pravi objekat tipa ofstream da bi se \zlazni podaci prosledili u dato-
cip rada: teku. Da biimo manje kucali, a i radi demonstracije tehnike pravljenja makroa
ll: Cla:0rder.cPP (koju iemo u poglavlju 16 zameniti znatno naprednijom), stvaramo makro za
// Redosled poziva konstruktora i destruktora pravljenje nekih klasa, koje iemo posle koristiti pri slaganju i nasledivanju. Svi
4i ncl ude <fstream> tonsiruktori i destruktori ispisuju poruke u datoteci. obratite paZnju na to da
usi ng namesPace std; konstruktori nisu podrazumevani, vei svaki od njih poseduje argument tipa int.
ofstream out("order'out") ; Sam argument nema identifikator i postoji samo zato da bi vas naterao da
izridito pozovete konstruktor u listi za inicijalizaciju. (ldentifikatori se ne navode
#define CLASS(lD) class ID {\ da prevodilac ne bi upozoravao na nekoriSiene promenljive.)
publ i c: \ Rezultat ovog programa je:
ID(i nt) i out " #lD " konstruktor\n"; ) \
-lD0 { 6ut << #lD " destruktor\n"; } \ konstruktor Basel
I; konstruktor Memberl
konstruktor Memben2
CLASS(Base1); konstruktor Deri vedl
CLASS (Memberl) ;
konstruktor Membe13
CLASS (l"1ember2) ;
konstruktor Membe14
CLASS (l4ember3) ;
konstruktor Deri ved2
CLASS (l'4embe14) ;
destruktor DerivedZ
destruktor l,lember4
cl ass Deri vedl : Publ i c Basei { destruktor Membe13
Memberl m1; destruktor Deri vedl
Member2 m2 I destruktor Member2
pubi ic: destruktor Memberl
Derjvedl(int) : m2(1), m1(2), Basel(3) { destruktor Basel
out << " konstruktor Deri vedl\n" ; Pravljenje, kao Sto vidite, podinje na samom whu klasne hijerarhije i na sva-
I kom nivou Se prvo poziva konstruktor osnovne klase, a zatim i konstruktori
-Derivedl0 { objekata dlanova. Destruktori se pozivaju obrnutim redom u odnosu na kon-
out << "destruktor Deri vedl\n"; struktore - ovo je vaZno zbog moguie uzajamne zavisnosti. (U konstruktorima
) ili destruktorima izvedenih klasa morate obezbediti da podobjekat osnovne
); klase uvek bude na raspolaganju, da je napravljen ili da joS uvek nije unisten.)
Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 445
444

Zanirr.rljivo je rla na reclosled poz-iva konstruktora objekata dlanova uopSte


ne class Derived3 : Public Base {

objekata dlanova' publ i c:


utiie redoslcd u Iisri z-a inicijalizaciju, vei redosled deklarisanja
pomoiu liste za //Promena tipa rezultata:
Kada bisre rnogli da prronrenite redosled konstruktorskih poziva f0
nizapozivau dva razliiita konstruktora, aii void const { cout << "Derived3::f0\n"; }
inicijaliz-aciju, iiobili Liste dva raz-lidita t,
clestnrkror nc bi z.nao koji jc ispravan redosled pozivaza unistavanje, tako dabi
nastao ltroblelll ztlog z-avistrosti class Derived4 : ic Base (
Publ
publ i c:
//
Promena liste argumenata:
Skrivanje imena i nt f(i nt) const {
Ako rr nasledenoi klasi trelta iznova cla deflnisete neku funkciju dlanicu osnovne cout << "Derived4: :f 0\n";
klase, inraiete dve ntoguct.tosti. Prva je da lirnkcija u izvedenoj klasi ima
isti pot- return 4;
pis i tip rezultata kao u osnomoj klasi. U sludaju virtueinih funkcija, takva
)
zamena zove se redefinisanje (engl. ouerriding). (Virtuelne funkcije se desto );
redefini5u - ro iemo detalino obraditi u poglavlju l5). Sta se dogada ako funkciji
ilanici promenimo listu argumenata ili tip u izvedenoj klasi. Evo jednog primera: int main0 {
string s("zdravo");
//: C14:NameHidi ng.cPP
Deri vedl d1;
// Sakrivanje preklopljenih imena prilikom nasledivanja int x = d1.f0;
Sinclude <iostream>
f i ncl ude <stri ng>
d1.f(s);
Deri ved2 d2;
usi ng namespace std;
x = d2.f0;
/ll d?.f(s); /l verzija koja radi sa znakovnim nizovima ie skrivena
cl ass Base {
Derived3 d3;
lll x = d3.f0; /l uerzija iiii ie tip rezultata int je
publ r c: skrivena
int f0 const i
Deri ved4 d4;
cout << "Base::f0\n";
return 1; I/l x = da.f0; II skrivena verziia f0
x = d4.f (1);
rnt f(strrng) const i return 1; )
| / //,-
void s0 i) Klasa Base ima dve preklopljene funkcije fo. Klasa Derivedl ne menja
t; tunkciju f( ), ali zato menja deflniciju funkcije g( ). u funkciji main( ) vidite da su
obe verzije funkcije f( ) dostupne u kiasi Derivedl. Ipak klasa Derived2 menja
cl ass Deri vedl : Publ i c Base i samo jednu preklopljenu verziju funkcije f( ), pa druga zbog toga vise neie biti
publ i c: na raspolaginlu. U idasi Derived3, promena tipa rezultata skriva i verziju iz
void g0 const {} os.orr.r" klise, a klasa Derived4 pokazuje kako se isto de$ava prilikom promene
je
); liste argumenata. Kada se u izvedenoj klasi definise nova verzija funkcije koja
preklofllena u osno'rnoj klasi, sve ostale preklopljene verzije se skrivaju. U
cIass Deri ved2 : Publ i c Base {
pogravuu 15 videiete kako rezervisana ree virtual utide na preklopljene funkcije.
publ i c: ' Izmenite Ii potpis i/ili tip rezultata funkcije dlanice u izvedenoj klasi, kori-
// Promena deflnicije: stiiete klasu ni nudin d.rgadiji od onog predvidenog osno-urtim nadelom nasle-
rnt f0 const {
divanja. To ne znadi da privite gresku, vei samo da je osnovni cilj.nasledivanja
cout << "Derived2: :f 0\n";
retu rn 2;
taj di se podrZi polimorfizam. A izmenom potpisa funkcije ili tipa rezultata,
,ipruuo menjate interfeji osnonne klase. Ako vam je to namera, tada nasledi-
vanje koristite kao nadin'za ponovnu upotrebu koda, a ne za upotrebu interlejsa
)

);
osnormih klasa (Sto je osnorma primena polimorfizma) Korisieniem nasledi-
vanja na ovaj nadin, specijalizovaiete klasu opste namenc z.a nektt posebntt
upotrebu - za Sta se obiino, mada ne i r-rvek, koristi slaganje'
l4: Nasledivanje i slaganje 447 t-
Misliti na jeziku C++ Poglavlje
446

9' Iedan od problema s ovom


PostosuSvefunkcijedlaniceuk]asiStack4.humetnuteuk6d,programne
"putStack iz poglavlia
Na prinrer, poglcclaite klasu prilikom uzimania treba da se povezuje s drugim objektnim datotekama'
klasom ie taj sto.,.,uutill'o'it morali da'i<onvertuiete tip StringStack specijalizuje klasu Stack tako da funkciia push( ) prihvata samo
a niie ni bezbedno - mogli ste konverto-
rnt'tno' -String.
Klasa stack prihvata i pokazivade tipa void, tako da se
pokazivada iz. konteinera- pokaziva-de tipa
vati pokazivaa Ll neispravall tlp' op5te prilikom umetanja,Jp.ou"ruuu tip pokazivada. Sada funkcije peekO i popo
RcScn je ko ji nam ." t',u pt'i
pogled dini pogodnim ieste speciializaciia
iz
Evo primera u kom koristimo k]asu iaiaju pokazivade na string umesto pokazivada tipa voidx, tako da za kori-
klase Stack pomoiu ""t[Ji""jt Sienje pokazivada nije potrebna konverzija'
poglavlia 9: Zieraulree, ati ova dodatna bezbednosna provera usporava funkcije pushO,
: Clra: lnheri tStack'cPP peek( ) i pop( )l Prevodilac dobija dodatnu informaciju o tipu koji koristi prilikom
I I
izacija klase Stack prerroae.rla, ali kako su funkcijeistog nivoa nema dodatnog generisanja koda.
// SPecijal
". ./C09/Stack4'h"
^ U primeru dolazi do skrivanja imena, jer funkcija push( ) ima.razliiit potpis'
#include
#i ncl ude " ' . /requi re ' h" odnoino njena lista urgu*"nutu je drugadija. Ako unutar iste klase imate dve
#i ncl ude <i ostream> verzijefunicije push( ), obieno se javlja preklapanje. U ovom primeru je prekla-
#i ncl ude <fstream> panjenepoZetlnoaasenebiidaljeprosledivaopokazivadtipavoid*pre.
#i ncl ude <stri ng> iAopf;""o1 ,".iiji tu.tk.ije pushO. Na svu sreiu, programski
jezik C++ skriva
us i ng namesPace std; u"iriiu pustrtvoid*). Oostupna je samo verzija koja je definisana u izvedenoi
klasi i zato samo pokazivad; tipa string mo7emo da stavimo u StringStack.
cl ass Stri nqStack : Publ i c Stack i po5to sada tadno znamo kbje objekte imamo u kontejneru, destruktor bez
publ i c: smetnji obavlja svoju funkciju i ne pojavljuje se problem vlasnisrva, odnosno
voi d Push (stri ng* str) {
izbegnut je barem iedan aspekat tog problema' Ako pokazivad na tip string
ck: :Push(st r ) ;
S t a
staviLo u StringStack, tada(barem prema znadenju klase StrigStack) takode
)
prenosimo vlasrii5wo nad tim pokazivaeem u StringStack. Pozivanjem funkcije
stri ng* Peek 0 const { pop( l, dobijamo pokazivad i vlasniswo nad pokazivadem. Svi ostali pokazivadi
return (string*)Stack: :Peek0 ;
ioii r" ostali u kontejneru StringStack-a, biie obrisani prilikom pokaziva-
pozivanja
)
destruktora. Po5to su to pokazivadi tipa string, iskaz delete radiie s
stri ng* PoP ( ) {
return (strjng*)Stack: :PoP0 i iima na string umesto i pokazivaiima na void. Uni5tavanje se zato odvija
pravilno i bez problema.
klasa radi samo s pokazivadima na tip string.
I
-Strr ngStack 0 { 'Stack ova
Ipak postojl i manjkavosti.
stri ng* toP = PoP ( ) ; Ako Zelite da klasa radi i s drugim tipovima objekata, moraiete da
napiSete novu verziju k]ase. To wlo brzo postaje zamorno pa iemo
problem
while(toP) {
del ete toP; reS1ti upotrebom Sablona, Sto iete videti u poglavlju 16'
toP = PoPO; Uovomprimeruuo.avamojoSne5to:prilikomnasledivanjamenjase
i intrefejs klase stack. Ako je interfejs drugaiiji, tada se. stringstack ne uklapa
I potpuno u klasu Stack i nede moii pravilno da se koristi kao Stack. To postavlja
pred-
); plt*j. ispraT nosti nasledivanja u o,om sludaju' Ako klasa StringStack ne pokaza-
stavtla veiziju klase Stack, 5ta se onda nasleduje? Kasnije u poglavlju
int majn0 (
iemo vam ispramiju verziju klase StringStack'
i fstream i n(" Inheri tStack'cPP") ;

assure(rn, "lnheritStack'cPP") ;
string line; Funkcije koje se ne nasleduju
Stri ngStack textl i nes; lost6le funtiile koje se ne prenose automatski iz osno"ryte klase u izvedenu
whi le(getl ine(in, I ine) ) klasu. Konstruktor i'destruktor stvaraju i uniStavaju objekte odredene
klase Pri-
textl ines.push(new strjng(l ine) );
Iikom unistavanja moraju se pozvati svi konstruktori i destruktori u hijerarhiji
strr ng* s; praviti za svaku
0) { // konverzije! nasledivanja. Zato sekonstruktori i destruktori moraju posebno
while((s = textlines'pop0) l= Nema !

izvedenu klasu.
cout << *s <' endl;
del ete s;
Misliti na jeziku C++ Poglavlje I4: Nasledivanje i slaganje 449
148

Izistilrraz.logasencnasleciuienioperator='jeronradislidanposaokaokon-
class 0ther {}; /l ugneZdena klasa
objekata s leve strane // Automatska konverzija tipa:
stnrktor. Iako umcte da doclelite vrednosti svim dlanovima operator 0ther0 const {
i nakon nasledivanja'
of.ru,oro =, fle ITIord da znadi da iete to umeti cout << "Game: :operator 0ther0\n";
Prilikom nasledivanja, prevodilac pravi ove funkcije ako ih niste sami return 0ther0;
i konstruktor za
napravtli (prevodilac ie napraviti podriz-umevani konstruktor
konstruktor u toj klasi). ovo je )
kopiranle, samo ako vi nisie napravili niiedan
konstruktori inicijalizuju dlanove' -Game0 { cout .. "-Game0\n"; }
ukratko prikaz-ano u poglavliu 6.'sintetizovani );
dodele kopiraju wednosti dlanova' Evo kako prevodilac
a sinretizovani operatori
sintetiz-uie ftrr-rkcii e : class Chess: public Game i);
I I : Cla:SYnthesi zedFunctions'cPP
void f(Game::0ther) 0
// Funkcije koje sintetizuie prevodilac
#i ncl ude <i ostream>
usi ng nanesoa5g std I
class Checkers : public Game {
publ i c:

class GameBoard i //Poziva se podrazumevani konstruktor osnovne klase:


publ i c: Checkers0 { cout .. "Checkers0\n"; )
GameBoard0 { cout " "GameBoard0\n"; ) // t(oiete iznieito pozvati konstruktor za kopiranje osnovne klase
GameBoard(const GameBoard&) { // i1i ee se automatski pozivati
cout << "GameBoard(const GameBoard&)\n"; f f podrazunevani konstruktor:
Checkers(const Checkers& c) : Game(c) {
i
GameBoard& operator=(const GameBoard&) t cout << "Checkers(const Checkers& c)\n";
cout << "GameBoard: : operator= 0 \n" ; )

return *thi s; Checkers& operator=(const Checkers& c) {


)
// l{oleteizridito pozvati verziju operatora dodele
{ cout "-GameBoard0\n"; // osnovne klase ili neee biti dodeljena vrednost
-GameBoard0 " )

); // dlanovima osnovne klase


Game: : operator= (c) ;

cl ass Game {
cout << "Checkers: :operator=0\n" ;
GameBoard gb; // Slaganje return *thi s;
publ i c: )

I I Pozi,ta se
podrazumevani konstruktor GameBoard: );
Game0 ( cout << "Game0\n"; )
I I Moiele izriiito pozvati konstruktor GameBoard int main0 {
Chess d1; // Podrazumevani konstruktor
I I i1i se automatski Pozi
va

// konstruktor za kopi ranje i i podrazumevani konstruktor: 1 Chess d2(d1); // Konstruktor za kopiranje


s tjpa int
Game(const Game& g) : gb(g'qb) { //! Chess d3(1.); l/ GreSka: nema konstruktora parametrom
cout << "Game(const Game&)\n"; d1 = d2; // Sintetizovani operator=
t(dt); /l Konverzija tlpa je nasledena
)
{ cout "Game(int)\n"; Game::0ther go;
Game(int) " }

Game& oPeratoP= (const Game& g) { /ll dl = go; // 0perator= nije sintetjzovan


izridito pozvati operator dodele GameBoard // za ostale tipove
// Morate
c1, (c1)
// i 1 i voj gb nece bj t i
Promenl.l i
Checkers c2 ;

// dodel.lena vrednost cl = cZl


gb = g 'gb; \ ///,-
cout << "Game: : oPerator= 0 \n" ;
return "thi s;
I
Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje t-
450 451

Konstruktor i operator = za klase GameBoard i Game ispisuju poruke' tako Nasledivanje stariakih funkcija danica
da moZete videti kada ih prevoclilac koristi. Operator Othero automatski kon- Statidke funkcije ilanice pona5aju se kao i nestatiake:
vertuje objekat tipa Game u objekat ugneZdene klase Other' Klasa Chess I . Nasleduju ih izvedene klase.
prevodilac
naslcduje klasu Game i ne pravi nikakve funkciie (pogledajte kako
Other zbog plovere automatske 2. Promenom definicije statidkih funkcija, biie skrivene sve ostale pre-
reaguje na ro). Parametar funkcijc )ief( tipa
klopljene funkcije iz osnor,ne klase.
konverziie tipa fr.rnkci je.
U fr.rnkciji mainO pozivaju se sintetizovani podrazumevani konstruktor i
kon- 3. Kada promenite potpis funkcije osnovne krase prilikom nasledivanja,
stnrktor za kopiranie izveclene klase Chess. Poziva se i verziia ovih konstruktora iz skrivaju se sve verzije funkcija iz osno'rne klase (ovole samo varijacila pret-
klase Game, kao deo hijerarhi.iskog Ianca poziva. Mada lidi na nasledivanje,
nove hodnog wrdenja).
konstruktore ie sintetizovao prevodilac. Kao Sto oiekujete, konstruktor s algu- Statidke funkcije dlanice ne mogu biti virtuelne (podrobnije obradeno u
rnentima se ne pravi automatski, to je ipak preveliki zahtev za prevodioca. poglavlju 15)
Operator = se takode sintetizuje kao nova funkcija u klasi Chess, koristeii
jer ta
clodelu prema dlanovima (na ovaj nadin se poziva verzijaiz osnovne klase),
funkcija niie posebno napravljena u novoj klasi. Nararmo, prevodilac automatski Slaganje ili nasledivanje
sintetiz-uje i destruktor. Slaganjem i nasledivanjem smestaju se podobjekti u novu klasu. U obe tehnike
Usled svih ovih pravila pono\]Tlog pisanja funkcija kojima pravimo objekte, se za pravljenje podobjekata koriste liste za inicijalizaciju. Dosad ste se vei upi-
rno2e se udiniti dr.rdnom dinjenica da se operator automatske konverzije tali kakva je razlika izmedu njih, i kada treba izabrati koju.
nasledtrje. Za tako nesto postoie razloz.i. Ako u klasi Game postoji dovoljno Slaganje uglavnom koristimo kada Zelimo da neku karakteristiku postojeie
inforrnacija z-a pravljenje oblekta tipa other, te informacije se dalje nalaze u klase iskoristimo u novoj klasi, ali ne i u njenom interfejsu. Naime, vi ugradujete
svirn klasama iz.vedenirri iz klase Game, a operator konverzije tipa ie nastaviti
da
objekat da biste realizovali novu klasu, ali korisnik ie videtl samo interfejs nove
vaTi (mada iete mo7-da htcti da ga redefiniSete)' klase, ne i onaj koji je korisrila originalna k]asa. To se najdesie radi ugradnlom
opcrator = se sintetiT-uje samo za dodelu objekata istog tipa. operatore privatnog objekta postojeie klase u novu klasu. Ipak, poneiad bi treba.lo dozvoliti
clodele za drr.tge tipove trvek morate sami da napi5ete' korisniku klase direktan pristup podobjektu, odnoino udiniti objekte jawrim
Ako pazljivo pogtedate klasu Game, primetiiete da konstruktor za kopiranje i (engl. public). Bezbednosni aspekt je zadovoljen jer objekti dlanovi
sami kon-
opcraror rlociele iz,iielto pozivaju konstruktore za kopiranje i operatore dodele troli5u pravo pristupa, pa je korisniku ditav interfeji znatno razumljiviji je r zna d,a
'lb obie no rt redu, inade bi u konstruktoru za kopiranje bio
za clanove klase. ;e je objekat sklopljen od delova. I(asa Car (automobil) dobar je primer
za to:
pozvan podrazurnevani konstruktor za objekte, a operator dodele ne bi objek-
tin.ra dodelio nikaklu wednost.
//: CL4:Car.cpp
Na kraiu, pogledaite kiasu Checkers, u kojoj su napisani podrazumevani
// Javno slaganje
konstruktor, konstruktor za kopiranje i operator dodele. Podrazumevani kon- class Engine
je {
strtrktor autontatski poziva podrazumevani konstruktor za osno\'Yle klase i to publ i c:
tr principu ono 5to ,ulnu tr.bu. e im sami pisete operatore dodeje i konstruktore void start0 const {}
z_a kopiianje, prevodilac ie pretpostaviti da znate Sta radite
i neie automatski void rev0 const {)
pozivati verzile iz. osnovne klase, Sto bi inade dinio u sintetizovanim funkcijama' void stop0 const {}
Vtrz-lju iz osnovne klase, sami morate izridito pozvati. Konstruktor za.kopiranje );
klase Checkers poziva konstruktor osnovne klase u iisti za inicijalizaciju:
Checkers (const Checkers& c) : Game(c) {
class t,/heel {
pub'l i c:
operator cloclele klase checkers poziva operator iz osnor,'ne klase u prvom d nt
redu tela funkcije:
voi i nf1 ate (i psi ) const {}
);
Ga"re::operator-(c) ;
class Window
ovakve pozivc bi r.rvek rrebalo koristiti prilikom nasledivania klasa. publ i c:
{
Nasledivanje i slaganje 451
450 Misliti na jeziku C#

Konstruktor i operator = za klase GameBoard i Game ispisuju poruke, tako Nasledivanje statickih funkcija flanica
da moZete videti kada ih prevodilac koristi. Operator OtherQ automatski kon- Statidke funkcije dlanice pona5aju se kao i nestatidke:
vertuje objekat tipa Game u
objekat ugneZdene klase Other. ICasa Chess
L Nasleduju ih izvedene klase.
nasleduje klasu Game i ne pravi nikakve funkcije (pogledajte kako prevodilac pre-
reaguje na to). Parametar funkcije fO je tipa Other zbog provere automatske 2. Promenom definicije statidkih funkcija, bice skrivene sve ostale
konverzije tipa funkcije. klopljene funkcije iz osno'vne klase'
U funkciji main( ) pozivaju se sintetizovani podrazumevani konstruktor i kon- l. xaaa promenite potpis funkcije osnovne klase prilikom nasledivanja, pret-
struktor za kopiranje izvedene klase Chess. Poziva se i verzija ovih konstruktora iz skrivaju ," su" r"riil" fu.rkcilu i, osnovne klase (ovo je samo varijacija
klase Game, kao deo hijerarhijskog lanca poziva. Mada lidi na nasledivanje, nove hodnog twdenja).
konstruktore je sintetizovao prevodilac. Kao Sto odekujete, konstruktor s argu- Statidke funkcije dlanice ne mogu biti virtuelne (podrobnije obradeno u
mentima se ne pravi automatski, to je ipak preveliki zahtev za prevodioca. poglavlju 15)
Operator = se takode sintetizuje kao nova funkcija u klasi Chess, koristedi
dodelu prema ilanovima (na ovaj naiin se poziva verzija iz osnorme klase), jer ta
funkcija nije posebno napravljena u novoj klasi. Naramo, prevodilac automatski Slaganje
-Sugirrl"*
ili nasledivanje
sintetizuje i destruktor. se podobjekti u novu klasu. U obe tehnike
i nasledivanjem sme5iaju
Usled svih ovih pravila ponovnog pisanja funkcija kojima pravimo objekte, se ia prav5enle podobiekata korisie liste za inicijalizaciju' Dosad ste se vei upi-
moZe se uainiti dudnom dinjenica da se operator automatske konverzije tali kakvaie razlika izmedu njih, i kada treba izabrati koju'
nasleduje. Za tako ne5to postoje razlozl Ako u klasi Game postoji dovoljno Slaganje uglarmom koristimo kada Zelimo da neku karakteristiku
postojede
informacija za pravljenje objekta tipa Other, te informacije se dalje nalaze u klase iskoristimo u novoj klasi, ali ne i u njenom interfejsu. Naime, vi ugradujete
svim klasama izvedenim iz klase Game, a operator konverzije tipa ie nastaviti da nove
objekat da biste realizovali novu klasu, ali korisnik ie videti samo interfejs
vaZi (mada iete moZda hteti da ga redefini5ete). klase, ne i onaj koji je koristila originalna klasa. To se najdesde radi ugradnjom
Operator = se sintetizuje samo za dodelu objekata istog tipa. Operatore privatnog obj.ttu ioitol"Ce klase u-novu klasu. Ipak, ponekad bi trebalo dozvoliti
javnim
dodele za druge tipove uvek morate sami da napi5ete. korisniku klase direktan pristup podobjektu, odnosno udiniti objekte
Ako paZljivo pogledate klasu Game, primetiiete da konstruktor za kopiranje i (en$. public). Bezbednosni aspikt je zadovoljen jer objekti elanovi sami kon-
operator dodele izridito pozivaju konstruktore za kopiranje i operatore dodele t ofsrrpruuopristupa,pajekorisnikuditavinterfejsznatnorazumljivijijerznada
za ilanove klase. To je obidno u redu, inade bi u konstruktoru za kopiranje bio jeobjekatsklopljenoddelova:KlasaCar(automobil)dobarjeprimerzato:
pozvan podrazumevani konstruktor za objekte, a operator dodele ne bi objek-
tima dodelio nikakvu wednost. //: Cl4:Car'cPP
Na kraju, pogledajte klasu Checkers, u kojoj su napisani podrazumevani ll Javno slaganje
konstruktor, konstruktor za kopiranje i operator dodele. Podrazumevani kon-
class Engine {
struktor automatski poziva podrazumevani konstruktor za osnovne klase i to je c:
Publ i
u principu ono Sto vama treba. eim sami piSete operatore dodele i konstruktore void start0 const {}
za kopiranje, prevodilac ie pretpostaviti da znate Sta radite i neie automatski void rev0 const ()
pozivati verzije iz osno'urre klase, Sto bi inade dinio u sintetizovanim funkcijama. void stop0 const {}
Verziju iz osnorme klase, sami morate izridito pozvati. Konstruktor za kopiranje l.l.
k.lase Checkers poziva konstruktor osnovne klase u listi za inicijalizaciju:
Checkers(const Checkers& c) : Game(c) { class }lheel {
publicl
Operator dodele klase Checkers poziva operator iz osnovne klase u prvom void inflate(int Psi) const ()
redu tela funkcije: I.
t,
Game: : operator= (c) ;

Ovakve pozive bi uvek trebalo koristiti prilikom nasledivanja klasa. class }lindow {
Publ i c:
452 Misliti na jeziku C+r Poglavlje I4: Nasledivanje i slaganje 453

void rollup0 const {} publ i c:


void rolldown0 const {} FNamel0 : named(false) {}
); FNamel(const string& fname)
: fileName(fname), file(fname.c_str0) {
class Door { assure(fi I e, fi l eName) ;
publ i c: named = true;
Window window; )
void open0 const {} string name0 const { return fileName; }
void close0 const {) void name(const string& riewName) {
pronena.imena
); if(named) return; ff nije dozvoljena
fileName = newName;
class Car { named = true;
publ i c: )
Engine engine; operator ifstream&0 { return file; }
Wheel wheel [4] ; );
Door 1eft, right; // Druga vrata
); int mainQ {
FNamel f i I e("FNamel.cpp,,) ;
int main0 { cout << file.nameQ << endl;
Car car; // Greika: close0 nije dlanica:
car. I eft . wi ndow. rol I up ( ) ; //! file.close0;
car.whee'l [0] . i nfl ate(72) ; I ll/:-
| // /,- ovde postoji problem. Pokusali smo da iskoristimo objekat tipa FNamel
Kako je struktura klase Car dobijena analizom problema (ugradeni objekti se umesto objekta tipa ifstream, pa je zato napravljen operator za automatsku
ne koriste samo interno), omoguCavanje javnog pristupa dlanovima pomaZe konverziju objekta tipa Fnamel u objekat ifstream&. u ivakom sludaju, red:
programeru klijentu da razume upotrebu klasa, a i k6d klase je jednostavniji. file.close0;
Ako malo razmislite, videiete da nema nimalo smisla praviti klasu automo-
bila ugradivanjem objekta tipa vozilo, zato sto automobil ne sadrZi vozilo veC nece moci da se prevede jer se automatska konverzija tipova primenjuje samo
jeste vozilo. Odnosno, relacija je predstavlja nasledivanje, a sadrii predstavlja na argumente funkcija, ali ne deluje na izbor dlanova.
slaganje. Nararmo, mogli bismo da defini5emo funkciju close( ) za klasu FNamel:
void close0 { fjle.close0; }

Podtipovi To moZete raditi kada postoji samo par funkcija koje hocete da prenesete iz klase
Pretpostavimo da pravite objekat tipa ifstream koji otvara datoteku i sadrZi i ifstream. Ako koristite samo deo klase, slaganje senamede.
njeno ime. Upotrebom slaganja, u novu klasu moZete ugraditi objekat tipa Sta se desava ako Zelite da iskoristite sie sio se narazi u krasi. ovo se naziva
ifstream i objekat tipa string. pravljenje podtipoua (engl. subtyping)jer od postojeceg tipa pravite nov, a Zelite
da interfejs novog tipa bude jednak interfejsu postoleceg tipa (uz, eventualno
ll: C14:FNamel.cpp neke nove funkcije dlanice), tako da ga moZete upotrebitinisvim mestima gde
l/ fstrean sa
imenom datoteke
b-iste inade koristili postojeci tip. U ovom sludaju nasledivanje je neophodno.
#incl ude "../requi re.h"
vidite da pravljenjem podtipova u potpunosti resavamo prethodni problem.
#i ncl ude <i ostream>
#i ncl ude <fstream> //: C14:FName2.cpp
#i ncl ude <stri ng> // Pravljenje podtipova re5ava problem
usi ng namespace std; #include "../require.h
#include <iostream>
class FNamel {
#include <fstrearn>
i fstream fi I e; #include <string>
stri ng fi I eName;
bool named;
454 Misliti na jeziku C# Poglavlje l4: Nasledivanje i slaganje 455

using namespace std; MoZda se pitate kakva je swha privatnog nasledivanja, jer se kao altemativa
namede upotreba slaganja za pravljenje privatnog objekta u novoj klasi. Privatno
class FName2 : Public ifstream { nasledivanje postoji radi zaokruZenja programskog jezika. Ako ni zbog (ega
stri ng fi I eName; drugog, da biste smanjili konfirziju obidno iete koristiti slaganje umesto privat-
bool named; nog nasledivanja. Medutim, ponekad Cete hteti da od dela interfejsa napravite
publ i c: no-vu klasu i da onemogudite objektu da se pona5a kao objekat osnoure klase.
FName20 : named(false) {} OVo nam omogudava privatno nasledivanje.
FName2(const string& fname)
: ifstream(fname.c-str0), fileName(fname) {
Objavljivanje privatno nasledenih dlanova
assure(*thi s, fi leName) ;
Prilikom privatnog nasledivanja, svi jarmi dlanovi osnovne klase postaju pri-
named = true;
vatni. Ako neki dlan hodete da udinite vidljivim, u odeljku public izvedene klase
)
navedite njegovo ime (bez ikakvih argumenata ili powatnih wednosti) uz
string name0 const { return fileName; )
rezervisanu red using.
void name(const string& newName) {
if(named) return; // Promena imena nije dozvoljena / / : Cl4tPrivatelnheri tance. cpp
fileName = newName; class Pet {
named = true; publ i c:
) char eatQ const { return 'a'; }
)i int speakQ const { return 2; }
float sleepO const { return 3,0; }
int main0 ( float sleep(int) const { return 4.0; }
FName2 fi 1 e("FName2.cPP") ; l.t,
assure(fi le, "FName2.cPP") ;
cout << "name: " << file.name0 .. endl; class Goldfish : Pet ( // Privatno nasledivanje
stri ng s; publ i c:
getline(file, s); // I ovo radi ! using Pet::eal ll Imenuj javni dlan
file.seekg(-200, ios: :end) ; using Pet::sleep; // Objavljuju se oba preklopljena llana
fjle.close0;
I I I l,-
Ioaia Fname? moi.e da se koristi umesto klase ifstream, a sve funkcije klase int main0 {
Goldfish bob;
ifstream su dostupne. Takode vidite da funkcije koje niste izridito definisali u
bob.eat0;
izvedenoj klasi, poput funkcije getline( ), takode mozete koristiti u objektu tipa
bob. sl eep 0;
FName2. Eto zasto je klasa FName2 wsta toka ifstream, a ne samo klasa koja (l) ;
bob. sl eep
sadrZi takav objekat. Ovo je wlo vaZna tema, pa Cemo je paZljivo obraditi na
kaju ovog i na podetku sledeieg poglavlja.
//! bob.speak0;// GreSka: privatna funkcija elanica
l lllr
Ova tehnika omogudava da se privatno nasledivanje koristi za skrivanje dela
Privatno nasledivanje funkcionalnosti osnovnih klasa.
Privatno nasledivanje osnormih klasa ostvaruje se izostavljenjem rezervisane Obratite paZnju na to da objavljivanjem imena funkcije, sve preklopljene
reii public ispred imena osnovne klase, ili izriditim navodenjem redi private (Sto verzile funkcije u osnouroj klasi postaju vidljive.
je isprarmija taktika jer je korisniku jasno da ste to hteli). Privatnim naslediva- Pafljivo razmislite pre nego Sto se odludite za privatno nasledivanje umesto
njem pravite no!.Ll klasu koja ima sve podatke i funkcionalnost osnovne klase, ali slaganja. Prilikom privatnog nasledivanja javUaju se odredene komplikacije u
titco je ta funkcionalnost skrivena, predstavljaie samo deo unutra5nje realiza- identifikaciji tipova za weme izrn5avanja (to je obradeno u drugom tomu).
cije. Korisnik klase nema pristup osno'rnoj funkcionalnosti, tako da se objekat
izvedene klase ne moZe koristiti kao instanca osnovne klase (Sto je bio sludaj s
FName2.cpp).
454 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 455

u s r n9 namespdce s td ; MoZda se pitate kakva je s'urha privatnog nasledivanja, jer se kao alternativa
nameie upotreba slaganja za pravljenje privatnog objekta u novoj klasi. privatr.ro
cl dss FName2 : publ I c j fstream { nasledivanje postoji radi zaokruZenja programskog jezika. Ako ni zbog dega
string fr leName; drugog, da biste smanjili konfuziju obidno iete koristiti slaganje umesto prival-
bool named; nog nasledivanja. Medutim, ponekad iete hteti da od dela interfejsa napravire
publ i c: nor,u klasu i da onemoguiite objektu da se ponaSa kao objekat oinoyne klase.
FName20 : named(false) {} Ovo nam omoguiava privatno nasledivanje.
FName2 (const stri nq& fname)
: ifstream(fname.c_str0), fileName(fname) {

assure(*this, fi leName) ; Objavljivanje privatno nasledenih dlanova


named = true; Prilikom privatnog nasledivanja, svi jami dlanovi osno\me klase postaju pri-
I
vatni. Ako neki dlan hoiete da udinite vidljivim, u odeljku public izvedene klase
string name0 const ( return fi leName; ) navedite njegovo ime (bez ikakvih argumenata ili powatnih wednosti) uz
voi d name (const stri ng& newName) ( rezervisanu red using.
i f(named) return; // Promena imena nije dozvoljena / / ; Cl4 Privatelnheri tance. cpp
frleName = newName; class Pet {
named = true; publ i c:
) char eat0 const { return ,a,; }
); int speak0 const ( return 2; )
fl oat sl eep 0 const { return 3.0; }
lnt main0 {
float sleep(int) const { return 4.0; }
FName2 frle( FName2.cpp") ; l-

assure(fi le, FName2.cpP') ;


cout << "name: " << fi le.name0 t' gn61 '
class Goldfish: Pet | // privatno nasledivanje
string s; publ i c:
getlrne(file, s); // I ovo radi! using Pet::eat; // Imenuj javni clan
frle.seekg(-200, ios: :end) ; using Pet::s1eep; // Objavljuju se oba preklopljena clana
file.close0; );
\ lt,-
Klasa Fname2 moi.e cla se koristi umesto klase ifstream, a sve funkcije klase int main0 (

ifstream su dostupne.-lakode vidite da funkcije koje niste izridito definisali u Goldfi sh bob;
izveclenoj klasi, popr.rt funkcije getline( ), takode mozete koristiti u objektu tipa bob.eat0;
bob. sl eep 0 ;
FName2. F.to za5to je klasa FName2 wsta toka ifstream, a ne samo klasa koia
bob"sleep(1);
saclrzi takav objckat. Ovo ic vrlo vaZna tema, pa iemo ie paZljivo obraditi na
kraju ovog i na poictku slecleieg poglavlja. //! bob.speak0;// Greika: privatna funkcija ilanica
I I l/,-
ova tehnika omoguiava da se privatno nasledivanje koristi za skrivanje clela
Privatno nasledivanje funkcionalnosti osno'rnih klasa.
I)rivatno naslcdivanjc osnor,rrih klasa ostvaruje se izostavljenjem rezervisane obratite paZnju na to da objavljivanjem imena funkcije, sve preklopljene
reii public isprecl imena osnovne klase, ili izriiitim navodenjem redi private (Sto verzije funkcije u osno'rnoj ktasi postaju vidljive.
je ispravnija taktika jer je korisnikll jasno da ste to hteli). Privatnim naslediva- PaZljivo razmislite pre nego Sto se odludite za privatno nasledivanje umesto
rrjenr pravite novu klasu koja ima sve podatke i funkcionalnost osno\rne klase, ali gl.agan]a. Prilikom privatnog nasledivanja javljaju se odredene komplikacije u
kako je ta funkcionalnost skrivena, predstavliaie samo deo unutra$nje realiza- identifikaciji tipova za weme izwsavanja (to je obradeno u drugom tomu).
cije. Korisnik klase nerna pristup osnovt]oi funkcionalnosti, tako da se objekat
izvertlcr.rc klase r.re rno2e koristiti kao instanca osnovne klase (Sto je bio sluiaj s
FName2.cpp).
Misliti na jeziku C++ Nasledivanje i
456

Zaitiieni pristuP Preklapanje operatora i nasledivanje


lzuzev operatora dodele, operatori se ne prenose automatski prilikom nasle-
Postoster.tlloz,natisatlasledivanjem,rezervisanareiprotected(zastiien) divanja. To moZemo pokazati sledeiim primerom, u kome se nasleduje klasa
konacno inta srnisla. ll iclealnoj situaciji, privatni dlanovi uvek ie
biti privatni' U
Byte.h iz poglavlja 12:
projektinlanamponekadzatrebadanekeStvariSakrijemooddrugih,aliida
clozvolirno pristup nekirn dlanovima objektima izvedenih klasa
Rezervisana red / I :
Cl4z)Peratorlnheri tance. cPP
protected ima pragmaticnu ulogu, i trebalo bi da nam kaZe: ,,Sto se tide
kori. // Nasledivanie preklopljenih operatora
#include "../C12/BYte.h"
snika klase ovo ;e piivatno, ali je dostupno izvedenim klasama'"
#i ncl ude <fstream>
Najboliejedapodacidlanovibuduprivatni-trebauvekzadrZatimoguinost
using namespace std;
promeneu,nnu.,.realiz-acije.Tektadaizvedenimk]asamamoZeteomoguiiti
ofstream out("BYteTest.out") ;
tontrolisan pristup dlanovima pomoiu za5tiiene funkcije'
ll: CIa Protected.cPP class Byte2 : Public BYte {

// Rezervisana rea Protected Publ i c:


#i ncl ude <fstream> // konstruktori se ne nasleduju:
us i ng namesPace std; Byte2(unsigned char bb = 0) : Bvte(bb) {}
// operator= se ne nasleduie,
cl ass Base { ll a1i ee biti sintetizovan za dodelu prema elanovima'
i nt i ; // Medutim, samo operator za dodelu
Protected: ll istog tipa vrednosti ie sintetizovan' a ostale morate
int read0 const { return i; }
// posebno Praviti:
void set(int ii) { i = ii; } Byte2& operatsp=(const Bvte& right) {
Publ i c: Byte: : oPerator= (ri ght) ;
Base(int 0) : i (ii) ()
ii = return *thi s;
int value(int m) const ( return m*i; ) )
); BYte2& operatsP=(int i) {
Byte::operator=(i);
class Derived : Public Base i return *thi s;
int ji )
Pub l i c: );
Derived(int:j = 0) : l(.ll) {}
void change(int x) { set(x); } I I ia sl i dna onoi u programu C12: ByteTest.
Probna funkci cpp:
); vojd k(Byte2& bl, Byte2& b2) {
bl=bl*b2+b2%bl;
int main0 {
Deri ved d; #define TRY2(0P) \
d. change ( 10) ; out <<,'b1 =,,; bl.print(out); \
\ Iil,- out << ", bZ = "; b2.Print(out); \
S,u,epotrebne primere z.a upotrebu rezervisane redi protected pronaii iete out << "; b1 " #0P " b2 daie "; \
kasniie u ovoj kniiz-i i r'r drugom tomu'
(bl 0P b2) . pri nt (out) ; \
out << endl ;

Zaitiieno nas ledivanje bl=9;b?=47;


da sve jarme
Prilikom nasledivanja, podr-azumeva se privatan pristup, Sto znadi TRYz (+) TRYz (-) TRY2 (*) TRY2 (/)
klase postaju privatne' obidno
funkcije dlanice o..,n.,.,. klase za korisnika nove rRY?(%) TRYz (^) TRY2 (&) TRYz ( I )
tako da se interfejs osnovne klase prenosi na
se koristi javno nasledivanje, TRY2(<<) TRY2(>>) TRY2(+=) TRY2(-=)
izvedenu klasu. Medutim, mo7-ete koristiti i zastiieno nasledivanje' TRy2(*=) rRyz(/=) TRYz(%=) TRY2(^=)
Zastiienonasledivan)eiz-gledakaoprivatno,osimStoizvedeneiprijateljske
klase vide potpun interfels oinoun" klase. Sve ovo neiete
iesto koristiti, ali upot-
prrnirr je vaic zrlatrje progran'rskog jezika'
458 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 459 I
TRY2(&=) TRY2(l=) TRY2(>>=) TRY2(<<=) Postupni razvoj
TRY2 ( = )
,/,/ 0perator dodel e Jedna od prednosti nasledivanja i primena postupnog razuola
i slaganja jeste
(engl. iniremental deuelopment), koji omoguiava pisanje novog koda bez
/, Us'ovlJavanJe:
stviranja problema u postojeiem. Problemi mogu nastati samo u novom kodu.
rdefi ne rRYC2 (0P) \
Nasledivanjem (ili slaganjem) postojeiih, funkcionalnih klasa i dodavanjem
out << ,,b1 = ,, ; bl.print(out); \
podataka i funkcija dlanova (kao i redefinisanl'em postojeiih funkcija dlanica
out << " , b2 = ,'; b2. pri nt (out) ; \
out.< "; bl " #0P " b2 daje "; \ prilikom nasledivinja) ostavljate vei postojeii k6d (koji moZda neko jos uvek
out << (b1 0P b2); \ icoristi) netaknut i bez ikakvih problema. Ukoliko se problem javio, znate da je
out << endl; nastao u novom kodu, pa iete ga brZe i lak5e pronaii nego kacia biste morali da
ispravljate
- ditav Postojeii kOd.
prosto je neverovaino kako su klase iasno podeljene. eak vam za pono\,'nu
bl'9;b2-47;
TRYC2(<) TRYC2(>) TRYC2(==) TRYC2( l=) TRYC2(<=) upotrebu koda ne treba ni izvorni k6ri funkcija dlanica; dovoljna je datoteka
TRYC2 (>=) TRYC2 (&&) TRYC2 ( I) ziglavlja koja opisuje klasu i objektna datoteka ili biblioteaka datoteka s
prevedenom funkcijom dlanicom (i za nasledivanje iza siaganje)'
Byte2 b3 ' 92; VaZno je razumeti da se razvoj programa, ba5 kao i ljudsko udenje, odvija
// Ul anaana dodel a: postupno. Mozete obaviti brojne analize, ali ipak neiete imati odgovore na sva
b1 = b2 = b3; pitan;a kada podnete da radite na projektu. Mnogo vise uspeha imaiete - i
kao Zivo biie,
l bostlSi iete bize rezultate - ako projekat poanete da,,razvijate"
umesto da ga pravite odjednom ptput kakvog staklenog nebodera'2
rnt main0 i eksperimenti s nasledivanjem su korisni, ali iete u odredenom trenutku,
out << "funkci3e: " " endl; nakon Sto se stvari smire, podeti drugadije da gledate svoju hiierarhijsku struk-
Byte2 b1 (q7) , b2(9) ; turu klasa - odludiiete dale preuredite u razumniji oblik.r Zapamtite, nasledi-
k(b1. b2); vanje je samo nadin d.a se iztazi odnos: ,,Ova nova k-lasa je ursta slarc klase". VaS
\ /'t.-
I ttt p.og.i- ne bi trebalo da se bavi menjanjem bitova u memoriji, nego stvaranJem
Klasu ispitr,rjento kao u programll Cl2:ByteTest.cpp samo sto se umesto iaz[eitlrr tipova objekata i njihovom primenom za resavanje zadatih problema.
klase Byte koristi klasa B1.te2.
'lhko sc preko nasledivanja proverava da li svi
opcratori rade s klastlrrl BYte2.
Kada podrobnije proverite klastr Byte2, videiete da se konstruktor mora Svodenje naviSe
izricito clefinisati i da se sintetizuie samo operator = koji dodeljuje objekat klase Vei ste videli da objekat klase izvedene iz klase ifstream poseduje sve karakteri-
Byte2 objekttr klase Byte2. Sve ostale potrebne operatore dodele moraiete sami stike i pona5anje objekta tipa ifstream. Svaka funkcija dlanica klase ifstream
da napiSete. moZe biti pozvana za objekat tipa Fname2.
NajvaZnill aspekt nasledivanja nije preno5enje funkcija dlanica u novonastale
klase, nego prikiz odnosa izmedu nove i osnovne klase. Taj odnos se moZe saZeti
ViSestru ko nasledivanje kao: ,,Nova klasa je wsta postojeie klase".
I)oSto moZete izvoditi jcclnu klasr.r iz druge, dini se logiinim da istowemeno ovakav opis ne predstavlja ulepsan prikaz nasledivanja - direktno ga podrzava
rrroTere izvesti klasrr iz viic klasa. I zaista je tako, ali jc svrsishodnost tog dina joS prevodilac. Uzmimo, na primer, osnolTlu klasu Instrument koja treba da pred-
rrvck pod znakotn pitanja. Ipak, u jednom se svi slaZu: ako nemate proglamer- stavlja neki muzidki instrument i izvedenu klasuWind (duvaiki insirument). Kako
sko rskrrstvo i ako ncclovoljno poznajetc jezik, ne koristite viSestruko nasledi- nasledivanje znadi da sve funkcije osnovne klase postoie i u izvedenoj klasi, bilo
vapie Kada stekncrc potrt-.ltno iskustvo, ma koliko vam se upotreba vi5estrukog koja poruka koju iete poslati osnovnoj klasi dolazi i do izvedene klase. Ako klasa
nasledivanja iinila ltrirnarnljivon'r, r.rvek iete naii nadin da takav problem re5ite Initrument ima funkciju ilanicu play( ) (srp. suira), posedovaie je i klasa Wind.
na drugi naain. To znadi da je ispravna twdnja da je objekat tipaWind takode i wsta objekta tipa
[J podctkq se viSestnrko nasledivanje dini dovoljno jednostavnim: prilikom Instrument.
nasleclivanja umetnete dodatne osnovne klase na listu i odvojite ih zarezima.
Meclr-rtim, viSestruko nasledivanie moZe dovesti do vi5esmislenosti imena, pa je 2 Da biste sznali viSe o ovome, p ogledajte Extreme Programming Explained, knjigu Kenta Becka
z.ato ovoj ten.ri l.losveicno poglavlje u drugom tomu. 3 Pogledajte Rep ctoring: Improuin1 the Design of ExistingCode, Martina |owlera'
.+60 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 461

prilikom nasiedivanja samo moZe da izgubi funkciju dlanicu, a nikako da je


Il: Cla: lnstrument. cPP
// Nasl edi vanje i svodenje navi 5e dobije. Eto zasto prevodilac dozvoljava svodenje navise bez konverzije ili dodat-
enum note { middleC, Csharp, Cflat }; I I Etc' nih uslovljavanja.

ass I nstrument
c'1
publ i c:
{
Konstruktor za kopiranje i svodenje navise
voi d p1 ay(note) const { i Ako ste prevodiocu dozvolili da sintetizuje konstruitor za kopiranje izvedene
klase, automatski ie pozvati konstruktor za kopiranje o..,o,on. klase, a zatim i
i;
konstruktor za kopiranje svih ostalih objekati dlanova (ili ie kopirati bitove
II Wind ie vrsta kl ase lnstrument dlanova ugradenih tipova) :
//:er imaiu isti interfejs: / / : CI4:CopyConstructor. cpp
class l^lind : Public instrument {}; // Pravilno naprav)jen konstruktor za kopiranje
#include <iostream>
void tune(lnstrument& i) { using namespace std;
il pl...
i . ay (mi ddl eC) ; class Parent {
) int i I
publ i c:
int majn0 { Parent(int ii) : i(ii) {
Wi nd fI ute; cout << "Parent (i nt i i ) \n,,1
tune(f1 ute); I I Svodenje navi5e )
I lll,- Parent (const Parent& b) : i (b. j ) {
LJovornprimerujezarrimljivafunkcijatune()dijiargumentjereferencaklase cout << "Parent (const parent&) \n,,;
j
lnsrrument. I;unkcija main( poziva funkciju tune( ) prosledujuii
joj referencu )

iipa Wind. l,na)uci da C++ dosledno proverava tip' sve dok ne shvatite da je Parent0 : i(0) { cout << ,'parent0\n',; }

of 1.tu, tipaWind istowemeno obiekat iipa Instrument' dudiie vas to Sto funkcua fri end ostream&
tuneo os, const parent& b)
prihuutu iarugi tlp argumenta (upravo za to sluZi nasledivanje)' U funkciji operator<<(ostream& {

postoji k6d koii radi s klasom Initrument i svime Sto je iz te klase izvedeno. Cin return os << "Parent: ,,<< b.i << endl;
na Instru-
lonverzile referenci ili pokazivada na Wind u referencu ili pokazivai l.
)

ment naziva se suodenie nauiie (engl' upcasting) '

class Member {

Zaito,,svodenje naviSe"? int i;


publ i c:
ovaj izraz potide iz tra-dicionalnog naiina crtanja dijagrama nasledivania:
osnova

je na whu, a grana se nadole (narivno, diiagram moZete crtati na bilo koji nadin)' Member(int ij) : j(ii) {
cout << "Member(i nt .i j ) \n,' ;
biiugrurn nasledivanja za Instrument'cpp izgleda ovako:
)
Member(const I'lember& m) : j(m.i) {
cout << "Member(const Member&)\n,,;
)
friend ostream&
operator<<(ostream& os, const Member& m) {
return os << "Member: ', << m.i << endl;
)
);
Kor.rverzija iz izvedenog tt osnovni tip kreie se nagore u diiagramu
nasle-
(engl. upcasting). Svodenje navi5e : public parent
divan ja pa se zato koristi iziaz sLtodenie nauiie class Child {

;e uvek bez.bedno,
jer se od speciializovanih tipova ide ka op5tiiim' Interfejs klase int i;
462 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 463

l\'lember m; Parent (i nt i i )
publ i c: Member(jnt ii)
Chrld(rnt ri): Parent(ii), i(ii), m(ii) { Child(int ii)
cout <<'Child(int rr)\n"; ca1 1 ing copy-constructor:
Parent ( )
frr end ostream& Member(const Member&)
operator<<(ostream& os, const Child& c) { values in c2:
return os <. (Parent&)c << c.m Parent: 0
.< "Chi l d: " << c. i << endl ; Member: 2
) Child: 2
); Rezultat nije odekivan, jer obidno podobjekat osnovne klase treba kopirati u
novi objekat u okviru konstruktora za kopiranje.
int main0 {
Da biste ispravili ovaj problem, kad god piSete konstruktor za kopiranje setite
Child c(2);
se da ispravno pozovete konstruktor za kopiranje osnovrre klase (kao Sto to radi
cout << "Pozr vam konstruktor za kopi ranje: " << endl ;
prevodiiac).
Chi I d c2 = c; I I Pozi va konstruktor za kopi ranje
cout << "values in c2 \n" << c2; Na prvi pogled moZda izgleda dudno, ali poziv konstruktora za kopiranje je
joS jedan primer svodenja navi5e:
: ll l:-
Ope.rator << klase Child zarrirnljiv ,;e zbog nadina na koji se poziva operator Chi l d (const Chi 1 d& c)
<< z-a podobjekat klase Parent: konverziiom objekta Child u objekat Parent& : Parent(c), i(c.i), m(c.m) {

(ako konvertujete u objekat osnovne klase umesto u referencu tog tipa, uglav- cout << "Chi I d (Chi I d&) \n";
)
r.ronr iete dobiti neZcljene rezultate):
return os << (Parent&) c << c.m
Zbunjuje deo gde se poziva konstruktor za kopiranje k-lase Parent:Parent(c).
Sta se dobija prosledivanjem objekta klase Child konstruktoru klase Parent?
I']oSto prevodilac tu referencLl sada vidi kao objekat tipa Parent, pozvaie ver- Kako je klasa Child izvedena iz klase Parent, tako je objekat klase Child istowe-
ziju operatora << 7.a Parent. meno objekat klase Parent. Referenca klase Child svodi se navi5e u referencu
I.l klasi Child nije iz.ridito definisan konstruktor za kopiranje. Zato prevodilac k-lase Parent, a nakon toga se koristi u konstruktoru. To iete desto upotrebijavati
sintetrzujc konstruktor za kopiranje koji poziva konstruktora za kopiranje klase kada pi5ete konstruktor za kopiranje klase.
Parent i konstnrktora z.a kopiranje klase Member. To se vidi u rezultatu programa:
Pdrent(int ir)
Member(rnt r i ) Slaganje ili nasledivanje - ponovo
Chlld(int ii) Naljbolji nadin da izaberete slaganje ili nasledivanje jeste da se upitate hoiete li
cal 1 i ng copy-constructor: koristiti svodenje navi5e. Ranije u poglavlju, klasu Stack smo specijalizovali
Parent (const Parent&) nasledivanjem. Ipak, objekte klase Stringstack koristiiemo samo kao kontej-
Member (const l'lember &) r,ere za objekte tipa string. Po5to ih neiemo svoditi navi5e, kao pogodnija alter-
values in c2: nativa se nameie slaganje:
Parent: 2
t Cl4: Inheri tStack2. cpp
/ /
Member:2
Child:
// Slaganje naspram nasledivanja
2 #include "../C09/Stacka.h"
Ako poku5ate da sami napiSete konstruktor za kopiranje klase Child, a pri #i ncl ude " . . /requi re. h "
tonr napravrtc greSku: #i ncl ude <i ostream>
#i ncl ude <fstream>
Chjld(const Child& c) : j(c.j),
m(c.m) {}
#i ncl ude <stri ng>
autornatski se poziva poclrazunrevani konstruktor za osnovnu klasu, jer to pre- using namespace std;
vodilac radi kada vei nema nikakav drugi konstruktor na raspolaganju (upam-
tite da neki konstruktor mora da bude pozivan za svaki objekat, bilo da je on class StringStack {
podobjekat ili objekat druge klase). Rezultat ie tada biti: Stack stack; // ugraden, a ne nasleden
464 Misliti na jeziku C++ Poglavlje l4: Nasledivanje i slaganje 465

publ i c: Problemi
void push(strinq* str) {
Naravno, pri svakom svodenju navi5e gubi se informacija o tipu objekta. Ako
stack. push (str) ;
napi5ete sledede:
)

stri ng* peek 0 const { l,rlind w;


return (stri ng*)stack.peek0 ; Instrument* 'i p = &w;
)
prevodilac se prema argumentu ip moZe odnositi samo kao prema pokazivadu
stri ng* pop ( ) i na tip Instrument, i nikako drugadije. Ne postoji nadin da on zna kako ip stuarno
return (string*)stack.pop0 ; pokazuje na objekat tipawind. Tako, kada pozovete funkciju dlanicu izrazom:
) 1 p->p1 ay (mi dd1 eC) ;
);
prevodilac zna samo da poziva funkciju play( ) za pokazivad na tip Instrument,
int main0 i zove verziju funkcije iz osnorme klase Instrumenu:play( ). Umesto toga trebalo
{
i fstream in("lnheritStack2.cpp") ; bi da pozove funkcijuWind::play( ).
assure(1 n, " Inheri tStack2.cpp") ; Ovo je ozbiljan problem i reSiiemo ga u poglavlju 15. Uve5iemo jo5 jedan,
string line; treii kamen temeljac objektno orijentisanog programiranja. To je polimorfizam,
Stri ngStack textl i nes; a realizovan je u C++-u pomodu virtuelnih funkcija.
while(getl jne(in, line))
textl ines.push(new string(l ine)) ;
stri ng* s; SaZetak
whjle((s - textlines.pop0) != 0) // Nema konverzije! Videli smo da prilikom pravljenja novih tipova od vei postojeiih, moZete kori-
cout << *s << endl; stiti nasledivanje ili slaganje. obe tehnike ugraduju podobjekte u nove ripove.
\ lll,- Slaganje Cete obidno koristiti kao deo osnovne realizacije novih tipova prilikom
l)atoteka je iclentidna sa Inheritstack.cpp, samo sto je objekat klase Stack ponovnog korisienja koda, a nasledivanje kada novi tip mora biti wsta tipa
Lrgraden tr objekat klase StringStack, a funkciie dlanice pozivamo za ugradeni osnovne klase. Po5to interfejs izvedene kiase obuhvata interfejs osnovne klase,
objekat. Ovaj prograrn ne zauzima viSe memorije od prethodnog, niti se sporije izvedeni objekat moZe biti sveden naviSe, sto moZete videti u poglavlju 15.
izvr5ava, a dodatna provera tipa se obavlja za weme prevodenja. Premda je ponovno kori5ienje koda pomoiu nasledivanja i slaganja veoma
Iako bi moglo da vas zbuni, za vuslovnu realizaciju" moZete iskoristiti i pri- korisno, wlo je verovatno da iete prvo pojednostaviti projekat svoje klasne hije-
vatno nasledivanje. Razlika izmedu nasledivanja i slaganja postala bi bitna kada rarhije, a tek nakon toga dozvoliti ostalim programerima pristup programu. VaS
bisn.ro mogli da upotrebimo vi5estruko nasledivanje. Kori5ienjem slaganja cilj je hijerarhijsko uredenje gde svaka klasa ima specifidnu namenu i nile preve-
umesto nasledivanja, moZete izbeii viSestruko nasledivanje' lika (nema toliko funkcija da to onemoguiava ponovnu upotrebu), a ni premala
(moZe.se ponovo iskoristiti bez dodavanja funkcije).

Svodenje navise pokazivata i referenci


ll programu Instrument.cpp, dolazi do svodenja navi5e prilikom pozivanja VeZbe
trrnkcija. Ilelerenca ob jekta klase Wind pretvara se u referencu klase Instrument ReSenja izabranih zadataka potrazite u elektronskom dokumenru The't'hinking iil C++ Annotated Solutiotl
izvan firrrkcije, a fupkcija vidi tal objekat kao da pripada klasi Instrument. Guide, koji moZete preuzeti s Iokacije ww.BruceEckel.com.

Svoclenjc naviSe st: rnoZe clogoditi i tokom jednostavne dodele vrednosti refe- i ' Dodavanjem funkcije dlanice klasivehicle, izmenite program car.cpp tako
rcrrci ili pokazivaCtr: da klasa Car moZe da se izvede iz klase Vehicle (tako je, praviiete lunkcije
l^lr nd w;
dlanice). Dodajte i konstruktor s parametrima klasi Vehicle, pozovite ga iz
Instrument* rp = &w; // Svodenje navi5e konstruktora klase Car.
Instrument& ir = w; // Svodenje navi5e 2. Napravite dve klase, A i B, s podrazumevanim konstruktorima koji ispisujir
poruke. Izvedite no'urr klasu C iz klase A, a zatim klasi C dodajte objekat dlan
Kao ni poziv funkcije, nijedan ocl ovih sludajeva ne zahteva izriditu konverziju'
klase B. Nemojte praviti konstruktor za klasu C. Napravite objekat klase C i
posmatrajte rezultate.
466 Misliti na jeziku C++ Poglavlje I 4: Nasledivanje i slaganje 467
I
Napravite hijcrarhijrr od tri nivoa klasa s podrazumevanim konstrukto- 16. PotraZite jo5 funkcija dlanica kiase ifstream. U programu Fname2.cpp,
rinia i clestnrkrorima koji ispisuju poruke u tok cout. Proverite da li se za isprobajte ih na objektu file.
obje.kat r.ra niT.ent nivou hiierarhije automatski pozivaju sva tri konstru- I 7. Iskoristite privatno i za5tiieno nasledivanje da biste napravili dve nove
ktora i destrtrktora. Obiasnite redosled pozivania. klase. Tada pokuSajte da svedete navise objekte iz izvedene klase u osnovnu.
Izmc.nite program Combined.cpp tako sto iete dodati jedan nivo nasledi- Objasnite Sta se dogodilo.
r,anja i noV obickar dlan. Napisite kod koii prikazuje pozive konstruktora i 18. U programu Protected.cpp, dodajte funkciju dlanicu u klasu Derived koja
clestrr.rktora. zove funkciju read( ) iz klase protectedBase.
l.l lstorn programu napravite klasu D izvedenu iz klase B, koia sadrZi 19. Izmenite program Protected.cpp tako da se za izvodenje klase Derived
oblekar clan klase C. Napisite kod koji prikazuie pozive konstruktora i koristi zastiieno nasledivanje. pozovite funkciju valueo za objekat klase
dcst rttktora. Derived.
6. Izmenite program order.cpp dodavanjem jednog nivoa hijerarhiie. Dodajte 20. Napravite k-lasu Spaceship s metodom fly( ). Izvedite klasu Shuttle iz klase
klasu Derived3 sa obiektima dlanovima klase Member4 i Members i anali- Spaceship i dodajte metodu land( ). Napravite novu klasu shuttle, svedite
zirajte rezultat. je navi5e prema pokazivadu ili referenci klase SpaceShip i pokuSajte da
7. LI programu NameHiding.cpp utvrdite da li su klasama Derived2, Derived3 pozovete metodu land( ). Objasnite rezultate.
i Derived4 dostupne verzije funkcije f( )osnor,T re klase. 2I . Izmenite program Instrument.cpp, dodavanjem metode prepare klasi
8. lzntenirc [)rogrant NameHiding.cpp dodavanjem tri preklopljene verzije Instrument. Pozovite prepare( ) unutar metode tune( ).
Itrnkcijc h( ) tr klasu Base, a zatim pokazite da promenom definicije jedne 22. Izmenite program Instrument.cpp tako da funkcija playo ispis.je
od n jih u izverlcnoj klasi ar-rtomatski sakrivate druge. poruku u tok cout, a da Wind menja definiciju merode play( ) tako cla
9. Iz.r,edire klasu StringVector iz vector<void*> i promenite definicije funkcija ispisuje drugaeiju poruku u tok cout. pokrenite program i objasnite zasto
clanica push back i operatorll tako da rade s pokazivaiima tipa string*. biste hteli da izbegnete ovakvo ponaSanje. sada clodajte rezervisanu red
Sta cle sc desiti ako probare cla prosledite pokazivai tipa void*, funkciji virtual (o kojoj iete uditi u poglavlju I5) ispred deklaracije funkcije play( )
push-back? u klasi Instrument i posmatrajte promenu ponaSanja.
10. Napisite klasrr koja sacirzi podatak tipa long i iskoristite pseudokonstruk- 23. U programu CopyConstructor.cpp, izvedite novu klasu iz klase Child i
torsktr sintaksu z.a inicijaliz-acijtt tog podatka. dodajte joj dlan m. Napi5ite ispravan konsrruktor, konstruktor za kopiranje,
I 1 . Napravite klasu Asteroid. Nasledivanjem specijalizujte klasu PStash iz operator = i operator << za ostream i testirajte klasu u funkciji main( ).
poglavlja I.t (PSrash i PStash.cpp) tako da radi s pokazivadima na Aste- 24.rzmeoite program copyconstructor.cpp tako sto iete klasi child dodati
roid. Da biste proverili svoje klase, izmenite program PStashTest.cpp. konstruktor za kopiranje koji poziva konstruktor za kopiranje osnovne
ne
lzmenite klasu PStash tako da postane objekat dlan. klase. Pogledajte Sta se dogada. Ispravite problem tako sto iete izrieito
12. Ponovite vezbtr 11, ali ovog puta umesto klase PStash iskoristite Sablon pozvati konstruktor za kopiranje osnormih klasa u listi za inicijalizaciju
vector. klase Child.

13. ll pr()grantu SynthesizedFunctions.cpp izmenite klasu chess doda- 25.lzmenite program Inheritstack2.cpp tako da moZe da koristi vector
Van jern lt0clrazumevanog konstruktora, konStruktora za kopiranje i opera-
<string> umesto klase Stack.
torii dode Ic. l)roveritc da li ste ih napisali isprarmo. 26. Napravite klasu Rock, s podrazumevanim konstruktorom, konstruktorom
tipa za kopiranje, operatorom dodele i destruktorom, koji ispisuju poruke u tok
1 4. Napravite klase Traveler i Pager, pomoiu konstruktora s argumentom

string kojise kopira u unutra5nju promenljilrr tipa string. Za svaku klasu cout. U funkciji main( ), napravite vector< Rocb (koji sadrZi objekte tipa
naprivitc ispravan konstruktor za kopiranje i operator dodele. Izvedite Rock) i smestite u njega nekoliko objekata tipa Rock. pokrenite program i
klasu BusinessTraveler iz- klase Traveler i doda;te joj objekat elan tipa objasnite rezultat. Pogledajte da li se poziva destruktor za objekte tipa
pager. NapiSite ispravan podrazumevani konstruktor, konstruktor s argu- Rock u vektoru. Ponovite veZbu sa vector <Rock*>. Da li je moguie
nrentonr tipa string, konstruktor za kopiranje i operator dodele. napraviti vector<Rock&>?
15. Napravite klasu sa clvc statidke funkcije elanice. Izvedite klasu iz te klase i 27 . U ovoj veZbi primeniiemo obrazac projektovan ja posrednik (engl. pro.r! .

prrinrenite clcfiriicijtr icclr.re ocl funkcija rjlanica. PokaZite da su ostale funk- Podeiemo sa osnovnom klasom Subject. Ona ima tri frrnkcije: f( ), gO i
cilc ilanit:c izveclcnc klasc skrivene. hO. Iz klase Subject izvedite klasu Proxy i dvc klase Implementationl i
Implementation2. Klasa Proxy treba da sadrZi pokazivai na Subject, a svc
468 Misliti na jeziku C++

ltrnkcijeilarriccklaselProrytrebasamodapozivajuodgovarajuiefunkcije
prekopokazivaCanaklasu'subiect.ArgumentkonstruktorazaklasuProxy
1rokaz.i,,ai, je na klastr Subiect,
koji se ugraduje u objekat. klase Prory
dva razlidita obiekta
iobicno r.r konstftrktor). U {'unkci;i maino napravite
raz-lidite realizacije. Zal\m, izmenite klasu Prory
tipa Proxy, ktljiktlristc clve
tako da tttoZete dinanlicki menjati realizaciie'
2 8. lzrnenite program ArrayoperatorNew'cpp
iz poglavlja I3 da biste pokazali
--
tofo, u1.,rlos'nasleaivanlu, dodela idalJe ispramo funkcioni5e- Objasnite
13 ne bi funkcio-
za5to rrasleclivatlje tt prog.urn, Framis'cpp iz poglavlja
nisalo.
klase iz klase
29. lzn'renite program Framis'cpp iz poglavlja I3' izvodeniem
napraviti nove veizije operatora new i delete. Pokazite
Framis u koioi iete
da nova klasa radi isPravno'

5: PoIIMORFIZAM I VIRTUELNE
FUN.KCUE , ,

Polimorfizam je, pored ap.gtrakcija,lpodataka i nasledivanja, treie


osnovno svoi stvo obj ektno orijentisanih p ro gramskih j ezika.
470 Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcije 471 l
vaZnu ulogu Po5to su virtuelne funkcije tesno povezane s pojmom tipa, a tip je jezgro
I,olirrtorlizarn sc na lcziktr O++ rcaliztlje virtttelnim ftrkci)ama, i igra
raz-dvaja)uii ita \ kako. boljoj objektno orijentisanog programiranja, u tradicionalnom proceduralnom
rr orlvajirnjrr intcrfejsa od realiz.acije, _Doprinosi leziku
proiiriuih programa, koji ne postoji ni5ta Sto bi odgovaralo virtuelnoj funkciji. Ni na jedan proceduralni
rrrgirnizacili kocia i iitljivosti, i omoguiava pisanje pojam ne moZete se osloniti dok razmi5ljate o virtuelnim funkcijama, za razliku
,,,iig,, ,,,,n.or,ati" i ka4a zatrebajtr no\re moguinosti' a ne samo pri prvobitnom
od skoro svih drugih moguinosti jezika c++. Moguinosti proceduralnog jezika
razr jlrtrltr llrtrjt'kta.
i
mogu se razumeti na algoritamskom nivou, ali virtuelne funkcije mogu se razu-
Kapstrlrranjepravlnovetipove,korlbinujuiiosobineiponaSanja.Kontrola meti samo sa stanovista projekta.
privat-
pristJpa oclvaja inrerfejs od realizacije, proglasavajuii detalje realizaciie
programeri s iskustvom u procedural-
nirn. Or,akvu nrganirocilu Iako raz.trmeju
nonr [)rograrnirarlitr. Mecir-rtirn, virtueltre funkcije se bave razdvajanjem u Svodenje naviSe
re.ninirna tip,rta,ir. nilc toliko razttmljivo ljudima bez iskustva u objektnom
omoguiava rad s obiek- U poglavlju 14 ste videli kako se objekat moZe koristiti kao da je sopstvenog ili
,r.grar.ira. jrr. I.) prglavijr I4 ste vicleli ila nasledivanjeOva tehnika je znadajna, roditeljskog tipa. osim toga, s njim se moZe raditi preko adrese roditeljskog tipa.
ri*a kao ,la ,.., .,r1,.i'crog tipa i li roditeljskog tipa.
(izvedenih iz istog osnovnog tipa) koristi kao Posmatranje adrese objekta (pokazivada ili refercnce) kao da 1e aoresa
ltoiro onrogr.riaua ila sc viie tipova roditeljskog tipa naziva se suodenje nauiie (engl. upcasting), prema nadinu
jeclarr trp, ii isti kircl nro7.c poiilednako raditi sa svim ovim razliditim tipovima'
grafidkog prikazivanja stabla nasledivanja, u kome je osnovnakaia na vrhu.
Virrrrelna funkciia omoguiava iedrlorn tipu da iz-raz-i svoju razli'itost od
drugog,
Videli ste i kako nastaje problem koji je opisan u sledeiem primeru:
sli-nog,tipa,rrkolikosuobaiz;vedenaizistogosnovnogtipa.ovaosobenostSe
ispoljiva , razlidit.ni ltonaSaniu ftrnkcija koie moZete pozvati pomoiu referente //: Cl5: Instrument2. cpp
osnovtte klase. // Nasledivanje i svodenje naviSe
lI ovonr poglavlju a(,te upozllati virttrelne funkcije, poiinjuii od osnova i
jed- #include <iostream>
rrostar,nilt llrimcra koji z,ancmartt jt't sve osim ,,virtuelnosti.. programa. us i ng namespace std;
enum note ( middleC, Csharp, Eflat ) ; /l lta.
Razvoj C++ P rog ram e ra c1 ass Instrument
publ i c:
{

tz.glcclaclaCprogrameritrsvajajtr('++utrikoraka'Naprvommestu'tolesamo void play(note) const {


pre kori5ienjai
,,ltolji (,,', poSr, rras (.++ prirnoiava cia cieklari5ete sve funkcije cout << "lnstrument::play" << end'l.
naltrcr'c stroZa pravila z.a tlllotrebu promenljivih. Prevodenjem C proglama
jeziku iesto mozete pronaii greske u proSramu na i
ltOnt()ir.t ltrevodioca, na c++
];
jcziku C.
l)nrgi korak ie ,,objektno z-asnovani" c++. To znadi da lako mozete videti
pred-
strukture podataka i funkcija koje rade s // lbjekli klase Wjnd su i klase Instrument
nosti oigar.rizacijc koda grupisanjem // poito imaju isti interfejs:
njorn, z.nadaj konstruktora i <.lestruktora, a moZda i nekog
jednostar'nijeg
class Wind : public Instrument {
nasle clivanja. veiina programera koji su neko weme radiii
na jeziku c brzo uvida publ i c:
to poku5avaju da postignu kad god
korist od objektne ,ainoi,anosti, poSto upravo ff Pronena definicije funkcije interfejsa:
vam pomaZe da organizujete k6d objektno'
napraVC bibiiotckLr. Prcvodilac z.aC++ void play(note) const {
\1O2ctc ostari7.arol)ljcr.ri na nivottobjektne zasnovanosti'
posto do niegalako cout << "Wi nd: : pl ay" << endl .
Sti2CtCiostr,irrltjetedostadobitibezprevelikogumnognapora.MoZevamse i
t:initi rla src narri:ilr (.++ zato 5to clefiniSete tipove podataka: pravite klase i );
0b1t,kre, ialjr.rc prtrLrkc tint objektirna i sve je lepo i iednostavno.
NCnt0 jte sC ,/.avaravatl. Ako sc ovcle zaltstavite' propuState
najveie prednosti void tune(lnstrument& i) {

oVOg jez-ika, i ro One koje predstavljaitr skok u pravo objektno orijentisano pro-
funkcije nezaobilazne' j l ay (m i dd l
gralniranic. Zato stl virtuelne .p eC ) ;

Virtuelne firnkcije trnaprecluiu pojam tipa umesto da samo kapsuliraju k6d u )

sltrrktrrrc i snrcitajtr ga iza z.iclova, tako da stt nesr-rmnjivo najtezi pojam u c++-u
ktljirrrclra trsr,,r)jiti,rltlvajlija' Mcdutim, One SLI iprelomna ta.ka u razumevanju
int main0 {
jos nd fl ute;
0[tlcktno orijcntisanog progranlirania. Ako ne koristite virtuelne funcije, tada
Wi

ttvck rle shvatatc OOII


tune (f1 ute) ; // Svodenj e navi 5e
Misliti na Jeziku c++ Poglavlje l5: Polimorfizam i virtuelne funkciie 473
472

klase Instrument' ali se Da biste napravili virruelnu funkciju dlanicu, ispred deklaracije
lrunkcrji tune( ) se proslccltrje (po referenci) obiekat navedite rezervisanu red virtuar. Rezervisana red virtual je
te funkcije
nlrllcprosletlitiitlilo.staizveclerroiz,klaselnstrument.UtosemoZeteuveriti potrebna sarno u
deklaraciji, ne i u definiciji. Ako je funkcija deklarisana kao
kaclasctrlrrnkciji*ui"tlrlbjekatk]aseWindprosledifunkcijitune(),pridemu viriuelna u osnornol
klase lnstrument mora klasi, ona je virtuelna i u svim iivedenim krasama. Definisanje
nije potrebrlir ktlnvcrzijii Ovo ie prihv.atliivo; interfeis funtci.je u izvedenoj klasi naziva.s e redefinisanje (engl.
verzije virtuerrc
ilasa Wind javno nasleduie klasu Instrument. ouerridi,tg). '
postojati rr klasr Wira, p,,St,,
Sr,tlilerljetlar,iSeizWirrdrrlnstrumentrr-ro7-e,.suziti.,tajintcrfejs,alionnikada _ -
zapazite da funkciju morate dekrarisiti kao virtuernu
,u-o , "ornornoj krasi.
klase Instrument' Na sve funkcije izvedene krase koje odgovaraju potpisu
nt: tllrlT.e postatl rllarlii rlci l)otptlnog interfeisa a"ua.a.rj. funkcije
jedina je radika Sto korisnik osnovne klase biie primenjen mehanizam virtuernih
Ista n'rclerlia va2c i za llokazivaie' a Y..tot" virtual moZete koristiti. u deklaracijama izvedene klase
iunkcija. Rezeivisanu rea
ttirjekata kacla ih prosledujc funkciji' tnije Sieinol, af i ;e
izrir':it. .rora ,zetl arlresc suviSna i moZe biti zbunjujuCa.
Da. biste postigli odekivano pona.anje programa
Instrument2.cpp, ciodajte
rezervisanu rea virtuar ispred deklaracile funkciJe play(
Problem ) u orno*of tiu'ri,
progralnu Instrument2'cpp vidi se pri njegovom
izwsavanju'
I)robletn tl / /: C15: Instrument3. cpp
Ispisuje ,. trl.t.rn1"r,t::play lasno ie di ovo
nije Zeljeni rezulta.t'.posto znate da // Kasno povezivanje pomocu rezerv.isane reci virtual
je klasa oulettawi.rJ, a ne instr,rment. Trebalo bi da se ispiseWind::play. Iz tog #i ncl ude <i
ostream>
iz Instrument trebalo bi da koristi svoiu using namespace std;
razloga, ,rur.i nt 1.r.oi riu.. ir_r.a.ne
enum note ( mlddleC, Csharp, Cftat ) ;
u.rriii, l'trnkciie play( )' i to u svakoj situaciii' posmatramo
// Itd.
I)orraianlc 1,r,,g,1 ,',i,u Instrument2.cpp nije iznenadujuie ako
('-a btste razumeli
I)a ove probleme' treba da imate u cl ass Instrument
ftrnkc:ijt'ru .,n,,,,.iii,n publ i c:
{

viti tt Trol'c-lt'rirrlc ell gl lti rt rl i ttg)'


(
vi rtua l voi d p1 ay (note) const {
cout <<',lnstrument::p1ay,, << endl ;
Povezivanje Poziva funkcije pre
i
naz.iva se poueziuanie' Povezivanie
\rcz.j'arric 1,,,ri"a f..,,'.rkr,ije s tclont hrnkcije );
(engl' early.binding)' MoZda za
iz.rria'a' ja ,rograr.na sc paziva rarro portezittanje
or.'ai tcrtllitl niste culi, poito ot.t niic
postojio kao opciia u, proceduralnim // )bjekti klase l^lind su i klase Instrument
jczicima: prcvoclioci za il imalu sa,no icdnu.vrstu poziva funkciie,
na koii se // poito imaju isti interfejs;
c'l ass Wi nd : publ i c Instrument
jrl je ratlo lloverz-ivanje' {
prinlerl publ i c:
ranim povezivanjem. Pre.
I,roble rn je rt tlavedcnonl programu prouzrokovan
pozove' posto ima samo adresu / / Redefinisanje funkcije interfejsa:
voclilac nc zna tadno krlju funkiiju treba da void play(note) const {
obickta klase lnstrument' cout << "Wi nd: : p1 ay,, << endl .
RcserljeprotllelnaSeZoVekastlopoueziuanje(eng.,,lateb.inding),kojeseodi. )
gravazavrerrteizvrSavania,rraosno\utipakonkretnogobjekta'Kasnopove-
binding) tli );
zivanlc sc naz.iva i rtiitamiiko po'eziuanie (engl' !'y.na.mic
je realizo'
1to|t,ziUcrtr.je tokottn
izrtrirtrtnfia (ettgl. runtirne bind'ing). Kada u ieziku void tune(Instrument& i) (
pou.r.i*n]., ,r..lniu porioluti neki mehanizam koiim bi se odredio tip
varto kasno
fu1\cija dlanica' U iezicima
//...
objckta ,nrnn] Jwsorianla i pozvala odgovaraiuia i.p1ay(middleC);
ne kog tipa objekat' ali dodaie kod koji
koji se prcvodc, prevoclilac i dalje '-nI
ie )
povezivanja su
.tkri'ir i p.z.i'ir 1.f ,, n,f gnunrniLiie funkcije. Mehanizm.i kasnogmora biti ugradena
jezicima, ali mozete zarnisliti da u objekte int main0
raz-liciri u raznirn {

inlortnacija o tipti. Kasnije iete viclcti kako ovo funkcioni5e' l^/ind fl ute;
tune(fl ute) ) // Svodenje navi Se
| / //,-
Virtuelne funkcije deklaraciji
ova datoteka je identidna sa Instrumentz.cpp, osim sto je
dodata rezeri-
t)a triste izazvali kasritr povez'ivarrjc ltrnkcije' nienoj I "t""]l?^!3 sana redvirtual, ali se rezultat znadajno razlikuje. Sada se prikazuje wind::play.
lll()ratcclodatroz,llakuvirtual'Kasntlllovezivanjes.cprimenjujeSamonaur.
klase'
obiekta osnol'ne
ttrclrlc I'trrlkcilc koic sc lltlziva jtr pornoiu adrese
474 Misliti na leziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkcije 475 t
irivost voi d p1 ay ( note) const {
ProS
cout << "Stri nged: : p1 ay" << endl .
Poiro je frrnkcija play( ) rr osnovnoj klasi clcfinisana kao virtuelna, moZete doda'
)
vatt koliko gorl hoictc por,ilt tiltgva nc rnenjajtlii ftrnkciju tuneO. tJ dobro pro- char* what0 const { return "Stri nged"; }
jcktovanonr ob jcktrto orijt rrtisanrrrn prograrnu, rnoclel veiine ftrnkciia biie nalik void adjust(int) ()
lra tune( ) i konrrrnicirait: sarno sa intcrfejsonl osnovnc klase. Takav program je
);
proiirit',1toSto sistctttu rnoZcte clodavati ftrnkcir:nalnost izvodeii nove tipove
podataka iz zajcclnicke osnovrre klase. Irrrnkcije koie rade s interfejsom osnol'ne class Brass : public Wind i
klase rrol.ritc ne lrorate nreniati da bi se pritagodile novim klasama. publ i c:
Prethoclnont printenr str clocleite virtuelne lunkcije i nove klase i sve ispravno void play(note) const {
racic sa staron-I, treprontcnjenorn funkcijom tune( ): cout << "Brass: : p1 ay" << endl .
I I : C15: Instrument4.cPP )
char* what0 const { return "Brass";
I I Pro\i rivost u 00P-u l.
}

{i ncl ude <i ostream>


us i ng namespace s td ;
enurf note { mi dd1 eC, Csharp, Cfl at } ; I I ltd "
cl ass Woodwi nd : publ i c l,li nd {
publ i c:
class Instrument i
void play(note) const {
publ i c: cout << "Woodwi nd: : pi ay" << endl .
virtual void play(note) const { )

cout << "I nstrument: : P1 aY" << endl ;


char* what0 const { return "Woodwind"; )
I.
)

vr rtual char* what 0 const {


return " Instrument" I // Istovetna funkcija kao ranije:
)
void tune(lnstrument& i) (
// Pretpostavimo da ce ova funkcija izmenit'i objekat:
virtual vord adjust(int) {} i.p1ay(middleC);
I
);
// Nova funkcija:
class tiind : public Instrument {
void f(lnstrument& i) { i.adjust(1); }

publ r c:
vord play(note) const { // Svodenje navi5e tokom inicijalizacije niza:
cout << "l^/ind: : pl ay" .. endl ' Instrument* Atl = {
new l,ii nd,
)
r new Percussion,
char* what 0 const { return "14i nd" }
vord adjusl(int) { ) new Stri nged,
new Brass,
);
);
class Percussion : public Instrument i
p-01 c: int main0 {

voi d p1 ay (note) const {


Wi nd fl ute;
cout << "Percussi on: : p1 ay" <. endl ;
Percussi on drum;
)
Stri nged vi ol i n;
char* what0 const ( return "Percussion ;i Brass fl ugel horn;
nd recorder;
void adjust(rnt) { ) Woodwi

t; tune(flute);
tune (drum) ;
cl ass Stri nged : publ i c Instrument {
tune (vi ol j n) ;
publ i c: tune (fl ugel horn) ;
Misliti na jeziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkcile 477
476

tLtne(r'ecorder)l Kada pozovete virtuelnu funkciju preko pokazivada osnor.ne klase (clnrgirn
'(tlr ;e ho'r); redima, kada napiSete polimorfni poziv), prevodilac umetne k6d koji treba da
prodita VPTR i pronade adresu funkcije u tabeli VIABLE, pozivajuii tirne pravu
| ".
I /it.

funkciju. Tako se realizuje kasno povezivanje.


lspgcl klasc Wind jc clodat ioS jedan nivo r.rasledivanja, ali mehanizam vir-
Sve ovo - definisanje tabele VIABLE za svaku klasu, inicijalizacija pokazivaia
tuclnih lirnkciia ispravno radi, ilcz- obzira na to koliko nivoa postoji' Funkcija VPTR, umetanje koda za poziv virtuelne funkcije - odigrava se auton-ratski, tako
adiust( ) rrrlc rcdefinisana lt klasarna Brass iWoodwind. [J ovakvom sludaju se da ne morate brinuti o tome. Uvek se poziva odgovarajuia virtuelna funkcija,
arrtonratski koristi ,,naibli7-a" clelinicija u hijerarhiji nasledivanja - prevodilac dak i ako prevodilac ne zna tadan tip objekta.
garaprlig cla trvck t)ostoji rre[z clefinicija virtuelne funkcije, tako da nikada Sledeii odeljci detaljnije opisuju ovaj postupak.
r.rcr,t'tt,rlo(i rr sitrurc'i1rr rla pozir, ltrnkcijc nije povezan s telom flnkcije. (To bi
bilo katastrolaltto.) x
\iz At I sitrlr2i ltokazivirit' na osnovr)u klasu Instrument, tako da se objekti LuvanJe rnlormacue o trpu
sy6rit' payiit: r6k6rir ipicijalizacije niza. Ovaj niz. i flnkcija f( ) koristiie sc u kasni- MoZete videti da u klasama ne postoji izridita informacija o tipu. Medutim, pret-
jittt nrztttitl I ;tttiilttlt. hodni primeri i logika ukazuju vam na to da se informacija o tipu mora duvati u
ll p()ziVirna lrrnkciir. tune( ), razlieiti tiptlvi objekata se svode navise, a pro- objektima, po5to se tip inade ne bi mogao utvrditi tokom izvr5avanja. To je
kao ,,slanje poruke objektu i
!lrirrn se u\,ck [)oltasa oi:ckivtrrlo.'ltl sc InoT-e opisati tadno, ali je informacija o tipu skrivena. Da biste se uverili, naveden je primer
1,r.,prrita11c objt,ktrr tla orlltrii kaktl ie na
nju rcagovati". Virtuelna funkcija je koji ispituje i uporeduje velidine klasa koje koriste virtuelne funkcije i klasa kojc
s,ri-ir.o kroz koje trcba l)osrllatrilti proiekat tokom analize, isagledati gde bi tre- ih ne koriste:
ital6 cla sc pojirvc,,.,,,,r,,,. klasc ikak<t biste mogli Siriti program. Cak iako ne
otkllctg ()clgovarajrric interlcjse osnovnih klasa i virtuelne funkcije na podetku //: C15:Sizes.cpp
/l Ueliilne objekata s virtuelnim funkci.lama i bez n31h
prsanja progranta, acsto aete ih otkriti kasnijc, nekada imnogo kasniie, kada #i ncl ude <i ostream>
pocncte cla proiirrrjetc ili na lleki clrr.rgi naain odrzavate program. Ovo nije usi ng namespace std;
greika pri anlliz-i ili projcktovanjr-r, nego znaai da na podetktr niste znali ili niste
iri rnogli znati svc r6lornraciie. S obzirorn na modularnost klasa u C++-u, ovai c'l ass NoVi rtual {
pru1.,l.,., nc prcdsrar,lja veliki prottlent, posto promene koje napravite u
jednom
int a;
rlt'ltt ststcttta Ilc rltiatl tla tlrttgtl clt'ltlvc, kao Sttl je slu-ai u C-u' publ i c:
void x0 const {}
int i0 const { return 1;
Kako C++ realizuje kasno povezivanje
}
)r
Kaks sc izyrSaya kasno povezivanjc? Posao obavlja prevodilac koji instalira meha-
nizant neoltltoclan z.a kasno povczivarr)e, ka<la to od njega zatraLite (trazite tako cl ass 0neVi rtual {

St9 napravite virtr.telne tirnkcije). PoSto je programerima aesto vaZno da razumeju int a;
6rt'h11izapr yirtrrr:lnil.r hrnkcija lr (l++-u, ovaj odeljak ie detaljno obraditi nadin publ i c:
rcalizat'i1t: tog Irlcltitttiztlla virtual void x0 const {}
Ilt,zcrrisuprr rci'virtuirl sitop!tava prcvoclioctt cia ne treba da primeni rano int i0 const { return 1- I

irlstalira sve neOphodne meha- l.


lt()r,r,zitun;r'. IJntt'sto togit, trcllit atltolllatski da
r.rizlrg z3 kaspg ltovi.zivanje.'lil znadi cla iete pozvati odgovaraiuiu funkciju z-a
ob jckat klasc Ilrass ako llozrlve te l'unkciitr play( ) preko adrese obiekta osnovne
cl ass TwoVi rtual s {

klasc Instrument.
int a;
public:
I)a tri se clobila odgovaraiLria funkcija, prevodilacl obidno formira jednu virtual void x0 const {}
tabelu virtttclnih ftrnkcija (tr programerskom Zargonu se zoveVIABLE) za svaku virtual int i0 const { return 1; i
klasir k6ja satlrTi virtuclnc hrr.rkcije. l)rcvodilac sme5ta u tu tabelu adrese vir-
);
rLrclrrih tirnkcija klase. ll svaki ob)ckat klase s virttrelnim funkcijama prevodilac
rliskrr.rpo snteita pokaziva- na tabcllr VlAIll-E (koji se u Zargonu zove \rPTR). int main0 {
cout << << sizeof(int) << endl'
l,revorlrricr nrrgLr nir irrlo koji nirr'in rtalizrrr';rti ratl s virltteltritr [rrrtkcijarna, ali ol'cle opisalli natin je skoro cout << "Klasa bez virtuelne funkcije NoVirtual:
r rrrrr ltz;tlrttl << si zeof (NoVi rtua'l ) .. endl ;
478 Misliti na jeziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkcije 479 I
c0ut << 'votd* : " " sizeof(void*) << endl' Niz pokazivada na objekte klase Instrument nema nikakve informacije o
cout << "Kldsa s jednom virtuelnom funkcijom 0neVirtual: " odredenom tipu; svaki pokazuje na jedan objekat tipa Instrument. Klase Wind,
.. si zeof(0neVi rtual ) " endl ; Percussion, Stringed i Brass su izvedene iz klase Instrument (znadi da imaju isti
cout << "Klasa s dve virtuelne funkcije TwoVirtua'ls: " interfejs kao Instrument i mogu odgovarati na iste poruke), pa se uklapaju u ovLt
.. srzeof(TwoVirtuals) << endl' kategoriju. zato se adrese njihovih objekata takode mogu smestiti u ovaj niz.
i lrl,- Medutim, prevodilac ne zna da su elementi niza nesto vise od objekata klase
Rez. r,irtuelnih funkcija, velidina objekta ie upravo onakva kakvu odekujete: Instrument, pa bi, prepuiten sopstvenim mehanizmima, uvek pozvao verzije
veliiina jcclno92 broia ripa int. objekat klase oneVirtual s jednom virtuelnom funkcija osnovne klase. U ovom sluiaju su sve navedene funkcije deklarisane
funkcijont veii je ocl oblekta klase NoVirtual uveiana za veliainu pokaziva'a na
primenom rezervisane redi virtual, tako da se de5ava ne5to drugo.
Svaki put kada napravite klasu koja sadrZi virtuelne funkcije ili iz nje izvedete
tip void. Prorzlat.i cla ltrcvodilac clodaie jedan pokazivad (VPTR) u strukturu ako
irnate jednu l1i Ul.ie virtuelnih funkcija. Ne postoii razlika u velidini izmedu klasu, prevodilac napravi jedinstvenu tabelu WABLE za novu klasu, ito se vidi na
je ista jer\IPTR poka- desnoj strani dijagrama. u ovu tabeiu sme5ta adrese svih funkcija koje su dekla-
ob jekaia klasa OneVirtual i T\,voVirtuals. Veliiina objekata
,.,.,j" nu tabel, adresa f,nkciia. Treba vam samo iedna tabela, po5to se u njoi
risane kao virtuelne u toj klasi ili u roditeljskoj klasi. Ako ne redefini5ete virtuelnu
nalaze adrese svih virtuelnih iunkciia.
funkciju iz osnovne klase, prevodilac u izvedenoj klasi koristi verziju iz osnorme
[J ovom prinreru bio je potreban bar jedan podatak ilan' Da nije.bilo
poda- klase. (To mozete videti u stavci adjust tabele WABLE za klasu Brass.) Zatim u
raka ilanova, C++ prevrtdilac bi ipak dodelio obiektima velidinu veiu od nule, klasu smesta pokazivad vPTR (otkriven u programu sizes.cpp). pri korisienju
poSto svaki oit jekai rtrora irnati razliditu adresu. Ovo iete raz-umeti ako zamislite ovako jednostavnog nasledivanja, postoji samo jedan pokazivad \lprR za svaki
prisrup preko i.clcksa niz-tr objekata aila ie velidina nula. U obiekte koji bi imali objekat. Pokazivad vPTR se mora inici.jalizovati adresom odgovarajuie tabele
vclrdinu nula doclaje se,,lazni" ilarr. Intbrmacija o tipu, koia se dodaje zbog vrABLE. (ovo se de5ava u konstruktoru, sto ie kasnije biti detaljnije opisano.)
rezervisane reei virtual, zauz.ima mesto ,,laznog" elana. Da biste se uverili, Kada se VPTR inicijalizuje, objekat ,,zna" kog je tipa. Medurim, ova samo-
pokuSalte tla stavite potkomentar int a u sviln klasama navedenog primera' spoznaja je bezvredna ako se ne koristi na mestu poziva virtuelne funkcije.
Kada pozovete virtuelnu funkciju preko adrese osnovne klase (situacija u
kojoj prevodilac nema sve neophodne informacije za rano povezivanje), dogada
Craficki prikaz virtuelnih funkcija se nesto posebno. umesto obidnog pozivanja funkcije, jednostarmog asembler-
Sra sc desava kada koristite virtuelne
I)a ttistc taa:no ra:/.!.lt'ncli iunkcije, prika- skog iskaza GALL uz navodenje konkretne adrese, prevodilac generile poseban
z.aiertro na dijagranttr aktivnrlsti koje se odvijaju u pozadini. Na slici je prikazan k6d koji poziva funkciju. ovde je prikazano kako izgleda poziv funkcije idjust( )
niz pokazivaia Al I u programLr Instrument4'cpp: objekta klase Brass, preko pokazivaia na Instrument (referenca objekta klase
Instrument daje isti rezultat):
Tabel e VTABLE
Pokazi vac
VTABLE klase Brass
Obj ekat na
Niz pokazrvaca Instrument ,_----, @tol &Brass: : p1 ay
objekata klase
Instrument
&l^/ind::adjust
.T It-t.+!21
Fi;e-- I :t1l &Brass: :what
&Wi nd: : adj ust
,u, &Percussi on:
,/ 0bJekat trpa Percussion
: P1 aY

,/ &Percussi on: :what


Prevodilac polazi od pokazivaia na Instrument, koji pokazuje na podetnu
&Percussi on: : adi ust adresu objekta. Svi objekti klase Instrument ili klasd izvedenih iz Instrument
imalu svoj pokazivad vPTR na istom mestu (desto na poietku objekta), tako da
Obj ekat t i pa Stri nged &Stri nged: : P1 ga prevodilac moze proditati. VPTR pokazuje na podetnu adresu tabele wABl.E.
&Stringed::what Redosled adresa funkcija u tabeli VTABLE isti je, bez obzira na tip objekta.
&Stringed::adjust Funkcija play( ) je prva, funkcija what( ) je druga, a funkcija adjust( ) je treia.
Prevodilac zna da se funkcija adjust( ) nalazi na lokaciji \prR+2, bez obzira na
Obj ekat
\ tip objekta. Zato, umesto da kaze: ,,Pozovi funkciju na apsolutnoj lokaciji Instru-
ment::adjust" (to bi bilo rano povezivanje), prevodilac generiSe k6d koji kaZe:
,,Pozovi funkciju na adresi \PTR+2". Po5to se tokom izvr5avan;a dita pokazivad
480 Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkciie 48t

VP I R i oclreclrrjc stvarna aclresa funkciie, dobijate Teljeno kasno povezivanje. Kada se izraduna adresa pokazivada rrazene funkcije
u taberiwABLL,, poziva
Saljete ponrktr objektrr, a objekat odlrrduje kako ie reagovati. se ta funkcija. Adresa se dita i funkcija se poziva u istoj naredbi:
caiI word ptr [bx+4]
lza scene Na kraju se pokazivad-steka waia nagore, kako bi
se ukronili argumenti
Ilice varrr zanimlji','o da pogledate kocl na asemblerskom jeziku, generisan smeste.ni pre ovog poziva. U asembrersko.ri kodu
za c i c++ desto mozete videti
poz-ivonr virtrrclne lirrrkcije. MoZete uoditi da se zaista primenjuje kasno pove- da pozivajuia funkcija ukranja argumente, ali
to zavisi od realizacija procesora i
zivar.r je. Ovo je rez-ultat jednog prevodioca za poziv: prevodioca.
j.ad:ust(1);
r.urutar fnnkci je f(Instrument& i) :
I n icijal izacija pokazivaia VPTR
push I Po5to pokazivad VpTR.:$1eauj9 ponaSanje virtuelnih
funkcija objekta, vidite
push si koliko je znadajno da vprR uvek pokazuje na pravu
taberu vrABLE. Virtuernu
mov bx, word ptr Isi] ne moZete pozvati p." n"go sto se ispravno inicilaiiffi pokazivad
cal l word ptr Ibx+4.]
Ir[tiil
\PTR. Naravno, inicijalizacija se moz-e obezbediti
u konstrukttru, ii ,i;"oun oa
add sp, 4 primera koji rade s klasom Instrument nema
konstruktore.
Argtrrnenti poziva C++ funkcije, poput poziva C funkcije, smeStaju se na stek Inicijalizacija pokazivada vprR je jedan od razroga
za definisanje podra-
zdesna uler,o (ovai redoslecl je obavez-an, kako bi se podrZale liste argumenata zumevanog kontruktora. u primerima u kojima
se koristi klasa Instrument,
promenlji.,,e duZine u jeziku C), tako da se argument I prvi sme5ta na stek. Na prevodilac pravi podrazumevani konstruktor,
ko;'i inicijalizuje vprR. ovaj kon-
ovom mcstu u firnkciji, registar si (deo arhitekture Intelovog xB6 procesora) struktor se, nararr'no, automatski poziva za sve-objekie
naie Instrument pre
saclrZi aclreslr ocl i. Ona se takocle srneSta na stek, poSto je to podetna adresa nego Sto bilo sta moZete udiniti s njima, tako da
znate da je uvek bezbedno po_
tekuicg objekta. Prisetite se da podetna adresa odgovara vrednosti this, a this se zvati virtuelne funkcije.
automatski smeita na stek kao argument, pre bilo kog poziva funkcije dlanice, Kasnije iemo razmotriti posredice automatske inicijarizacije
pokazivada
tako da lunkcila ilanica tadno zna s kojim objektom radi. Tako iete uvek videti VPTR u konstruktoru.
da sc na stek smeSta doclatni argument pre poziva funkcije dlanice (osim u
sludajrr statiakih lunkcija dlanica, za koje ne postoji this). Objekti se razlikuju
Sada se rnora stvarno pozvati virtuelna funkcija. Prvo se dita VPTR, tako da se
vaZno je shvatiti da se svoclenje navise primenjuje
moZe pronaii tabela VIARI-E. LI sludaju ovog prevodioca, pokazivad \IPTR se samo na adrese. Ako prevodi-
lac radi s objektom, on tadno ina kogle tipa i
sr.neSta na podctak objekta, tako da vrednost this odgovara pokazivadu \?TR' zato (u C++_u) neie koristiti kasno
gov.eziyanie za ni zajedan_poziv runtctye _ ili, bar, p;;ni;;au frlroailu.
Red:
koris.ti kasno povezivanje. Radi poveianja efikasnosti,"ij"
ptr Isi] veiina prevodilaca ie pri-
mov bx, word meniti rano povezivanje.pri polivanju virtuerne funkcije
ouletta, foslo radno
ruzima rec na koju pokazuje si (znadi, this), a to je VPTR. Pokazivad VPTR se znaju kog je ripa. Sledi primei:
smeSta u registar bx. //: C15:Early.cpp
\PTR, kolise nalazi u bx, pokazuje na podetnu adresu tabeleWABLE. Funkcija // Rano povezivanje j virtuelne funkcije
koju treba pozvati nije na podetku tabeleVTABLE, nego na lokaciji broj dva (po5to #i ncl ude <i ostream>
je to treia ftrnkcija u tisti). Svaki pokazivai funkcije je Sirine dva bajta u ovom #include <string>
nrernorijskonr modclu, tako da prevodilac dodaje eetiri na \?TR kako bi using namespace std;
iz.racunao adrestr traZene tirnkcije. Ovo ie konstantna wednost, uwrdena tokom
prevoden ja, pa je jedino znaiajno da pokazivad funkcije na lokaciji broi dva odgo- class Pet {
vara ftrnkciji adiust( ). Sreiom, prevodilac umesto vas brine o svim ovim admini- publ i c:
stratr\rnim poslor.irna i obezbeduje da se svi pokazivadi funkcija u svim tabelama .l. vi rtual stri ng speak 0 const { return ",,; }
\"IABLE odredene hijerarhije klasa polavljuju istim redosledom, bez obzira na
redosled redefinisanja u izvedenim klasama.
class Dog : public pet {
public:
string speak0 const { return,,Lavez!,,; )
I.
{

Mrsliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcile 483


482

Rezervisana red virtual sruZi za poboljSanje efikasnosti.


int narn0 i
Medutim, ne bi tre_
balo da brinete o eflkasnosti pri projektovanju klasa. Ako
Dog ralPh; nameravate da kori-
stite polimorfizam, koristite svuda virtuerne funkcije. Kada
pet* 01 - &ra'1 ph; trazite nadine da
ubrzate k6d, samo treba da potraZite funkcije koje ne moralu
Pet& P2 - ral Ph; (obidno se veia poboljsanja mogu postiii na
biti virtuerne
Pet p3; drugim mestima: iobar optimiza-
tor ie bolje otkriti uska grra nego sto vi to mozete"udiniti,
r Kasno Povez i van3 e za oba:
,i nagadajuii).
<<end1 I Prida se da se velidina i brzina c++ programa razlikuju
.ori-.. "p1-,speak0 - " << p1->speak0<< velidine i brzine c programa, a desto su ove wednosti priblizno
za"do t'o proccnata ocl
" p2'speak0 endl;
.or, .. p2.speak0 = " iste. Iiazrog pove-
1/ Rano Povezi vanje (verovatno) : .
ianja efikasnosti je kompaktnost i brzina raz,voja programa
na c++-u odnosu na
cout << "p3.speak0 = " t' p3'speak0 '< program na C-u.
endl i

\ I i l,-
r) pozivirra pr->speak( ) i p2.speak( ) I9lltlt,::..i1':::;:l:;lT'f:riil?lll;
,,.:,iJli:;j"i;,1i.;:;ili),;.Is;;ri';J'i":ii* 1*:.:1oj::?:,1,:il.,:,:llli'?',; fRs.traktne osnovne klase i potpuno virtuelne
'Jlil"'J:,]:"L:il::,';:[" ;;".;';T;; k*i,iiti ,,er'anizam virtuernih funkciia' Pri funkcije
ff 'Ti' ; fi #""";
JX
i;'
,.,"i,1,."
u a,
i';
"'"koristi1' rano
;"'l'
.--^ .^x^- tl^.i -rna.la qp radi o
I i ::::.,'lli
povezivanje S,, :,'#$lJ
Medutim,
"'",1
pre- -
cesto tokom projektovanja postoji potreba da osnorma klasa
opisuje samoinrer-
:;'_1i,,:ii::;?"',1;;;";. povezlvanle'
fejs klasa koje se iz nje izvode. orugrm redima, ne
Zelite da neilo napravi objekat
voclilac tno7.e cla primeni i kasno osnovne krase, nego samo da primeni svodenje navise
tako da moZe koristiti
njen interfejs. To iete postiii definisanjem apsiraktne (engi.
abstracr) klase koja
ima bar jednu potpuno uirtuelnu
funkiiju (engl. pure uirtial yuntction). porpuno
Za(to vi rtuelne funkcije?
postaviti pitanie: ,, Ako ie ova tehnika
toliko znadainai
virtuelnu funkciju moZete prepoznati po rezervisanoj redi virtuar
na podetkr_r i =
lJ rx,.r. trc..tk. r.ozctc ona samo iednaod
0 na kraju dekraracije. prevodilac onemoguiava pravilen]e
objekata apstraktne
.iia, zasto ie klase' ovo sredstvo podrzava ideju da osnovna klasa
ako sc pont()itr njc svaki put poz.iVa'pruuo'frl,nt samo ciaje interfejs
z'a njtr?"'
trtrlgtrt'rtrlst i? Zltittr ltltrratl tla znittl't izvedenim klasama.
Ovo jc tlobro f ittt"i" a oclgrlvrlr leTi
tt osnovnoi zamisli iezika C++: "Zato 5to Pri izvodenju klasa iz apstraktne krase, moraju se realizovati
vidite da se' sve potptrno vir-
rriit' zatlovrllji tnt"tna:' ll prethodnom asemblerskom kodu tuelne funkcije, inade i izvedena klasa postaje apstraktna.
Deklarisanje potpuno
"tl":t' ('r\t'l' sa apsoltltnol .udt:tn*1 poiavljuju dva
virruelne funkcije vam omoguiava da imestite u interfejs
tlrrlL'sto ttavoclcn ia iedntlg iskaz'a poziva virtuelne kJase funkciju dlanicu,
za definisanje
sl.ie .ija n..n.,ul.J.tu i.t ar-a, neophodna a da pri tome ne morate pisati k6d tela funkcije,
koji moZda n. ui i..,uo smisra.
iz-vr5avanie'
tr nkciier.'l o llovciava k0cl i procltrZava Potpuno virtuelna funkcija istovremeno primorava izvedenu
klasu da obezbedi
da je kasno povezivanje
I

Atrtori nekih ,,rrl"li,r" oiilentisanih iezika smatraju definiciju te funkcije.


rolikosvojstvenoobiektnoorijeniisanomorijentisanomprogramiranju,dabi Funkcije osnovne krase Instrument su bile ,,raine.u
svim navedenim pri-
rltlrltrcbrrloLrvekdascprirnenjuje,aun.r,itrebalodabudeopcionoidakorisnik merima. Ako bi te funkcije ikada bile pozvane, to znak
]'e da nesto nije u redu.
tlctrebaniclazrracla<lnopostclii.Ovoieodlukakojasedonosipriprojektovanju Namena klase Instrument jeste da izvedenim kiasama
u":Tu znaiaina' Najzad' obezbecri zajednidki
llz'ika b' tl.to'" ie efikasnost interfejs.
iczika.:r r;** i. ,,n.ioo
oc1
sistema
(. jc naprar"lie,.l ,i;'l;i asemblerski iezik u realizaciji operativnog Iedini razrog za zajednidkog intert'ejsa jeste
';;;trio LInix, dalekl prenosiviji od svoiih
prethodnika)' ^usposravljanje
razliditog definisanja funkcija
moguinosr
(zato le ,ni ,,,p.rniir,-Ii-;i;i;r, u pojedinienrm po.-dtipovr.nu. zu;.a"ieki inrerfe.is
C++-a bio je das,e poveia efikasnostpro-
Icclan ocl gfu,,nif,'r,,rinlu ,*,,io.,unnk pitaiu: "Kakavde
opisuje osnormi obrazackoji odreduje Sta je zajednidko
svim izvedenim klasama
s C++-om' C programeri
grartrcra rla jcziktr i'' 'tltt't sc sLlsretntl -.i ni5ta viSe. Zato je Instrument pogodan kandidat za apstraktnu klasu. Napra-
urti Lrticaj tra vcliiinr'r i brz-inu p'ug'otul'; q;.ry:1*:::::]:;;t,:t^'.1^?llilal
bi radije ostari pri c-u
vite apstraktnu krasu kad samo rrocete da radite sa skupom
ttasa preto ,alea-
,rari dodatak', r,inogi
::';'ll';:iili,,ll'iii,liiitl;;"r.iil^iiosin"lsi: nidkog interfejsa koji ne mora biti realizovan (ili, bar,
ne u potpunostil.
ncgo iur hi prcsli presli iai'**' Ylt^tllt-t::::l:,1*lg5t:#;
u taberuwABl-E.7,'',,
Ako u projektu postoji pojam poput Instrument,
koji se ponaSa kao apsrrak_
,,o* in,otiadresu koja se smesta tna klasa, objekti te k-lase ne bi ni imali smisla. znaci
;::il,llll,::ili:;l,il;:
{inlkciie t,,t";j;;;t';a *ngttc"otti
da je nu..nu uu.. Instru_
ment da predstavi samo interfejs, ne i odredenu rearizaci;u,
su virtuelttc iftl"k:i]:^!:*11ITe"Y:T#J
je njegova vodilia bila: "Ne ,"to an definisanje
pa srr br7.c. t,r"r.,"rr.,p 1" ir.lat;in da objekta klase Instrument nema smisla i verovatno iete
hteti da spreiite kori-
'irruclr.rc,
plariti za otlo (to ltc koristite' snika da to uradi. Resenje moZe biti da sve virtuelne
funkcije krase Instrument
ispisuju poruke o gresci, ari se.poruke pojavrjuju tek
tokom izvr.avanja - ovaj
: ri'likittt ttqllelltltlt koriste oval prtstttll'
pristup zahteva od korisnika da sveobuhvatno tesrira
\.r pt ttrrr'r. \rrr.tllt,rll l'rr'r t l'ttlltltl sistern. Mnogo je bolje
I j.,',,,,,,r,,,:ii,.,,.+r, ratli trttlogo(- prograllleril' N'lakar i ncznatno otkriti eventualne probleme tokom prevoclen ja.
l I llt,l,r r.r lirlr.rirr(r.rii.ril g,,"
, ,,. , ,'f,f L'rr,,'r rio'rorL lrlllr"ll ll'rl;rtlr lrrlrlllllrliii
Poglavlje l5: Polimorfizam i virtuelne funkcije 485
Misliti na jeziku C++
484

class Instrument (

publ i c:
In stru ment
/l Potpuno virtuelne funkcije:
virtual void PlaY0 virtual vojd play(note) const = 0;
virtual char* whato vjrtual char* what0 const = 0;
virtual void adjustQ // Pretpostavlja se da ce ova funkcija menjati objekat:
virtual vojd adjust(int) = 0;
t.

// 0statak datoteke ie isti ...


class Wind : public Instrument {
public:
void play(note) const {
Percussion cout << "l,Ji nd: : p'l ay" << endl '
void Playo void plaYo )
void plaY( ) char* what 0 const { return "l,Ji nd'' ; }
charx what0 ch ar* what( ) charx what( )
void adjust(int) ()
void adjust0 void adjusto
void adjusto );

class Percussion : public Instrument {


publ i c:
void play(note) const {
cout << "Percussion: :p1ay" << endl;
)
Woodwind char* what0 const { return ''Percussion"; )

void plaY( ) void adjust(int) {}


void playo
char* whato );
charx whato
class Stringed : public Instrument {
koristi se sintaksa:
Za deklarisanic potpuno virtuelne funkciie publ i c:

virtual uo,6 r0 = 0; void play(note) const {


cout << "Stri nged: : p1 ay" << endl ;
NaovainacirrsaopStavateprevodiocr'rda'rezerviseredzafunkcijuutabeli klase
n. .r.itu ua..ru. eak i ako je samo iedna funkciia
)
\.1A81.1,, ali da u toi ,...f char* what0 const { return "Stri nged"; )
niie kompletna'
cleklarisana kao potpuno virtuelna' tabelaWABLE void adjust(int) {}
Sta prevodilac treba;" ;;i ako neko poku5a di napravi obiekat klase iija I.

tabela VlAIlt-L nijc kompletna? Po5to


ne m.oZe bezbedno napraviti obiekat
apstraktne klase, priiavll,i" g'"st"' Na taj
natin prevodilac sprovodi apstraktne cl ass Brass : publ i c l"l'i nd {
klase.Pravljenlemapstraktntkiu"spredavateprogrameraklilentadaiepogre- publ i c:
5no r-rpotrebi. void play(note) const {
virtuelne funkciie' Po5to
il program Instrument4'cpp dodate su potpuno cout << "Brass: : p1 ay" << endl '
klasa itrra .o*n pn,1.,,,no ui'ti'elne funkciie'
nazivamo ie potpuno apstraktna )

l,1a.sn (errgl. pttre altstract clctss\" char* what0 const { return "Brass"; }

);
Il: C15: Instrument5'cPP
osnovne kl ase
// Potpuno<iostream>
apstraktne
class Woodwi nd : publ i c l,,li nd {
#include publ i c:
us i ng names Pace s td; void play(note) const {
enum note { middleC' Csharp' Cflat }; ll ltd' ..
cout << "l,,/oodw'ind::P1aY" endl;
(

Poglavlje I 5: Polimorfizam i virtuelne funkct.le


487
Misliti na jeziku C++
I
I
486

Ovako izgledaju definicije potpuno virtuelnih funkciia:


)

char * what 0 const { return "l^loodwi nd"; } //: C15:PureVi rtual Defini tions.cpp
I I Definicije potpuno virtuelnih
funkcija u osnovnoj klasi
#i ncl ude <i ostream>
using namesPace std;
/i Ista fLn(ciJa kao rantje:
void tune(lnstrument& i) {
class Pet {

i.p1ay(middleC);
public:
)
virtual void sPeak0 const = 0;
vi rtual voi d eat ( ) const = 0;

/ '/ Novd f unkcl3 a : // Nedozvoljena definicija umetnute()potpuno virtuelne funkciie:


void f(instrument& ') ( i 'ad:ust(1); ) l/l virtual void sleep0 const = 0
);
int marn0 {
je u redu, nisu umetnute funkciie
[lind flute; // Sada
Percussion drum; voi d Pet: : eat 0 const {
Stringed viol in; cout << " Pet: : eat 0 " << endl ;

Brass flugelhorn; )

Woodwi nd recorder;
tune ( f1 ute) ;
void Pet::sPeak0 const {
tune (drum) ;
cout << "Pet::speak0 " << endl ;

tune(vio1 in); )

tune(flugelhorn); class Dog : Public Pet {


publ i c:
tune(recorder) I
l(rluqelnorn)l I I Koristi se zajedni dki kod kl ase Pet:
void speak0 const { Pet::speak0;
\ I I t:' void eat0 const { Pet::eat0; i
)

jasno
[).r,rrno virruernc trrnkcijc su korisnc posto ":qlls"]ii: -",!'straktnost
upotreba klase'
\.
J,
i k,l,isnit<u i prevodlocu kakva je predvidena
klasc i saopStat'uiu
/.apaz.\te da potpuno virtuelne funkciie
spre'avaiu pl"tl:9]l1i:. objekta
spre'avanja presecaniaobiekta
int main0 {
apstraktne klase po urnii,oiii z-uto je ovo i nadin Dog simba;
apstraktne klase
(engl. ol.rjecr sllc,rg), t,,i. J. uiti u('utko opisano' Pravljenjem s i mba. speak 0 ;
nu'i." tu klasu' uvek koriste pokazivai
mo,ete obez.bediti an ,i, pti svodeniu ' simba.eat0;
ili referenca. I I ll,-
'lo (to samo jedrra potpr-rno virtuelna iunkcija onemogltiava kompletiranie
tela drugih funkcija. Cesto iete Red u tabeli WABLE za klasu Pet I dalje je prazan, aii postoii funkciia s tim
tabcltl \,.1.r\I]l-H ne z,riaei cl'a ,onl nisu potrebna imenom, koja se moZe pozvati u izvedenoj klasi'
u"rr.i1l.,-ii"tfttije osnovne klase' iak i ako ie virtuelna' Uvekie
htctr cla po:/.ovele
blize vrhu hijerarhije. Tako se Stedi Druga korisna osobina definisanja potpuno virtuelnih funkciia jeste to 5to
ciobro rcsunjc srrrestiti )iii",i,riJr.l k0d 5to vam omoguiava promenu obidne virtuelne funkcije u potpuno virtuelnu bez-
nlenjanje sistema
llrostor za kirtl, ali si: i olakia\Ia naruSavanjapostojeiegkoda.(ovojenadindapronadeteklasekojene
redefini5u tu virtuelnu funkciju.)
Potpuno virtuelne definicije uvek saop5ta-
{irnkci;tr rr osnovno klasi m,oZete i definisati. JoS
j
n,r1rJu.'u
vatc
'irruclnu
ne ,in'uuf i pravlicnie
prevodi(lctt tla obiekata te apstraktne osnovne klase' a Nasledivanje i tabela VTABLE
porpr.rno virrrrcl.e t,,,lt..i1" ipoi ,ruiol.i t,iti ieclefinisane u izvedenim klasama da MoZete zamisliti Sta se de5ava kada izvedete klasu i redefini5ete neku od vir-
bi bilo rnoguc. pruuf l"nl. t'iJ1"tnto Mo7'da postoji
zajedniiki 9"o \1d.u koji bi bio tuelnih funkcija. Prevodilac pravi tabelu WABLE za no\,Il klasu i unosi adrese
pclz,ir,anizclefinicija.',i1.',i1i,.u,,'nnekih,izvedenil-rklasa'.lakavk6dsmestiteu novih funkcija, a koristi adrese iz roditeljske klase za sve virtuelne funkcije koje
(dija
klase, r,rmesto da ga ponavljate u svakoi
funkcili' ne redefinisete. U svakom sludaju, za svaki objekat koji se moZe napraviti
iirnkcilrr osnovne
funkctje - 489
Poglavlje I 5: Polimorfizam i virtuelne
Misliti na jeziku C++
488

&Pet: :name &Pet: : name


klasatletrlal)()tl)tlllovirtuelnelunkcije)trvekpostoiipotpunskupadresafun.
moZete pozvati funkciiu koia
se tamo
kr:ija u tatreli\rl'r\lll'tr, ttkr;;; "ikudu'n" &Pet::sPeak &Dog: :speak
izttedenoi
'" l;ll11ll:*iii]:i11i::l)];li]:]."da doclate nove virtuerne runkciie &Dog : :sit
klair? SIt'tii jedrrostirvart printcr:
/ : C15:Ador'rg\/r rtJals'cpo lzvedenoj klasi speak( ) na isto mesto'u tabeli
i, o.i.tl".,:. u'ttutlnih funkcija Zapaziteda prevodilac sme5ta adresu funkcije
d i nc l ude <i ost ream> WABLEklaseDogtuo,,tuu"tiVIABLEklasePet.Sliino,akobik]asaPugbila
lincl ude <stri ng> tabeli bila na istom mestu
sit( ) bi u
izvedena iz klase Dog, niena verzijafunkcije
usrng namesodce stdl bof nJ6g;e. tkao Sto ste videli u primeru na asembler-
kao Sto je u tabeli f.rur"
zaizbor virtuelne tunkcije koristi
skom jeziku) Sto prevodll"al;;"#; k6d.koji
class Pet pJt"il tuUtt" vfesLE' Bez obzira na odredeni
I ri .rr-"rien """tut
stri ng
iednostarT organizovana je na isti
Pname;
podtip kome pripad" li:g* P?.eiaWABLE
publ i c:
pname(petName) ()
";i;il,
naiin, tako da ie se poz# virtuelni"h funkcila
uvek odvijati na isti-nadin'
Pet(const string& petName) : na obiekat osno\"ne
U ovom sluiaju, prevodilac radi samo s pokazivadem
,}

virtual strrng name0 const ( return "";


pname;
zu"kcije speak( ) i name( )' tako da ie.prevodiiac
klase. Osnovna klasa i."u t"-"
vrrtual,tt,rng speuki) const { return }
bi prevodilac mogao znati da^radite s obiek-
dozvoliti samo njihove p"'1"' fi"t"
); objekat ottto"nt klase? Taj pokazivad
tom klase Dog ako i*":;;;;ku'lt'ui "u funkciju sit( )' Na tom mestu u
class Dog : Publ r1 Pet i fi rnog"o pok'azivati naneti drugi tip koji-nemaneke druge funkcije' U svakom
stri ng name; tabeli WABLE moZe, ufi "t rnotl' bitl iatttu
publ I c: sludaiu,neZelitepozivfunkcijesteadrese'Prevodilacvas5titiodpozivaniavir-
(const strr ng& petName) : Pet (petName) {}
ir"t.,iit f,r.,t.ija kbje postoje samo u izvedenim klasama'
Dog
u klasi kada znate da pokazivad stvarno
))-*o"u virtuelna funkcija
Dog:
Postoie netl manle "oilieuj"t'i sludajevi
da pozovete funkciju koia
vi rtual stri ng sr t0 const { pokazuje na objekat
pokazivad' Na sledeii naiin moZete
"iltd";;;;tttutt''ntto.hoiete
return Pet: : name0 + " sedi "; oostoii samo u ,ol pottt*i' konvertujte
o gr"S.i koju proizvodi prethodni
program:
) Iu".i,i poruku
s tri ng sPeak const { //
() Redefini5e
((Dos.)P[1])->sit0
return Pet:: name0 + " Laje!"; u opStem
Ovde znate da ptll pokazuje na objekat kiase Dog' ali to ne znate
)
sludaju. Ako je p.oUr"'* tuG postavljen.da
morate t1:1:^Tl:iove svih
); poSto verovatno-neisp^ra'"rto kori-
objekata, trebalo bi d;;; potto'o razmotrite'.
jnt main0 stite virtuerne tunkci;e.?oltoj. ,it"u.i;"
u kojima projekat najb_orie tunkcionise
{
") 'new Dog("bob") }; koji se euvaju u op5tem
pet- p[] = {new Pet("opsti (ili nemate drugog izUotaiuLJ '"ut" tipove svih obiekata
je p,oAt"i-pipozniuania tipa iokom izuriauania (eng' run-
cout << "PIo]-'sPeak() = "
kontejneru. ovo
.. p[0]-'speak0 << endl;
time tYPe identification, RTTI)'
YJase naniZe' u pokazivade
cout << "P[1]-'sPeak() = "
RTTI se tiee svodenja pokazivada osnovne
.. p Iil ->sPeak 0 << endl ; se na uobidajeni dijagram
izvedenih tturu tpo;r,iJilti"is"" i "naniZe".odnose nauiie se obavlja
cout.. "p[1]-rsit0 = "
llt -" klasa, u kome se osno"ma klasa). Svodenie
" p[i]-'51t0 "
endl; // Nedozvoljeno "u'*ir" "J-i po5to ie potpuno
Itt automatski, Uez ikafcvo[*p;;"b.", postupka, ,b::i-t-11:]
\ I I l,- po51o prevodilac nema informaciie o stvarntm
Dog dodale ir"A""i" naniZenile bezbedno,
fr'rnkcije: speak( ) i name( )' Klasa tipovima, pa morate tarno znati tip obiekta.
Ako konvertuiete oblekat u pogresan
Klasa Pet saclrTi dve virttlelne funkciie speak( )' Diia-
i rcctcfinise znaeenie
rrt'irr virrttt'ltrtr lirtrkt i;tr i,)()a 'itt ) su tabelevrABLE koje tip, biiete u nevolji.
a ovoj temi ie u drugom tomu
gram ic vam pomoii tl' l;;;;i; sto'" Jtsuuu' Prikazane RTTI se opisuje kasnije u ovom poglavlju'
z'a klase Pet i Dog: posveieno celo Poglavlje'
fe prevodilac napravio
490 Misliti na jeziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkcile 491 l-

Funkciji describe( ) se objekat tipa Pet prosleduje po urednosti. Ona zatirrr


Presecanje objekta poziva virtuelnu funkciju description( ) r.a taj objekat. L) firnkciji mainO biste
prrsledivarliu 1tl'::1 obiekata
Sa srano\ rsrii irolrrrr,,r{rzrra, ,ostoii ritzlika izrneiltr odekivali da prvi poziv proizvede ,,Ov<-r je Alfred", a rezultat drugog da bude ,,l,esi
iprrlsletlir,irrljirrliljckatitprlvrt,tlrrtlsti'Sr'iprrrncriktljcsteovdcvidclii-skorosvi voli da spava". U su5tini, oba poziva konste verziju funkcije description( )
5to su sve
pri.tcri k.jc ircba rla 'iciite prosleciu jtt aclrese, a ne vrednosti. Raz-log ie osnovne klase.
tako tla je proslcclir"anje acircse obiekta izvedenog tipa
ari*'st, isrc U ovom programu se deSavaju dve stvari. Prvo, poSto jc argument funkcije
'clicinc,'
(.itiC.. jc t. vcci .bjckat) isto kai) pr.sleclivanje adrese rliljekta osnovnog tipa
to je cilj polimorfizma: kOd
describe( ) objekat klase Pet (umesto pokazivaaa ili reference), svaki poziv
iko;i 1c,ilria,,,, rnanji). Kao ito ic ranijc obja5nieno' funkcije describe( ) prouzrokovaie da se podatak velidine objekta klase Pet smesti
koji radr s rrr.7.c isro tako racliti i s objektima izvedenog tipa'
.sr.v.i.r rip..r na stek i ukloni posle poziva. Ako se objekat klase izvedene iz Pet prosledi funkciji
Aktl t.ttt.ttlstrl llrlkaz-ivai:a ili rele rerrce objekat svedete navise, dogodiie Se nesto describe( ), prevodilac ga prihvata, ali kopira samo deo z.ajednidki sa objektorl
samo podobjekat koii
sto vas rnoTe izncnacliti: obiekat se ,,sede" svc clok ne ostane tipa Pet. On preseca objekat na osno\mi i izvedeni deo, na sledeii nadin:
odgovara tiprr tr koji konvertuictc. ll slecieiem primeru videiete Sta se dogada
prlikon'r presecarlja objekta: Pre presecanj a Posl e presecanja
//: C15:0b3ectSl icing.cPP
#include <iostream>
lincl ude <stri ng>
Lrstng'la-esPace sld;

class Pet i favori teActi vi ty


string Pname;
publ i c:
Pet (const stri ng& name) : pname (name) ( ) Sada se moZete zapitati o pozi\lr virtuelne funkcije. Funkcija Dog::descrip-
vi rtual strl ng name0 const { return pname; } tion( ) koristi delove objekta tipa Pet, koji i dalje postoji, i objekta tipa Dog, koji
virtual string description0 const { viSe nepostoji, po5to je iseden! Sta se deSava pri pozir,u virtuelne funkcije?
return "0vo je " + Pname; Spaseni ste od katastrofe, po5to se objekat prosleduje po vrednosti. S
obzirom na to, prevodilac zna tadan tip objekta, po5to je iz-vedeni objekat
l; pretvoren u objekat osnovnog tipa. Pri prosledivanju po vrednosti, za objekat
cl ass Dog : Publ I c Pet i klase Pet koriSien je konstruktor za kopiranje, koji inicijaliz-uje pokazivaa VP'l'R
slrt ng favorl teActlvi tY; adresom tabele WABLE za k-lasu Pet i kopira samo dclove podobjekta klase Pet.
publ I c: Ovde nije izridito naveden konstruktor za kopiranje, pa ga prevodilac sam pravi.
Dog(const string& name, const string& activity) Objekat presecanjem zaista postaje tipa Pet, u svakom smislu.
pet(name), favoriteActivity(activity) {}
, Presecanjem se, uklanja deo postojeieg objekta pri njegovom kopiranju u
stri ng descri oti on 0 const { novi objekat, umesto da se jednostavno promeni znadenje adrese kao pri upo-
return Pet::name0 + " voli da " + trebi pokazivada ili reference. S obzirom na to, svodenje naviSe u objekat se ne
favoriteActivitY; koristi desto, i to treba na werne primetiti i sprediti. Da je u navedenom primeru
)
funkcija description( ) u osno'"noj klasi bila potpuno virtuelna (imalo bi smisla,
poSto ona niSta ne radi u osno'"noj klasi), prevodilac bi spredio presecanjc
objekta, po5to ne biste mogli ,,napraviti" objekat osno!.nog tipa, Sto se de5ava
void describe(Pet p) ( // Preseca objekat prilikom svodenja naviSe po vrednosti. Ovo bi mogla biti i najznadajnija osobina
cout << P. descri Ptj on ( ) << endl l
potpuno virtuelnih funkcija: spredavanje presecanja objekta tokom prevodenja.
)

int main0
Pet P("A1 fred');
{
Preklapanje i redefinisanje
Dog d("Lesi ", "sPava"); U poglavlju 14 ste videli da promena deflnicija preklopljene funkcije u osnovnoj
descrl be (P) ; klasi skriva sve druge verzije te funkcije osnovne klase. U sludaju virtuelnih
descri be(d) ; funkcija, ponaSanje se malo razlikuje. Razmotrimo izmenjenu verziju primera
I lll,- NameHiding.cpp iz poglavlja I4:
Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcije 493
492

Derived2 d2;
//: I5: NameHi di ng2. cPP
C
preklapanje x = d2.f 0;
// Virtuelne funkcije ogranidavaju l/l d2.f(s); ff znakovna verzija ie skrivena
$i ncl ude <i ostream>
Deri ved4 d4;
#i ncl ude <stri ng>
x = da.f(1);
us i ng namespace std
l/t x = da.f0; ll verzija f0 je skrrvena
;

c'l ass Base l/l da.f(s); ff znakovna verzija je skrivena


Base& br = da; /l svodenje navlse
{

publ i c:
virtual int f0 const { //l br.t(l); ff lzvedena verzija je nedostupna
cout << "Base: : f 0 \n" ;
br.f0; // 0snovna verzija je dostupna
return 1;
br.f(s); // 0snovna verzija je dostupna
)
\ / //,-
virtual void f(string) const ii Prvo se mole zapaziti da u klasi Derived3 prevodilac neie dozvoliti promenu
virtual vord g0 const (i tipa rezultata redefinisane funkcije (dozvolio bi da f( ) nije virtuelna). To je
); znadajno ogranidenje, po5to prevodilac mora omoguiiti polimorfni poziv
funkcije preko osno'r'ne klase. Ako osnorma klasa odekuje da f( ) wati wednost
cl ass Deri vedl : Publ i c Base { tipa int, tada verzija funkcije f( ) izvedene klase mora poStovati to pravilo, inade
pubi i c: nastaje greSka.
void g0 const {) Pravilo prikazano u poglavlju 14 i dalje vaZi: ako redef,niSete jednu od pre-
); klopljenih funkcija dlanica u osnovnoj klasi, ostale preklopljene verzije postaju
skrivene u izvedenoj klasi. Kdd koji testira Derived4 u funkciji main( ) pokazuje
cl ass Deri ved2 : Publ i c Base {
da se ovo de5ava dak i ako nova verziia funkcije f( ) u su5tini ne redefini5e po-
publ i c:
stojeii interfejs virtelne funkcije - funkcija f(int) skriva obe verzije funkcije f( )
II Redefinisanje virtuelne funkcije: osnovne klase. Medutim, ako d4 svodite navise u tip Base, postaju dostupne
int f0 const { samo verzije funkcije iz osnorme klase, a verzijaizizvedeoe klase nije dostupna
cout << "Derived2: :f0\n"; (poSto to nije definisano u osnovnoj klasi).
return 2;
)

i; Promenljivi tip rezultata


Navedena klasa Derived3 navodi na pomisao da se, tokom redefinisanja, ne
cl ass Deri ved3 : Publ i c Base {
moZe promeniti tip rezultata virtuelne funkcije. Ovo je tadno u op5tem sludaju,
publ i c:
ali postoji specijalan sludaj, u kome je moguie neznatno izmeniti tip rezultata.
// Ne moZe se promeni tl ti<<
'l
p rezul tata:
Ako vraiate pokazivad ili referencu na osnovnu klasu, tada redefinisana verzija
ll void f0 const{ cout "Derived3::f0\n";) funkcije moZe watiti pokazivad ili referencu na klasu izvedenu iz tipa rezultata
I; funkcije u osnovnoj klasi. Na primer:
class Derived4 : Public Base { //: C15:VariantReturn.cpp
publ i c: ll Uraea pokazivad ili referencu na izvedeni
//
Promena 1 i ste argumenata: // tjp posle redefinisanja
int f(int) const { nclude <'i ostream>
#'i
cout << "Derived4: :f 0\n"; #include <string>
return 4; using namespace std;
)

); class PetFood {
publ i c:
int main0 { virtual string foodType0 const = 0;
string s("zdravo"); );
Derl vedi d1;
int x = d1.f0; class Pet {
d1.f(s);
494 Misliti na jeziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkctle 495 I
publ i c: Funkcija dlanica Pet::eats( ) waia pokazivaa na objekat klase PetFood. U
vr rtual stri ng type0 const = 3; kiasi Bird je ova funkcija dlanica preklopljena i ista je kao u osnor,'noj klasi,
vrrtual PetFood* eats0 . 0; ukljudujuii i tip rezultata. Znad da Bird::eats( ) svodi navi5e objekat tipa Bird-
Food u tip PetFood.
Medutim, u klasi Cat, tip rezultata funkcije eats( ) je pokazivaa na CatFood,
cl ass Br rd : publ r c Pet { tip izveden iz PetFood. Ovo se moZe prevesti samo zato Sto je tip rezultata
publr c: izveden iz tipa rezultata funkcije osnovne klase. To jeste u skladu s osnovnim
stri ng type ( ) const { return " Pti ca" ; i opisom, poSto funkcija eats( ) uvek waia pokazivai na PetFood.
:
cl ass Bi rdFood publ i c PetFood { Ako razmiSljate polimorfno, ovo ne izgleda neophodno. Za5to se svi powatni
publ i c:
tipovi ne bi svodili naviSe u PetFood*, kao u sludaju funkcije Bird::eats( )?
stri ng foodType const { 0 Obidno je ovo dobro reSenje, ali na kraju funkcije main( ) vidite razliku: funkcija
return "pt'icju hranu" ;
Cat::eats( ) moZe da wati pravi tip PetFood, dok rezultat funkcije Bird::eats( )
)
mora biti sveden naniZe u pravi tip.
);
Moguinost vraianja pravog tipa je malo op5tija, a ne gubi se inforntaciia o
.riSvoden;e navr5e u osnovnl tip:
tipu automatskim svodenjem naviSe. Medutim, waianje osnovrtog tipa ie, u
PetFood* eats 0 { return &bf; i op5tem sludaju, re5iti probleme.
private:
rdFood bf;
i.
Br
Virtuelne funkcije i konstruktori
Pri pravljenju objekta koji sadrZi virtuelne funkcije, mora se inicijaiizovati njegov
class Cat : publ ic Pet { pokazivaa VPTR, tako da pokazuje na odgovarajuiu tabelu VIABLE. To se mora
publ r c: udiniti pre pozivanja bilo koje virtuelne funkcije. Kao Sto moZete pretpostaviti,
stri ng type0 const { return "l4acka"; } po5to konstruktor ima zadatak na napravi objekat, on treba i da defini5e \PTR.
cl ass CatFood : publ i c PetFood { Prevodilac automatski dodaje k6d na podetak konstruktora koji inicijalizuje
publ i c: VPTR. Kao Sto je opisano u poglavlju 14, ako izriiito ne defini5ete konstruktor
strl ng foodType ( ) consl { return "pti ce" ; klase, napraviie ga prevodilac. Ako klasa ima virtuelne funkcije, konstruktor ie
); isprarmo inicijalizovati pokazivadVPTR. To ima nekoliko posledica.
,/,/ Za promenu vraca pravi ti p: Prva posledica se odnosi na efikasnost. Motiv za uvodenje umetnutih funkcija
CatFood" eats0 { return &cf; } jeste da se smanje resursi potrebni za pozivanje malih funkcija. Da u C++-u ne
prlvate: postoje umetnute funkcije, za pravljenje ovih,,makroa" mogao bi se koristiti pret-
CatFood cf; procesor. Medutim, pretprocesor ne zna zapraYa pristupa niti za klase, tako da se
t.
ne bi mogao koristiti za pravljenje makroa funkcija dlanica. Osim toga, pretpro-
cesorski makro uopSte ne moZe dodati skriveni k6d u konstruktor.
int marn0
rd
{
Kad optimizujete program, morate imati na umu da prevodilac dodaje
Bi b;
Cat c; skriveni kOd u konstruktore. Osim inicijalizacije pokazivada \?TR, prevodilac
Pet- p[] = { &b, &c, }; mora da proveri i wednost this (u siudaju da operator new wati nulu) i da
for(rnt i - 0; i < sjzeof p / sizeof *p; i++1 pozove konstruktore osnovrre klase. Sav ovaj k6d moZe uticati na ono Sto ste
cout << pIi] -,type0 <. " 3ede " smatrali pozivom male umetnute funkcije. U nekim sludajevima, velidina kon-
.. pIi] -,eats0-rfoodType0 << end'l ; struktora moZe prevaz.iii u5tede postignute umetaniem funkcije. Ako pozivatc
./.,/ l'4oZe da vrati pravl ti p: puno umetnutih konstruktora, velidina koda se moZe poveiavati, bcz bilo
Cat::CatFood* cf - c.eats0; kakvog poveianja brzine.
Brrd::BjrdFood. bf; Nararmo, verovatno neiete odmah ukinuti sve male umetnute konstnrktore,
/r/Ne moze da vratr pravi tip: poSto se funkcije obidno lak5e piSu kao umetnute. Medutim, kada optimizujete
llt bf = b.eats0; program, razmotrite uklanjanje umetnutih konstruktora.
/,/ 0bavezno svodenje nani Ze:
bf - dynamic_cdst<Bird: :BirdFood*r(b.eats0) ;
I I ll:-
496 Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcije 497

o pripadnosti objekta osnormoj ili nekoj drugoj krasi. Kada prevodilac generiSe
Redosled poziva konstruktora k6d za konstruktor, on prevodi konstruitor ie'krase, u rr" oinou.r. ili izvedene
Drugi zanimljir; aspekt konstruktora i virttrelnih iunkcija odnosi se na redosled klase (klasa ne zna-koje su klase iz nje izvedene).ZatoVpTR mora pokazivati
pnr.i"n k,,,..'.t.uktoia i nadin pozivanja virtuelnih funkciia unutar konstruktora. tabelu vTABLE re klase. vprR pokazuje na tu rabelu do kaja postojanla
na
Svi konstruktrtri ostrovllc klasc se ttvek pozivaju u kOnstruktoru izvedene osim ako to nije posrednji poziv konstruktora. Ako se port" togu pozove
objekta,
klase. Or,o inta stttisla, l.toStrl konstnrktor ima poseban zadatak da proveri da li
je kon-
struktor izvedene klase, vprR se menja tako da pokazule nZ njenu tabelu
objekat pravilno napravlien. Izveclena klasa nema ovlasienie da pristupi privat- vrABrE, i ro se ponavrja do poslednjeg konstruktora. Stanje'pokazivada \? tR je
ninr elanovirra osnovne klase, pa samo konstruktor osnorme klase moZe odredeno poslednjim pozvanim konstruktorom. To
isprar,,no inicijalizovati nasledene elemente. zalo 1e neophodno da se pozovu svi
je'jos jedan razrog za
pozivanje konstrukrora od wha ka dnu hijerarhije nasledivinja.
konstruktori, inade objekat ne bi bio u potpunosti pravilno konstruisan. Zbog Tokom izwsavanja niza poziva konstruktora, svaki konstruktor povezuje
toga prevodilu. nu-.i. poziv konstruktora za svaki deo izvedene klase' On ie VPTR sa svojom tabelom VIABLE. Ako bi se u konstruktoru
pniriti podraz.umevani konstruktor ako ne pozovete izridito konstruktor, koristi mehanizam
virtuelnih funkcija, poziv bi se realizovao kroz njegor,u taberu VTABLE, a ne
osnovne Llor" ,., listi iniciializacije konstruktora. Ukoliko ne postoji podrazume- tabelu klase najniZe u hijerarhiji (kao Sto ui uioitueal posre poziva suihkon-
kroz
vani konstruktor, prevodilac ie prijaviti gre5ku. struktora). Zato, mnogi prevodioci prepoznaju poziv viriuelne funkcije
Redosled poziva konstruktora ie znadaian. Kada izvodite klasu, znate sve o iz kon-
struktora i primenjuju rano povezivanje. U obi sludaja, rezultati kole aobijete
osnovnoj klasi i moT.ete pristupiti bilo kom njenom javnom ili za5tiienom dlanu' pri pozivu virtuelne funkcije iz konstruktora neie biti oeekivanr.
'fo znaci da su svi dlanovi osnovne klase ispravni kada se izwSava k6d u izvede-
noj klasi. Kada se pozove obidna funkcija ilanica, objekat je vei konstruisan,
tako da su definisani svi dlanovi svih delova objekta. Medutim, i tokom rada Destruktori i virtuelni destruktori
konstruktora rnoraitt biti definisani svi dlanovi koje on koristiti. Jedini nadin da Ne moZete koristiti rezervisanu red virtual za konstruktore, ali destruktori
se ovo obezbccli icste da sc prvo pozove konstruktor osnovne klase. U tom
mogu, a desto i moraju biti virtuelni.
slLrcajLr. konstrttktor izvcclcne klase zna da stl inicijalizovani svi dlanovi osno\rne
Konstruktor ima specijalan zadatak da sastavi objekat od dclova, pozivajuii
klase, kojitna nro2c pristrrpiti.,,saznanje da su svi dlanovi ispravni" unutar kon-
prvo osnovni konstruktor, a zatim izvedene konstruktore po
srnrkrora je takocle razlog cla, kacl gori ie moguie, inicijalizujete sve objekte redosledu
clanovc (objckte snreitcne u klasu primenom slaganja) u listi za inicijalizaciju.
nasledivanja (usput mora pozivati i konstruktore objekata dlanova). Slidno
tome, i destruktor ima specijaran zadatak da rastavi objekat koji moZe pripadati
Ako sleclite ovaj postupak, rnoT-ete pretpostaviti da su inicijalizovani svi dlanovi
hijerarhiji klasa. Da bi.se ro,postiglo, prevodilac generise toi tcoli poziva
osnovne klase i obiekti dlanovi tekuieg objekta. sve
destruktore, ari obrnutim redosledom u odnosu ni pozive konstruktora
. zna(i
da destruktor zapodinje od najniZe krase u hijerarhiji i ide ka osnovnoj
klasi.
Ponaianje virtuelnih funkcija u konstruktorima ovaj nadin je bezbedan i pozeijan, posto tekuii destruktor uvek moZe znati
da
Hijerarhija plziva konstruktora nameie jedno zanimljivo pitanie. Sta se de5ava dlanovi osnovne klase postoje i da su u ispra,rnom stanju. Bezbedno je,
iz
ako iz konstruktora pozovete virtuelnu funkci)u? MoZete pretpostaviti Sta bi se destruktora pozvati funkciju iianicu osnovne klase. Na taj nadin, destruktor
rlesilo tr obidnoi ftrnkciji ilanici: poziv virtuelne funkciie se razre5ava tokom moZe osloboditi resurse, a zatim pozvati sledeii destruktor u hijerarhiji,
koji ie
izvriar,anja, posto objekat ne zna da li ona pripada klasi u kojoj ]e definisana osloboditi resurse suoje klase itd. svaki destruktor zna izkoje Hase je njegova
firnkcija ilanica ili nekoj klasi izvedenoiiznie. MoZete pomisliti da bi se, radi klasa izvedena, aii ne zna koje su klase izvedene iz nje.
konsistentnosti, isto dogodilo i tr konstruktoru. Trebalo bi imati na umu da su konstruktori i destruktori jedine funkcije
za
Ako iz konstnrktora f oz-ovete virtuelnu iunkciju, koristi se samo lokalna ver- koje se sprovodi ova hijerarhija poziva (zato prevodilac automatski formira
odgo-
zija tirrrkcije. /-rraii cla rtlchaniz-arn virtuelnih funkcija ne vaZi za konstruktore' varajuiu hijerarhiju). u svim drugim funkcijama, ne poziva se automatski
i ver-
Ovo pravilo inta sntisla iz. clva razloga. Konceptualno, zadatak.konstruktora zi;'a iz osnovne klase), bez obzira na to di ii je viriuelna ili nije.
Funkciju iz
jeste cia napravi objekat (to i nije jednostavan podvig). U bilo kom konstruktoru, osnovne klase u obidnim funkcijama (virtuelnim ili obidnim) morate
izriiito da
ob jekat mo2e biti samo clelimidno formiran - moZete znati samo da su inicijali- pozovete.
z6var.rr ob jekti osnovne klase, ali ne moZete znati koje klase su izvedene iz tekuie obidno je destruktor sasvim odgovarajuii. Medutim, sta se desava ako hoiete
klase. Medutim, poziv virtr.rclne funkcije se prostire ,,unapred" ili ,,spolja' u hiie- da radite s objektom preko pokazivada na osnovnu klasu (opsteg
interfejsa)? ova
rarhiji naslerlivanja. Ona poziva fi.rnkciju izvedene klase. Kada bi to bilo tehnika je znatajna u objektno orijentisanom programiranju. problem polav-
ie
clozvoljeno u konsrnrkroru, poz-ivali biste funkciju koja bi radila s dlanovima koji ljuje kada hoiete da primenite operator dereie ni pokazivad osnovnog
tipa za
joi uvek nistr inicijalizovani, a to ie poLrz-dan recept za nevolju' objekat koji je napravrjen u dinamidkoj memoriji operatorom new.
Ako radi s
I)rtrgi razlog jc rl1ehanidker prirode. Pri pozivu konstruktora, on najpre inici-
jirlizrr jri svoj pokazivai'\'l)'l'll. lVIt'clr.rtitll, krltrstntktor nema nikakm informaciju
498 Misliti na jeziku C++ Poglavlje l5: polimorfizam i virtuelne funkcije
499
l
pokazivaienr na osnovnu klasu, prevodilac tokom operacije delete moZe samo Potpuno virtuelni destruktori
pozvati verziju destruktora osnovne klase. Zvudi poznato? Ovaj isti problem vir-
Iako su potpuno virtuerni destruktori
tuelne funkcije treba da reSe u op5tem sludaju. Sreiom, virtuelni pozivi se mogu dozvoljeni u standardnom c++_u, posto.ii
ogranidenje pri njihovoj upotrebi:
prirne'niti na clestnrktore, kao i na sve druge funkcije osim konstruktora. morate^napisati telo po,puno virruelnog
desrrukrora ovo se p.oiirri intuiciji-
: C15: Vi rtual Destructors. cpp [uro turt.iru.noz.
ii,li"ipr"o r,r,,
I I elna" ako je neophodno. rero funkcijet
r'/ Ponaian3e vi rtuel noq i nevi rtuel nog destruktora veoirrim, ro riobija smisao ako ima{e
umu da su konstrukrori i.destruktori ,a
linclude <lostream> por.un. operacije, narodito ako se prisetitc
da se uvek pozivaju svi destruktori
us i ng namespace std; ,'rri.Iri,i;i
definiciju potpuno vrrruelnog a.rrru[iorl,'kojekrasa. Ako histe mogli izostaviti
c1 ass Basel { tokom unistavanja objekta? iato p;;;;il. rero iunkcije bi ie pozivaro
publ i c:
tela [unkcije za porpuno virruelni
i povezivad zahievaju postojan.ie
-Base10 { cout .. "-Base10\n ; 1
aert.uttoL
Ako je funkcija potpuno virtuelna,
I; ali mora,imati.telo, u demu je njen znadaj?
Iedina razlikr,r*"1: a"r,rrt,ora.i obidnog virruelnog
destruktora jeste u tomel:,pr"o "l.iu"ino"g
sto ie potpuno
cl ass Derr vedl : publ i c Basel {
osnov'a klasa bude apstraktna, tako
vi'rtuelni destruktor prouzrokovati
da
publ i c: da ,e mozete nup.uuiii'oqliu, ornoun"
klase (mada bi ovo va7,o i ako bi
-Derivedl0 { cout .. -DerivedlO\n'; ) u," t";" irrga funkcija dranica osnovne krase
bila potpuno virtuelna).
);
stvari postaju mato zbunjujuie
ako izvodite klasu iz krase koja sadrZi
potpuno
c1 ass BaseZ {
;:):|n;ff:l::[fi"o razlikuod biro k"r;;,s. potpuno yirtuerne tunkcije, ne
publ i c:
vi rtual -Base2 0 { cout .. "-Base20\n"; ) il;
u d i n j e ni ci d a j ; rillrd:""Jfi[ll,.r#nx;il
ri:ff
. n o j kr as i D o laz j e
"
i; //: C15:UnAbstract.cpp
// Potpuno virtuelni destruktor.i se
cl ass Derj ved2 : publ i c Base2 {
// ponaiaju neob.idno
public:
-Deri ved2 0 { cout << "-Deri ved2 0 \n" ; } cl ass AbstractBase
{
I; pubi i c:
virtual -AbstractBase0 = O;
int mainO { );
Basel* bp - new Deri vedl I I Svodenje naviSe
del ete bp; AbstractBase: :-AbstractBase0
{}
Base2* b2p = new Derived?; ll Svodenje naviSe
del ete b2p; cl,ass Derived : public AbstractBase {};
I lll:- // Ntje neophodno redefinisan3e aestruktoraz
I)ri izvrSavanju programa, videiete cla delete bp poziva samo destruktor
osno\nrc klasc, clok delete b2p poziva destruktor izvedene klase, a zatim int main0 { Der"ived d; t ///,_
dcstnrktor osnovnc klase, a to je Zeljeno pona5anje. Propust da se destruktor ukoliko potpuno viluelna funkcija osnovne.
triini virtrrclnim jc poclmukla greika, poSto aesto ne utiae neposredno na klase nije definisana prilikom
nasledivanl'a, izvedena klasa biie
ponaSanje llrogrernla, ali neosetno nloZe dovesti do curenja memorije. Osim "p;;il;;;destruktorima.
nije sludaj' Medutim, prisetite r"'d; ovde, izgleda, to
p.;;"dirac..automatski pravi definiciju
toga, -in jenica da se orl'.,ija neko unistavan,e objekata moZe dodatno zamaski- destruktora za svaku klisu ako ri ," ,o ,. desava ovde: destrukror
rati prohlcrn. osnovne krase se automatski redefinise, ""'"."ii".
auto-au prevodirac pravi definiciju i
Iako je ciestnrktor, kao i konstnrktor, ,,izuzetna" funkcija, moguie je da klasa Derived nije stvarno apstraktna.
dcstruktor brrdc virtrrelan, poito objekat vei z-na kog je tipa (to ne z-na pri sada dolazimo do zanimijiv.og pitanja:
u demu je su.tina potpuno virruernog
izvrSavanju konstrrrktora). PoSto se objekat napravi, a njegov pokazivad \rPTR destrukrora? Za r azriku o o o.6ierr".'poiflr""
inicijalizuje, mogu se pozivati virtuelne ftrnkcije. fu nkcij e, m o ra tedefr nisa ti
njegovo relo' U izvedenoj krasi niste;;;;;;;i "i.ir"r.e
da defini.eie a..t.rttor, posto
prevodilac pravi destrukior umesto
virtuelnog destruktora i potpuno
r;.. p;, ;;"- u je razriia iz..lr"ouienog
virtuelnog destruktora?
500 Misliti na jeziku C++
lgglavlje I5: Polimorfizam i virtuelne funkcije 50r

Jt-.rlina razlika se pojavljuje Lr klasi sa samo jednom potpuno virtuelnom / /: C15:Vi rtual slnDestructors.cpp
lirnkcijonr: clestrtrktorom. IJ ovonr slrrdaju je jedini efekat potpuno virtuelnog // Poziv vjrtuelne funkcije iz destruktora
clcstnrktora cla spredi pravljenje objekta osnovne klase. Da su postojale i druge #i ncl ude <i ostream>
potpr.rno virtlrelnc funkcije, one bi spredile instanciranje osnome klase, ali ako us i ng namespace std;
ne nra rlrtrgih, upotrcbitc potpuno virtuelni destruktor. Iako je dodavanje vir-
trrelnog ciestruktora znacajno, nije toliko vaZno da lije potpuno virtuelan ili nije. class Base {
[)ri iz.vr5avanju sledeieg primera, videiete cla se telo potpuno virtuelne publ i c:
funkcije poz-iva posle verzije iz izveclene klase, kao i u sludaju bilo kog drugog virtual -Base0 { .

d estrukto ra: cout <<,,Base10\n,,;


f0;
Il: Cl5: PureVi rtual Destructors. cpp )
I I Ielo potpuno vi rtuel ni h destruktora virtual void f 0 { cout .. ,'Base::f
#include <iostream> 0\n,,; }

usi ng namespace std;


);

class Pet
class Derived : public Base {
{
publ i c:
publ ic:
vi.tual -Per0 = 0;
-Deri ved 0 { cout .. ,,-Der.i ved 0 \n,, I }
void f0 { cout .. ,,Derjved::f0\n,';
I; );
}

Pet::-Pet0 {
int main0
cout << "-Pet0" .. endI
{
Base* bp = new Derived; // Svodenje navi5e
)
deiete bp;

class Dog : publ ic Pet { | /l/:-


publ i c: Tokom poziva destruktora, funkcija Derived::f( se nepoziva,
) iako je funkcija
-Dos0 {
f( ) virtuelna.
cout << "-DoS 0 " << endl ; sta je razlog? pretpostavimo da je mehanizam virtuernih funkcija
-, bio kori-
) Sien u destruktoru. Tada bi bilo moguie da se pozove verzijayirtuerne
funkcije
I; jg ,,niZe" u hijerarh-iji nasredivanja od iekuieg desiruktora. Medutim,
\oju
destruktori se oozivaju,,odozdo navi5e,, (bd destruktorl klur.
najniZe uhijerahiji
int main0 { do osnor, rog destruktora), tako da bi se pozvana funkcija osranjara
na delove
Pet* p = new Dog; // Svodenje naviSe objekta koji je uei uniiten!.umesto toga, prevodilac rairesava'po,ziie
deiete p; II Poziv virtuelnog destruktora tokom
prevoden.ia i poziva samo ,,rokalnu" verziju funkcije.
zapazimo da i.to vai.i za
I I ll:- konstruktor (kao sto je ranije opisano), ari u sludaju'konstiuktora
nrle uiia dostu-
Sar,e't je cla, svaki put kada imate virtuelnu funkciju u klasi, odmah dodate i pna informacija o tipu, dok u destrukroru ta informacija (to jest,
ali nije pouzdana.
Vlfni posto;i,
r.'irtrrclni clestruktor (dak i ako ne radi niSta). Na ovaj nadin se obezbedujete od
bilo kakvih naknaclnih iznenadenja.
Formil3nje hijerarhije zasnovane na objekru
Virtuelne
-fokom
funkcije u destruktorima Tokgq prikazivanja kontejnerskih krasa stack i stash u ovoj injizi, ponavljao se
uniStavanja objekata, de5ava se ne3to Sto moZda ne biste odekivali. Ako ,,problem vlasni5wa'. ,,Masnik" je onaj dija je odgovornost da unistiobjekte
koji
iz obidne ftrnkcije ilanice pozovete virtuelnu funkciju, u pozivu se primenjuje su bilinapravljen dinamidki (kori5ienjem operatora new). pri koriSienju
kasno povezivanje.Za destruktore ovo ne val|bez obzira na to da Ii su virtuelni. kontejnera, problem je Sto oni moraju Uiti aovot,no fleksibilni,
da bi se u njih
U destruktoru se poziva samo ,,lokalna" verzija funkcije dlanice, a mehanizam mogli smestiti razliditi tipovi objekata. Da bi se to ostvarilo, kontejneri
su
virtuelnih lrrnkcija se zaobilazi. sadrZali pokazivade na tip void i nisu znali tadan tip smestenih
objekata.
Brisanje *
.pokazivada tipa void ne poziva destruktor, iako da kontelner nile
mogao biti odgovoran za uklanjanje svojih oblekata.
Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkci.,le 503
502 t-
je iz
ierltro rcsernje jt'prikazallo tt prinlertt Cl4:InheritStack'cpp' u kome
-Stack 0 {

pokazivade whjle(head)
klasc Stack izveclcna nova klasa koia je prihvatala i proizvodila samo
objekte tipa string, mogla ih je del ete pop0 ;
na strir.rg. [)oit() jC sarlr7ala sattlo pclkazivade na
pravilpriirrisitri. li, 1c bilo rl6bro re5enjc, ali ono zahteva da izvedete novu konte-
)
voi d push (0bject* dat) {
jnerrku klasrr za svaki tip koji hoictc c1a smeitate u kontejner. (lako ovo sada
head = new Link(dat, head);
rlclr,l" n;rptrnttt, zatiovoliiic tlirs clrl lloglavlja 16, rr kome se uvode Sabloni') i
[)roblcnt jc tt totrte Stokontejner treba cla sadrT.i viSe od jednog tipa, ali ne Zelite Object* peek0 const {
pri
da korisrite pokaz.ivaie na void. Drugo reienje je da se koristi polimorfizam, return head ? head->data:0;
cerrlu svi otiiet ti iz- kOnteir.rera rnoraiu biti iz-vecleni iz iste osnorme klase' Znadi,
)
kontejner sadrli objektc osnovne klase, a zatim pozivate virtuelne funkcije Object* pop0 (
problem vlasni$fva'
- kolkrctrr<t, p6ziyate virtttelne clcstruktore da biste re$ili if(head 0) return 0;
==
gvo re Scrijc k.risti pristup poznat kao hiierarhiia s jednim korenom (engl. Object" result = head->data;
sirtgllr-v6117e(l lrierarclty;) ili hijeiarhiia zasnouana rut obiektu (engl' object-based Link* oldHead = head;
se kiasa nivrhu hijerarhije (koren) obidno naziva,,Objekat".
Itiirart:trt,), poito head = head->next;
postoje in.,,-,,,g" drLrge preclnosti korisienja hijerarhije s jednim korenom; u su- delete oldHead;
Stini,.svi objektno oiiientisani osim C++-a, insistiraju na upotrebi takve
iezici, return resul t;
hijerarhije kacia rlctiniSete klasu, alrtomatski je izvodite, posredno_ili nepo- )

sreclno, iz. z.ajeclnickc osnovne klase koju su ustanovili autori jezika. U sluiaiu i;
iczika (.++, snrarralO se cla bi Obavez.rra upotreba
ove zajednidke osnovne klase #endif ll 0STACK_H ///:-
ltrouzrokovala koriiccnjc cloclatnih resLlrsa, tako da ie izostavljena. Medutim, Da bi se k-tasa po;'ednostavila, (obavezna) delinicija potpuno virtuelnog
rrt()Tcte ocllrrciti da rr svoiim projektirna koristite z-ajednidku osnovnu klasu,
a
destruktora i funkcija pop( ) (mogla bi se smatrati prevelikom za umetanje)
ova tcma ;e dalle razradena u u drugom tomu' umetnute su u datoteku zaglavlla.
I)a tti ic reSio problent vlasnistva, moZemo napraviti izuzetno jednostavnu Objekti tipa Link sada sadrZe pokazivade na Obiect umesto pokazivada na
osno\rnu klastr Object, ko]a sadrZi samo virtuelni destruktor. U kontejneru
klase
void, a kontejner tipa Stack ie prihvatati i waiati iskljudivo pokazivade na
Stack mogrr se nalaziti objckti klasa iz-vedenih iz Object: Object. Klasa Stack je sada mnogo fleksibilnija, poSto ie sadrZati veii broj
ll: Cls:OStack.h raziiditih tipova, ali ie i uni5tavati sve preostale objekte na steku. Po novom
// Upotreba hrjerarhije s jednrm korenom ogranidenju, (konadno ie biti uklonjeno kada budu primenjeni Sabloni, u
I r fndef 0STACK_H poglavlju I6) sve Sto se sme5ta u Stack mora biti izvedeno iz kiase Object. to ie u
rriefi ne 0STACK_H redu ako podinjete pisanje klase iz podetka, ali Sta ako vei imate klasu kao Sto je
string i hoiete da je smestite na stek? U ovom sludaju, nova klasa mora biti i
cl ass 0biect { string i Object, 5to znadi da mora biti izvedena iz obe klase. 'fo se naziva
publ r c: uilestruko naslediuanje (eogl. multiple inheritance); posveieno mu je celo
vi rlual -0b3ect 0 = 0; poglavije u drugom tomu. Kada proditate to poglavlje, videiete da viSestruko
i; nasledivanje moZe biti previ5e sloZeno i treba ga oprezno koristiti. U ovoj situ-
aciji je sve dovoljno jednostarmo, pa ne moramo da zaobilazimo zamke
0bavezra oe'tniciSa: viSestruko g nasledivanja:
rnl rne Ob.iect: :-Ob.tect0 {}
//: C15:0StackTest.cpp
class Stack { //{T} 0StackTest.cpp
#i ncl ude "0Stack. h"
struct Li nk {
0bj ect* data; #include ". ./requi re.h"
#i ncl ude <fstream>
Lr nk* next;
nxt) #i ncl ude <i ostream>
Link(0b.iect* dat, Link* :
#i ncl ude <stri ng>
data(dat), next(nxt) i)
i
* head;
using namespace stdt
publ i c:
Stack0 : head(0) {}
504 Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcije 505

,,, Upolreba vraeslrukog nasledivania. Potreban nam Je Preklapanje operatora


,/7'objekat ko3i 3e i string i Object: Operatori mogu biti virtuelni kao i funkcije dlanice. Realizacija virtuelnih ope ra-
class l'4yStrrng: publtc string, public Object { tora je aesto zbunjujuia, posto mozete raditi s dva objekta ei;e tipove ne znare.
pub)rc: Sa operandima nepoznatih tipova obiino rade matematidke komponenare,
za
-layStrinq 0 { koje se desto preklapaju oneratori. Na primer, razmotrimo sistem koji se bavi
cout << "bri se se znakovni ni z: << *this .< endl;
matricama, vektorskim i skalarnim velidinama, a sve tri su izvedene iz klase
)
Math:
l4yString(string s) : strinS(s) {)
i; //: C15 :0peratorpolymorphi sm.cpp
/ / Polinorfizam sa prekiopljenim operatorima
int marn(int argc, char* argv[l) { #i ncl ude <i ostream>
requrreArgs(argc, 1); ,// Argument je ime datoteke us i ng namespace std;
r fstream rn(argv[1] );
assr.e( r, a"qvLIl)r c1 ass Matri x;
Stack textl I nes; c1 ass Scal ar;
c1 ass Vector;
strrng Iine;
r,' Ci ta se datoteka i redovi se smestaju na stek:
whi e(getl I ne(in, i ne) )
1 1 class Math {
textl ines.ptrsh(new MyStrrng(l ine) ) ; publ i c:
// Uci tavanje nekih redova sa steka: virtual Math& operator*(Math& rv) = g.
MyStri ng* s; virtual Math& multiply(Matrlx*) = 0;
for(int i = 0; i < i0; i++1 1
virtual Math& multiply(Scalar*) = 6;
i f ( (s=(MyString*)text1 ines.pop0)==0) break; virtual Math& multiply(Vector*) = Q;
cout << *s '< endl; virtual -Math0 {}
del ete s l );
l
Lout << 'Preptlstd se destruktoru da obradi ostatak:" cl ass l,4atri x: publ i c Math {

endl; publ i c:
"
\ I ll,- Math& operator*(Math& rv) {
return rv.multiply(this); I/ drugo pozivanje
Iako je ovai printer sliaan prcthodnoj verziji programa za testiranje
klase
da su vero- )
Stack, zipaziieie da se samo i0 elemenata dita sa steka, Sto znaai Math& multiply(Matrjx*) {
vatno pr;ostali neki objekti. Po5to klasa Stack sadrZi objekte klase Object'
cout << "Matrjx* Matrix" << end'l;
pravilno osloboditi rcsurse, Sto iete videti na osnovu rezultata
tlesrnrktor r.nozc return tthi s;
p rogranla. )
iicfi.isa.j. k..rei.cra koji sadrT.e objekte klase Obiect razuman je pristup Math& multiply(Scalar*) {
rrl, i,ra(e jcrirrtr Siicrar.hiirr s jccl.i.t korenom (z-ato 5to vas na to primorava cout << "Scal ar * l"latri x,, << endl
jezik ili zal.rrcv da sve klasc bucllr izvcdene iz- klase Obiect). U tom sludaju se
;
return *thi s;
koristiti
rrttt,zhCrlrrlc da 1c svc tipa obiect, taktl cla nijc previSe komplikovano )
j.t,*'. \lcclrrrirl. iczikri (,++ r.tt-'tno7.ete oaekivati od svake klase, da pri- multiply(Vector*) {
k..te rr Math&
pada icdnoj hijcrarhiji, pa rte, ak,r prihvatite ovaj pristup' prinudeni dakoristite cout << "Vector* f,latrix" << endi;
i'iic.truko nasledivanjr', t) p.glavlju l6 iete videti da Sabloni re5avaju navedeni return xthi s;
problcrn ntnogo jeclnostavnije i elcgantnije' )
);

cl ass Scal ar : publ i c Math {


publ i c:
f,lath& operator* (Math& rv) {
s06 Mislitr na jeziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkci.le 507
r
I

return rv.rnultrpiy(th1s); ll drqo pozivanje Radi jednostavnosti, prekJopljen je samo operator *. cilj je da pomnozirno bilo
koja dva objekta klase Math - treba zapaziti da se mnoZenje matrice vektorom
Math& multiply(l'4alrix-) { razlikuje od mnoZenja vektora matricom. problem je sto, u funkciji main( ), izraz
cout << 'Matrr x * Scal ar" .. endl ; ml * m2 sadrZi dve reference tipa Math svedene naviie i, samim tim, clva objekta
return -thi s; nepoznatih tipova. virtuelna funkcija moZe da uradi samo jedno slanje, to
lest da
) odredi jedan nepoznat tip objekta. Da bi se odredila oba tipa, u ovom primcru sc
l4ath& multlply(Scalar*) i koristi tehnika uiiestruko rasporediuanje (engl. muttipli dispatching, u kojoj
cout << "Scal ar * Scal ar" <. endl ; jedna virtuelna funkcija poziva drugu virtuelnu funkciju. Do trenutia, drugog
return *tht si poziva odredeni su tipovi oba objekta i moZe se pozvati odgovarajuia funkcija.'To
t
nije na prvi pogled odigledno, ali, ako pazljivije pogledate primer, trebalo bi da
l,lath& mul trply(Vector*) {
uodite smisao. ova tema je detaljnije obradena u poglavlju obrasci projektouanja,
cout << "Vector * Scal ar" .< endl ;
u drugom tomu.
return *thi s;
I

I; Svodenje naniZe
: Kao Sto moZete pretpostaviti, posto postoji svodenje navise pomeranje uz
class Vector pub1lc t4ath { -
hijerarhiju nasledivanja - trebalo bi da postoji i suodenje naniZe (eng\. downcast_
publrc:
f,lath& operator* (Math& rv) {
ing) za pomeranje niz hijerarhiju. svodenje navise je jednostavno, posto se klase
return rv.multrpiy(thjs); I I drugo pozivanje uvek pretvaraju u op5tije klase dok se pomerare uz hijerarhiju nailedivanja. To
)
znadi da je pri svodenju navi5e jasno da je klasa izvedena iz neke osno'une klasc
Math& mLrl trply(l'tatrlx*) {
(obiino samo jedne, osim u sludaju vi5estrukog nasledivanja), ali pri svoclenjrr
cout << l'lalrr x * Vector" .. endl; naniZe obiino postoji nekoliko moguinosti za konverziju. Konkrernije, Krug je
return "thi s; tipa oblik (to je svodenje navise), ali ako pokusate oblik da svedere nuniz.,
i mozete dobiti Krug, Kvadrat, Trougao itd. problem je otkriti nadin za bezbedno
Math& mul trply(Sca1ar") { svodenje nanize. (Io5 je znaiajnije da se prvo zapitate zasto svodite nanize,
cout << 'Scalar * Vector" .< endl; umesto da koristite polimorflzam da bi se automatski otkrio pravi tip. Izbe-
return *thi s; gavanje svodenja naniZe obradeno je u drugom tomu.)
) C++ podrZava dynamic_cast, posebnu izriiitu konuerziju (engl. explicit cast),
Math& multip1y(Vector*) { koja je opisana u poglavlju 3. To je bezbedno xtodenje ianizelengi. type-safe
cout << "Vector * Vecto! " .. endl; downcast). Rezultat operatora dynamic_cast
return *thi s;
ie biti pokazivad na zeijeni tip
samo ako je konverzija ispravna i uspesno izwSena, inade ie biti nula, sto uka-
)
zuje da nije naveden ispravan tip. Ovo je jednostavan primer:
t;
/ :
/ Cl5 :Dynani cCast. cpp
rnt marn0 i #i ncl ude <'i ostream>
Matrix m; Vector v; Scalar s; us'l ng namespace std;
['1ath" mdth[] . { a*, &v, &s };
for(inti=0;i.3'i++) cl ass Pet { publ i c: vi rtuat -pet 0 (});
for(rnt:=0;i.3;i+*){ class Dog : public pet {};
Ilath& m1 - *mathIi]; class Cat: public pet {};
Math& m2 = *math[i];
m1 * m2; int majn0 {

l Pet* b = Cat;
new // Svodenje navi5e
\ lli:- // PokuSaj konverzije u Dog*:
Dog* d1 = dynamic_cast<Dog*>(b);
// Pokusaj konverzije u Cat*:
so8 Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcije

Cat' ci2 = dynami c_cast<Cat*>(b) ;


'if (sp != 0)
cout << 6l . " .< (long)d1 .. endl; cout << "Toje kvadrail,, << endl ;
coul << "d? - ' .. (long)d2 .. endl; // Statjako kretanje je SAMO tri k za poboljSanje efi kasnostr ;
i':- I f konverzija dynamic_cast je uvek bezbednr3a. l,ledutim:

Oltcnrtor dynarnic cast, IttoZctu ltritncrliti silmo na pravll polimorfnu hiie- // )thet* op = static cast<0ther*>(s);
rarhijrr koja irla virtu('lrtc lirnkciie, poito odrcduie stvarni tip na osnolT r infor- // Daje prigodnu porrk, o greSci, dok
0ther* op2 = (0ther*)s;
ntaciia iz tabelc \.lAIll,tr. Ovde osnovna klasa sadrZi virtuelni destruktor i to je
/ / ne daje
clovoljno. ll ltrnkciji mainO pokazivaa na Cat se svodi navi$e u Pet, a zatim se
pokgsava s\/odenie naniT.e pokazivaaa na Dog i cat. oba pokazivaaa se ispisuju,
l / / /,-
il l)ri iz-\,r!avan ju progralna ietc vicleti da neispravno svodenje naniZe daje rezu- u navedenom programu koristi nova moguinost koja se je opisana u drugonr
Itat nula. Naravno, pri svakom svodenju naniZe morate Se uveriti da rezultat tomu u poglavlju o mehanizmu prepoznauanja tipa tokom i2uriauanja (ingl.
konYcrz.ije nije jednak nuli, Osim toga, ne bi trebalo da pretpostavite da ie run-time type identification, RTTI). RTTI vam omoguiava da otkrijeie infol-
arlrcsa rr pokazivaarLr ostati porpLlno ista, posto se, pri svodeniu navise odnosno maciju o tipu, izgubljenu pri svodenju navise. operator dynamic_cast i pred-
nartrZr., poltcka(l lncnia vrcdnost pokazivaaa (konkretno, u sludaju visestrukog
stavlja jedan oblik prepoznavanja tipa tokom izwsavanja. Ovde se rezervisana
n aslccl ivan ja ).
red typeid (deklarisana u datoteci zag]avlja <typeinfo>) koristi za odredivanje
Olterator dlmamic -cast koristi vrlo malo dodatnih resursa, ali ako ga desto tipova pokazivaaa. Mozete videti da se tip pokazivada svedenog navise u shape
koristitc u prograrru (tada bi trebalo cla preispitate projekat), moZe dovesti do redom uporeduje s pokazivaaem na circle i pokazivadem na Sq.r*". Mehani-
problenta s perforntansalta. Ako potlzdano znate s koiim tipom radite, mozete zam prepoznavanja tipa tokom izvrsavanja mnogo je sloZeniji od toga, ali
kr:rirrrti static cast. l:ro pt itttera: mozete pretpostaviti i da bi bilo prilidno jednostarmo da, uz primenu virtuelne
funkcije, realizujete sopstveni sistem informacija o tipovima.
i I : Cl5: Stati gati on.cpp
cHi erarchyNavi
Napravljen je objekat klase circle, a adresa je svedena navise u pokazivad na
,/,1 Kretanj e po hi j erarhl j r' k1 asa pomoau operatora stati c-cast Shape; drugaverzija ovogizrazapokazuje da koriSienjem konverzije static_cast
*i ncl ude <i ostream>
mozete izriditije izwsiti svodenje navise. Medutim, posto je svodenje navise
#i ncl ude <typet nfo>
uvek bezbedno i uobidajeno, smatram da je, u ovom sludaju, izridita konverzija
us i ng 1d-espace std;
zbunjujuia i nepotrebna.
class Shape { public: virtual -Shape0 {}; }; Mehanizam RTTI je korisien za odredivanje tipa, a zatim je operatorom
class Crrcle : public Shape {}; static_cast tip sveden naniZe. zapazite da je u ovom resenju postupakisti kao da
class Square : public ShaPe {}; se koristi dynamic-cast, a programer klijent mora ispitati rez-ultat da bi se uverio
cl ass 0ther { i I u uspe5nost konverzije. Obidno iete hteti da situacija bude odredenija nego u
pretposlednjem primeru i koristiiete static-cast raciije nego dynamic cast (joS
-sto
int main0 { ;'ednom: paZljivo ispitajte projekat sistema pre nego upotrebite
Crrcle c; dynamic_cast).
Shape* s = &c; I I Svodenje navi 5e: uobi iajeno i i spravno Ako hijerarhija klasa nema virtuelnih funkcija (to je sumnjivo re5enje) ili ako
i,l Izrtatttje, a1i nePotrebno: imate druge informacije koje vam omoguiavaju bezbedno svodenje nanize,
s = static_cast<Shape*>(&c) ; statidko svodenje naniZe je malo brZe nego dynamic_cast. osim roga, operator
1,/ (Posto je svodenje naviSe tako bezbedno j uobiiaieno' static-castvam neie dopustiti da izadete iz hijerarhije klasa, za razliku od tradi-
,' ,t moZe postati zbunjuiuce) cionalne konverzije, tako da je bezbedniji. Statidko kretanje po hijerarhiji klasa
Crrc'l e* cP = 0i uvek je rizidno i trebalo bi da koristite operator dlmamic casi, osim u izuzetninr
Square* sP = 0; situacijama.
,'r'staticko kretanje po hiierarhiii klasa
/7'zahteva dodatnu informaciju o tlpu:
rf(typeid(s) == typejd(cp)) // C++-ov RTTI SaZetak
cp = static_caSt<Circle*r(s) ;
i f (typeld(s) .= typeid(sp))
Pollmorfizam, realizovan u jeziku c++ pomoiu virtuelnih funkcija, znadi
,,razliditi oblici". U objektno orijenrisanom programiranju desro se javljiju jedna
sp = statj c_cast.Square*r(s) ;
spolja5njost (zajednidki interfejs osnovne klase) i razli3ite oblike-koilstenya te
i f(cp !. 0)
je " << endl spoljaSnjosti: razlidite verzije virtuelnih funkcija.
cout << "To krug l ;
F
slo Misliti na jeziku C++ Poglavlje I 5: Polimorfizam i virtuelne funkci.le 5lr I
I

sre Virlcli cla niic rnogltic ni razunleti ni napraviti primer 6. Napravite hijerarhiju nasledivanja klasa glodara, sa osnovnom klason
lJ0ronr poglavljrr
Rodent i izvedenim klasama: Mouse, Gerbil, Hamster itd. U osnovnr
prilinrorlrzrllu lte z koriit'clria apstrakcile poclataka i nasledivarlja Polimorfrzam
jt, tch.ika ko ja sc t.r. t,.7.e ltosrnatrati iz.olovano (kao, na primer, oznaka const ili klasi navedite metode zajednidke za sve glodare i redefini5ite ih
izvedenim klasama, da bi se obezbedila razlidita ponaSanja, u zavisnos:
iskitr switch), l)osto racli santo rr skloptr vcz-a meciu klasama, kao deo..velike
slikc". I)rrrgc rnogucrr()sti jcz.ika o++, koie nisu objektno orijentisane, kao
Sto su od tipa glodara. Napravite niz pokazivada na Rodent, popunite g
argttrtrettti, aesto deluju zbunjujuie kada se tako razliditim pojedinadnim tipovima i pozovite metode osnovne klase, d
,rcklapa.it, i 1.,,,iir.r.,,,,,.r,a.i biste videli Sta se deSava.
prikazirjtr kao olticktne. Nentoite se prcvaritr: ako nema kasnog povezivanja,
trcttra tti llrllilltorfizrla. 7. Izmenite zadatak 6 tako da umesto niza pokazivada koristite ver
I)a ltiste u pr<tgratninra efikasl.to koristili polimorfizam, samim tim i obiektno tor<Rodent*>. Uverite se u ispravnost oslobadanja memorije.
oripnrisane ichnikc, morirte pro5iriti svoj pogled na programiranie. Osim 8. Polazeii od prethodne hijerarhije sa osnovnom klasom Rodent, izvcdit
clai.va i ,u^rka pojedinacne Llase, trcba da razmisljate io zajednidkim ele- klasu BlueHamster (plavi hrdak) iz klase Hamster (da, plavi hrdak postoj
nrenrirna klasa i irjlirovim meclusobnim vezama. Iako ovo zahteva znaiajan imao sam jednog u detinjstvu), redefini5ite metode osnovne klase i poki
pro-
.apor, vrcdno je r*;cla, posro se program brierazviia, k6d bolje organizuie, Zite da nije potrebno menjati kdd koji poziva metode osnovne klase, rar
grarn postaje pro5iriv i jednostavnije se odrZava' prilagodavanja novom tipu.
jezika, ali postoje joS
Polirnorfizarll z-aokruZuie objektno orijentisana svojstva 9.Polazeli od prethodne hijerarhije sa osnovnom klasom Rodent, dodaj
(uvode se u poglavlju 16 i detalinile
dve vazne moguinosti c++-a:' Sabloni nevirtuelni destruktor, napravite objekat klase Hamster primenom operr
obraciu ju r.r drr-rgont romu) i obrada izuzetaka (obraduje se u drugom tomu)' Ove tora new, svedite pokazivad naviSe u Rodent* i primenite delete na pok;
nlogl'titlostivanlpruT-ajuveiumoiuprogramiranju,kaoidrugekarakteristike zivad, kako biste pokazali da ne poziva sve destruktore u hijerarhi
objektno orijen tisanog jezika. Promenite destruktor tako da postane virtuelan i pokaZite da je sar
ponasanie ispravno.
10. Polazeii od prethodne hijerarhije sa osnovnom klasom Rodent, izmeni
VeZbe 'llP l'hinkinF, irt C++ Annotaled solution
Rodent, tako da postane potpuno apstraktna osnovna klasa.
llrierrjr rzalrrrrrilt zltialrkr nirlrzt se tt t'leklrotrskotr rlokttlncnltt
(,rrtr/r'krlli \l llloT{'l)leLlltll sr\\'ell atlrtlse rvrvrr'llrrtccli:ktll'ctlltr' 1 1. Napravite sistem za kontrolu vazduSnog saobraiaja sa osnovnom klaso

1 . Nitllrar'itt, ]C(ln()Sta\rllrl Irijcrarhijtr ,,obiika.,: osnovnu klasu pod nazivom Aircraft i razliditim izvedenim tipovima. Napravite klasu Tower ko;a sadr
Shape i izvcrlcne klase circte, Square i Triangle. u osnovnoi klasi
napra- vectorcAircraft'r> i Salje odgovarajuie poruke razliditim letilicama ko

r,,irc Virrrrclrtr.r ftrnkciirr pocl tlazivom draw( ) i redefinisite ie


u izvedenim kontroliSe.
pravite u
kiasanta. Napravite riiz pokazivada na objekte klase Shape, koje I 2. Napravite modei staklene baSte, izvodeii razlidite tipove biljaka iz osnora
dinarnr-koi men'roriji svedite (i pokazivade navi5e) i pozovite funkciju kiase Plant i ugradujuii u staklenu ba5tu mehanizme za gajenje biljaka.
,l3.
draw()prekopokazivacaosnovneklase,kakobisteproveriliponasanje Izmenite primer Early.cpp tako da Pet bude potpuno apstraktna osnovr
v.irtuelrle fr.lnkcije. Prolazite kroz- k6d korak po korak, ako program za klasa.
otklarlian je greSaka to podr2ava'
.l4.
Izmenite primerAddingVirtuals.cpp tako da sve funkcije dlanice klase P
2. promcnire zadatak l, tako da lunkcija draw( ) bude potpuno virtuelna' budu potpuno virtuelne, ali napiSite definiciju za funkciju name(
potpuno
Pokuiaite cla napravite <lbjekat tipa Shape. Pokusajte da pozovete Promenite, po potrebi, klasu Dog, koristeii definiciju funkcije name( )
virruelnu ltrnkciiu iz konstruktora i vidite Sta se de5ava. Napi5ite definiciju osno'u.ne klase.
firnkcije <iraw( ), koia je i dalje potpuno virtuelna' I5. NapiSite kratak program koji pokazuje razliku izmedu pozivanja virtuel;
3. Proiirujtrii zaclatak 2, napravite funkciju koioj se prenosi objekat
klase
funkcije iz obidne funkcije dlanice i iz konstruktora. Program treba ,

ShapeT,rot,rtlrlnostiikaoargunlentproslediteizvedeniobjekatsveden dokaZe da ova dva poziva proizvode razlidite rezultate.


naviic. I)rovcrite sta se cleSava. Prepravite iunkciju tako da argument bude I 6. Izmenite primer VirtualslnDestructors.cpp izvodenjem klase iz Deriver
relercnca objekta tiPa ShaPe. redefinisanjem funkcije f( ) i destruktora. U funkciji main( ) napravl
4. lzltletrite program Cl4:Combined.cpp tako da funkcija f( ) bude virtuelna objekat novog tipa, svedite ga naviSe, zatim primenite operator delete.
Lr osnuvrr<lj ilasi. lzrnenitc funkciju main( ) tako da svodi
tip navi5e i I 7. U reSenju zadatka 16 u svakom destruktoru pozivajte funkciju f( ). Obj
ju.
1'roziva vi rtttclntr lunkci snite Sta se de5ava.
5. lznterrritc program Instrument3.cpp dodaiuii virtuelnu funkciju prepare( )'
Pclzovite ltrnkciiLr prepareO ttntttar funkciie tune( )'
512 Misliti na jeziku C++ Poglavlje l5: Polimorfizam i virtuelne funkcije 5li

1 8. Napravite klasrr s jednim podatkom dlanom i izvedenu klasu koja dodaje 28. (Malo teze) Napravite osnovru krasu X bez podataka eranova i konstruk
d^igi prdatak ilan. NapiSite posebnu funkciiu koioi se prosleduje objekat tora, ali s jednom virtuelnom funkcijom. Iz nje izvedite klasu y
koja nenr
,,.,,nr,,,. klasc 7;o urednosti. Ona treba da ispisuje veliiinu tog objekta, izriditi konstruktor.
.prevedite
program na aiembrersti ;ezit i' ogr.au;,
f
prrntcrr jrrlrrcli operator sizeof. LI turrkciii main( ) napravite obiekat izve- k.d, da biste utwdili da ri je konsiruktor napisan r pozvan .u x
i, oLu
ilCnc klase, ispiSitc rrjcgovr.r veli(:inu, a z-atirn pozovite svoiu funkciiu. Obia- tako, Sta taj k.d radi. Ob.fasnire ono Sto oikri;ete" po.to klasa X ner. I

snire ita se rleiavit. podrazumevani konstruktor, zaSto prevodilac ne prijavljuje


gr.St.,f
19. Nirpiiitc jt'drtostavitn prittter l)ozlva virttlelnc funkciie i prevedite ga na 29. (Malo teZe) Promenite zadatak 28 tako sto iete napisati konstruktor
za ob
asembler.ski jczik. I)rrtnaclite asetnblerski k6d za poziv virtuelne funkcije, k-lase, svaki ie konstruktor_ pozivati jednu virtu;lnu
funkciju. prevedit
proi'itaite i obiasnite k6d. program na asemblerski kod. odredite da li se pokazivadu
\rprR doderjuj
20. NapiSite klasr,r s iednort.r virtuelnom i iednom nevirtuelnom funkcijom. wednost u svakom konstruktoru. Da ri vas prevodilac koristi
mehanizar
Izveclite nonr klasu, napravite objekat te klase i svedite ga navise u poka-
virtuelnih funkcija u konstruktoru? Ustanovite zasto se i
darje pozr'
zivad tipa osnovne klase. L)potrebite funkciju clock( ) koja se nalazi u lokalna v er zija funkcije.
<ctime> (poslirT.ite se priruinikom o bibliotekama jezika c) da biste 30' (Napredno) Da pozivi funkcija objektu prosledenom po wednosti
rtisu bi
iz-nterili raz.liku izmedu poziva virtuelne i nevirtuelne funkcije. Da biste rano povezani, poziv virtuelne funkcije mogao bi pristupati
delovima k<r
videli razliku, moraiete da napisete vise poziva svake funkcije unutar nisu postojali. Da li je.to moguie? Napiiite tOa u tt.. sl poriru
,lrtr.tn
petlje z-a merenje vremena. funkcija i proverite_da ri to pro,rr.oku,e gresku. Da bisie
objasn,i ov
ponasanje, ispitajte sra se deSava pri prosredivanju
2I . Izmenite primer C14:Order.cpp dodavaniem virtuelne funkcije osnovnoj objekta po wldnosti.
klasi rnakroa Ct-qSS (neka neSto ispiSe) i pretvaranjem destruktora u vir- 3l . (Napredno) Tadno utvrdite koliko je viSe wemena potrebno
za poziv vi
tuelnr-r firnkciju. Napravite obiekte razliditih potklasa isvedite ih navise u tuelne funkcije na osnovu informacija o asembrerskom jeziku
rus'.g pro..
osnovnr.l klasu. Provcrite pollasanie virtuelne funkciie i ispravnost pra- sora ili nekog drugog tehnidkog priruinika, pronadite broj procJsorskii
vljcnja i trniitavanja obiekata. taktova signala potrebnih za obidni poziv, i upotrebite gu
su b.tle_ toktor,
22. Napiiite klasu s tri preklopljene virtuelne funkcije. Izvedite iz nje noru za izvr5avanje instrukcija virtuelne funkcije.
klasu i reclefiniSite iednu od funkcija. Napravite objekat izvedene klase' 3 2 ' Primenom operatora sizeof odredite
veiidinu pokazivada \?TR. Zatim pri
Mo7-ete Ii pozyati sve fr.rnkciie osnovne klase preko objekta izvedene klase? menite viSestruko nasledivanje na dve ktase koje sadrze virtuerne
iunkcijt
Svedite naviSe adresu objekta u osno'"ni tip. MoZete Ii pozvati sve tri Da li ste u izvedenim krasama dobili jedan ili dva pokazivada
vprRi
funkcije preko objekta osnovne klase? Uklonite redefiniciju funkcije iz 3 3 ' Napravite. k.lasu koja sadrZi podatke
dlanove i virtuerne funkcije. Napisit,
izvedene klase. MoZete Ii sada pozvati sve funkcije osno\rne klase preko funk,ciju koja ispituje memoriju objekta ove klase i ispisuje njegov,
ob jekta iz.veclene klase? razlidite delove. Da biste ovo postigli, moraiete eksperimentalno
da otkri
2 3. lz.rncnite progrant VariantReturn.cpp da biste pokazali da se isto ponasa jete gde se u objektu nalazi pokazivad VpTR.
pokazivai: reference. 34'uz pretpostavku da. virtuelne funkcije ne postoje, izmenite
progran
24. Kako u l)rogramu Early.cpp mozete odrediti da Ii prevodilac pri pozilu Instrument4.cpp tako da pomoiu operatoia dynamic_cast
napravit,
koristi rano ilr kasno povezivanie? (lstanovite 5ta radi vaS prevodilac. ekvivalent pozivima virtuernih funkcija. objasnite ;asto ye ovo tosa iaela.
2 5. Napravite osnovnu klasu koja sadrzi funkciju clone( ) Sto waia
pokazivad 35.Izmenite program StaticHierarchyNavigation.cpp tako da,
umesr(
na kopryrr tekuieg obiekta. Izvedite dve potklase koje redefinisu funkciju kori5ienja mehanizma RTTI jezika i++, n"apravite Jopstveni
mehanizan
cloneO',takodavraiakopijenjihovihtipovaUfunkcijimainOnapravitei pomoiu poziva virtuelne funkcije whatAml( ) osnovne klase
i nabrolivol
sveclite navi5e objektc dva iz-vedena tipa, zatim pozovite funkciju clone( ) tipa { Circles, Squares }; .
za svaki orl njih i proverite da li su klonirane kopije ispravnih podtipova' 36. Polazeii od primera pointerToMemberoperator.cpp
l:ksperirnentiSite s fr,rr.rkcijom clone( ) tako da vraia osnovni tip, zatim pokaZite da polimorfizam funkcionise i s pokazivadima
iz poglavlja 12
na dlanove, dak
pokusajte cla vratite odgovarajuii izvedeni tip. Da Ii vam pada)u na pamet
;

ako je operator ->* preklopljen.


situacije u koiirna ie neophodan poslednji navedeni pristup?
26. Izrnenitc prograrn OstackTest.cpp dodaiuii svol'u klasu, zatim primenite
viSesrrr.rko nasleclivanie i iz dodate klase i Object izvedite klasu koja se
rno2e smesttti u Stack. 1'estiraite svoju klasu u funkciji main( )'
2 7. Dodajte tip Tensor programu OperatorPolymorphism'cpp'
llii. ,, . .., , , .fi ,, ;
. ..1...,::r; ::. r, ..

. ,:;
:, .

l6: Uvo-b "u,SABtoue


Naslddivanj e i' slaganj e omo guiavaju po no\rno ko ri5ienj e obj ekt -
nog koda. Sabloni ujeziku C** o*oguiavaju ponovno lioriiienje
izuornogkoda.

I
5r6 Misliti na jeziku C++ Poglavlje l6: Uvod u 5ablone 5I7

Iako stt iablilni (engl. tenrplare's) programska tehnika op5te


namene u jeziku // Da bi bilo zanimljivjje, dodajemo Fibonaiijeve brojeve:
(.++, kacla.,,, ,,r.,l.iii iz.gledalo ie cla iu u suprotnosti s upotrebom hijerarhiia
for(inti=0;i<20;i++)
(prikazanih nakraju poglavlja l5)' i s.push (fi bonaccj (i ) ) ;
k.rrrc j.erskih klasa zaslovanih na objektima
Na pri,rrcr, srarrlarclrri (.++-ovi konte jneri i algoritmi (obja5njeniu dva poglavlja // Udi tavamo i h i i spi suj emo:
for(intk=0;k<20;k++)
drLlgogtolriaknjigc.napravljenistli.skljudivopomoiuSablonaiprogrameriih cout << js.pop0 << endl;
nrogtr relativno lako koristiti. j ///,-
u. kontejnere koji
ijvo t-,oglavlje prikazuje osnove 5ablona, ali je takode i uvod
objektno orijentisanog programiranja i skoro u potpu- Klasa IntStack je jednostavan primer potisnog steka. Radi jednostavnosti,
.,-, n.nnvn" kontponente
biblioteke' Videiete da se ovde je napravljen stek fiksne velidine, ali ga moZete izmeniti tako da se auto-
r.tosti srt realiz.ovarri putem .(ublono standardne c++
Stash i Stack, s ciljem da ovladate matski Siri, zauzimajuii dinamidku memoriju, kao u sludaju klase Stack koja je
kroz celu knjigu koriste primeri konteinera,
ovinr kontejneiskim klasama; r.r ovo poglavl;e ie biti dodat i po)am iteratora' prethodno razmatrana u knjizi.
printeri Siblona, iz- drugog toma (koje sadrZi Funkcija main( ) dodaje cele brojeve na stek i uditava ih sa steka. Da bi primer
lako str k..reineri sar.,rieni
poglavlje o iablor.ri.ra z-a .apiedni ,ivo) naudiiete da postoie i mnoge druge bio zanimljiviji, celi brojevi se formiraju funkcijom fibonacci( ), koja generiSe
primene 5ablona. brojeve Fibonadijevog niza. Ovo je datoteka zaglavlja, u kojoj se deklari5e
funkcija:
//: C16:fibonacci.h
Kontej neri // Generator Fibonaeijevog niza brojeva
preipostavinro cla hcliete da napravite stek, kao Sto smo radili vi5e puta dosad' i nt fi bonacci (i nt n) ; / / I :-
Radi lednostavnosti, tlva klasa ie sadrZati cele brojeve: Ovo je realizacija:
I l: Cl6: Intstack.cPP / I : Cl6:. fi bonaccj .cpp {0}
/,/ Jednostavni stek s cel im brojevima #j ncl ude " . . /requl re. h "
I I 'l \ r'boracc i
rinclude "fibonacci'h" jnt fibonacci (int n) {
lrnclude' . .,/requlre'h" const int sz = 100;
#include <iostream> requi re(n < sz) ;
us i ng namesPace std ; static int flsz); / I Injcijal jzovano nulom
f[0]=f[1]=1;
c'l ass IntStack {
// Irali nepopunjene elemente niza:
enum {ssize = 100 }; int i;
inl stackIssize]; for(i=0;i<sz;i++)
i nt top; if(fIi] == 0) break;
publ t c: while(i .= n) {
IntStack0 toP(0) {}: f[i]=fIi-1]+fIj-2];
void Push(int i) ( j ++;
require(top <. ssjze, "Previse dodavanja funkcijom push0"); )
stackIloP++] = i; return f[n] ;
) | ///:-
',.:.::llltl.op o, "Previse ucitavania runkcijom pop0"); Ovo je prilidno eflkasna realizacija, po5to se brojevi generi5u samo jednom.
' Koristi se statidki niz celih brojeva, i oslanja na dinjenicu da ie prevodilac inici-
return stack [--toP] ;
jalizovati nulom elemente statidkog niza. Prva petlja for pomera indeks i do
)
1. prvog elementa niza koji je jednak nuli, a zatim petlja while dodaje nizu
Fibonadijeve brojeve, sve do dostizanja traZenog elementa. Zapazite da se petlja
int main0 {
while preskade ako su Fibonaiijevi brojevi do elementa s indeksom n vei
IntStack is; inicijalizovani.
518 Misliti na jeziku C++ Poglavlje I6: Uvod u iablone
5r9
t
Potreba za kontejnerima di gov pri me r,
Oi'iglcdno li: da stek celih brojeva nije veoma znadaina alatka. Konteineri posta- y i:i:y:',1},1'tll,:o.T
nasledivanje. o, f "
"1i.1-;l,1tJ"
ui"" ro rearizovaro, ,,,uru
, sr e n je u ze r i s u j e ci
1tr rrcophotlni kitrlit po-rtctc cla pravite obiekte u dinamidkoj
memoriji opera-
toroln new i cla ih urriStavate opcratorom delete. U opsem siuiaiu, tokom sadr2i elemen,. ffi:il".fi'ilH
I:tr#?:'-r"'x:
prograptiranjit lr('zltate koliko r-'e vam objckata biti potrebno. Na primer, u
or.::,o^r:1"n. r.rur.
r5)' U Sma,tarku, nikada ne pravite ijil; (.ui;;;;;;;;';r';,.r.;,, pogravtja
krasu od poierka. IJmcsto
toga, morate,v.,k
sisrcprrr za kontrollr vazclrrinog saobraiajtr, ne Zelite da ogranidite broj aviona izvesri klasu iz neke oa posto;etrt,.p."r"r"i" krasu na,sriini,,
kojinta sistcnt ntoTc trpravljati. Nc 7-elite cla se prekine izvrsavanje programa izvedere ktasu iz nje imato j";;;;;.-o* Jnol to,, z.tir"
smanju je vaSe nanore (i oeigledni prednost, posto
sanlo zato 5t0 jc prekoraien neki broj. L-l sistemu za projektovanje pomoiu i..
oblaSnjava ruJio proroaite
blioteku klasa pre neg" s," mnogo wemena uicci bi-
racunara, bavite se mnoStvom oblika, ali samo korisnik odreduje (tokom ri"r,l."i" ;i:* programer
, S;uii;;]ku'r".kraju posrajuSmartarku).
na
izvriavania) koliko ie oblika biti potrebno. Ako se potrudite, i sami iete smisliti To takode znaii da.sve kiur"
jednog stabla
priliiarr hroi slii rtih primera. nasledivanja' pri oravljenju
bla. Najveii deo srabri ,.c po.,L;i
,""" kr;r;,';;;:te je izvesri iz nekedeograne ovog
Progranrcri na jczikrr C, koji se oslanjaju na virtuelnu memoriju da obradi i. sra-
problerne ,,trpravljanja memoriiom", aesto smatraju uznemiravajuiom ideju o kl asa p od n azivom o?i::: _ ;;,; i"'L]fr,"i"r" kt.r, ,;;ll;.:rll, u ror.n
il;;; k"t r" rra.ri rrrii;;, ;iiili,o 1"
koriSien jtr operatora new, delete i kontejnerskih klasa. Na C-u se obiino napravi ovo je jednosravan rrik, posto jf ,rrtu
klasa u hijerarhiji krasa Smal-
n r c, n er.

jedan ogroman globalni niz., dija velieina prevazilazi potrebe programa. ovaj Italka (i Iavel) izvedena iz idase -znati " da svaka
u svaki kontejner (pa i kontejne.
ou""t, iJto krasa moze biri smestena
pristLrp moZcla ne zahteva mnogo razmiSljanja (ni poznavanje funkcija malloc( )
ifreeO), ali ltroizvocli programe koji nisu sasvim prenosivi iu kojima se skrivaju hijerarhije krasa u iednom stabru, -;;;;i;;e.sren u drugi kontejner). ovaj rip
,urnouun nu osnovnom opstem
ripu (cesro se
podnrukle gre5ke. i, ilJir"""
naziva obiect, a ro ie ,rrea;
." ,,ir,;"r".hi;; ;u;;;;;;,,i;
Osim roga, ako napravite veliki globalni niz objekata u C++-u, izvrsavanje
ooP-a, kao polimorfir,lT:?l
i;;;il;;
MoZda sre vei duri ovaj nuii,
ia -,e
objekru,,
to neki ,""i
k6psrlrktora i clestrrrktora moZe znacajno usporiti program. Mnogo bolje deluje
klasom nekog srienog imena)
,ir"ri"r" r,i"lu.i,i;,
kr"r; ; ouiect ftri "rr"rri koncepr
k;.;;;ir
pristrrp jez-ika (-++: kacl vatn treba objekat, napravite ga operatorom new a i kontelnerskim krasama koje
sadrZe object.
pokaziva- ntr objekat sntestite tr kontejner. Kasnije ga pokupite i radite s njim. Posro se bibrioreka k.lasa
Smartart'" t"ri.til,
Na ovaj naiin, ltravite samo one objekte koji su vam zaista potrebni. Takode, na i posto prvobitni c++ prevodio ci T.noco duZe od bibrioteke c++_a,
nisu i.*ii'uiuLio,.ke konrejnerskih klasa, iz_
new
l.roictkr-r prograrna vam iesto nisu poznati svi uslovi inicijalizacije. Operator d' il;il;rilia"uiurioier,;;;#;';
ornoguc,ava da sar:ekate dok se ne5to desi r.r okruZenju, pre nego Sto napravite f,::lii:i"*T So",o##;'" '" ;n* ,e
jekat. '.,o
ob
sadrZi pokazivade na znaaajne obiekte. Te
1,,",g;;;;i,,#'::,,1._1'-"r,."..Jliff TffJl:.Jx,":..xif li;;il:;nJ;_*
;e otkriven pri pokuSaju korisienla ton,"ir"'rr"tif,
Najcciic ietc praviti kontejner koji nu*
ob;cktt'tlcte prar,iti prirnertorn operatora new a dobijeni pokazivad iete sme6tati Problem ie bio Sto se.u Smallialku
fi ,1.jini'arugih ohjekrno orijenrisanih je_
rrk6rrtt:jrrcr (rr-rolclit ictc ga konvertovati naviSe u ovom postupku) iiitati poka- zika' za koje znam) sve krase
.ri""r""ir;;;#; rz Jedne hijerarhi;e, ari to
t)yir( iz kontejncra kada ne5to hoiete da uradite s objektom. Ova tehnika proi- o* ne vazi
zvodi najflcksibiltri;tr, ttpSttr vrstlt programa. #ffi ,U"r:il::Tl[o ? nii".".rri rJl
r r"",
"*an
u na obj ektu, s,n en im ko n j j
te _

p ro izvo d ea, -;
a ; ;l;;' "-Tif H ;|:,:,ti',l j#"f ;xi*,,::,X; : i *",:f
dovodi uporreba te hiierarhije, j;r;"'';;;;;lio i?l
Pregled 5ablona gava,u c programeri). (ako
,;";ii;;r'"1;;liuo,o ,toriscenja resursa, koje izbe_
auru u kontejnersku
Sacla sc pojavlluje prohleln. Imate klasu Intstack, koja duva cele brojeve. Medu- svoje hijerarhije zasnovane na oble{tu? p.our".n krasu iz
izgreda ovako:
rim, l.rorreban vanr je stek koji mo2e da sadrZi ili oblike ili letilice ili biljke ili neSto
i'r.tvrto. I)r'ltot,tto ltisartjc tzvornog koda niie posebno pametan priStup u sluda;'U (Ni su i zvedene
jczika koji podr2ava ponovno korisienie koda. Mora postojati neki bolji nadin. iz
Kon tej ner klase Objekat)
I)ost<,rjc tri tehnike z.a ponovrlo kori5ienje izvornog koda u ovoj situaciji: pri- (SadrZi pokazivade
srrrpr svojsrvcn jeziku C, koji se navocli radi uodavanja raz-lika; pristup Smalltalka, na objekte tipa
koji je z-na-ajno Ltticao rta (l++; pristLlp jczika C++ - Sabloni. objekat)
Resenie na ieziku C. Naravno da pokusavate da pobegnete od pristupa jezika
(,, poSto jc neprijatar), pocllo2an grcskan'ra ipotpuno neelegantan. U ovompri-
srrrprr, kopimtc iz-vorni kod klasc Stack i rueno ga meniate, iineii nove greske
tokorn ovog I)osttlpka.'lil svakako nijc narodito produktivna tehnika.
U lu"l., izuzerak prosti,,r.yl
I" efikasno\ri, or)i nr\rr i/vedeni
Keith Gorlen je napravio l:Or:Ii.*adi
bibliorekrr OOps. dok i" f,i,,',,.r"1.1.r,,,rr
iz klirrge[iss1
\,rr.ror,il.on) rrr..;r.r,rr z r /,r..i\..,,.
Misliti na jeziku C++ Poglavlje I6: Uvod u iablone
52t
520

parametar. Kada koristite sablon, preuodila.c zamenjuje


parametar, slidno kao r.r
PoStrl(.++prlclrzavaviScnczavistlillhiicrarhija'smalltalkovahiierarhiiazasno- pristupu s makroima, ari je sablon jasniji i koristi se jedntstavnile od makroa.
ttr tle l'rtnkciolliic n aroiito ciobro' sada ne morate vise brinuti o nasledivanju, odnosno
Ileie nic ic izglcclalo t';';;;;;
"0,-l,,',r,r',rfri.f ;; mo7'c'tt' imativise hijerarhija nasledivania'
ie reSiti pro- da koristite kontejnersku krasu. pomoiu satlona
o slaga.,lu, tuau noc.,.
,r. vise klasa: visestruko nasledivanje konte]'nera"m oLete ianapra-
tacla ltisre rlogli izvesti rii.,, vite konkretnu verziju za svoj problem, na sledeii
blen.r. /.ato raclite sledeiJ't;;il;
pti""' ie naveden na kraju poglavlja 15): nadin:

Kontej ner
Obl i ka

r_oout L
1
T--
Kvadrat

Prevodilac se brine o svemu, a na kraju dobijate upravo


I
onakav kontejner
kakav vam treba, umesro sloZene hijerarhije nuru.
L
0Krug suutJn, ;.;ik,,
koncept parametursklS.t1na (engl.'parameterized typeste).6ruga
c++ realizuje
korist od pri_
stupa zasnovanog na sabionima jeste da programer
novajrija, kiji se mozda ne
snalazi u nasledivanju, odmah moZe koristiti zaokruzene
oblik, ali, po5to ie izvedena
klase kontejnerske kJase
Sarla klasa oobrik irna osobine i ponasanja (kao Sto smo desto u knjizi koristili vector).
t'''"'iiti u Konteiner. Pod1t": yv1$enie klasa
i iz. klase Obiekat,
'ozt"tt kako Ui mogte Uitisvedene navi5e
u Ooblik
oKrug, oKvadrat ittr' 'ttnpi'nJno ie'
pJna(anje Svari.se.brzo zapetliavaiu'
zadrT.ati ispravrto Sintaksa Sablona
i tako
'-
i)',,
p, n i p,."
aur na l J' i'; [I l'jT]]i H:' :'Jffif"X ffi :fi:'*:;
u' ;' ;;l; i Rezervisana red temp-rate saopStava prevodiocu da
definicija kJase, koja sredi,
viur(' na objcktLr, orl koiilr ic veiirra 7'amenJena
problema obuhvata jedan ili vise neodredenih tipova. u trenutku kada se generise k6d
potrebno za reiavanie opStih
prigovoriti tla ic vi'cstrrrit'llt"fttr*^"ie izbegavati sloZenost stvarne klase na osno\,'u Sablona, ovi tipovi moraju biti
definisani, tako da ih pre_
progranriranio, oli u^..l;;;;; ;";;
t"tt ie naibolje
li9"tld.u vodilac moZe zameniti.
spcciialnim slu(alevima'
riit'stntkog ttit'lctltvltttla' t'sim u sintaksu sablona prikazaiemo kratkim primerom niza
dije se granice prove-
ravaju:

Reienje Primenom na iablona konceptu-


//: Ct6:Anay .cpp
obiektu' uz vi5estruko nasledivanje' #incl ude ". ./require.h',
Iako je hiierarhiia '-utnuJ*u mudno' Stroustrup je u
alno jednostarnu, ;;;; Lt njeno korisienie
za hijerarhiiu zasno-
#i ncl ude <i ostream>
''nuliJ')i; prihvatliivom zamenom usi ng namespace std;
svoioj kn jizi, pokazao <i" t"t""o kao ve.liki pretprocesorsh
vanu na objekru., Kontejnerske klase.su.naprurii.n"
bilo koiim tipom' Kada ste templ ateccl ass
makroi s argumentim;i"l; ;;"gli
biti zamenjeni T>
tip' pozivali ste makro' class Array
htcli cla napravite tt'nitlnit 'u odrldeni
{

niit'hio u skladtrc po'io1"Coln Iiteraturom o Sma]ltalku enum { size = 100 };


\.tzalrrst, ovai [)risttrl) niie
i pt'malo glt"'u'un U suSrini ga niko T A[si ze] ;
i ltt,gt rttttcr''kittr iskttstvotrr' a bio 1c publ i c:

za'-'?L,c]l:.1.1'::'L?,:T"iboratori-
T& operator[](jnt jndex) i
""'i,"',1\'i'.r,,"rcrne.tr sr't Strotrstrup i tim require(index >= 0 && index < size,
ga i premeSta'
janra izrt'renili pr,t)uitni fiittt'1-) tn'ot'uima' fol!anostavliujuii "Indeks niza je izvan dozvoljenih granica,,);
prevodioca' Novo sredslvo za zamenu
tl rlotnen neturn A Ii ndex] ;
irrr'i iz drlnlt'r,,, 1"t''p't'tt''ttra t''upto'nt i pi"attu'lja sasvim drugadiii nadin
koda nazvano ;t sot'i"n' "ngl' f
oblektnog koda' kao u )

r)on()\'rtt' tlpotrcht' rt"lo'o tt'i"*to ponovrlog kori5ienia );


ponovo korisri izuorni kdd Konteinervi5e
sltrcajrt rraslcclivanja i 'lirgania' iahlon
oUlect' nego ledan nedefinisani
ne sadrzi opsttr osnovrtti;i;;' pod naz-ivom

1986
slrorrslrtrp' prro iztlan jc' Ad(lison-wesle\''
;;;**-,-,rlltr"('
, i. ,1,1 L, r,,,'rr r' rz l"zlfll \ll\
Misliti na jeziku C++ Poglavlje t6: Uvod u iablone
522 s23 f-
templ ate<c1 ass T>
rnt marnO 1

nt' j a; c'l ass Array {


Arraycl
Array< f1 oat> fa; enum ( size = 100 );
T A[size];
for(lnt I - 0; i < 20; i++) ( publ i c:
ra[r] = i " i; *
faIr] = float(i) t.+tq; .I. T& operator[] (i nt i ndex) ;

for(int3=0;j'20;i++) templ ateccl ass T>


COUI<<i"":""iahl
.. ", " .. fah] << endl; T& ArraycT>:;operatorU (int index) {
nequire(index >= 0 && index. s.ize,
\ t I i:- "lndeks njza je izvan dozvoijenih granica ,,);
Klasa izglccla tlo[]it'aieno, osilll rcda: return AIi ndex] ;
templ ate<cl ass T> )

koji saopitava da ie T parametar koji se zameniuie i da


predstavlja,ime tipa'
-fakoclc vidite cla se T koristi u klasi na svim mestima gde bi se inaie nalazio int main0 {
Anraycfloat> fa.
oclrcdcni tip snrc(tcn u kontejner' fa[0] = 1.a1a;
is-tom funkcijom:
t,l.,r.,nii se u obiekat tipa Array dodaju I iz njega 'itaju koristiti s obe ) ///,-
da moZe
prcklopljenim operator;rn tl' On u'iCu referencu' tako
se
durednost)'zapaztted'ase uz svako obraianie imenu klase Sablona,
srrarrC zrrakir joclnakosti rau'tr", ikao lt,rerlno.srikao mora se navesti rista argumenata
ako ie indeks izvan dozvoljenih sablona, kao u ArraycT>::operato.U.
l.rrnkcija require( ) toristi za ispisivanje porr.rke
verziju ste rnogli koristiti da biste obeleZava argumentima iz lisie
r";i;iii;
;;'.;.,';;,;;rl,",i.. ruu."
granica. 1)oito jt: operator Il unletnrrt' ovu u.gr*"ruiu'sabrona, toto ui .r. a'obilo
izvrsavania programa, azatim stveno ime klase za svako instancirinje .lecrin-
isproltali cla li sc pr.t nrorul,i granicc niz_a tokom SuULonr.
verziie programa'
biste uklonili ltrnkciitr require( ) iz konadne
ilftrnkcijimain()rn,,Z.,"videtikakoje)ednostavnonapravitiklaseArray Datoteke zaglavlja
koje sadrTe iazlidite tipove obiekata' Kada napiiete: cak i ako defini.ete runtcile koje nisu
umernure, obiino iete Zeleti da smesrire
sve deklaracije i definicije-za sibron
Arrayci nt> i a; u ,"anr"autot"oJ;;&,,r].. irila"
ovim narusava uobidajeno prarr,o au,JiJ.)ugravlja: a" ,"
Array<f1 oat> fa; ,,Ne smestajte
(to se naziva instanci' zauzima memorijski prostor" (time nista sro
prevoclilac clvapltt zanlcrljuje parametre Sablona Array viSestrukih.definicijar, ari su definicii.
se, rokonr povczivanja, spr.r,cavairr greskc
',a,,1e;,aabi trapravicl ,tu",."''"'generisaneklase(engl' generatedcla'sses)'okojima suuronu poseban sruiaj. prevodirac
tom trenutku rezeryisati memoriju, nece u
(Razliaiti prevodioci obele'
,r.lerc razmi5ljati ton ,, nr.u-"y-int i Array-float nego ie eekati dok se to ne z.atraZi(instan_
ciranjem sabrona)' a prevod,ac i p"rErir"e
lavajtr irnena na razliiite nadine.) Te klase su poput
onih koje biste napravili imaju mehanirn,e za uttanlarl"
vrsestrukih definicija identiinog
nrcr"roltt zatllenolll pararnetara, sanlo Sto ih
prevodilac pravi umesto vas kada satrona. iiti c"t", radi jednosta,"nosri,
uvek smeSrari kompletnu dekraiaciju skoro
na nekoliko mesta u proglamu pro- iJ"nr-,i, Sabrona u datorcku zagravrja.
ile llniSctc objekte ia i fa. Ako se Sablontr U nekim
koristiti istu definiciju, ili ie povezivad siruaciiama moZe biti po,r.uno'iu
sle clrr jrr isti parantctri, prevodilac ie uvek odvojenu cpp datoteku, da bi.se.isprlnifi
smestitc a.hri.,[',rurona u
spo jiti s','c dcfrnici je tl icclnr't' p"..Uri zahtevi (na prirner, da Sablon
moZe da se instancira samo u jedno;
Wndo*souoj dll datoteci). V"Cl,",u p."uoai
laca ima mehanizam koji ovo o*oguJu"u,
Jil ,noru,. da proudire dokumen-
Definicije funkcija koje nisu umetnute
lunkcije ilanice u Sablouu
taciju svog prevodioca.
Neki ljudi smarraju da,sme.tanje
Svakako postoje situacij6, treba-definisati obi.ne kompletnog izvornog koda za rearizaciju
Prevorlilac mora naiii ,iu'a.nu'utllu template pre definicije funkSiil
fl1s datoteku zaglavlja omoguiava drugima
d;;k;;;, i menjaju k6d, ako kupe biblio-u
,rethod.i primer ir-*;"j;; ;; bi ,.
i" pokurula definicija obidne funkcije cla: teku' ovo bi mogro pred-stavlati p,iur"-,
Ji ,avisi.od nadina posmairanja: da
nice tr Sablonu:
li se kupuje proizvod iti usrugaraio:rG;;;;;izvod,". tada morate sve preduzeti
da ga za.titite, a verovarno neiete
11: C16:ArraY2.cPP irpoireitii^orni k6d, nego samo prevedeni.
dlanice
Medutim' mnogi posmatralu sortver "i kio i,rr,rg,.l, e"t
// Deflnicija obldne funkcije 5ab'lona ivise ocr roga, kao pretpratnu
rr nclucle "../requi re.h"
Misliti na jeziku C++ Poglavlje l6: Uvod u iablone 525
524

da vi nastante Sledi preradeni primer za testiranje Sablona:


rrslugrr. Kupcittta jc llotretlrlo vaSe struino znanje' oni Zele
,dr7.a'a.ie .vog dela iru,,uur.u trpotrebliivog koda, kako oni sami to ne bi morali //: C16:StackTempl ateTest.cpp
ratliti rkiik.5i sc rrr.gli posvetiti .st,orrl ,oslu. Mislim da ie vas veiina kupaca / I Iestiranje jednostavnog Sablona steka
na kocktt svoj odnos s vama. Kao i I {.t]r f: bonacci
s.ratrari clrag.r:e nirn i ncJc T.elcti cla stavliajtr /
mal.br. jre irsobe kole bi racliie ukralc nego kupile k6d ili ga razvile same, ni kupci #i ncl ude "fi bonacci . h"
strtti'ttrttn zllaniLl verovatno nistr clorasli' #i ncl ude "StackTempl ate.h"
varlr []o
#i ncl ude <i ostream>
#i ncl ude <fstream>
Klasa lntStack kao 5ablon #i ncl ude <stri ng>
Kontcjener i iteriltor iz prograrna IntStack'cpp realizovan ie' pomoiu Sablona' using namespace std;
kao opSta korrtejnerska klasa:
int main0 i
I I : Cl6:StackTemPlate.h StackTempl ate<i nt> i s;
// Jednostavan Sablon steka for(inti=0;i<20;i++)
# i fndef STACKTEI'lPLATE-H i s.push (fi bonacci ( j ) ) ;
#def i ne SIACKTET'4PtATE-H for(intk=0;k<20;k++)
#include "../require.h" cout << is.pop0 << endl;
i fstream i n ("StackTempl ateTest. cpp") ;
lempl ateccl ass T>
assure(in, "StackTemp'lateTest.cpp") ;
cl ass StackTemPl ate {
string line;
enum { ssize = 100 i; StackTempl ate<strj ng> stri ngs;
T stack Issi ze] ;
whi le(getl ine(in, l i ne) )
i nt top; strings.push(1ine);
publ i c: while(strings.size0 > 0)
StackTemPl ate toP 0 : (0) {i
cout << strings.pop0 << endl'
voi d push (const T& i ) {
| //1,-
require(top < ssize, "Previse dodavanja funkcijom push0");
stack[toPr'] i; Iedina razlika u odnosu na raniju verziju je u definisanju objekta is. U listi
l argumenata Sablona definiSete tip objekta koji stek i iterator treba da sadrZe. Da
I poPO i bi se prikazala opStost Sablona, napravljen je i StackTemplate za znako",ne
requrre(top'0, "Previse crtania funkcijom pop0 ); nizove. Testiran je uditavanjem redova iz datoteke izvornog koda.
return stack [--toP] ;

)
i nt si ze0 { return toP; }
Konstante u Sablonima
i; Argumenti Sablona nisu ogranideni na tipove klasa, nego moZete koristiti i
#endtf ll STACKTET'4PLATE-a lll,- ugradene tipove.Vrednosti ovih argumenata tokom prevodenja postaju konstante
za konkretno instanciranje Sablona. Za ove argumente moZete koristiti dak i
Zapal.iteciaSablonpraviodredenepretpostavkeoobjektimakojesadrZi.Na podrazumevane wednosti. Sledeii primer omoguiava da deflni5ete veliiinu klase
primer, StackTemplate unutar lunkcije push( ) pretpostavlja da zaT postoji Array tokom instanciranja, ali obezbeduje i podrazumevanu wednost:
koje
opcraror ciociele. Mogli biste reii da 5ablon ,,implicira interfejs" za tipove
moZe sadrZavati. //: C16:Array3.cpp
(engl // Ugradeni tipovi
Drrrgim reiirna, Sabloni obezbeduiu mehanizam slabe prouere tipoua kao argumenti 5ablona
u,eak rypingl u jcz-iku c++, koji inade ima strogu ploveru tipova' umesto insisti- #include ". ./require.h"
#i ncl ude <i ostream>
,ania cia oblckai brrdc konkretnog tipa da bi bio prihvatljiv, slaba provera tipova
pozivaju za odredeni using namespace std;
sa,r.ro z.ahtera rla ,uosroie oclreclene funkcije dlanice, koje se
objekat. Na taj naein, sa slabom proverom tipova, k6d se moZe primeniti na
suuki nbi.kut koji prihvata navedene pozive funkcija dlanica i zato ie mnoSo templatecclass T, int sjze = 100>
cl ass Array {
fleksibilniji.5 T array[size];
:, S\1,ntrlr)(lr rr Sntirllralkrr i I,r,llr<rnrr prirnenjtrjtr slabu provertt tipova, takO da
ovim jezicima nije potreban
lt,'lr rr z.t,r,i.,lrl,rt,;t I I 'rlillrli i lrt'z (ltlllrltlll rlolliialr'(llllotle
;26 Nlisliti na jeziku C++ Poglavlje l6: Uvod u iablone 527 rl
publ ic: pristupanja. Ova tehnika se naziva lenja inicijalizacijaili inicijalizacija na zah-
T& operatorIl ( j nt j ndex) { teu (engl. lazy initialization) i moLete je koristiti ako pravite veii broj objekata,
require(index >= 0 &&index < size, ali ne pristupate svima i Zelite da u5tedite prostor.
"lndeks nrza je izvan dozvo'ljenih granica"); Zapazi(,ete da se u oba Sablona, wednost size ne sme5ta u klasu, ali se u
return arrayIi ndex] ; funkcijama dlanicama koristi kao da je podatak dlan.
)

int length0 const { return size; }


l; Klase Stack i Stash kao Sabloni
Problemi ,,vlasni5tva", koji se ponavljaju s kontejnerskim klasama Stash i Stack,
c1 ass Number (
a koji su viSe puta dosad razmatrani, potidu od dinjenice da ovi kontejneri nisu
fl oat f; mogli tadno znati koje tipove sadrZe. NajbliZe reSenju je bilo da je klasa Stack
publ r c:
,,kontejner objekata klase Object", Sto se moZe videti u primeru OstackTest.cpp
Number(float ff - 0.0f) : f(ff) { }
na kraju poglavlja I5.
Number& operator= (const Number& n) {
Ako programer klijent ne ukloni izridito sve pokazivade na objekte koji se
f = n.f ;
r,alaze u kontejneru, trebalo bi da kontejner moZe pravilno da oslobodi memo-
return *thls;
riju. Znadi, kontejner,,je vlasnik" svih objekata koji nisu uklonjeni i zato je odgo-
voran za njihovo brisanje. Prepreku je predstavljalo to Sto brisanje zahteva
)

operator fl oat ( ) const { return f; }


poznavanje tipa objekta, a pravljenje opSte kontejnerske klase zahteva zanema-
fri end os t ream&
operator<< (ostream& os, const Number& x) {
riuanjetipa objekta. Pomoiu Sablona moZemo napisati kOd koji ne zna tadan tip
return os.< x.f; objekta, a novu verziju jednostarmo instanciramo za svaki potreban tip. Pojedi-
I
nadni instancirani kontejneri znaju koji tip objekata sadrze i zato mogu pozvati
); odgovarajudi destruktor (pretpostavljajuii, da postoji virtuelni destruktor).
Ispostavlja se da je, u sludaju klase Stack ovo priliino jednostavno, po5to se
templatecclass T, int size - 20> sve funkcije dlanice mogu napisati kao umetnute:
class Holder {
Array<T, size>* np;
//: C16:TStack.h
publ i c:
// Klasa Stack kao Sablon
#i fndef TSTACK_H
Holder0 np(0) {} : #defi ne TSTACK_H
T& operatorll (int i ) {
require(0 <= t && i . size); templ ate<c'1 ass T>
1 f( !np) np - new ArraycT, size>;
class Stack {
return np->operator[] (i ); struct Link {
I T* data;
int length0 const { return size; }
Li nk* next;
-Holder0 { delete np; )
Link(T" dat, Link* nxt):
); data (dat) , next (nxt) {}
)* head;
rnt marn0 { publ i c:
Hol der <Number> h;
Stack0 : head(0) {}
for(rntj=0;i.20;r++) -Stack 0 i
hIr] = rl whi I e(head)
for(intJ=0ii<20;j++) del ete pop 0 ;
cout << h[j] " endl' )
\ lll,- voi d push (T* dat) {
Kao i rar.rije, Sablon Array je kontrolisan niz obiekata i spredava vas da pristu- head = new Link(dat, head);
pate elementinta s ir.rdeksima izvan dozvoljenih glanica. Klasa Holder je slidna )

klasi Array,ali saclrZi pokazivaana ArrayLrmestoobiektatipaArray.Ovai poka-


zivai se ne rnicijaiizrr je u konstrttktoru, nego je iniciializaciia odloZena do prvog
Misliti na jeziku C++ Poglavlje l6: Uvod u iablone 529
s28

de1 ete s;
T* peek ( ) const {
) // Destruktor brj5e druge znakovne njzove.
return head ? head->data:0;
I
// Pokazuje da se jspravno uniitavaju objekti:
StackcX> xx;
T. popO i
for(intj=0;j<10;j++)
rf(head == 0) return 0;
xx. push (new X) ;
T* result = head->data;
Lrnk* oldHead = head; | ///,-
head = head-'next; Destruktor zax je virtuelan, ne zato Sto je to ovde potrebno, nego zato sro bi
del ete ol dHead; se objekat rc< kasnije mogao koristiti za duvanje objekita izvedenih-iz klase X.
return resul t; lav17ite koliko je jednosta'mo napraviti raziidite wsre stekova za ripove
) string i x Primenjujuii sablon, dobijate najbolje iz oba sveta: jednostarmost
); upotrebe klase Stack i ispra'rno uklanjanje objekata.
#endif ll TSTACT-H ///:-
poglavlja 15'
Ako rrporeciite ovai primer s primerom OStack'h na kraju Sablon dinamickog niza pokazivata
videiete da ie klasa Stack prividno ista, osim Sto je klasa Obiect zamenjena
je takode skoro identidan, osim Sto vise Reorganizovanje koda klase pstash u Sablon nije tako jednostavno, poSto neke
paramerrom T. Program za testiranje
nasl;divaniem izvede nova klasa od string i funkcije dlanice ne bi trebalo napisati kao umetnuie funkcije. Medutim,
,'en,a ,ar-l,,g,r da se vi5estrukim u
postoji klasa MyString koja sludaju Sablona, te definicije funkcija i darje pripadaju datoteci zaglavlja (pre-
OUi"., (tlak'.se vise nc koristi ni klasa Obiect). Ne vodilac i povezivad vode raduna o problemima visesrrukih definicija). KOd je
nova klasa koja pokazuje da kon-
i.spisulc porukr.r prilikom brisania' pa ie dodata
veoma slidan prethodno navedenom, ali eete zapaziti da je koral uveianja
tcjncr tipa Stack trri5t: sadrTane objekte: (koristi ga inflate( )) parametar Sablona koji ima podrazumevanu vrednost (i
ne
//: C16:TStackTest.cPP odnosi se na klasu, vei na ceo broj). Korak uveian jamozese izmeniti u trenutku
//{I} TStackTest.cPP instanciranja (zapazite da to znadi da je korak uveianja konstantan, pa biste
#i ncl ude "TStack. h" mogli prigovoriti da uvecanje treba da bude promenljivo tokom Zivotnog veka
#include "../requrre.h" objekta):
#include <fstream>
{include <iostream> //: C16:TPStash.h
#i ncl ude <stri ng> #ifndef TPSTASH H

us:ng namespace s1 d; #defi ne TPSTASH-H

class X {
template<c1ass T, int incr = l0>
publ i c: class PStash {
vr rtual -X 0 { cout <<
rr-X rr
" end1 ; } int quantity; // Broj sktadiita
I; int next; // Sledeei prazan prostor
T** storage;
int main(int argc, char* argv[] ) { void inflate(int increase = incr);
requireArgs(argc, 1); // Argument je ime datoteke publ i c:
ifstream in(arqv[1]); PStash0: quantity(0), next(0), storage(0) {}
assure ( i n, argv [1] ) ; -PStash 0 ;

Stackcstri ng> textl i nes; int add(T" element);


string Iine; T* operator[] (int index) const; // Uzjma se element
// j smeitanie redova u stek:
Cltan3e datoteke // Uklanja se referenca iz ovog objekta pStash:
whi1e(getl ine(rn, ine)) 1 T* remove(i nt 'i ndex) ;
tex tIi n e s' pu s h( n ew s t r i n g( 1 i ne )) ; // Broj elemenata u nizu:
/,/ Nekr redovl se uzimaju sa steka: int count0 const { retunn next; }

strl ng* s i );
for(int i - 0; i'101 i++) 1

if((s = (string*)textllnes'pop0)==0) break; templ ateccl ass T, 'i nt i ncr>


cout << *s " end'l ; int PStash<T, ino^>::add(T* element) {
Misliti na jeziku C++ Poglavlje l6: Uvod u iablone
r
I
530 53t

I f (next >= qv6nti tY) Podrazumevani korak uveianja, koji se ovde koristi, mali je,
kako bi funkcija
rnflate(incr); inflate( ) sigurno bila pozvana. Nu tul nadin se mozemo uveriti
da funkcija radi
storage Inext**1 = el ement; lspra\mo.
return(next - l): ll Broj indeksa Da bi se ispitalo upravljanje vlasniStvom, sledeia klasa
ie izve5tavati o
) pravljenju i uni5tavanju objekata i garantovaie da se svi napravljeni oblekti
uniStavaju.
7 asnr itvo preostal i h pokazi
r' V) vaia:
temp) ate<c1 ass T, i nt j ncr>
//: C16:AutoCounter.h
#ifndef AUT0COUNTER
PStash<T, incrr: :-PStash0 { H
#define AUTOC0UNTER
for(int i = 0; i < next; i++) {
#include "../requi re.h',
H

delete storagelil; I Prazni pokazivaai


I su u redu
#include <iostream>
storage Ii ] = 0; I I Samo radi si gurnosti
#include .set, // Kontejner standardne biblioteke
I C++_a
#include <string>
del ete [] storage;
)
class AutoCounter {

T, i nt static i nt count;
templ ate.cl ass i ncr>
T* PStash<T, incr>::operator[] (int index) const (
int id;
class CieanupCheck
require(jndex >= 0, {
std: : set<Autocounter*> trace;
"PStash: :operator[] indeks ie negatjvan") ;
publ i c:
jf(index r= next)
void add(AutoCounter* ap)
return 0; I I Da ukaze na kraj {
trace. i nsert (ap) ;
require(storageIindex] != 0,
)
"PStash: :operator[] vraca prazan pokazivac");
void remove(AutoCounter* ap) {
// Daj e poka zi vai na el ement :
requi re (trace. erase (ap) == 1 ,
return storageIi ndex] ;
"Pokusaj da se AutoCounter izbrise dvaput,,);
)
)

ass [. i nt I lcr>
ternp I ate<c1
-C1 eanupCheck 0 ,,-C1
{
std: : cout << eanupCheck ,,<<
T* PStash<T, incr>::remove(int index) { 0 std : : end1 ;
require(trace.size0 == 0,
// operator[] proverava i spravnost:
T* v = operatorU(index); "Nisu jzbrisani svi objekti k1ase,,);
.'UklctnJanje' Pokazivaca:
)

rf(v 1.0) storageIindex] = 0; );


statj c Cl eanupCheck veri fi er;
return v;
AutoCounter0 : id(count++) {
)
verifier.add(this) ; // prijavljuje se
I, int incr>
std::cout << "napravl jen[,, .. i6 .. ,'1 ,'
lemplate<class
<< std::end1;
void PStash<T, jncr>: :inflate(int increase) {
const int psz - sizeof(T*); )

T** st = new T*[quantity + increase]; // Spreiavanje dodel j i vanja i konstrui sanja kopi ranjem:
AutoCounter(const AutoCounter&) ;
memset(st,0, (quantity + increase) " psz);
memcpy(st, storage, quantity * psz);
void operator=(const AutoCounter&) ;
publ i c:
quant i ty += i ncrease;
del ete [] s tordge; I I Staro s kl adi 5te // Sano ovako se mogu praviti objekti:
sf; I I Pokazuje na novi prostor u memorrji
static AutoCounter* create0 {
storage =
return new AutoCounter0;
)
)
tendif I I TPSTASH_H ///: -
532 Misliti na jeziku C++ Poglavlje I 6: Uvod u 5ablone 533

-AutoCounter ( ) {
Po5to su sve funkcije dlanice realizovane kao umetnute funkcije, datotcka
std::coul << "unistava[" <' id realizacije sadrZi samo definicije sratidkih podataka dlanova:
.. "l " .. Std::endl; //: C16:AutoCounter.cpp {0}
veri fi er. remove (thi s) ;
// Oefinicila statidkjh dianova klase
l #i ncl ude "AutoCounter. h"
// Ispi suju se i objekti i pokazi vadl :
AutoCounter: :CleanupCheck AutoCounter: :verifier;
friend std: :ostream& operator<<( 'int AutoCounter: :count = 0;
std::ostream& 0s, const AutoCounter& ac) {

return os << "AutoCounter " " ac. i d;


Sada moZemo isprobati Sablon PStash. Sledeii primer pokazuje da clestruk-
)

frrend std: :ostream& operator<<( tor Sablona PStash briSe sve objekte koje trenurno poseduje, ali pokazuje i kako
std::ostream& os, const AutoCounter* ac) {
klasa AutoCounter otkriva objekte koji nisu izbrisani:
return os << "AutoCount0t^ " aa ac->i d; l/: C16:TPStashTest.cpp
) //{ L} AutoCounter
); #include "AutoCounter.h"
tendif I I AUT0C0UNTER_H /i /: - #include "TPStash.h"
Klasa AutoCounter racli clve stvari. Kao prvo, ona redom numerise Svaku #include <iostream>
insrancu klase AutoCounter: podatak dlan id sadrZi identifikator koji se gene- #i ncl ude <fstream>
riie koriSienjem statiakog podatka dlana count. using namespace std;
Kao drtrgo, i sloZeniic, statiaka instanca (pod nazivom verifier) ugnezdene
klase CleanupCheck prati sve obiekte klase AutoCounter, koji se prave i int main0 {
PStashcAutoCounter> acStash
LrniSravaju, i izvestava vas ako ih sve ne izbriSete (tl. ako nastane curenie memo- ;

rije).'lo se postiT.e printenom klase set (skup) iz standaldne biblioteke c++-a, i


for(inti=0;i<10;i++)
acStash. add (AutoCounter: : create 0 ) ;
preclstavlja sjajan primer kako dobro proiektovani Sabloni mogu olak$ati Zivot
cout << "5 uklanja rucno:" .< endl;
(korrtcjncri stanclarcltte bibli<ltekc obradeni su u drugom tomu).
for(intj=0;j<5;j++)
Klasar set je Sablon s paralnetrom sadrZanog tipa, a ovde je instancirana tako del ete acStash. r"emove (j ) ;
da saclrzi pokazivade na AutoCounter. Klasa set dodavanje ie vam dozvoliti cout << "Uk1anja 2, ali ih ne brise:"
sapg jeclpe instancc svakog razliditog objekta; u funkciji add( ) moZete videti << endl ;
kako se ovo ostvantje funkcijom set::insert( ). Rezultat funkcije insert( ) vas // ,.. generiSe poruku o greici pri brisanju.
obaveSrava cla li ste pokusali da dodate nesto sto vei postoji; medutim, posto se cout << acStash.remove(5) << endl.
doclajrr aclrese objekata, moZemo se osloniti na Saranciju da svi objekti imaju cout << acStash.remove(6) << endl;
ie(linstvcne adrese. cout << "Destruktor brise ostatak:"
I.l ftrnkciji removeO se set::erase( ) koristi z-a uklanjanje pokazivaia naAuto- << endl;
Counter iz skupa. Ilczr.rltat govori koliko instanci elementa je uklonieno, a u // Ponavlja se test iz prethodnih poglavl;a:
na5ent sltria jrr oicku jerno iskljudivo nula ilijedan. Ako je wednost nula, znadi da i fstream in("TPStashTest.cpp") ;
jc o,,,a1 ob jekat vec' izbrisan i da ponovo poku5avate da ga briSete, Sto je program- assure(in, "TPStashTest.cpp") ;
ska grcika o kojoj ie vas obavestiti funkcija require( ). PStash<stri ng> stri ngStash;
l)cstruktor klasc CleanupCheck konaino proverava da li je skup prazan, Sto string line;
bi znaeilo da su svi objekti pravilno izbrisani. Ako skup nije prazan, memorija whi 1e(get1 ine(in, 1 i ne) )
crrri, o cemu vas obaveSttiva funkcija require( ). stri ngStash. add (new stri ng (l i ne) ) ;
Konsrrukror i clestnrktor klase Autocounter prijavljuiu se i odiavljuju pomoiu / / Ispisuju se znakovni nizovi :

olrjckta verifier. /.apazjle da su konstmktor, konstruktor za kopiranje i operator for(i nt u = 0; stri ngstash Iu] ; u++)
cloclele privatnr, tako objekat moZete napraviti iedino statidkom funkcijom dlani-
cout << "stringStash[" .. u .. "] = "
<< *stri ngStash [u] .. sn61 '
conr create( ) - ovo je jednostavan primer fabrike, a garantuje se da se svi objekti
I)rave u clinanriikoi mcmoriii, tako da se obiekat verifier ne optereiuje I /l/,-
doclel i ivaniern vrednosti i pravlieniem objekata kopiranjem.
t-
s34 Misliti na jeziku C++ Poglavlje t 6: Uvod u iablone I

Kscla sc peti i Sesti elernent tipa AutoCounter uklone iz dinamidkogniz'a, void push(T* dat) {
pozir,;rjuia iLrnkcija postaie odgovorna za niih, ali ih ne bri5e. Zato nastaie head = new Link(dat,head);
cttren jc t'netnorije, koie AutoCounter otkriva tokom izvriavanja' )

[)ri izvrSavartjtr prrtgrama, videiete da poruka o gre5ci nije dovoljno odre- T* peek0 const {
rlena. r\ko ,, ,,,,r,r, siiterntr koristite prikazanu Semu za otkrivanje curenja return head ? head_>data : 0;
rlcpr11lje, \,cro\Iittno tlctc Teleri ispisivanje detalinijih informacija o obiektima ]
k0 ji nisrr izbrisani. ll cirrrgo|n tomLr su opisani napredniji nadiniobave5tavanja o T* pop0;
greSkartr a.
bool owns0 const { return own; }
vojd owns(boo1 newownership) {
own = newownership;

Problem vlasniStva )
// Automatska konverzija:
Vrarinto se problemu vlasnistva. Kontejneri koji sadrZe objekte po wednosti, true ako nije prazan:
openator bool0 const { return head != 0;
obiir.ro nemaju problema s vlasniStvom, po5to je jasno da su vlasnici objekata I. )

k0jc sacirT-e. Medutim, ako kontejner sadrZi pokazivade (to je desii sludaj u c++-u,
naroiito z.ltog polimorfizma), oni se verovatno koriste i na drugim mestima u template<c1ass T> T* StackcT>::pop0
programp. Ne rreba cla brisete objekat, poSto bi se drugi pokazivadi u programu if(head == 0) return 0;
{

.hricali nepostojciern objektu. Da bi se to spredilo, pri projektovanju i kori- T* result = head->data;


iienitr kontejncra nlorate razmotriti problem vlasniStva' L'i nk* ol dHead = head;
lI veiini programa se ne nailazi na problem vlasnistva: jedan kontejner head = head->next.
saclr7i pokazivade na objekte koje koristi samo tai kontejner. U ovakvom sludaju' del ete ol dHead;
vlasniStvo ie jasno: kontejner posecluje svoie objekte' return resul t;
Najbolje resenje problema vlasni5tva jeste da programer klijent odredi vla- )
-lb
snika. se aesto reiava argumentom konstruktora, za koji se podrazumeva da
rrkazpjc na vlasniin,o (naiiednostavniji sludaj). Osim toga, mogu postojati pri- template<c1ass T> Stack<T>::-Stack0 (
srlpne fgnkcije za iitanje i izmenu objekata u vlasniStvu kontejnera' Ako kontej- if(!own) return;
ler saclr7i frrnkcijc z-a brisanje objekta, indikator vlasniStva obidno utide na whi I e (head)
brisanje, tako ila rr lLrnkciii za brisanje mozete pronaii i opcije za kontrolu delete pop0;
brisanja. Svakako biste mogli dodati podatke o vlasniStlu za svaki element u kon- )

tcinerir, tako da iri se z-a svaki element znalo da li treba da bude uni5ten. Takav #endif // 0WNERSTACK_H ///:_
rnehiiniz.am se ntoT-e napraviti prebrojavaniem referenci, tako da kontejner ima Kontejner podrazumevano uni.tava sadrZane objekte,
ali to moZete promt
poclatak o broitr referenci koje pokazuiu na svaki objekat' niti pomoiu argumenta konstruktora i funkcije dlanice
owns( ).
Kao i sludaju veiine Sablona koje dete videii,
ll: Cl6:0wnerStack.h celokupna .eaiizucrla se nalazi
dat-oteci zaglavl,ja. ovo je mari piogram za ispitivanje
i7 Stek s kontrolom vlasni5tva tokom izvrSavanja resenja piour.,,u ur,
#i f ndef 0l^INERSTACK_H sniStva:
#defi ne Oi,lNERSTACK-H //: C16:0wnerStackTest.cpp
//{ L} AutoCounter
temp'1 ate<c1 ass T> cl ass Stack { #i ncl ude ',AutoCounter. h,,
struct Ll nk { #incl ude "0wnerStack.h,,
T* data; #jnclude "../require.h,'
Li nk" next; #'i n c'l ude <i os t ream>
ti nk(r* dat, Lj nk* nxt) #'i ncl ude <fstream>
: data(dat), next(nxt) {i #j ncl ude <stri ng>
)
* head; usj ng namespace std;
bool own;
Publ i c: jnt majn0 {
Stack(bool own = true) : head(0), own(own) {}
/ / Ulasni!tvo je ukljuceno
Stack<AutoCounter> ac;
-Stack ( ) ; Stack<AutoCounter> ac2(fai se);
I / Iskijuau.te se
Misliti na jeziku C++ Poglavlje l6: Uvod u iablone 537
536

// 0bjekat i dalje postoji kada ga pokupite sa steka;


AuloCounter' aP; // medutim, nije vi5e dostupan:
for(rnt. I = 0; I < i0; i++) 1
r popO {
aP' AuloCounter: :create0 ;
require(top > 0, "Previse citanja funkcijom pop0");
a(.PLlsn(aD); return stack [--top] ;
rf (i ' 2 == 0) )
ac2'Push(aP); );
l #endtt /l VALUESTACK_H ///:-
whrle(ac2)
Konstruktor za kopiranje obuhvaienih objekata radi najveii deo posla, pro-
cout << ac2 PoP() " endl ;
,',i Nr J e Potrebno bri sanj e ' Po5to
sledujuii i waiajuii objekte po vrednosti. Unutar funkcije push( ), objekat se
smeSta u niz pomoiu operatora = k-lase T. Klasa SelfCounter prati pravljenje i
/1 .le ac "vl asnr k" svi h objekata kopiranje objekata, i pokazuje da nova verzija steka radi ispravno.
\ lll,-
Ob)ckataczllcposedr'rjeotljcktekoje,unositettniega'takodaleac"glavni" //: C16:Se1 fCounter.h
Zivotnogveka kontei-
Tokom fndef
kontejner koji preu;.inlri o,'lgorornu-r, za vlasnistvo.
#i SELFCOUNTER_H
promeniti pomoiu funkcije owns( )' #defi ne SELFCOUNTER_H
ncra, r,lastliStun n,,cl oi:rjektinra mo7-ete
pr,,*.ttiti'ig.o""tu'nu" vlainiStva' tako cla se ono odreduje zapoje- #include "Val ueStack.h"
!lozete #i ncl ude <i ostream>
dir-racneobjckte,alibitoVerovatnoueinilore5enjeproblemaviasnistva
sloZel.rijinl od satnog problema' class SelfCounter {
static int counter;
vrednosti int id;
Smeitanje objekata Po
obiekata unutar op5teg kontejnera sloZen ie
pro- public:
Ilez iablona, p,uuiltn;t kopiie da smeitate SelfCounter0 : id(counter++) {
blen.r. Salllor]i ci']c in iednostavnim' turno navedite std: : cout << "Napravl jen: " << i d << std: : endl ;
olrlt'ktt', lt ttt' llttkltzivitit':
"lu'i''''o
)
SelfCounter(const SelfCounter& rv) : 1d(rv.id) (
//: C16:ValueStack'h std::cout << "Kopiran: " << id << std::end1;
i / Smeitan.le objekata po vrednosti na stek
,r fndef VALUTSTACK H )

*defi ne VALUESTACK-H SelfCounter operator=(const SelfCounter& rv) i


rinclude "../require.h" std::cout << "Dodeljen r' << rv.id << " to "
<< id << std::end1;
rn xth i s
templatecclass T, 1nt ssize = 100> retu ;

class Stack { )

// Podrazumevani konstruktor inicijalizuie -Sel fCounter0 {


obiekat za svaki element niza: std::cout << "Unisten: "<< id << std::end1;
//
T stackIssize]; )
j nttoP; friend std: :ostream& operator<<(
publ i c: std: : ostream& os, const Se1 fCounter& sc) {
Stack0: too(0) {} retunn os << "SelfCounter: " << sc.id;
u nr z:
// Konstruktor za kopi ranje kopi ra objekte )

vor d Push (const T& x) { );


push0");
require(top' .,'ttt, "Previse dodavanja funkcijom #endif // SELFC0UNTER_H ///:-
stack ItoP++l = x;
)
//: C16:Se1 fCounter.cpp {0}
T peek0 const ( return stackItop]; ] #i ncl ude "Sel fCounter. h"
i nt Sel fCounter: : counter = O; // / :-
538 Misliti na jeziku C++ Poglavlje l6: Uvod u iablone s39 I
#i ncl ude " . . /requi re.
1'7': C16:Val ueStackTest.cPP h,,

/i LII Sel fCounter #include <iostream>


!i ncl ude "Val ueStack. h" us i ng namespace std;

*r ncl ude "Sel fCounler. h"


il ncl ude <i ostream> cl ass IntStack (

us i ng narnesPdce std; enum {ssize = 100 };


int stackIssize];
rnt marn0 {
jnt topi
Stack<Sel fCounter> sc i publ i c:
for(int i = 0; I ' 10; i++) I ntStack 0 : top (0) { }

sc . Push (Sel fCounter0 ); void push(int i) {


'','Poziv funkcije peek0:e u redu, rezultat je privremen: require(top < ssize, ,'prevjse dodavanja funkcijom push0,,);
cout << sc . Peek) '< endl ;
( stackItop++] = 1 .
for(intk=0;k<10;k++) )

cout << sc . PoP ( ) " endl ; jnt popO {


require(top > 0, ,,previse citanja
\ I I l,- funkcijom pop0,,);
return stack [--top]
Kacla se napravi kontejner tipa Stack, z-a svaki objekat u nizu poziva se podra- ;

zurlevani konstruktor. Na podetku iete videti da je I00 obiekata klase Self-


)
frj end cl ass intStacklter;
Counter, napravljcno bez oiiglednog razloga. Oni su stvoreni prilikom );
inicijalizacije niza.'lo mo7.c cla clclrrje kao nepotrebno, ali se ne moZe zaobiii u
ovako jcclnosta\rnorn projektu. SloTenija situacija nastaie ako Stack udinite // Iterator je poput ,,pametnog,, pokazivaia:
.pitijirii, clozvrljavajuii cla r.rjcgova veliaina dinamidki raste, poSto bi to u cl ass IntStacklter (
rravr:rlenoj realizaciji z.nadilo pravljenje novog (veieg) niza, kopiranje starog niza intStack& s;
rr p6vi i rrniStavanjc starog niz.a (u stvari, to radi klasa vector standardne bi- i nt i ndex;
bliotekc jezika (.++). publ i c:
IntStacktter(tntStack& is) : s(is), index(0) {}
int operator++O { // pref.iks
Uvod u iteratore require(index < s.top,
Iterrttrtr je Objekat koii sc krcie kroz kontelner drugih objekata i bira ih,
jedan po "iterator je prekoracio granicu,,) ;
je,dan, a ne omoguiava neposredan pristup realizaciji tog kontejnera. Iteratori return s.stack[++1 n6.ri .

irrrtrlguiavaju nefosrcclno pristupanje elementima kontejnera na standardan )

nac.in. \/irlcccre rla sc itcratori najieiic koriste u vezi s kontejnerskim klasama' i nt operator++ (i nt) { // Sufi ks
Ircratgri srr jcclan ocl osnovnih pojnrova u biblioteci standardnih kontejnera require(index < s.top,
(.++-a, koja ic detalirro opisana u drttgom tomu. Iterator je i jedan obrazac pro- "iterator je prekoracio granicu,,) ;
jektolrtttjct, ce'nltl ie prlsvcicno poglavlje u clrtrgom tomu' neturn s.stackIindex++] ;
Na rn1og1l naiina, iterat<lr je ,,llarnetni pokazivad", a uoeiiete da iteratori )

otricrto oponaiajtr veriintt <lperaciia s pokaT-ivaaima. Medutim, za razliku od );


p6kaz.ivae a, iteratrtr jc projektovan tako da br.rde bezbedan. Verovatnoia da iete
kori- int main0 {
frckora-iti granice niz-a jc mnogo rnanja ako koristite iteratore nego ako IntStack i s;
stitc pokazirrrtic (i ako se to drlgodi, lakSe iete otkriti)' for(i nt i = 0; .i < 20; i ++)
llazpretrinro prvi printcl u ovonr poglavlju. Sada mu je dodat jednostavan i s. push (fi bonacci ( i ) ) ;
it crat o r:
/ / ProlaZenje iteratorom:
I l: C16: IterlntStack.cPP IntStacklter i t (.i s) ;
,// Jednostavan stek cel ih brojeva s jteratorima for(int i = 0; j < 20; j++)
i 1 { L} fi bonaccr cout << it++ << endl.
rinclude "frbonacct .h" ] / l/,-
l6: Uvod u Sablone 54I
Misliti na jeziku C++ Poglavlje
s40

void push(int i) {
Klasa IntStacklter je napravliena iskljtrdivo za rad s klasom IntStack'
pri- require(top < ssize, "Previse dodavanja funkcijom push0");
/.apar.\reda ie klasa
priiatelj klase.IntStack' 5to io1 omoguiava
l"tst";kil"; stack[top++] = i;
r,rip-.tt* privatnim elementima klase IntStacn',- ,^ da u- se
.o kreie
vroic kroz
kroz kontejner
kc i
Sliino pokaziuoeu, 'utiuiut ttase IntStacklter ie primeru' IntStacklter se int popO t
tipa Intstack i e itn uttti'''n'ti tl ovonl
jcclnostavnom require(top > 0, "Previse citanja funkcijom pop0');
(koristeii i preflksni i sufiksni oblik operatora
rrroTc potrerati sallro t"ttp'"a koiim return stack[--top];
raci iteratora nameie kontejner s
++). ll ttpStcrn sltrialtr, t'fi''tie""i^ z'a konteinera) )
(r.rllutar granica odgovaraiuieg class iterator;
itcrator ra(li. l)otpulto jc prihvatljivo u
se ircraror. .a bilo toli nae i. kreie unutar konteineri i da menja wednosti fri end cl ass j terator;
c1a
*t"il:];;;.,ro class iterator {
jednom
ie da se iterator
pravi konstruktorom koji ga pridruzuje IntStack& s;
veka' ne pri-
kontcjncrsko,r..r orrl"ttt' ia? tt'i"l iit"t"t.
tolorn svo[ Zivotnog int index;
(lteratori su obidno mali i ne tro5e puno publ i c:
drr.rTtrie nekonl ilrr.tgotn konteineiu
iterator(IntStack& is) : s(is), index(0) 0
,.'.ur*, tako da Iako rnoT'ete napraviti drugi') steka, a da ih pri tome ne ditate' Pravi se jterator
koji pokazuje na vrh steka:
I)onroiu iteratora n-roi-ete preraziti eremente ll
clemente niza' Medutim' iterator iterator(lntStack& is, bool )
ka. ito se pokazivac ;;t;;; ;;;;'ati kroz' kako da se kreie preko elemenata' : s(is), index(s.top) {}
poznaie strtlkttlru ,,,f g"'""itiCtg steta
i z-na
pokazivada"' ono Sto se i nt current 0 const { return s. stack Ii ndex] ; ]
tako cla, cak iako t{" p;;;;;i;o}onasa;uii"uveiavanie
I.l je sustina iteratora: on apstrahuje int operator++O I ll Prefiks
rleia'a rr .s..vi nr<lzc Siti sloT-enijc. tome do sledeieg elementa require(index < s.top,
ponleranja ocl jednog clementa kontejnera
sloT-eni proces
suaki iteratoi ima isti interfejs, tako
da "iterator je prekoracio granicu") ;
rr rrr.it. r.ralik na p"tu)i"ue. 6it1 ,.''au t9*: na Sta on return s.stack[++i ndex] ;
ne moraiu voditi raduna
clclovi kocla tr ko jima se koristi iterator 9
jc da se svaki iterator mo7e pomeriti na isti naiin' a kon- )
pokaz.tric - r'aZtt<t sat.no
pisati op5tiji int operator++(int) { // Sufiks
tcine r tra koji itcrator ;;i;'i; niie z-nadaian,' Na ovai nadin moZete require(index < s.top,
biblioteke iezika c++ zasnovani su na
koct. Sr,i konrejneri i .t;;;;;;,i.i"niardne "iterator je prekoracio gr anicu") ;
return s, stack Ii ndex++]
kad bismo mogri reii da "svaki
;
""'il:'ili1'Jtlil,,ji'lliilii;r.tosti, b,o bi crobro )
dovelo
nazivom iterator", ali bi to verovatno
k0ntcjtrcr ima priclruT.er.l,l tl"rl., p",i doda ugneZdena // Pomeranje iteratora unaPred
je da 'se svakom konteineru terator& oper ator+= (i nt amount) (
clo problenra s imenima' ne$enje
'i

(zapazlte Ja' Lr ovom'slu'aiu' ime klase


podinie malim slovom' tako require(index + amount < s.top,
klasa iterator
biblioteke C++-a). Sledi primer lterlnt- " lntStack: : iterator: :operator+=0
rla odgovara .tifu pir,-o,l1o .r,"nJuran. "

Stack.ipp s trgneTclenotn klasom iterator: "pokusaj prekoracenja grani ca") ;


index += amount;
//: C16:Nestedlterator'cPP return *thi s;
// UgneZdivanje iteratora u konteiner )
//1r l fibonacci
i ncl ude " fi bonacci ' h"
ll Koristi se u proverama granica:
+
bool operator==(const iterator& rv) const {
#include "'./require'h" return i ndex == rv. i ndex;
#i ncl ude <i ostream>
)
ude <stri ng>
, r ncl
bool operatorl=(const jterator& rv) const {
usi ng namesPace std;
return 'i ndex ! = rv. i ndex;
)
class lntStack (
fri
end ostream&
enum { ssize = 100 }; operator<<(ostream& os, const iterator& it) (
rnt stack[ssize] ;
return os << it.current0;
I nt top;
)
Publ i c: \.
lntStack0 : toP(0) ()
542 Misliti na jeziku C++ Poglavlje I6: Uvod u iablone 543 t
i terator begi n 0 { return j terat0r(*thi s) ; i (ovo je prvi element smesten na stek). Drugi konstruktor, koji koristi ttrnkcija
ii Pravr se "oznaka kraja": end( ), neophodan je da bi se napravila oznaka kraja. Biti ,,na kraju" znadi pokazi-
r terator end ( ) i return I terator(*thj s, true) ; ) vati na wh steka, po5to top uvek ukazuje na sledeii dostupan, ali neiskorisien,
I; prostor na steku. ovaj konstruktor klase iterator ima drugi argument tipa bool,
koji je laZan, kako bi se dva konstruktora razlikovala.
rnt marn0 i Ponovo se koriste Fibonadijevi brojevi za popunjavanje steka klase Intstack u
IntStack rs; funkciji main( ), a iteratori se koriste zaprolaz kroz ceo stek, kao r kroz suzenu
for(rnti=0;i<20;i++) sekvencu,
r s. push (f i bonacc j (i )) ; Sledeii korak je, naravno, da se napravi Sablon, tako da se, umesto iskljudivo
cout << ' Prel azi se ceo IntStack\n" i celih brojeva, na stek moZe smestiti bilo koji tip elemenara:
IntStack: :rterator rt = is.beqin0 ;
whl1e(it != rs.end0) / I : Cl6:lterStackTempl ate.h
cout << it++ << endl' // Jednostavni sablon steka s ugneZdenim iteratorom
cout << "Prelazi se deo IntStack\n"; #i fndef ITERSTACKTEMPLATE H

I n t S t a ck : :rterat o r #define ITERSTACKIEMPLATE H

start = is.begin0, end = is.begin0; #jnclude "../require.h"


Start += 5, end += 15; #i ncl ude <i ostream>
cout << "pocetak = " << start .. endl;
cout << "kra5 = " << end.. endl; templatecclass T, int ssize = i00>
wh11e(start != end) class StackTemplate {

CoUt << Start++ " endl ;


T stackIssize];
\ /t/,- 'i nt top;
publ i c:
I)ri pravljcrrju rrgncT.dcnc prijatcljskc klase, morate deklarisati ime klase, de- StackTemplate0 : top(0) {}
klarisati da je klasa prijatclj idefinisati klasu. U suprotnom, prevodilac ie se voi d (const T& i ) {
push
ztrrrniti. require(top < ssize, "Previse dodavanja funkcljom push0,,);
Itcr:rtonr sLr cloclatc r)ekc novc, ncobiane osobine. Funkcija dlanica current() stackItoP++] = 1t
da jc lckrrii clcn)cnt kontejnera na koji pokazuie iterator. Pomoiu operatora += )
nro2ctc ,,preskoaiti" proiz-voljan broj elemenata. Videiete i dva preklopljena T pop0 {
operatora: == i!= za lrporedivanje dva iteratora. Oni mogu uporediti bilo koja require(top > 0, "Previse ucitavanja funkcijom pop0 ,);
clva objekta klasc IntStack::iterator, ali su uglavnom namenjeni ispitivanju da li return stack[--top] ;
je itcnrtor na krajir sckvcr.rcc. na isti naain kao Sto to rade,,pravi" iteratori stan- i
darclrre lribliotcke jczika (.++. Idcja ,;e da dva iteratora defini5u niz od elementa class iterator; // Neophodna je deklaracija
na koji pokaz-uje prvi iterator, do elementa na koji pokazuje drugi iterator, ne friend class iterator; // Postaje prijatelj
rrkljue Lrjrrii i poslednji element. Ako hoiete da se kreiete kroz niz definisan cl ass i terator | / I Sada se defi ni ie
porn0cu ova clva ite ratora, napiSite nesto sliano sledeiem: StackTempl ate& s;
i nt i ndex;
while(start 1= end)
publ 1 c:
cout << start++ << endl ; i terator(StackTempl ate& st) : s (st) , i ndex (0) { }
gdc srr start iend po-etni i krajnji itcrator. Tapazite da se element na koji poka- // Pravi se iterator
koji pokazuje na vrh steka:
zrrje itcratrrr end, koji i:csto nazivanyt oztt(tkn kraja (engl. end sentinel ), nikada iterator(StackTemplate& st, bool )
nc cita.'laj itcratrlr postoji sarno cla bi varn saop5tio da ste na kraju sekvence, i : s(st), index(s.top) ()
predstavlja ,,prvi clerlent iza poslednjeg". T operator*0 const { return s.stack[.index];]
NajrleScc aetc htcti cla sc kreicte kroz celu sekvencu u kontejneru, tako da je T operator++0 | // preftksni oblik
potrcban naiin cla kontejner napravi iteratore koji ukazuju na podetak sekvence i require(index < s.top,
oznakrr kraja. Kao i rr stanclardnoj biblioteci C++-a, ovi iteratori se prave funkci- "iterator je prekoracio gran.icu,') ;
jarna clanicanra kontejnera begin( ) iend( ). F-unkcija begin( ) koristi prvi kon- return s. stack [++1 n6gr1 .

stnrktor klasc iterator, za koji se poclrazirmeva cla pokazuje na podetak kontejnera )


Misliti na jeziku C++ Poglavlje I6: Uvod u Sablone 545
544

#include <iostream>
T operator++(tnt) \ ll Sufiksni oblik #'i ncl ude <fstream>
requ re (, ndex
' s . toP
' #i ncl ude <stri ng>
" i terator ie prekoraci o grani cu" ) ;
using namespace std;
relurn s. stack Ii ndex++] ;

.//' PorneranJ e i teratora unaPred int majn0 {

r teral0r& operator+- nt amount) (I {


StackTempl ate<i nt> i s;
requrre(index + amount' s.loP'
for(inti=0;i<20;i++)
' StackTemplate: :iterator: :operator+=0 "
(fi bonacci (i ) ) ;
i s. push
"PokusaJ Prekoracenja granlca") ; // Prelazak steka iteratorom:
tndex += arnount;
cout << "Prelazj se ceo Stacklempiate\n";
StackTemplate<int>: :iterator it = is.begln0
return *thi s; ;
while(it != is.end0)
)
cout << it++ << endl'
/,/ Provera da I i ste na kraju: cout << "Prelazi se deo\n";
bool operator== (const i terator& rv) const {

return i ndex == rv ' i ndex; StackTemp l ate<i nt> : : i terator


start = is.begin0, end = is.begin0;
i
bool operator | = (const i terator& rv) const {
start += 5, end += 15;
return index I= rv.index; cout << "pocetak = " << start << endl ;
cout << "kra5 = " << end << endl;
)

friend std: :ostream& oPerator<<(


while(start l= end)
std: : ostrearn& os, const i terator& i t) {
cout << start++ << endl ;
return os aa *i t i i fstream i n (" lterStackTempl ateTest.cpp") ;
assure(in, "IterStackTemplateTest.cpp") ;
l
string line;
I; StackTempl ate<stri ng> stri ngs;
i terator begi n 0 { return i terator(*thi s) ; }

Pravl se "oznaka kraja": while(get1 ine(in, l ine))


/i stri
r terator end ( ) { return i terator("thi s, true) ;} ngs. push (1 i ne) ;
StackTempl ate<stri ng>: : i terator
); sb = strings.begin0, se = strings.end0;
#endif I I ITERSTACKTEMPTATE-H I I I :-
while(sb != se)
prirne irr jc se cla je rransformacija iz- obidne klase u Sablon prilidno odigledna' cout << sb++ << endl'
greske' a z-atim se
Ovaj pristtrp, tt kort.tc se prvo napravi obidna k-lasa i otklone se ) I l/,-
klasa'prervori rr iablon, srnatra se jedrlostavnijim od pravljenja Sablona od nule'
U prvom koriSienju, iterator se samo pomera od podetka do kraja (i pokazuje
/.apatitc (la se tlnlesto: da oznaka kraja ispravno funkcioniSe). U drugom koriSienju, iteratori
frr end i terator; // Posta: e pri i atel i omoguiavaju jednostalmo definisanje sekvence elemenata (kontejneri i iteratori
piic-: standardne biblioteke C++-a skoro s\,'uda koriste ovakve sekvence). Preklopljeni
priiateli operator +- pomera iteratore start i end na pozicije u sredini niza elemenata u
friend class iterator; // Postaje
steku is i ovi elementi se ispisuju. Zapazite da, u izlaznim rezultatima, oznaka
ovo je znadajno, poSto je u opsegu vei definisano ime ,,iterator", iz ukljudene k;rajanije ukljudena u sekvencu, tako da ona moZe oznadavati mesto iza kraja
clatoteke. * z.a izbor sekvence, kako biste saznali da ste prekoradili kraj - medutim, nemojte dereferen-
lJmesto firnkcije ilanice current( ), klasa iterator ima operator cirati oznaku kraja, jer se moZe dogoditi da dereferencirate prazan pokazivad. (U
rekuieg elernenra, 5ro je uobidaieno i iini iterator mnogo slidnijim
pokaziva'u'
klasu StackTemplate::iterator ugradio sam za5titu, ali takav k6d, radi efikasnosti,
Ovoie preracleni primer za testiranje Sablona: ne postoji u kontejnerima i iteratorima standardne biblioteke C++-a, tako da mo-
I l: CI6: I terStackTempl ateTest. cpp rate paziti.)
I I \L\ fi bonacct Na kraju, da bi se proverilo da li StackTemplate radi s objektima klase, Sablon
#include "fibonacci .h" se instancira za tip string i stek se popunjava redovima iz datoteke izvornog
#incl ude " IterStackTemPlate.h" koda, koji se zatim ispisulu.
546 Misliti na jeziku C++ Poglavlje l6: Uvod u iablone
547
I
Operator derefenci ranja
Stek s iteratorima T* operator->0 const i
pokazi vada:
Evo klase Stack u konlbinaciji s ugneT.clenim iteratorom:
require(p t= 0,
,,pStack:
I l: Cl6: TStack2.
h
:iterator: :operator_> vraca 0,,)
i r Sabl on steka s ugneZdenim i terat0r0m return current 0 ;
;

i i fndef TSIACK2_H )
ddefi ne TSTACK2_H T* operator*0 const { return current0;
// konverzija.u logidki tip rali iipitivang.a}
usrova:
templ ate<c1 ass T> cl ass Stack { operator bool 0 const i return boo.i
struct Li nk { ip) ; )
// Uporedivanjem se irpitr.lu Ju-ii
bool operator==(const iteritort) :u
T* data i t"u:,
const {
Li nk* next; return P == 9'
Lj nk (T* dat, Li nk* nxt) )
: data(dat), next(nxt) i) bool operatorl = (const i terator&)
const
). head; return p != 0;
{

publIc: )
Stack0 : head(0) {} );
-Stack ( ) ;
jterator begin0 const
{
voi d push (T* dat) { return jterator(*this) ;
head = new Li nk (dat, head) I )
)
. iterator end0 const { return iterator0;
T* const {
peek ( ) ); }

return head ? head-'data:0;


) template<ciass T> Stack<T>::_Stack0
l- popo; whj I e (head)
{

// UgneZdena kl asa i teratora: delete pop0;


cl ass i terator; I Dekl araci ia I je obavezna )
friend class rterator; // Postaje prijatel.l
cl ass j terator { // Sada se defi ni 5e template<c1ass T> T* Stack<T>::pop0
{
Stack: : Li nk* P; if(head == 0) return 0;
publtc: T* resuit = head_>data;
i terator(const Stack<T'& tl ) : p(tl.head) {} Link* oldHead = head;
// (onstruktor za koPi ranje: head = head_>next.
i terator(const i terator& t'l ) : p(tl.p) {} delete oldHead;
// Iterator oznaka kraja: return result;
iterator0: P(0) t) )
// operator ++ vraca logicku vrednost koja ukazuje na kraj #endit
:
// TSTACKZ_H
///:_
boo'1 operator++0 {
zapazifete i da ie klasa promenjena
i f(P-'next) tako da preuzlma vlasni5tvo nad
tima' To je sada moguie,'po-s,o r.iuru elemen-
p_ p_>next; ,ni*, rip (ili bar osnovni tip, ako se
el se o 0; / ' Ukazuje na kra.j Ii ste koriste virtuelni desrrukt;ri). poa.u.r..il*..
iu'itr,"i".,, ,nisiurru ,uo;.
objekte' ari ste vi odgovorni za sue pokazirue.
return bool (P); ro;" proditate'funl.ilon-', popr
)
Irerator je jednostavan i veoma
napravite obiekat krase^i1:110r,
_.ri l;;ri,.;;;;;;;;;Jo.illl,i.r.
l.
*ro.
bool operator++(int) { return operator++0; o,n se inicijalizule na poietak povezane
T* current0 const { moZete ga samo pomerati unapred Iisre i
kroz Iistu. Ako hoiete da poinete
napravite nov iterator, a ako hoiete iz poietka,
if( !p) return 0; au ,ufu-iit" neko mesio u listi,
return p-rdata; nov iteraror od postoieieg iteratora napravite
strukror za kopiranje iieratora).
t";i-i"t"^i" na ro mesro (koristite kon_
)
548 Misliti na jeziku C++ Poglavlje I6: Uvod u Sablone 549

pomoiu funkcije Sablon Stack je instanciran tako da sadrZi objekte tipa string i popunjena
I:unkcije objekta na koji pokazuje iterator, nlozete pozvati
current( )', opcrator *, ili operator -> (uobidaieni prizor u programima s itera- redovima iz datoteke. Zatim se pravi iterator i koristi se za pomeranje kroz or,u
torima). Ilealiz.acija operat;)ra -> izgleda identidno funkciji current( )' po5to sekvencu. Deseti red se pamti tako Sto se pravi drugi iterator konstruktorom za
ali lunkcionalno razlikuje, posto operator kopiranje; kasnije se ovaj red ispisuje, a dinamidki napravljeni iterator
r.,raia pokaz.iVac na tekuii obiekat, se se
(videti poglavlje uniStava. ovde se koristi dinamidko pravljenje objekata da bi se upravljalo zivot-
za derlcferenciranjc pokazivaaa clodatno dereferencira adresu
nim vekom objekta.
l3)
Klasa iterator je napravljena po uzortl na klasu iz prethodnog
primera'
kotlstruktore pravljenie iteratora koii poka-
I)gnezclena je u kontejner, sadrT.i z.a
Sablon PStash s iteratorima
poietak kontci'nera i oz.nakr.t kraia, a klasa konteinera ima metode begin( )
,.ij,., nu Dodavanje iteratora ima smisla za veiinu kontejnerskih klasa. Sledi primer ire-
iend().kojeproizvodeoveiteratore.(Kadabudetesaznaliviseostandardnoj ratora dodatog klasi PStash:
biblioteci C++-a, vicieiete da su imena iterator, begin( ) i end( )'
preuzeta iz stan-
clardnih kontejnerskih klasa. Na kraju ovog poglavlia, saznaiete da se zato ove //: C16:TPStash2.h
klase nrogr.t koristiti kao da pripadaju standardnoj biblioteci') // Sablone klase PStash s ugneZdenim iteratorom
postoji posebna #i fndef
Celokupna realiz-acija se'naiazi u datoteci zaglavlla, tako da ne
TPSTASH2_H

mali test primene iteratora: #define TPSTASH2 H


cpp datoteka. Ovaj program ie
#include "../require.h"
//: C16: TStack2Test. cPP #i ncl ude <cstdl i b>
#i ncl ude "TStack2. h"
#jnclude "../requi re.h" template<class T. int incr = 20>
#i ncl ude <i ostream> class PStash {
xinclude <fstream> j nt quant i ty;
#1ncl ude <stri ng> i nt
next;
usinq ndresPace std; T** storage;
voi d i nfl ate (i nt i ncrease = i ncr) ;
rnt main0 { publ i c:
i fstream fi I e("TStack2Test.cpp") ; PStash0 : quantity(0), storage(0), next(0) {}
assure(f i le, "TStack2Test.cPP") ; -PStash ( ) ;
Stack<stri nq> textl i nes; i nt add (T* el ement) ;
ll Ctta datoteku i upisuje redove na stek: T* operator[] (int index) const;
strrng line; T* remove(int index);
whi 1e(getl jne(fi le, I i ne) ) int count0 const { return next; }
textl ines.push(new stri ng (l i ne) ) ; / / Ugneidena kl asa i teratora:
int i = 0; class jterator; // Deklaracija je obavezna
1/ Iterator se koristi za 5tampanje redova iz I iste: friend class iterator; // Postaje prijatelj
Stack<string>:: iterator it = textl ines'begin0; cl ass i terator { / / Sada se defi ni 5e
Stack<string>::iterator* it2 = 0; PStash& ps;
while(it != textlines.end0) { int index;
cout << i t-'c-str0 t' endl ; publ i c:
it++; i terator (Pstash& pStash)
i f(++1 == 10) // Pamti deseti red : ps (pStash) , i ndex (0) {}
it2 = new Stack<string>: :iterator(it) ;
// Za pravljenje oznake kraja:
) iterator(PStash& pStash, bool)
cout << (*i t2) -'c str0 << endl '
: ps (pStash) , i ndex (ps. next) {)
delete it2; // Konstruktor za kopi ranje:
I I ll,- i terator(const i terator& rv)
: ps (rv. ps) , i ndex (rv. i ndex) ()
i terator& operator= (const i terator& rv) {
ps = rv. ps;
5so Misliti na jeziku C++ Poglavlje I6: Uvod u Sablone 551 t-

i ndex = rv. i ndex i T* operator*0 const ( return current0; )


return *thi sl T' operator->0 const i
)
require(ps.storageIindex] != 0,
r teralor& operator++ ( ) { "PStash: :iterator: :operator-> vraca 0") I
requl rg(++1ndex .= PS.next, return current 0 ;
'PSlash: : I terdtor: :operator++ " )

"tndeks rzvan grantca") ; Uklanjanje tekuceg elementa:


return *thr s; T* remove ( ) {

)
return ps. remove(i ndex) ;
r terator& oPerator++ ( i nt) { )

return oPerator++0 ; // Uporedivanjem se ispituje da li je kraj:


)
bool operator==(const iterator& rv) const {
i terator& oPerator-- 0 ( return index == rv.index;
requ'i re (- -'i ndex >= 0, )

"PStash: :iterator: :oPerator-- " bool operatort=(const iterator& rv) const {


"i ndeks 1 zvan grani ca" ) ; return index != rv.index;
return *thi s; )

) );
iterator& oPerator--(int) { iterator begin0 { return itenator(*this); }
return operator-- 0 ; i terator end 0 ( return i terator(*thi s, true) ;)
I.
)

,17' Premeitanje lteratora unapred ili unazad:


i terator& operator+= ( i nt amount) i // Uni 5tavanje objekata kontejnera:
requjre(index + amount < ps.next && templ ate<c1 ass T, i nt i ncr>
index + amount >= 0, PStashcT, incr>::-PStash0 {
' PStash: :i terator: : oPerator+= " for(int i 0; j < next; i++) {
=
'i ndeks i zvan grani ca" ) ; delete storageltl; I I Prazni pokazivadi su u redu
index += amount; storageIi] = 0; ll Samo radi bezbednostj
return *thi s; )

I
de1 ete [] storage;
rterator& operator-=(int amount) { )

requi re ( i ndex - amount < ps. next &&

rndex - amount >= 0, templ ate<c'1 ass T, 'i nt


i ncr>
"PStash: : i terator: :oPerator-= " int PStash<T, incr>::add(T* element) {

"indeks izvan granica") ; if(next >= quantity)


index -= amount; inf1ate0;
return *thi s; storage[next++] = element;
l return(next - t); // Broj indeksa
// Pravj se nov iterator kojl se pomera unapred )

i terator operator+ ( i nt amount ) const {


i terator ret (*thi s) ; templ ate<c1 ass T, i nt i ncr> i nl i ne
ret +- amount; // operator += proverava granice T* PStash<T, incr>::operator[] (int index) const {
return ret i require(index >= 0,
l "PStash::operator[] indeks je negativan,') ;
l* current ( ) const { if(index >= next)
return ps. storageIindex] ; return 0; l/ Da ukaie da je kraj
I require(storageIindex] != 0,
"PStash: :operator[] vratio prazan pokazivac");
return storage[index] ;
552 Misliti na jeziku C++ Poglavlje l6: Uvod u iablone 553

l //: C16:TPStash2Test.cpp
#i ncl ude "TPStash2. h,,
templ ateccl ass T, i nt i ncr> #i ncl ude " . . /requi re. h,,
T* PStashcT, incr>::remove(int index) { #'i ncl ude <i ostream>
// operator[] proverava i spravnost: #i ncl ude <vector>
T* v = operator[](rndex); #i ncl ude <stri ng>
,/, "trt lanja' ookazivai: usi ng namespace std;
storage Ii nderl = 0;
return v; class Int {
) int i;
publ i c:
template<class I, int incr> Int(int ii = 0) : j (ii) (
void PStash<T, incr>::inflate(int increase) { COUI << ,,>" .. .i .. , ,;
const i nt tsz = si zeof(T*) ; )
I*" st = new T*[quantity + increase]; -lnt0 ( cout <<'-" << i..' ,; )
memset(st, 0, (quantity + increase) * tsz); operatoli nt0 const { return i; }
memcpy(st, storage, quanti ty * tsz) ; friend ostream&
quant i ty += i ncrease; operator<<(ostream& os, const Int& x) {
delete []storage; // Staro skladi5te return oS << "Int: ',.. X.i;
storage = st; I I Pokazuje na novi memorijski prostor l
I friend ostream&
tendtf ll IPStASHZ-H lll:- operator<<(ostream& os, const Int* x) i
Najveii deo ove datoteke predstavlja prevod klase PStash i ugneZdene klase return Os << "]nt: ".. x-r.i;
iterator Lr Sablon. N4edutim, ovoga puta operatori waiaju reference na tekuii )

itcrator, ito jc iciii i fleksibilniji pristup.


];
i)estruktor poziva delete z-a sve pokazivaie r-r konteineru, a po5to je tip obu- int main0 {
hvaien Sablonom, objekti se ispravno tlniStavaju. Trebalo bi da imate na umu
| // Da bi se pozivao destruktor
da, ako kontcjner sadrT-i pokaz-ivade na objekte osnovrle klase, destruktor te PStashclnt> i nts;
klase rnora biti virtuelan da bi se ispravno uni5tavali objekti izvedenih klasa. for(intj=0;j<30;i++)
Klasa PStash::iterator sledi model vezivanja iteratora zaiedan objekat kontej- ints.add(new Int(i));
nera tokonr celog Zivotnog veka. Osim toga, konstruktor za kopiranje vam cout << endl ;
omoguiava da od postojeieg iteratora napravite novi, koji pokazuje na istu PStash<Int>: :iterator it = ints.begin0 ;
lokaciju, e ime sc pravi obeleZivad pozicije u kontejneru. Funkcije dlanice opera- it += 5;
tor+= i operator-= omoguiavaju da pomerite iterator za odredeni broj mesta, a PStash<Int>::iterator it2 = it + 10;
da ne prekoraeite granice kontejnera. Preklopljeni operatori za uveianje i for(; it l= it2; it++)
rrrnan jen je pomera ju iterator za jedno mesto. Operator + daje novi iterator koji je delete jt.remove0: // podrazunevano brisanje
ponrere n rrntrprecl za vrednost sabirka. Kao i u prethodnom primeru, operatori za cout << endl;
dercfercnciranjc se' koriste za rad s elementom na koji iterator pokazuje, a for(it = ints.begin0;it t= ints.end0;it++)
lirnkcija remove( ) uniStava tckuii objekat pozivanjem funkcije remove( ) kontej- j f(*j t) / / funkcija remove0 pravi ,,prazni
ne,,
nera. Oz-naka kraja se pravi isto kao ranije (slidno kontejnerima standardne bi- cout << *it << endl;
bliotekc (.++-a): 1.lot'noiu drugog konstruktora i funkcije end( ) kontejnera. ) // ovde je pozvan destruktor za ',ints,,
Opt'ratori -- i !- koriste sc za ttporedivanie. cout << " \n- - --- --- --- -- - -- - -- \n,, ;
ll
sledeie rn prinreru razlidite wste dinamidkih nizova:
prave se i testiraju dve i fstream i n("TpStash2Test.cpp,,) ;
Lr jednoj se nalaze objekti nove klase pod nazivom Int, koja ispisuje poruke prili-
assure(in, "TpStash2Test.cpp") ;
konr pravljcr.r ja i rrniStavanja obiekata, a u drugoj se nalaze objekti klase string. // Instanci ranje za kl asu stri ng:
PStashcstri ng> stri ngs;
string line;
whi)e(getl i ne(in, I ine) )
Misliti na jeziku C++ Poglavlje l6: Uvod u iablone
r
554 555 I

stri ngs.add(new stri ng(l jne) ) ; l.


PStash<string>: :iterator sit = strings.begin0 ;
for(; srt l= strrngs.end0; slt+*1 cl ass Ci rcl e: publ i c Shape i
cout << **si t << endl ; publ i c:
srt = strrngs.begln0; Circle0 {}
rnt n - 26; -Circle0 { std::cout << ,,Cjrcle::-Circle\n,,; }
5it +- n; void draw0 { std::cout <<,,Cjrcle::draw\n,,;}
for( ; sr t l' slrr ngs. end ( ) ; si t++1 void erase0 { std::cout << ,,Cr'rcle::erase\n',;}
cout << n++ <<': ' << **sit << endl; J;
| / il''
class Square: public Shape (
Ilurli ltogorlrtosti, klasa lnt inra ol)cratorc it.lttznog toka << iza Int& i za Int*.
public:
t)n,r blok koda [unkcijc main( ) okruZen jc vitidastint zagradama, da bi se
Square0 {)
aktivirao destlrktor klase PStashclnt> i automatsko brisanje tim destruktorom. -Square0 ( std: :cout << "square: :-Square\n"; )
Sekr,enca elemenata je uklonjer.ra i izbrisana ruano, da bi se pokazalo da klasa void draw0 { std::cout << ,'square::draw\n,';}
PStash briSe ostatak. void erase0 { std::cout <<,,Square::erase\n',;}
Za obe instance klase PStash pravi se iterator i pomera kroz konteiner.
);
/.apaz-re clcganrnll upotrebu ovih konstrukcija; niste optereieni detaljima rea-
liz.ar:ije koriSc'en ja niza. Kontejnerr-r i objcktima iteratora saop5tavate ifa da rade, class Line : public Shape {
a ne kako. Na taj rta-in sc clollija reierl,e koje se IakSc razume, piSe i menia. publ i c:
Line0 ()
-Line 0 { std: : cout << ', Li ne: : -Li ne\n,,
; }
ZaSto iteratori? void draw0 { std::cout <<,,Line::draw\n,,;i
I)ssacl stq yiclcli ntt:haniztrrn iteratora, ali razumcvanie nlihovog zna(aja zahteva void erase0 { std::cout <<,,Line::erase\n,,;}
sloTeniji pritrter. )r
1J plavonr o[rjcktno rtrijentisanrttrl I)rogramu uobiiajeno ie da se zajedno #endif // sHApE_H ///:-
k6ristc polirnorfrz-anr, clinamidko pravljenje objekata i kontejneri. Kontejneri i
riilanriiko pravljerrjc oltjckata rc5avaju problern nepoznatog broja i tipa potreb- . virtuelne funkcije iz osnor.ne klase, redef,nisane su u izvedenoj klasi. Zapazite
da klasa Shape ima virtuelni destruktor - trebalo bi ga automatsli ciodati
svakoj
triI objckata.,\ko, porcd toga, kontejner sadrZi pokazivade na obiekte osno'rrle k-lasi koja sadrZi virtuelne funkcije. Ako kontejner sadrZi pokazivade ili reference
klasc, tada se ltri svakorn snteStanju pokazivada izvedene klasc u kontejner na objekte klase shape, tada ie sve biti pravilno izbrisano pri pozivu virtuelnih
aciresa syodi naviie (postoji i korist od organizacije i proSirivosti koda). Poslednji destruktora za ove objekte.
prograrr ovoj knjizi spojiic raz.liiitc aspekte svega Sto ste dosad naudili - ako
Lr u sledeiem primeru, svaki razliditi tip crteza koristi razlititu wstu sablo-
ra7-unretc ovaj printer, spremni ste za drugi tom' nizovane klase kontejnera: k-lase pstash i Stack, koje su definisane
u ovom
Za11tislite progrant ko ji omogucava korisniku da ureduje i pravi razlidite vrste poglavlju, i klasu vector iz standardne biblioteke c++-a.
,,Upotreba,, kontejnera
crtcZa. Svaki crtcZ ic objekat koji sadrT.i skup obiekata klase Shape: je rzuzetno jednosta,na. Nasledivanje moida nije najbolji pristup (sraganje
bi
r'7': C16:ShaPe.h imalo vi5e smisla), ali je u ovom sludaju nasiedivanje jldnosiau,ije, a ne
;r fndef SHAPE_H naru5ava suStinu primera.
rdefr ne SHAPE_H
# i nc I ude <l ost ream>
//: C16:Drawing.cpp
#include <vector> // Takode koristi standardnu klasu vector!
"'nc l ude <st -r ng> #i ncl ude "TpStash2.h,'
#'include "TStack2.h,,
c1 ass Shape { #include "Shape.h,,
Publ i c: usi ng namespace std;
vrrtual vold draw0 = 0;
vi rtual void eraseO = 0; je osnovni kontejner objekata klase
vrrtual -Shape0 {}
// K)asa Drawing Shape:
cl ass Dnawi ng : publ i c pStash<Shape> {
publ i c:
Misliti na jeziku C++ Poglavlje l6: Uvod u iablone 557
556

<' ' cout << "Schematic s:" << endl;


-Drawi nq ( ) { cout <' "-Drawi ng" endl )
drawAl I(s.begin0, s.end0 ) ;
1.
cout << "Array sarray:" << endl;
j
l l Radi cak s pokaz i vaii ma na n i zove:
,,'1Klasa Pian 3e drugacrjr kontejner objekata klase Shape:
(sarray,
drawAl I
cl ass Pl an : Publ r c Stack'ShaPe' { sarray + sizeof (sarray)/sizeof (*sarray)) ;
publ ic-:
cout << "Kraj funkcije main" << endl;
-planO { cout " "-Plan" " endl; i
);
| //1,-
Svi ovi razliditi tipovi kontejnera sadrZe pokazivade na obiekte klase Shape i
I klasa Schemdtic je drugaii'1i kontejner obiekata klase
I I
Shape: pokazivaie na objekte klasa izvedenih iz klase Shape, svedene naviSe. Medutim,
ci ass Schemati c : publ t c vector<Shape*> { s obzirom na polimorf,zam, pona5anje je ispralmo pri pozivima virtuelnih
publ i c: funkcija.
-schematic0 { cout << "-Schematic" <' endl; i Zapazite da se i sarray, niz pokazivada tipa Shape*, moZe smatrati kontej-
); nerom.

// Sablon funkcije:
templ ateccl ass I ter> Sabloni funkcija
void drawAll (lter start, Iter end) { U funkciji drawAll( ) zapaiate ne5to novo. U ovom poglavlju smo dosad koristili
while(start t= enO) t samo iablone klasa (engl. class templates), koji instanciraju nove klase na
(*start) -'draw0 ; osnovu jednog ili vise parametarskih tipova. Isto tako jednostavno mozete
start++ ! napraviti iablonefunkcija(engl.functiontemplates), koji prave nove funkcije na
) osno\,.u parametarskih tipova. Razlog za pravljenje Sablona funkcije isti je kao i
) za Sablon klase: poku5avate da napravite op5ti k6d i zato odlaZete def,nisanje
jednog ili vi5e tipova. Pri tome samo hoiete da navedete da parametarski tipovi
int marn0 ( podrZavaju neke operacije, a ne i koji su to tipovi.
// Svaki tiP kontejnera ima
Sablon funkcije drawAll( ) moZe se smatrati algoritmom, Sto je i naziv veiine
ll razlicit interfejs: Sablona funkcija u standardnoj biblioteci C++-a. On samo kaZe kako da uradite
Drawrnq d:
neSto ako imate iteratore koji opisuju niz elemenata, sve dok se ovi iteratori
d.add(new Cjrcle);
mogu dereferencirati, uveiavati i uporedivati. Upravo takvu vrstu iteratora smo
d . add ( new Square ) ;
razvijali u ovom pogiavlju, a kontejneri standardne biblioteke C++-a proizvode
d.add(new Line);
istu wstu iteratora, Sto se vidi pri koriSienju klase vector u navedenom primeru.
Pl an p;
p.push(new Line);
Hteli bismo i da funkcija drawAll( ) bude opiti algoritam, tako da kontejneri
p. push (new Square) ;
mogu biti bilo kog tipa, a da ne moramo pisati novu verziju algoritma za svaki
p.push(new Circle); poseban tip kontejnera. Sablon funkcije automatski generiSe poseban kOd za
Schemat i c
s; svaki razlidit tip kontejnera. Medutim, ova op5tost ne bi bila moguia bez dodat-
s.push_back (new Square) ; nog posredovanja iteratora. U tome je znataj iteratora - omoguiavaju pisanje
s. push-back (new Ci rcl e) ; koda opSte namene, koji radi s kontejnerima, bez poznavanja strukture samog
s.push-back(new Line) ; kontejnera. (Zapazite da su Sabloni funkcija potrebni za rad iteratora i opStih
Shape* sarraYU = { algoritama u jeziku C++.)
new Ci rcl e, new Square, new Li ne Dokazza ovo moZete videti u funkciji main( ), po5to se funkcija drawAII( ) ne
I; mora menjati da bi radila sa svakim posebnim tipom kontejnera. Sto je los
// lteratori i 5ablon funkcije zanimljivije, funkcija drawAll( ) radi i s pokazivadima na poeetak i kraj niza sar-
// omogucavaju oPSti nadi n rada: ray. Ova moguinost da se s nizovima radi kao s kontejnerima jedna je od
cout << "Drawtng d:" << endl; osno'r'nih ideja projekta standardne biblioteke C++-a, diji su algoritmi veoma
drawAl I (d.besin0, d.end0) ; slidni funkciji drawAll( ).
cout << "P1an P:" << endl;
drawAl I (P.begin0, P.end0) ;
558 Misliti na jeziku C++ Poglavlje I6: Uvod u Sablone 559 I
I)oSto st, na iablont klasa k<lnte jnera retko primen ju je nasledivanje 5. Pretvorite funkciju fibonacci( ) u sablon po tipu wednosti koji proizvodi
i svorlcn jc navric koje sr(,1<Lrtc kod ,,obiinih" klasa, skoro nikada neiete videti vir- (tako da, osim tipa int, moZe dati i brojeve tipa long, float itd.).
tuclnc lLrnkcijc rr kontcjne rskinr klasama. Pono'"no kori5ienje kontejnerskih 6. Primenom standardne klase vector, napravite sablon klase set, skupa koji
klasir realizovano jc Sablor.rima, a ne nasledivanjem. prihvata samo po jedan primerak od svakog tipa objekta koji dodajete.
Napravite ugneZdenu klasu iterator, koja podrZava ,,oznaku kaja,,, opisanu
u ovom poglavlju. Napi5ite u funkciji main( ) k6d za restiranje klase set, a
SaZetak zatim je zamenite Sablonom set standardne biblioteke c++-a, da biste
Kontejnerskc klase su znadajan deo objektno orijentisanog programiranja. One proverili isprarmost ponaSanja.
predstavljaju drugi nadin pojednostavljenja i skrivanja detalja programa, kao i 7. Izmenite datoteku zaglavljaAutocounter.h tako da se moZe koristiti kao
rrbrzar,anja razvo ja l)rogranra. Osinr toga, one u velikoj meri poveiavaju bezbed- objekat dlan unutar bilo koje klase dije pravljenje i unistavanje objekata
nost i flcksibilrrost, z;rnrcnjrrjrrii proste nizove i relati'"mo neudobne tehnike rada hoiete da pratite. Dodajte dlan tipa string, koji ie sadrzati ime klase.
sa stnrktlrranra podataka u C-u. Isprobajte ovu alatku u nekoj klasi.
PoSto srr kontcjncri potrebni programeru klijentu, znadajno je da njihova 8. Napravite verziju datoteke zaglavlja ownerstack.h, koja koristi stan-
trllotreba bLrde je clnostavna. 'fu nastupa Sablon. Uz Sablone, sintaksa ponotr'ne dardnu klasu vector. MoZda ie biti potrebno da potraZite neke funkcije
rrpotrcbc izvornog koda (nasrrprot ponovnc upotrebe objektnog koda,
dlanice klase vector da biste ovo uradili (ili da samo pogledate datoteku
onroguiene nasledivanjern i slaganjem) postaje dovoljno jednostavna i za zaglavlja <vector>).
podetnika. Ponovna upotreba koda sa Sablonima znatno je jednostal'nija od
9. Izmenite kontejner iz zaglavlla Valuestack.h tako da se dinamidki pove-
rrrslcdivan ja i kompozicijc.
iava kada se prekoradi rezervisani prostor. Izmenite programvalueStack-
Iako ste iz ovc knjigc trdili o pravijenju klasa kontejnera i iteratora, u praksi je
Test.cpp da biste isprobali nor,rr funkcionalnost.
nrnogo korisnije da nauiite o kontejnerima i iteratorima standardne biblioteke
jezika C++, poSto rnoZete odekivati da ie or.ri biti dostupni uz svaki prevodilac. I0. Ponovouraditezadatak9,alikoristitestandardnuklasuvectorkaointernu
Kao 5to iete',,ideti u clnrgom tomrr, kontejneri i algoritmi standardne biblioteke realizaciju zaValueStack. Zapazite koliko je ovo jednostavnije.
(.++-a skoro uvck ie isprrrriti vaSe potrebe, tako da ih ne morate praviti sami. I I . Izmenite program valuestackTest.cpp tako da koristi standardnu klasu
lJ ovom poglavljrr sr.r dotaknuta znadajna pitanja u vezi s kontejnerskim kla- vector umesto klase stack u funkciji main( ). posmatrajte ponaSanje
sanra, ali ste n'roZrla zakljudili da ona mogu dosezati mnogo dalje. SloZena bi- tokom izwiavanja: da Ii se pri pravljenju objekta klase vector automatski
bliotcka kontc;ncrskih klasa nroZe obuhvatati ra7.na dodatna pitanja, pravi skup podrazumevanih objekata?
Lrkljtrr'rrjtrc'i r,rit'nitni rarl, trajnost i skupljanje smeia. 12. Izmenite kontejner iz zaglavlja TStack2.h tako da interno korisri stan-
dardnu klasu vector. Uverite se da ne menjate interfejs, tako da se ne mora
menjati pro gram TStack2Test.cpp.
VeZbe I 3. Ponovo uradite zadatak 12. Koristite standardnu klasu stack biblioteke
llcirnja izal)ranilr zaclataka se nal;rze u elektronskom dokumentu The Tltinking in C++ Annotated Solution
(iuirlc ko ji se, uz nralu nadoknadu, mo2e preuzeti sa adrese rmuBruceEckel.com c++-a umesto klase vector (moZda ie biti potrebno da potraZite infor-
I . Realizujte hijerarhiju nasledivanja Ooblik prikazanu dijagramom u ovom macije o klasi stack ili da pregledate datoteku zaglavlja <stack>).
poglavlju. I 4. Izmenite TPStash2.h tako da koristi standardnu klasu vector. uverite se da

2. Iznrenite rezirltat zaclatka I u poglavlju 15, tako da se u zaglavljuTStack2.h ne menjate interfejs, tako da se ne mora menjati program TpStash2-
kuriste klase Stack i iterator umesto niza pokaz-ivada na objekte klase Test.cpp.
Shape. I)odajtc clestruktore hijerarhiji klasa, pa iete videti da se objekti I 5. u programu lterlntstack.cpp izmenite Intstacklter rako da postoji i kon-
klase Shape uniStavaju kada se iz.ade iz oblasti vaZenja objekta klase Stack. struktor,,oznake kraja" i dodajte operatore == i !=. U funkciji main( ) isko-
3. Izrnenite TPStash.h tako da se korak uveianja u iunkciji inflate( ) moZe ristite iterator za pomeranje kroz elemente kontejnera, sve clok ne dodetc
rnenjati tokrlrn Tivotnog veka kontejnera. do oznake kraja.
4. Iznrenitc TPStash.h tako da se korak uveianja u funkciji inflate( ) auto- 16. Kori5ienjem TStack2.h, TPStash2.h i shape.h, instancirajte konrejnere
nratski menja, da bi se smanjio broj poziva. Na primer, pri svakom pozivu stack i PStash za tip shape*, popunite ih pokazivadima svedenim navise, a
lirnkcije, nroTe se udvostruditi vrednost koja ie se koristiti pri sledeiem zatim upotrebite iteratore za kretanl'e kroz svaki kontejner i za svaki
poziviinju. Prika2itc ovrr [unkciorralnost ispisivanjem poruke pri svakom objekat pozovite funkciju draw( ).

1.roz-ivanjr.r lirnkcije i napiSite k6d za testiranje u funkciji mainO.


Misliti na jeziku C++
560

tako da sadrzi
I 7. klas. Int iz- programa TPStash2Test.cpp u Sablon,
klasi dodelite ime koie joi vi5e odgovara)'
'rerrroritc
bilo koii tip objekta tsioUoAno
I g. prctvoritc klasu IntArray iz programa
Iostreamoperatoroverloading'cpp
(poglavlie I2), tako Jn pu'nt"iti budu tip sadrTanog obiekta ivelidina
internog niz-a.
(pog-
'I
9. I)rctvorite klasrr obicontainer tr programu NestedSmartPointer'cpp
klase'
lavlje l2) tr iablon,-festirajte ie pomoiu dve razlidite
pretvaranjem klase Stack u
2 0. Izrrtcrtitc ClS:OStack.h i ClS:OStackTest'cpp
Sablon,takodaatrtomatskivi5estrukonasledujeparametarsktt'klasui
klasu Obiect. Dobijena klasa Stack treba da
prihvata i
samo proizvodi
pokazivaic sadrTanog tiPa'
2l.Ponovorrraditcz,adatak20koristeiiklasuvectorumestok]aseStack.
22. Izveclite klasu Stringvector iz klase vectorcvoid*>
i redefinisite funkciie
-- prihvataiu i.proizvode samo
;1";i.. push-backi) i operatorll tako da
pokaz-ivade tipa string* (izvr5ite odgovaraiuiu
konverziiu)' Zatim napra-
vite iablon tnnt.ln.rikoii isto tn automatski zapokaziva(e bilo kog
'idi
tipa.Ovatehnikasecestokoristidabiseumanjilonarastaniekodausled
pievelikog broja instanciranja Sablona'
itestirajte ga, po
23. tJ TPStash2.h dodajte operator - klasi PStash::iterator
uzortl na operator +'
24. t) Drawing.cpp cloclajtt'itestirajtc Sablon funkciie za pozivanje funkcija
ilanica erase( ).
25. {Napredno) Izmenite klasu Stack u Tstackz'h tako da se vlasniStvo
oclredtr jc ,.n na1nlanj" jeclinice: svakoj vezi
dodajte indikator koji ukazuie
na to (la ti u"ru p,,J"jtrie objekat na koii pokazuje i koristite ovu infor-
i u Dodajte funkcije dlanice za
n.raciiu tr irrnkciii p,,snt ) destruktoru'
ditanie i izmentr vlasniStva svake veze'
iz poglavlja 12' pret-
26. (Napreclno) Izmenite PointerToMemberoperator.cpp
varanjerrlklaseFunctionobiectioperatora->*uSablonezaradsbilokojim
iablone ilanoua
tipom rezultata. Za operator ->* iete morati da koristite
(engl. nternlter templ'ates), opisane u drugom tomul. Dodajte,i,testiraite
podrsktr za nula, leian i d'u uig'*et'ta u funkciiama dlanicama klase Dog'

A: STII PISANJA PROGRAMA


Ovo nije dodatak o uvladenju koda i kori5ienju zagrada i vitidastih
zagrada, mada ie i to biti spomenuto. Navode se opSLe smernice,
kori5iene za organizovanje teksta programa u ovoi knjizi.
562 Misliti na jeziku C++ Dodatak A: Stil pisanja programa t-
563

lako str nlltogc ternc o kojirna ie biti redi vei razmotrene u knjizi, ovaj lmena datoteka
do<iatak sc pojayljuic pa kraiu, tako da z-aokruZuie celinu. Ako neSto ne razu- U jeziku C tradicionalno se datotekama zaglavlja (sadrZe deklaracije) dodeljuju
tne lc, trtolcte to potraliti tr odgrlvarajuiem odeljku' imena s nastavkom .h, a datotekama realizacije (dovode do zauzimanja memo
Sye 6dlrrkt,() paiipl pisanja prograrna rr ovoj knjiz-i palljivo su promisljane i rijskog prostora i generisanja koda) imena s nastavkom .c. Jezik C++ se poste-
rl6rteit,pt', p6pckarl i tokorn rriza gotlina. Naravno, svako ima svoje razloge za peno razvijao. Prvo je razvijen pod Unixom, gde su za operatir.ni sistem
pisarrjc progranta na oclrcclcni tlai:in, pa iu vam preneti kako sam dosao do zna(,ajna velika i mala slova u imenima datoteka. Prvobitno su imena
svo jilt 0cllr.rka i kOja su rne ()granidenja i uslovi okruzenja do njih doveli.
datoteka
imala nastavke kao u c-u, ali napisane velikim slovima: .H i .c. To nije funkcio-
nisalo za operativnim sistemima koji nisu pravili razliku izmedu malih i velikih
s]ova, kao Sto je Dos. proizvodadi c++-azaDoS koristili su nastavke h:o<
Opita pravila i oo< za
datoteke zaglavlja i datoteke realizacije, ili hpp i cpp. Kasnije je neko otkrio
ll tckstu knjige srr iclentifikatori (imena funkcija, promenljivih i klasa) napisani razliditi nastavci samo postoje da bi prevoditaCmogio odrediti'da li da datoteku
da
polucrnim slovinta. Veiina rezervisanih reei ie takode napisana polucrno. prevodi kao c ili c++. posto prevodilac nikadi nije neposredno prevodio
tl printerinta krlristim odrecleni nadin pisania. On je razviian tokom vise datoteke zaglavlia, trebalo je promeniti samo nastavak imena datoteke rea\iza-
goclina idclintidno ier inspirisan stilom Biarnea Stroustrupa iz njegove knjige cije. Sada je uobidajeno, u skoro svim sistemima, da se za datoteke realizacije
prograntski jezik C++. O formatiranju se moZe voditi visesatna wuia rasprava,
koristi cpp, a za datoteke zagravrjah. Zapazrte da se standardne datoteke zi-
tak<, cla preko primera ne pokusavam da nametnem nadin koji smatram iedino glavlja c++-a, mogu ukljuditi i ako se izostavi nastavak imena, na primer: #in-
ispravninr; ima6r svoje razloge za koriSienie prikazanog stila. Posto je c++ pro- clude <iostream>.
gianiski jezik sloboclnog oblika, mozete nastaviti da pi5ete na nadin koji vam
odgovara.
'Napomenuiu
da je vazno dosledno oblikovati program u okviru jednog pro- Oznake za podetak i kraj komentara
jr:kta. Ako pretraTite Inrernet, naii iete veii broj alatki koje moZete iskoristiti za veoma znadajan zahtev autora u vezi s ovom kry'igom jeste da se mora proveriti
preoblikoranje celokupnog koda u svom projektu, kako biste postigli ovu drago- isprarmost koda (bar jednim prevodiocem). To se poitiZe automatskim izdva-
cenrt tloslccltrttst. janjem datoteka iz knjige. Da bi se postupak olaksao, svi tekstovi programa
pr6grar.ni, naverleni u ovoj knjizi, jesu datoteke koje se automatski izdvajaju koje
treba prevesti (za razliku od malobrojnih delova koda) imaju oznake komentara
iz reksta knjigc, iro orr.rogrrial,a da se tcstira njihova isprawost. Tatobi trebalo na podetku i na kraju. ove oznake koristi programzaizdvajanje koda Extract_
rla syi prggranri tr krrjiz.i racle bcz. gresaka pri prevodenju, ako realizacija prevo- code.cpp u drugom tomu, kako bi izlukao t.krtou" prograrna iz ASCII verzije
cli6ca 6clgovara standarclu jezika O++ (in.rajte u viclu da ne podrZava svaki pre- teksta knjige.
r,,oclilac sve n.togt tinosti). GreSke koje treba da prouzrokuju poruke pri oznaka za kraj_programa saopstava programu Extractcode.cpp da je to kraj
se otkrivaju i
ltrcvoclctrjrr stavlicnc su pocl komentar oznakom //!, iednostavno
.
teksta programa. rza oznake za podetak programa narazi se infoimacija poa-
11o11.r sc alrrgltatski tcstirati. GrcSke koje ditaoci otkrivaju i prijavljuju autoru, o
direktorijumu kome pripada datoteka (rasporedene su po poglavljima, pa bi
pryo ic sc pojaviti u clektronskoj verziji ove knjige (naWeb lokaciji www.Bruce' datoteka koja pripada pogravrju - engl. chapter - B imala ornit, c0B), praienu
Eckttl.t:ont), a zatinl ir.r izmenjenim izdanjima. znakom.dve tadke i imenom datoteke programa.
Ierlno ocl pravila u ovoi knjizi je da se svi programi prevode i povezuju bez Poito program Extractcode.cpp pravi i datoteku makefile za svaki poddirek-
grciaka (iako ie ltonckad prouzrokovati r.rpoz-orenja). Radi toga ie neki pro- torijum, u tekstove programa su ukljudene i informacije o pravrjenju piograma i
grarni, koji slu7.e sarno kao primeri, a ne predstavljaju samostalne programe, komandni red za testiranje. Ako je program samostalan'(nije'potrebno pou.-
imati prazrttt ftrnkciiu main( ): zivanje s nekim drugim programom), ne postoje dodatne informacije.
Isto vazi i
int mainO {} za datoteke zaglavlja. Medutim, ako datoteka ne sadrzi funkciju main(
) i podra-
Io otttogttcrava ltrtvcz-ivanic be z. gre(ke zumeva se povezivanje s nekim drugim programom, tada se iza imena
.
datoteke
[,ravilo jc rla lLrnkcija main( )vraia vrednost tipa int, ali standard C++-a nalazi {o}. Ako tekst programa precistavlja giavni program, ali je potrebno pove-
rrstangvljaya rl:r, ako ne postoji iskaz return unutar funkciie main( ), prevodilac zivanje s drugim komponentama, racla postoji por.br., red koji podinje
ozna_
arr16qiarski gcneriSe k6cl za return 0. Ova opcija (bez iskaza return u funkciji kom //{L} i sadrZi imena svih datoteka koje treta povezari (bez nastavaka, poSto
nlairr())krlristirit.escrrkrljizi(rlekiprevclcliociidaljemoguispisivatiupozo. oni zavise od radunarskog sistema).
rcn ja, ali otti nisu Lrsklaclerri sa standardom iezika C++)' Primere iete pronaii na vi5e mesta u knjizi.
Misliti na jeziku C++ Dodatak A: Stil pisanja programa 56s
564

i.kraja.teksta plograma ne i definiciji u jednom redu, koja se aesto koristi za umernute funkcije:
,\krl trclla izdr,rljiti tlatrltcktt, ali crz-nakc poietka
trebaukljtreitittiz-dvojerltrdatotektr(na.primer,akodatotekasadrZipodatkeza int func(int a) ( return (a + 1) * 2; )

tcstiranjc), tada se neposredno izaoz'nake podetka nalaz'i'l'' Slidno vaZi i za klasu:


ci ass K1 asa;

Zagrade, vititaste zagrade i uvladenie


u ovoi kniizi razlikuie od mnogih
jeste deklaracija imena klase, a definicija klase je:
Primetili ste tla se nadin pisanja programa class Klasa {
jeziku c. Podrazumeva se da svako
tradicionalnih nadina programiranla na u svakom sludaju, ako pogledate samo jedan red, vei iete razlikovati deklaraciju
sl.arril ,.,,.,1 ,rn,.i,.., ,..,uil,jg,e iiii,,". Nae l, toii sam koristio zasnovan ie na iedno-
od.definicije. osim toga, ako otvorenu vitidastu zagradu ne pisete u posebnom
sa razlozima razviiania nekih
star,noj l.gici, koja ie Siti opisarla u korniinaciii redu, vi5e iskaza staje na jednu stranu"
drugih nadina.
-fckst prograrna se oblikr'r jc prema nadinu prezentaciie' u
-Stampanom
obliku i .. Za5to onda postoji toliko drugih nadina pisanja kod,az. Zapaziiete da veiina
ljudi pravi klase koristeii navedeni nadin (stioustrup ga korisii u svim izdanjima
potrebe drugaiiie,posto ne pravite
na predavanjin.ra. MoZcla smar;ate da su va6e svoje knjige Programski jezik c++, izdavad Addison-wesley), aii pise deflnicije
veliki broj p."r.n,olilu Medutim' tekst progiama se.mnogo deSie iita nego Sto
funkcija smeitajuii orvorenu vitidastu zagradu u poseban ied (to prouzrokule i
se pi5e i trebalo i..,ilu'e itun.u bude lako
strvittliv. Moja dva najznadajnija kriteri-
viSe razliditih nadina uvladenja redova programa;, osim u sludaju kratkih
jr.rma su pr.gt.ann.i-tf.,rf lt" i. ditaocu lako da usvoji znadenje jednog reda) i broi umet-
kriteriiym.moie delovati smeSno' nutih funkcija. Uz pristup koji sam ovde opisao, sve je dosledno: imenujere ono
redova tnli ,.,,og,', -'tuii nu ;tanu stranu Drugi
kad izlagad mora da pomera sto definisete (klasu, funkciju, nabrojivi tip itd.) i u isti red smestate orvorenu
ali pri prez.er-,,o.iji-uZ-i'u, publiku dekoncentrise vitidastu zagradu da biste ukazali da sledi telo definicije. osim roga, otvorena
suviSnih redova'
slajdove unapredi unaz-ad, zbog samo nekoliko zagrada je na istom mestu za katke umetnute funkcije i obidne definicije
SviseslaT-rrdakrldunutarvitidastihzagradatrebadabudeuvuden.Najvise tunkcija.
nesltglasicaineaostednostijavliasepridono5enjuodluke:gdenapisatiotvorenu Twdim da ovaj nadin definisanja funkcija, koji mnogi koriste, potiae iz c-a
v.itidastuz,agradtt'Ovopitar-rje,polnommiSljenju'dovodidomnogobrojnih pre uvodenja prototipa funkcija, kada se argumenti nisu dek_laiisali unutar
moZete potraZiti u knjizi
razliiitih naeinu.prng,amiranja (opise raz-nilr stilova zagrada, nego izmedu zarvorene zagrade i otvorene vitidaste zagrade (to poka-
,foma pluma fjana Saksa tl++ Programming Guidelines,. Plum Hall 1991).
i zuje da su koreni C-a u asemblerskom jeziku):
PokrrSairrdavasubcdirndamnogidanaSnjinadinipotiduodogranieenjajezika
pogodni'
zato vi5e nisu voi d bar0
O pre standarai,uci;e (pre prototipa funkciia) i da
i nt x;
Prvoiuodgovoritinatokljuinopitanje:otvorena.vitidastazagradauv'ek
Sto
(dalje podrazumevam ,,onoga float y;
treba da bude u istom redu, kao ,,prethodnica..
riurr, funkciiu, aennicilu obiekta, uslovni iskaz itd."). To pravilo t
telo predstavrlu,
doslednopn.*f,it'"nu"ttekstoveprogramakojepi5emionopojed-- na /* telo funkcije */
obtiiovJnle koda. Navedeno piu,rilo pobolj.ava ,,preglednost"
)
nostavljuje
hilo prilidno nezgodno pisati otvorenu vitieastu zagradu u istom
primer,-kada Pogledate ovai red: .ovde bi
redu, pa to niko nije ni radio. postojala su razlidita misljenja o to-". da li vitidaste
int func(int a)l zagrade treba uvladiti s telom koda ili one treba da bud'u na nivou
,,prethodnice,,.
poraikiiz'arezrtnakrajtrredaznatedajetodeklaracijaidasenenastavlja,ali Tako smo dobili vi5e razliditih nadina oblikovanja teksta programa.
kada vidite red: Postoje i drugi argumenri za postavljanje vitidaste ,igrie u red koji nepo-
rnt func(int a) i sredno sledi iza deklaracije (klase, strukture, funkcije itd.). Navodim tetsileanog
ditaoca kako biste znali Sta su sporna pitanja:
tlcllnahz-tlatcdiijetodefrr-ricija,poStoseredz-avrsavaotvolenomvitidastom
ovaj pristup' nema razlike
zagradom, a ne tadkorn \ zarlezont' Ako koristite
Iskusni korisnici programa 'vi' (vim) znaju da ie dva pritiska na taster,l'
definiciji: dovesti korisnika do sledeieg pojavljivanja ,{, (ili
iz-n-ledu poloT.aia otvorene zagrade u vi5erednoj ^Lj u koloni 0. Ova
moguinost je izuzerno korisna pri kretanju kroz program (skok na sledeiu
int func(int a) { definicil'u funkcije ili klase). [Moj komentar: kada sari prvobitno radio pod
int b = a + 1; unixom, GNU Emacs se upravo pojavljivao i ja sam r" ,p".ao. poslediia je
return b * 2; da 'vi' meni nikada nista nije znadio i zato ne razmisljam o ,,lokaciji kolone
)
0". Medutim, prilidno je velik broj korisnika programa 'vi' i ova tema je za
njih znadajna.l
566 Misliti na jeziku C++ Dodatak A: Stil pisanja programa
567
I
[)isanjem'1' u slecleiem redr-r trklanja se zbunjujuii k6d u sludaju sloZe- u jedan red? ponovo nastojim da dosledno primenjujem pravilo preloma
nih Lrslovnih iskaza i poboljSava se pregledrrost. Primer: redova, rako da se. mogu rako pregledati..sve doi;. n"irJ J.oledne definicije,
i f(cond1 liste argumenata itd., naredniredovi treba da budu
ru ].aon'niro uv,udeni u
&& cond2 odnosu podetak
na te definicije, liste argumenata itd.
&& cond3 ) {

statement;
] lmena identifikatora
Navecleni kOd Itwdi eitalacl nije pregledan. Medr-rtim: oni kojima je bliska lava, zapaziee da sam za pisanje imena identifikatora
pri-
i f
(cond 1 menjivao standardni nadin Iave. Nisam bio, potpuno
aostJan, posro sc taj
&& cond2 nadin ne koristi u standardnim bibliotekama
lezlki C I C++.
&& cond3) Nadin pisanja je sasvim jednostavan. samo identiflkatori
krasa podinju
{ velikim slovom. y"1iT srovom podinju funkcije iti p."-.;t;.
ostutuk identi-
staternent; flkatora se sastoji od jedne ili viSe spojenih re8r
I
r p*o ,louo'ruake reei je veliko.
Klasa izgleda ovako:
odvaja'ii'od tela ipoboljSava iitljivost. IMi5ljenja o tome da li ie to taano class FrenchVanjlla : public IceCream {
razlikovaie se., u z.avisnosti od navika.l
identifi kator objekta izgleda ovako:
Najzad, nrnogo je lakSc vizitelno poravnati vitidaste zagrade ako se
nalaze rr istoj koloni. One su mtlogo bolje vizuelno ,,izdvojene". IKraj FrenchVani 1 1 a mylceCreamCone(3)
;
komcntara ditaocal a funkcija izgleda ovako:
O rlesttr otvorenc vitidaste zagracle verovatno postoji najvi5e nesuglasica. void eatlceCreamCone0 ;
Narriio sanr c1a glcclam oba nadina pisanja i na kraju postaje nevaZno na koji ste
oblik navikli. 7.apat.io sam da je zvanidni standard pisanja programa na Javi (vaLitza funkcije dlanice i za ostale funkcije).
(objavljcn na Sunovoj Wcb stranici posveienoj Iavi) isti kao onaj koji vam ovde Izuzetak su konstante i simboli (consi i #define),
diji identifikatori se piSu
prikazrrjcrn - poSto svc viSe ljucli podinje da programira i na C++-u i na Javi, velikim slovima.
korisno 1c da sc na oba jczika programi piir-r istim stilom. . ovo pravilo je znadajno jer na osnovu prvog slova vidite da li se radi o klasi,
Pristup koji koristim r.rklanja sve izuzetke i specijalne sludajeve, a logieno objektu ili metodi. To je posebno korisno kadi pristupate
siuiiJu* dranovima
sledi ijedinslven stil rrvladenja. Dosleclnost se zadrZava i unutar tela funkcije, klase.
kao u:
for(jnt i - 0; i.100; i++) {
Redosled ukljudivanja datote ka zaglavlja
cout << i .. endl;
cout << x * j << endl; zaglavlja se ukrjuduju redosredom ,,od najposebnije
!11o1eke do najopstije,,. prvo
ukljudujem datoteke zaglav\ja u lokalnom dlrekiiriyumu, zatim datoteke za-
l
glavlja svojih ,,aiatki", kao sto je require.h, zatrm
Or a j stil je jednostavno preneti drugima i zapamtiti - uvek dosledno koristite auiotet. ,"gr""ri. bibrioteka
drugih proizvodada, p.a datoteke zagravrjastandardne
jcclno pravilo, tako da ne postoji jedno pravilo za klase, dva za funkcije (za umet- bibrioteke c++-a i na kraju
datoreke zaglavlja C biblioteka.
nLrte firnkcije r.r jecinom redu iza funkcije definisane u vi5e redova), a moZda i ovaj pristup je potkrepljen izvodom iz knjige Large-scare
clrrrga pra','ila z-a petlie for, iskaze if itd. Sama doslednost dini ovo pravilo vred- c++ sofiware Desigrt,
Johna Lakosa, Addison-Wesley, 1996:
nirn raznratranja. Iezik C++ je noviji od jezika C i, iako moramo praviti mnoge
ustupke (.-u, ne bi trcbalo cia zadrZimo navike koje ie nam stvarati probleme u skriuene greike se mogu izbeii ako se obezbedi da se
.h clatoteka kontportertte
buclr.rinosti. N,Iali problcnri pomnoZeni sa velikim brojem redova koda postaju pojedinaino anarizira - bez sporjnih dekraracija iti aetr,ria1a (Jkrjuiiua_
ve-liki problcrrri. Ova tcma sc sveobtthvatno obradrrje u knjizi C Style: Standards njem .h datoteke Lt pruom redu .c-datoteke, obeibeduln
iu iiintoui irt.fornta_
a n rl (,t t i d al i rrc.s [ )avicla Strakcra ( ['rcnt icc- [ Iall 1 992).
cija' znaiajni.za fiziiki irltyfejs komponente, neie
iedostajati rr .rt dototeci
(ako nedostaju, to iete otkriti pri poktitiajtt
l)rugo ogranidenjc stila pisanja jestc Sirina reda, poSto je za knjigu posta- preuodenja , ,iniiirnt rr.
vlie'na granica od 50 znakova. Sta se deiava ako je tekst preSirok da bi se uklopio Ako je redosled ukijudivanja datoteka zaglavlja,,od
najposebnije do najop_
Stije", verovatno
iere na weme otkriti nekomp"l"tn. dutot.t. r"s;;r;.
i speiiiere
naknadne neprilike.
Misliti na jeziku C++

Zaitita od ukljucivanja u datotekama zaglavlja


r.tvek se koristi u datotekama za-
Z-aitito rul rtkl.itrtit,a,.ia (engl. inclurle guards)
tokom
glavlja, da bi se ,pr"diln viiekratno ukliudivanje iste datoteke. zaglavlja
kontrolise korisieniem pretpro-
prevodenja jeclne.cpp clatoteke. Prevoclenie se
lme identifika-
ccsorske naredbe +denn" i proverom da li je ime vei definisano
rura, koli se koristi za za5titti ocl ukljuiivania, pravi se na osno'tl imena datoteke
podvladenie' Na
zaglavlja. sr,'a slova str velika, a tadka se zarnenjuje znakom za
p ritner:
I I1ncl udeGuard. h
#i f ndef INCLUDEGUARD-H
#def i ne INCLUDEGUARD-H
ll ldo datoteke zaglavlja
#endit I I INCLUDEGUARD-H
pretploce-
Identifikator u poslednjem redtt naveden ie radi jasnoie. Iako neki
#endif, to nije standardno ponaSanje i
sori z.anemalrjLr sve znakove iza naredbe
z.ato je identifikator ispod komentara'

KoriSienje imenskih Prostora


u ciatoteli z.aglavlia se pazljivo mora izbegavati bilo kakvo ,,zagadivanje" imen-
promenite imenski pro-
skog prostorai, toil le .,t iire.nu datoteka zaglavlja' Ako
sror u konte se naiazi fr,rnkcija, odnosno klasa, prouzrokovaiete
tu promenu u
zaglavlja, Sto izaziva raznowsne pro.
sr,akrlj clatotcci koja rrkljudtrje datotekrr
a globalni
blerne. I)cklaracije using nisu dozvoliene izvan definicija funkciia,
iskazi using nisu clrlz-volieni r-r datotekama zaglavlja'
L.l cpp clatoteci' svi globalni iskazi using uticaie samq 11
tu datoteku i zato se
oni koristtr Lr ovoi knjizi, k6d malih programa postaie ditkiji'

Kori5ienje funkcija require( ) i assure( )


dosledno se koriste u
Ftrnkciie require( ) i aJsure( ), definisane u require'h'
vam bliski pre-
veiern delu kniige, tako da pravilno prijavl;uju probleme' A\9.tu
koje je uveo
rlLtsloui tengl. pi:econ.rlitioni) i izlazni usloui
Bertrancl Meyer, prepoz.naiete da se upotrebom
(engl' postconditions),
funkcija require( ) i assure( ) u
(powemeno)' Na
B: Voole zA p-RoGnIMIRANJE
(obiino) iizlazni uslovi
izvesnoj meri obez.beduiu preduslovi
p.cetkri f,.kciie, pre podetka izwSavanja ,,iezgra", proveravaju se
preduslovi, NA C++.U
kako bismo se uvcrili da je sve ispravno i da su ispunjeni svi potrebni uslovi"
Zatrnr se izvrsava ,,iezgro" funkciie i ponekad se proveravaju neki izlazni uslovi, Ovaj dodatak sadrZi skup saveta za programiranje na jeziku C++.
di'je novo sianie podataka odgovaraju1e.ZapaziCete da se
da tris.to sc rrverili
iz knjige, a funkcija assure( ) ie
izlazni uslovi rctko provcravaiu r-r primerima
ttglar.notnkoriSicrlazaproverudalisusvedatotekeuspeSnootvorene'
s70 Misliti na jeziku C++ Dodatak B: Vodic za programiranle na C++-u 571

Savctistr irlorl rlog isklrstva tt ltodltcavanju iprogranliranju izapazan)aprt' 8. Kontrola pristupa omoguiava vama (autoru klase) da ubuduie menjate
jatelja, nredrr kojirna su I)an Saks (r-rz'lttma [)luma, autor knjige C++ Program- klasu, bez narusavanja klijentovog koda u kome se ona koristi. Neka stcr
.I991),
rrrittg Otrirlelirrc.s, I)ltttt't llall, Scott Meyers (autor knjige Effectiue C++' veii deo klase bude privatan, a samo interfejs klase javan, i u intcrfejsu
clrugo izrlanle, ,'\clciison-Wcsley, I998) i Ilrtb Murray (autor knjige C++ Srrotegies uvek koristite funkcije, a ne podatke. podaci treba da budu jarni samo ako
& Iacric.s, Adcljson-We'slcr', 1993). Mnogi saveti stt saZeci iz ove knjige. je to neophodno. Ako korisnici k-lase ne treba da pristupaju funkciji,
neka
l. I)n'o napravrte Ilrograrl koji racli, a zatitl't ga trbrzavajte. Ovo vaZi dak iako bude privatna. U sludaju da delovi vase krase moraju biii dostupni potkra-
srt'sigrrrni rla jc ncki tieo kotla zilista zrlaaaian ida ie biti osnovno usko sama kao za5tiieni, obezbedite interfejs preko tunkcije umesto da izla,tete
grlo rr virse rn sistcrrrrr. Ncrnojtc ga oclnrah optirnizovati. Napravite sistem stvarne podatke. Na ovaj nadin ie promene realizaciie veoma malo uticati
koli rarli, sit ito jt'tltrosta",'rtijrrn projcktom. T.atirn ga poboliSavaite ako ne na izvedene klase.
r:rrii dovolino irrzo. Skoro rtr,'0k (cte otkrlti da ,'vaSe" usko grlo ne pred- 9. Nemojte dozvoliti da vas analiza paralise. postoje nekc stvari koje neietc
stavljir prol'rlcrn. tJitt-'clite vrcrlte za stvarno vaZne stvari uvideti dok ne podnete da piSere program i ne dobijete sistem koji radi. U
2. Llcgancija sc ttvck isplati.'lit nije bcz-l'raiajan zahtev. Dobiiate program koji jezik c++ ugradeni su zastitni mehanizmi dozvolite da rade za vas.
-
Gre5ke u jednoj klasi ili skupu klasa neie ugroziti celovirosr sistema.
se sastavlja i rr komc se lak5c otkrivaju gre5ke, razumljiviji je ijednostamije
sc oclrZava, a trr lcTi finansijska korist. Neiskusni programeri ne shvataju 10. Analiza i projektovanje moraju dati kao rezulrat bar klase sistema, njihove
ro, poito rnole tlclovati cla nisu produktivni dok ulepSavaju kird. Produk- jarme interfejse i njihove veze s drugim klasama, posebno osnovnim.
Ako
tivnost postiTetc kada se kocl savr5eno uklopi u vaS sistem, Sto je prime- vasa metodologija projektovanja daje viSe od toga, preispita;'te da Ii svi
tnijc pri izntenama koda ili sistema. delovi, dobijeni primenom te merodologije, imalu i,naeiia tokom celog
3. I)risctite sc pravila ,,z.avacli, pa vlaclaj". Ako vas posmatrani problem previ5e zivotnog veka programa. Ako nemaju, njihovo odrZava,je ie vas kostatr.
zbturju je, pokLriajtc tla zatlislitc Sta bi bila osnovna funkcija programa ako clanovi razvojnih timova nastoje da ne odrzavaju nesto sto ne doprinosi
hi posto jao nragiirri ,,de o" krtji obradtr je sltlTene delove 'taj ,'dco" je objekat njihovoj produktiwosti - tu Zivotnu dinjenicu mnoge metodologije projek-
- napisite krirl koji koristi taj objekat, z.atim ga pregledaite ikapsuliraite tovanja ne uzimaju u obzir.
rt.letole sloTcnt' r'lclovc tt cirtrgc objekte itd. I l. Prvo napi5ite k6d za testiranje (pre nego sto napisete Rasu) i iuvajte ga uz
4. \crrrojtc irLrtornatski pisrtti na (,++-tr celoktrpan k6d koji jc vei napisan na klasu. Automatizujte izwsavanje testova pomoiu datoteke maiefile ili
(.-tr, osirn irko trcl)il zrracajrro prorncniti njegovtr ftrtrkcionalnost (znaai, nekog slidnog sredstva. Na ovaj nadin, sve promene moZete automatski
nenrojtc popravljati ono Sto radi). Portoutto preuodenje programa na C-u proveriti izwsavanjem koda za testiranje i odmah iete otkriti greske. posto
pornoiu (.++ prcvotlioca je korisnrl, poSto moZc razotkriti skrivene gre5ke. ste svesni da sistem za testiranje pronalazi greSke, smelije iete praviti veie
\'lcclutirl, portovno pisanje na C++-tl ispravnog programa moZda nije promene kada to bude potrebno. Zapamtite da najveia poboljSanja jezika
nalbolji naiin cla se protroii vremc, osim ako ie C++ verzija, kao klasa, potiiu od ugradenog testiranja obezbedenog proverom tipa, obradom
prrrZiti viie rnogLtittosti z.a ponovntt upotrebu. izuzetaka itd., ali su ove moguinosti konadnog dometa. Da biste napravili
pouzdan sistem, morate preii i ostatak puta pisite testove koji prove-
5. r\ko Vcliki deo kocia na (l-tt treba menjati, prvo izdvojite delove koje neiete -
nrt'njatr, po nrogttittos(i otttotavajtrii te funkciie ,,klasom programskog ravaju moguinosti specifidne za va5u klasu, odnosno program.
irrte rli, jsrr zrr aplikacrjc" kao statiirke I'trnkcije dlanice. Zatim se usredsredite I2. Prvo napiSite kod za testiranje (pre nego sto napisete klasu), kako biste
na kird koli cetc rttcltjati: rasporeclitc ga tr klasc, da biste omoguiili jed- proverili potpunost dizajna klase. Ako ne napisete k6d za testiranje, neiete
n ost avn c rlcttLt t oko rn clal jeg od rZavan.i a.
p ro znati kako va5a klasa izgleda. osim toga, postupak pisanja k6di za resri-
6. Orlvolitt lrlogc atttrtra klase i korisrtika klase (progranrcra klijenta). Kori' ranje desto ie izbaciti na povrsinu dodatne moguinosti ili ogranidenja
snik klasc jc ,,potroSai" i ncnta ni potrcbtt ni Telju dazna Sta se de5ava u koja su potrebna u ktasi - ove moguinosti, odnosno ogranidenjalne pojav-
pozarlini klase.,\utor klase mora biti strudnjak za proiektovanje klasa i ljuju se uvek tokom analize i projektovanja.
rnorii napisatr kiastr tako da je moZe koristiti Sto vi5e podetnika progra- 13. Zapamtite osnovno pravilo softverske tehnike: sui problemi pri projekto-
nrcra, a tla i rlaljc l.lorrz-clano radi Lr aplikaciji. Llpotreba biblioteke ie biti uanju softuera, mogu se uprostiti uuodenjem tloclatnog niuoa konceptual-
jcdn()slilVllil satllo ako jc ocigledrra. nog posredouanjal . ovo je temelj apstrakcile, osnovnog svojstva objektno
7. Kacla pravrte klasr.t, inrena treba cla btrdu 51o jasnija.VaS cili treba da bude orijentisanog programiranja.
cla oknr/.cn jc [)rogramera klijcnta budc 5to razurnljivije. PokuSajte da for- 14. Napravite klase tako da budu sto nedeljivije, ro jest, dodclite svakoj klasi
rntrli(cte tako jasps irnepa cla kotnentari postanLl nepotrebni. (I tom cilju jednu jasnu swhu. Ako klase ili sisrem posraju previse srozcni, poderite
koristitr' prcklapanjc ltrrtkr:iia i ltoilrazttnlevane argumcnte, da biste slozene klase na jednostavnije. Najoiigledniji indikator je veridini: ako je
napravili inItritivrtrt oknrT.cnjc kojc se jeclnostavno koristi. klasa velika, postoji moguinost da je preopSirna i treba je podeliti.
s72 Misliti na jeziku C++ Dodatak B: Vodii za programiranje na C++-u
573

15. potraTite dugac.ke definicije ftrnkciia dlanica. odrzavanje dugadke ikom- 23' Manje je bolje' podnite od najmanjeg moguieg interfejsa
plikovane fitnkcije je tesko iskupo ifunkciia verovatno obavlja previse
krase, onolik.
malog i jednostavnog koliko je potrebno za pribllZno
re.avanje problema,
aktiutosri.'lakvu fr-rnkciju bi bar trebalo podeliti na vise funkciia. Ona ali nemojte pokusavati da predvidite ru" nudi.,. na koje
bi sekrasa nzogrri
takode moTe ttkazivati na potrebu da se napravi nova klasa. koristiti. Tokom korisienja krase, otkriiete na koje nadine
morate prosiriti
16. I)otraZitc clLrgaike listc argumenata. Zbog takvih lista postaje te5ko pisati, interfejs. Kada se k-lasa vei koristi, ne moZete suziti inrerf'ejs bez
iitati i odrT.aVati pozive firnkcija. PokuSaite da premestite funkciju dlanicu naru.avanja k_lijentovog koda. Ako treba da dodate
nor" funt.i;., to neCe
tr klastr gde (viSe) pripada i/ili joi prosledujte objekte kao argumente. naruSiti kdd, ali ie-biti neophodno ponovno prevodenje.
Medutim, eak r
17. Ne ponavljajtc se. Ako se deo koda ponavlja u vise funkcija u izvedenim ako funkcije dlanice zamenjuju funkcionalnost starih, ostavite pos-
19ve
klasarna, smestite taj kdd p jednu funkciju osnovne klase i pozivalte je iz tojeii interfejs (ako Zelite, m-oZete objediniti funkcionarnost u rearizaciji).
itrnkcija izvedenih klasa. KOd z,auz.ima manje mesta, a i sistem se lakie Ako treba da prosirite interfejs postojeie funkcije aoJuu*;"".,
l.gu.n.-
rnenja. Racli eflkasnosti mozete koristiti umetnutu funkciju. Ponekad ie nata, ne menjajte redosled postojeiih argumenata,
a svim novim argu_
otkrivanie zajednidkog koda dodati dragocenu funkcionalnost interfejsu. mentima dodelite podrazumevane vredlnosti _ tako
neiete narusiti
postojeie pozive te funkcije.
18. Potrazite iskaz-e switch ili ulandane iskaze if-else. To je obidno pokazatelj
ytrograntske prouere rlpa (engl. type-check codin$,Sto znadi da birate k6d 24. Proditajte naglas svoje krase da biste se uverili da
su logidne. vezu izmedu
koji c'c se izvriavati na osnoml informaciia o tipu (pravi tip moZda nije osnovne klase i izvedene k-lase aitajte kao ,,je", avezuizmedu
klase i objekta
oiiglc,dan). Ovrr vrstrr kocla obidno moZete zameniti nasledivanjem i poli- dlana kao,,mi".
rnorfrzrt'r<lnr - polirnorfni poziv ftrnkcije je pouzdaniji i olak5ava pro- 2 5 ' Kada birate izmedu nasledivanja
i slaganja, upitajte se da ri morate svoditi
Sirivaniit. klasu naviSe u osnormi tip. Ako je oagouo. odriean, koristite
,tugun;" u n.
19. S raikc glciliSta projcktovanja, potraZite i razdvojite stvari koje se menjaju nasledivanje. Tako se moZe eriminiiati uodena potreba
za viiestrukir,
od onil.r koje ostajr.r iste.'lb znadi da treba da pronadete elemente sistema, nasledivanjem. Ako izvodite klasu, korisnici ie smatrati
potrebno svodenje navi5e.
auj. ,..ouutno
k0jc [riste r.noZcla kasnije hte]i da promenite, a da ne morate ponovo da
projektrrjete, a zatim te elemente kapsulirate u klase. O ovome moZete 26. Ponekad treba izvesti krasu da biste pristupili zastiienim
dlanovima osno-
mnogo rriSe saznati iz poglavlja Obrasci proiektouania u drugom tomu. 'rne klase. To moze dovesti do potrete za visestrukim n*r.ai"un;.^. ato
2 0, I,azite na t,nri.iacije .l)va scnrantiiki razlidita objekta mogu imati identidne
objekte neiete svoditi navise, prvo izvedite novu krasu
radi pristupanja
aktivnosti ili odgovornosti i prirodno je nastojanje da jedan postane pot- zaStiienim dranovima. Zatim, umesto nasledivanja, krasama
tJ;eireua oa
klasa clrtrgog, kako bi se iskoristile prednosti nasledivanja. Ovo se naziva koriste noru klasu dodajte objekte re klase.
variiaciia, ali nc postoii nikakvo opravdanie za uspostavljanje veze nat- 27. obidno ie se osnorma klasa koristiti uglarmom za pravljenje interl.ejsa
klasa/porklasa ranto gde ona ne postoji. Bolje resenje )e da napravite opStu izvedenim klasama. zato,kad,apravite o,io*, klasu,
neka iun't<ciie etanrce
osnovnu klastr koia daic interfejs obema izvedenim klasama - biie podrazumevano budu potpuno virtuerne. Destruktor
takode moze biti pot-
ltorrcbno neito viSe prostora, ali iete ipak koristiti prednosti nasledivanja i puno virtuelna funkcija (kako bi ga izvedene krase
morale izridito ..oufinr-
vcrovatno iete napraviti bolji pro;ekat. sati), ali ne zaboravite da napisete telo funkcije
destruktora, postose uvek
2 I . Paziti. na ograniiat,anjepri nasledivanju. U najjasnijim projektima se izve-
pozivaju svi destruktori u hijerarhiji.
deninr klasanra dodaju nove moguinosti. U sumniivom projektu, ukla- 28' Kada klasi dodate virtuernu.funkciju, proglasite sve
funkcije te klase vir-
njaju se starc mogtlinosti iz izvedene klase, a ne dodaju se nove. Medutim, tuelnim i dodajte virtuelni-destrukior. ova"j pristup spredava
iznenadenja
pravila postoic cia bi se prekrsila i, ako polazite od stare biblioteke klasa, u ponasanju interfejsa. podnite da uklanjaie rezervisanu
rea virtuar samo
nroTc btti i:fikasniic da ogranidite postojeiu klasu u njenoj potklasi nego kada pobolj5avate efikasnost, a oprimizaio. ru. ukaZe
da 1e to pravl put.
da ponovo srrr.lkturirate hijerarhijr-r da biste novu klasu postavili na pravo' 29. Koristite podatke dlanove da opisete razrike
rnesto. iznati stare klase.
u vrednosti, a virtuerne
funkcije. za varijacile-u ponasanju. Ako pronadete
krasu koja koristi
22. Nt. pr()iirlitc osnovll [rrnkcionalnost gvodeniem potklasa. Ako je klasi promenljive stanja uz funkcije dranice koje menjaju
ponasan;'e no o.no*.,
ncophoriar.r rtcki clctretrt interfcjsa, on treba da bude u osnormoj klasi, a wednosri tih promenljivih, verovatno bi tiebalo da'promenite'prn;"tu,
i au
nr. rlorl:rl tokonr izvotlcnja. t) slrriajr.r da izvodenjem dodajete iunkcije razlike u ponasanju izrazite potk-lasama koje redefinisu
virtueine iunkcije.
ilarrrct', rrroTcla [ti lrcbalo rla ponovo pregledate proiekat. 30' Ako.morate da napisete k6d koji nije prenosiv, apstrahujte
tu uslugu i loka-
lizujte je unutar klase. ovaj dodaini nivo posredovanja
spreiava sirenje
neprenosivih elemenata kroz program.
s74 Misliti na jeziku C++ Dodatak B: Vodii za programiranje na C++_u
575

3 ). Iziregirvajte viicslrtrko nasleclivanjc. Ono slr-rZi da vas iz',r-rde iz neprilike, konstruktor osnovne
!1r. fiti ob].ekta dlana), a to verovatno nije ono Sto
rraroi-ito za popra','ljanje inti:rfejsa neispravrrih klasa nad kojima nemate hoiete. Da biste pozvali. konstruktor za kopiran je osnov,e LLu.", prn.r.ait.
kontrolrr (poglcclajte clrugi tont). Santo iskrrsni programeri bi trebalo da mu izvedeni objekat koji kopirate:
trgraclc rrrSestnrko nasleclivanje u projekat svog sistema.
Izvedena(const Izvedena& d) :
3 2. NcrIo jtc koristiti privatr.ro nasledivanje. Iako ta moguinost postoji u jeziku
0snovna(d) | // ...
39" Kada zaizved,enu krasu pisete operator
i prrvrcnreno lirnkcioniie, ona itat.iva zna(ajne nedoumice u kombinaciji dodere, setite se da izridito pozo-
sa idcntiflkacijorn tipa tokom izvrSavan;'a. Umesto koriSienja privatnog vete operaror dodele iz.osnorme klase. (pogledajte
poglavlje f +.j et o to n"
pristtrpa pri nasledivan ju, napravite privatni objekat dlan. uradite, nista se neie dogoditi s nasredenim d;ro;
objekte dlanove). D.a biste pozvaii operator dodere
oiieftuii.io ,uzi iru
33. r\ko su rlve klase medusobno funkcionalno povezane (kao Sto su kontej- orror.r" tctusl, toristite
ime osno'rme klase i operator razre5avanja
ncri i iteratori), Lrcinitc jeclnu klasu javnom ugneT-denom prijateljskom opsega:
klasorn clnrgc, kao ito se rr standardnoj biblioteci jezika C++ postupa sa Izvedena& operator=(const Izvedena& d)
{
iteratorima unLrtar korrtejnera (primeri su navedeni pri kraju poglavlja l6). 0snovna: : operator= (d) ;
'lako sc naglaiava veza izrnedn klasa, ali se i dozvoljava ponovno 40' Ako treba da umanjite potrebu za ponovnim prevodenjem
koriSclen je irnena klase pri ugne2clivanju u drugu klasu. U standardnoj bib- janja velikog projekta, tokom razvi-
upravljadke iaur" f"ngl. lr'iriin ,mra,
lioteci (,++-a definisana je klasa iterator, ugneZdena u svaku kontejnersku _korisrite
prikazane u poglavlju 5, a ukloniie ih samo
ako sistem nije dovoljno
klasu, tako da kontejneri imaju zajednidki interfejs. Drugi razlog za efikasan.
rrgneZdivanjc klase je privatna upotreba objekta u realizaciji. U ovom 4l . Izbeg^avajte pretprocesor. uvek koristite konstante
slueaju, rrgr.re2divanje vi5e sh"r7i z-a skrivanje realizacije nego za pove- umesto simbola i umet_
nutefunkcije umesto makroa.
z-rvanjc klasa i spre-avanje, ranije pornenutog, z-agadivanja imenskog pros- 42' odrzavajte sto uze oblasti vazenja, tako da vidljivosr
to rat. i Zivotni vek objekata
budu Sto manji. Thko se umanjuje moguinosr
34. I)reklapan jc opcratora jc sanro ,,zasladivad sintakse", drugaeiji nadin pozi- kori5ienja objekta u pogre_
Snom kontekstu i skrivanju g..:i. koiu je re5ko otkriti. Na primer, pret_
vanja lirrrkcijc. r\ko prcklapanjc opcriitora ne doprinosi jasnoii intcrlejsa postavite da imate kontejner i deo koda
klirst' i pojt'tJrrostar,'ljcnjLr koriSienja, nernojte ga koristiti. Napravite za koji mu iterativno f,ri.iupu. ,tto
kopirare taj k6d da bisre ga koristili s drugim iorrt.ln.ro-,
klasu sanro jeclarr opcratr)r za autorlatsku konverziju tipa. U op5ten-r slu- iskopirati velidinu starog kontejnera kao" gornju
ril'e";"" L"2.,.
['a ju, za prt:klapan jc opcratora sleclite srnernice, navedene u poglavlju.
granicu norog. M"arti,r,
ako stari kontejner nrje u tekuiol obrasti"vazenja,
greska de biti otkrivena
3 5. \t'rrolte se rrprrStati rr prcuran je rrr,r optimizacijr'I. Tu se kriju nevolje. lbkom tokom prevodenja.
pravljen ja prvc vcrzije siste ma posebno nemojte brinuti o pisanju (ili izbe- 43' Izbegavajte grobalne-promenljive. uvek nastol'te
gavartjrr) umetnLrtilr lirnkcija, pretvaranju nekih funkcija u nevirtuelne ili da podatke smestate u
klase. Verovarnije je da Ce se.pojavljivati potreba
skraiivanju koda radi efikasnosti. VaS osnovni cilj treba da bude doka- za globalnim irnt.i;u_u
nrqo globarnim promenrjivama, ari iete kasnije
zivanje ispravnosti pnljekta, osint ako projekat zahteva efikasnu realizaciju 3u iroZda ott.iti-Ju ui ,"
globalna funkcija bolje uklopila kao statidka
ot1 poietka.
runtiila era.,ica tiase.
44. Ako treba da dekrarisere krasu ili funkciju
36. Svakako cla neiete dozvoliti cla prevodilac umesto vas pravi konstruktore, iz biblioteke, uvek to iinite
ukljudivanjem datoteke.zaglavlja. Na p.i_..,
destrlrktore ili operator =. Projektanti klasa valja uvek taino da opiSu Sta ako hoieie au
funkciju za upisivanje uizriznitok, nikada nemojte *p.urt.
klasa treba cla radi i cla je drZe pod kontrolom. Ako ne Zelite konstruktor za sami deklarisari klasu
ostream koristeii nepotpunu speciflkaciju tipa,
kopirarrje ili operator =, dcklari5ite ih kao privatne. Zapamtite da, defini- poput:
cl ass ostream;
sanjcrrr bilo kog konstruktora, sltreiavatc pravljenje podrazurnevanog
konst rtrktol a. ovaj pristup dini vas k6d osetljivim na promene. (Na
primer, ostream bi
37...\ko vrria klasa saclrZi pokazivaee, moratc napraviti konstruktor za kopi- moglo biti ime definisa.ro redy, typea'ef.; Umesto
toga, uvek koristite
ran je, operatr)r = i dcstnlktor da bi klasa radila ispravno. datoteku zag\avlja:
3 8. Kada za izvedenu klasu l.liicte konstruktor za kopiranje, setite se da izridito #include <iostream>
Jloz.ovcte konstruktor za kopiran,e osnovne klase (i objekte dlanove).
(l)oglerlajtc poglavljc 14.) Ako to ne uradite, biie pozvan podrazumevani {ad1 nr.avite svoie klase, ako je biblioteka velika, obezbeditekorisnicima
skraieni oblik datoteke zaglivlja s nepotpunim
specifikacijama tipova
(zna('i, dekraracijama imeni.kraial
za siuealev. , to;i-u ,r-i,,-.,'poi..t ni
samo pokazivadi. (To moZe ubrzati prevodenje.)
s76, Misliti na jeziku C++ Dodatak B: Vodii za programiranje na C++-u 577

45. Kacia ltirate tip rezultata preklopljenog operatora, razmotrite Sta ie se 52. Izuzetke izbacujte iz funkcija po wednosti, a hvatajte po referenci. prepu-
dogoditi akO su izrazi ulandani. Vratite kopiju lwednosti ili referencu stite mehanizmu za obradu izuzetaka da upravlja memorijom. Ako izbacu-
(return *this), tako da se moZe koristiti u ulandanom izrazu(A = B = C)' jete pokazivade na objekte izuzetaka, napravljene u dinamidkoj memoriji,
Kada deftniSete operator -, prisetite se da je x=x. funkcija koja hvata iz:uzetak mora znati da ga uni5ti, a to je lo5a tehnika.
46. Kada piSetc fLlnkcijtr, neka vas prvi izbor bude prosledivanje argumenata Kada hvatate izuzetke po wednosti, izazivate dodatno pravljenje i

po referenci konstante. Ako rle morate da meniate prosledeni objekat, ovaj uniStavanje objekata; Sto je joS lo5ije, izvedeni delovi objekata izuzeraka
po vred- mogu biti odsedeni tokom svodenja naviSe po wednosti.
ltostr.rpak jc najirolji. Sintaksa je jedrrclstavna kao prosledivanja
posti, ali jc raz.lika u torle Sto ne zahteva skupe pozive konstruktora i 53. Nemojte pisati svoje Sablone klasa, ako ba5 ne morate. prvo pregledajte
clcsrlrktora za lokalne kopi,;e. Svakako ne Zelite da previ$e brinete o efikas- standardnu biblioteku C++-a, a zatim biblioteke proizvodada alatki
nosti (lok projcktrrjete ipravitc sistem, ali ta navika vodi ka sigurnoj posebne namene. Kada ovladate njihovim kori5ienjem, znadajno cete
pr-rbedi. poveiati svoju produktivnost.
47. lmajte na urnu prtvremene objekte. Kada poboijSavate performanse, 54. Pri pravljenju Sablona, potraZite kdd koji ne zavisi od tipa i smestite ga u
pazite na pravljenje privremenih objekata, narodito uz preklapanje opera- obidnu osnovnu klasu, kako biste spredili nepotrebno Sirenje koda. Kada
tora. Ako imate sloZene konstruktore i destruktore, cena pravljenja i koristite nasledivanje ili slaganje, moZete napraviti Sablone u kojima je
uniStavanja privremenih obiekata moZe biti visoka. Kada iz funkcije veliki deo koda zavisan od tipa i, samim tim, neodvojiv od dablona.
waiate wednost, uvek pokusajte da definisete objekat,,u mestu", poziva- 55. Nemojtekoristitifunkcije izzaglavlja<cstdio>, kao Sto jeprintfO. Umesto
juii konstruktor u iskazu zaizlaz. iz funkcije: toga, naudite da koristite ulazno-izlazne tokove: oni su bezbedni i pro5irivi
return MyType(i, j); i mnogo moiniji. VaS trud ie biti nagraden. Uvek koristite biblioteke C++-a
radije nego biblioteke C-a.
utnesto:
f4yType x(i, j); 56. Izbegavajte ugradene tipove jezika C. Oni su podrZani u C++-u radi pov-
return x; ratne kompatibilnosti, ali su mnogo manje moini od kJasa, pa bi se
potraga za gre5kama produZila.
Prvi iskaz- t.a it.laz, takoz-vana optimizaciia rezultata (engl. return-ualue
57. Kada koristite ugradene tipove za globalne ili automatske promenljive,
optitnizatiotl), uklanja potrebu za pozivanie konstruktora za kopiranje i
nemojte ih definisati do trenutka inicijalizacije. DefiniSite jednu promen-
destruktora.
ljivu po redu koda i odmah je inicijalizujte. Kada definiiete pokazivaee,
48. Kada pravite konstruktore, razmotrite izuzetke. U najboljem sludaju, kon- pi5ite '*' pored imena tipa. To moZete bezbedno uraditi ako definiSete
srrukror neie uraditi niSta sto pravi izuzetak. U sledeiem sludaju, klasa ie jednu promenljivu po redu. Ovaj nadin pisanja manje zbunjuje ditaoca.
biti sa-injer.ra i izvedena samo iz pouz.danih klasa, tako da ie one automat-
58. obezbedite inicijalizaciju u svim aspektima koda. Inicijalizujte wednost
ski osloboditi resurse u sludaju izuzetka. Ako morate da radite s pokaziva-
svih dlanova u listi za inicijaiizaciju konstruktora, dak i u sludaju ugradenih
dinra, odgovorni ste z-a hvatanje izuzetaka i oslobadanje svih resursa
tipova (koristite pozive pseudokonstruktora). Korisienje liste za inicijali-
vez-anih pokazivadima, pre nego Sto napravite izuzelak u konstruktoru.
zaciju desto je efikasnije pri inicijalizaciji podobjekata - u suprotnom se
Ako konstrtrktor ne moZe da napravi ispravan objekat, izazoite izuzelak.
poziva podrazumevani konstruktor, a na kraju pozivate i ostale funkcije
49. Ll konstruktorirna radite samo ono Sto je neophodno. Tako umanjujete dlanice (verovatno operator =).
koriSienje resursa pri poz.ivanju konstruktora (mnogi moZda nisu pod
59. Nemojte koristiti oblik definisanja objekta MojTip a = b;. Ova moguinost
VaSOnt kontrolont), a i verovatnoiu da konstruktori naprave izuzetke ili
je glavni izvor zabune, po5to se poziva konstruktor umesto operatora
izaz.ovu proltlerne. =.
Radi jasnoie, uvek budite odredeni i koristite oblik MojTip a(b); Dobijaju
50. Destruktor je odgovoran za oslobadanje resursa zauzetih tokom Zivotnog se identidni rezultati, a neiete zbunjivati druge programere.
veka objekta, a Ire samo tokom pravljenja objekta.
60. Koristite izridite konverzije, opisane u poglavlju 3. Konverzija nadjadava
5I . Koristite hijerarhije iztzetaka, po moguinosti izvedenih iz standardne uobidajeni sistem tipova i predstavlja potencijalno mesto greske. podto
hijerarhije iz-vze:u.ka iezika C++ i ugnezdite ih, kao javne k-lase, u klasu koja operatori izridite konverzije nisu univerzalni kao konverzija na jeziku C,
pravi izuz.ctke. Blok za obradu izuzetaka moze uhvatiti odredene tipove vei imaju jasne namene, svako ko traZi greSke i odrZava kOd moZe lako
iztzetaka, praiene osnormim tipom. Ako dodate nove izvedene izuzetke, naii mesta gde su se najverovatnije dogodile logidke gre5ke.
postojeii kod klijenta ie i dalje hvatati izuzetak preko osno'rnog tipa.
578 Misliti na jeziku C++ Dodatak B: Vodit za programiranje na C++_u
579 t
6l . Da bi prograrn bio pctuzdan, mora biti pouzdana svaka komponenta' U 70' Sakrijte pokazivade u kontejnerskim krasama. otkrijte
ih samo ako name.
svakoj klasi kojrr pravite koristite sva sredstva koia vam pruZa jezik C++: ravate da neposredno radite s njima. pokazivadi
su uu"t Ulti giurrni iruo,
kontr(tlu pristirpa, izt-tzetke, konstantnost, proveru tipova itd. Na tai nadin greSaka' Kada koristite operator new stavite dobijeni potazirii u ton,"1
nro7.e.re bezbeclnO preii na sledeii nivo apstrakciie pri izgradnii svog ner' Dajte prednost resenju da kontejner poseduje
svoje pokazivaee, tatu
sistenta. da bude odgovoran za brisanje. eak je Uoile
omorati pokazivad klasom, a
ako hoiete da i dalje izgleda kio pokazivad, preklopite
62. Isl.rravnclkoristitcko6stantnevrecinosti.'Iakoomoguiavateprevodiocuda operarore -> i x. Ako
prcpozna greske koje bi inaie bilo tesko pronaii. ova navika zahteva malo morate imati nezavisni pokazivad, obavezno ga inicijalizujte,
najbolje
discipline i morate ie dosledno koristiti u klasama, ali se isplati. .adlesom objekta,.a nulom ako je neophodno. Dodelite-mu nulu kada ga
bri5ete, kako bi se spredila sludajna vi5lstruka brisanja.
63 . Iskoristite prednosti otkrivanja gresaka pri prevodenju. Uvek prevodite pro-
granre tako da se prikazuiu sve moguie upozoravajuie poruke i popravite 7l . Nemojte preklapati grobarne operatore new i delete,
nego to uvek uradite
k6cl cla bisre r.rklonili uz-roke upozorenia. Pisite k6d koji omoguiava prevodi- na nivou klase. preklapanje globalnih verzija utide
na .Ztot,rp.ri-p.o;.tut
ocu da pronade greSke, umesto da izaziva gre5ke tokom izwSavanja (na klijentskog programera i to treba da kontroiisu iskr;uei"o
Pri preklapanju operatora new i delete za klase,
auilri'[-;"t,u.
primer, nentoite koristiti promenliive liste argumenata, koje onemoguia- nemojte p.etpoitar,rti aa
vaju svt: provere tipova). Za otkrivanie gresaka koristite funkciiu assert( ), ali znate velidinu objekta- moZda je neko izveo krasu iz vase krase. Koristite
koristite izr.rz.etke za greSke tokom izvrSavanja. dati argument. Ako radite bilo sta posebno, razmotrite
erekat koji to moze
imati na potklase.
64. PokuSajte cla otklonite Sto vise greSaka tokom prevodenja, da se ne bi ispo-
ljavale tokom rzwsavania programa. Obradite gre5ku Sto bliZe mestu 72 ' Spredite presecanje objekta" Nikada nema smisla svoditi
navise ob;'ekat po
r.r;en()g nastanka. Pokuiajte da reiite problem na mestu nastanka pre izba-
wednosti. Da biste spredili svodenje navi.e po wednosti,
stavire fo,prno
civanja iztrzetaka. L.lhvatite sve izuzetke najbliZom funkcijom koja ima virtuelne funkcije u osnor,rru klasu.
dovoljno infrtrntacija za njihovu obradu. Udinite s izuzetkom sve Sto 73. Ponekad jednosta,rno grupisanje zawsava posao.
Jedan ,,putnidki sistem,,
nroT-ete na tekuienr nivou, a ako to ne resava problem, ponovo izbacite na avionskoj liniji sastoji se od nepovezanih elemenu,u,
."drst., Himatiza_
izLrzctak. (ll drugonr tomrr potraZite dodatne informacije.) cija, video itd., a jo. je mnoge potrebno napraviti u
avionu. Da li f ravite
6 5. r\ko koristite specifikacije iz-uz-etaka (o obradi iz.uzetaka moZete vise saznati
privatne dlanove i gradite kompretan nov interfejs?
Ne - u ovom sluiaju su
ru drugom tornu), instalirajte svoju funkciju unexpected( ) pomoiu funkcije
komponente takode.d.": interfejsa, pa treba da napravite yavne
set._unexpected( ). Vasa lunkcija unexpected( ) treba da evidentira gresku i objekte dlanove. Ti objektil*C
imaju svoje privatne realizacije, koje su ipak
ponovo izbaci tekuii izuzetak. Na tai nadin, ako se postojeia funkcija bezbedne. Imajte na umu da jeanostar.no grupisanje
nije reienje koje
rcdefiniSe i poine da izbacuje izuzetke, imaiete podatak o krivcu i mozete treba desto koristiti.
iz-meniti kfid koji jc poziva, tako da obradi izuzetak.
66. Napravite svojtr ltrnkcijlr terminate( ) (treba da ukaZe na greSku progra-
rnera) da eviclentira gresku koja je izazvala nastanak izuzetka, zatim oslo-
bodite sisternske resurse i izadite iz programa.
67. Ako destnrktor poziva neke funkcije, te funkciie mogu izazvati izuzetke.
Destruktor ne moZe iz-baciti izuzetak (to moZe dovesti do pozivanja
iunkcije terminate( ), koja ukazuje na programsku gre5ku), tako da svaki
rlestrr.rktor koii poz.iva funkcije mora uhvatiti i obraditi svoje izuzetke.
68. tl inreninra pnvatnih podataka ilanova ne koristite znakove za pod-
vlaccnjc i matlarsktr notaciitr, osim ako vei imate mnoStvo globalnih wed-
rrostil clozvolite da klase i irnenski prostori zastite imena u oblasti vaienja.
69. I,azitr. na prcklapanje, Ne bi trebalo da funkcija uslormo izvrsava kdd u
zirvisposti url vreclnosti argtlmenta, bez obzira na to cla li je wednost
podraz.ur.ncvana. [Jnresto toga treba da napravite dve ili vise preklopljenih
funkcija.
t

", !'
. *;i,
,,.,;i_,,.
. .l ,':'r
\.r: iar
rf. ':t:,
Dodatak C: Preporucena literatura s83
Misliti na jeziku C++ {
582 {

i
Using C++ (osborne/McGraw-Hill, I9B9)' Iedna od prvih knjiga o jeziku C++'
C i ViSe se ne Stampa, izaSlo je drugo izdanje, pod promenjenim nazivom C++
Jezik I
Inside & Out.
ThinkinginC:Foundationsforlava&C++'atttorChuckAllison(MindView)' .l

st.tttitlarnul-,,o....--'.,.tlisku.Ovajktlrsobuhvatalekciieislajdoveoosnovama i C++ Inside & Out (Osborne/McGraw-Hill, 1993). Kao Sto sam napomenuo, ovo
Ktrrs niie sveobuhvatan'
jezika (. i rr"l,)",la,,tt priprt:nrizii Lrccnie Iave ili C++-a i
je drugo izdanle knjige using c++. U ovoj kniizi je c++ prilidno dobro obraden, ali
za prelaz.ak na clruge programske jezike' je pisana oko 1992. pa je knjiga koju trenutno ditate prsana s namerom da je
otrrarlrr;e sanr. tcnrrl n..plroclne i
'ei
I)oclatni ocleljci se oclnose r.ra pojedir.radrie
jez-ike i uvode pojmove zna(aine za zameni. Vi5e podataka o ovoj knjizi, kao i izvorni kOd, mo2ete preuzeti s Web
preduslovi: izvesno iskustvo u radu
brrcluie prograrncrc na ]avi ili c++. Irozelini lokacij e www. BruceEckel. co m.
nivoa''kao Sto le Pascal' BASIC' Fortran ili Misliti na C++-u, prvo izdanje (Prentice-Hal], 1995).
s ttekit. prngron.,iki"'' it'ittu'..I'' visokog
u ko$tac CO-n']l i bez ovog priznanja' ali kurs nije Black Belt C++, the Maste/s Collection, urednik: Bruce Eckel (M&T Books,
LISP (mogtrie 1e uhvaiiti se
'
organizovan kao lrvod u osnove programirania) I994). ViSe se ne Stampa. Predstavlja zbirku radova raznih strudnjakaza C++, na
osno\,1l njihovih izlaganja na odseku za C++ Konferencije za razvoi softvera,
kojom sam predsedavao. Korice ove knjige su me podstakle da ubuduie uvek
Opite o jeziku C++ proveravam izgled korica.
ProgramskiiezikC++,autorBjarneStroustrup(Addison.Wesley,l997).Doizves. Misliti na Iavi, drugo izdanje (Prentice-Hall, 2000; Mikro knjiga 2002). Prvo
da koristite Bjarneovu knjigu kao izdanle ove knjige je osvojilo nagradu Productiviry Award dasopisa Software
nog srepena, cili ove kniige ie da vam omoguii
opis jezika od autora tog jezika, verovatno Deuelopment Magazine i 1999. godine, nagradu Editor s Choice Award. dasopisa
referencu. trosto nlegova tnjiga sadrzi
oko toga .ta se na c++-u
icre posegnu,i ,; ;j;;r, l; r.,iiie ,arresitisve nedoumice Jaua Deueloper's Journal. MoZe se preuzeti s Web lokacije www,BruceEckel.com.
kada ovladate vestinom jezika do
moze ili ne moze uraditi. tsiie vam potrebna
naPrednog nivoa.
C++Primer,treceizdanie,autori:Stanley[,ippmaniJosee'Lajoie(Addison.ispu- Detalji i tajne
\\resle),, 1998). Nije viSe sanro z-a podetnike -
to je postala debela knjiga' Naredne knjige dublje zalaze u teme jezika i pomaZu vam da izbegnete uobida-
uz Stroustrupovu kada poku5avam da jene zamke pri razvijanju programa na C++-u.
njena mnostvonl detalia, koju uzimam
raz.re5imn.to.po,.,opitanje'KnjigaMisllrinajezikuC++trebadapruZiosno\u Effective C++ (drugo izdanje, Addison-Wesley, 1998) i More Effective C++
z.a razunlevanje ove i StroLlstrupove knjige' (Addison-Wesley, 1996), autor: Scott Meyers. Ovo su klasiini, nezaobilazni tek-
I99B). Pisac
c & c++ coae capsutes, autor: chuck Ailison (Prentice-Hall,one teme koja moZda
stovi za reSavanje ozbiljnih problema i projektovanje koda na C++-u. U knjizi
obraduje samo koju ditate, pokusao sam da obuhvatim iizrazimmnoge koncepte iz ovih knjiga,
pretpostavlia au ,.e po'nuiete C i C++' a
praznine u
pri ueenju jezika. Knjiga popuniava ali se ne zavaravam mislju da sam uspeo. Ako se ozbiljno posvetite ieziku C++,
Iosiie znate ili ih nisie usvojili
znan jtr iez-ika (. i O++' na kraju ie vam zatrebati ove knjige. Postoji i izdanje na CD-u.
Komitet wedno radio Ruminations on C++, autori: Andrew Koenig i Barbara Moo (Addison-Wes-
The C++ Standard l)okitment' na eiiem ie sadrZaiu
svihovilrgodina.NaT-alost'llifebesplatan.MozetegakupitiuelektronskomPDF ley, I996). Andrew je autoritet u ovoj oblasti i radio je sa Stroustrupom na mno-
obliktr' za 1B LISI), prekoWeb adrese uttutu'cssinfo'com' gim aspektim a jezrka C++. Tokom vi5e godina, otkrio sam da ie o5trina njegovog
zapaLanjanadahnjujuia i od njega sam mnogo naudio.
Large-Scale C++ Software Design, autor: Iohn Lakos (Addison-Wesley, 1996).
Spisak mojih knjiga Obraduje vaZna pitanja i daje odgovore, znaiajne zarazvoi velikih i malih pro-
nisu sve dostupne'
Navedene sll po vrenlentl iziavanla' Trenutno jekata.
ComputertnterfacingwithPascal&C(lzdavadjeautor'prekofirmeEisys
www'Bruce- C++ Gems, urednik: Stan Lippman (SIGS, 1996)' Izbor dlanaka iz dasopisa
inrprint, 1988. Do knjige se mo7'e doii samo putemWe!,a$rgse
joS uvek vladao' a The C++ Report.
Ii'L'r,1.r'r.rrrr). [.Ivocl tt od vremena kada je CP/M The Design & Evolution of C++, autor: Bjarne Stroustrup (Addison-Wesley,
"f.ii,nniftu,
r.,ri.,io jez'ike visokog nivoa' a
DOS bio tta nonroltt. sam !:tl" lpl:"lt-':ll::
proiektima Knllgu sacl- 1994). Zapal.anja autora jezika C++ o razlozima raznih odluka tokom projekto-
kljudak raeunara, za r'rpravlianie raznim elektronskim vanja. Knjiga nije neophodna, ali je zanimljiva.
objavljeni u dasopisu Micro Cornuc.op.ia'prvomi
njavajr.r moii preradeni dlanci'
o'Briena' dugo-
,jrl.* iniopl.L, ,u koli sam pitun tou p,arafraziram Larryjanaibolii raiunar-
"'.it
godiSnjeg rrrednika -asopisa Soitware Deuilop1.nent Magazine"
ptanirali da naprave robota u saksiiil) Na
;k;;;;ii, koji je ikacla izJu, -'eut su
nastanka Interneta' Rad na ovoi
moirr veliktr 7.alost, Micro C ie nestao mnogo Pre
iskustvo'
tcniizi ie preclstavliao iz.uzetno dobro izdavaiko
t-
584 Misliti na jeziku C++ Dodatak C: preporucena literatura
58s

Anal iza i p roje ktovanje ovo ne treba da vas navede na pomisao da metodorogije
ne vocle nikuda, ncgo
Iixtreme Prograrnming Fixplained, rrutrtr: Kcrrt Rct:k (Aclclison-Wesley, 2000). da treba da se naoruzate cro zuba mentalnim
tehnikama i";. c. ,""-, p..'oii cra
Oltrtitrrttrtt ovtr krtjrtu. lai'no jt: tla radikalno pristr.lpant stvarima, ali sam uvek nastavite eksperimentisan;.e (,,ovo ne radi, isprobajmo
pete u stanie odbacivanja. (,,To uop.te
n.ia J.rgJ,j i nc dos_
os('('ittt dlt Iri trogito llostojati sasvirrr tlrrrga-iji, lnnogo bolji postupak raz-voja nije pioblem. Sve ;.e ,;u;no] n" moramc)
l)roqrattta i rttislinr cla rttLr sc XI'sasvirn pribliT-io. Iedina knjiga koja je ostavila ni.ta da men;'amo."). Mislim da ie vas steoece
knjige, ako ih i,1"ei,"i. pre nego
tako snaTirrr rrtisak na nrcrrt: jc Peoplcl,Vare (opisana u nastavku), koja se uglav- Sto se opredelite za neku metodologiju,
snabdeti tim tehnikama.
trotrr lravi okrttTctticrtr i ktrlturom u 1-roslrlr,nonr svelu. Extreme Programming Software Creativity, autor: Robert Glass (prentice-Hall,
I995). Ovo je najbolji
[:.r'ltlnittarlgovori o proglarniran.jrr, ali kntikuje mnogc stvari, dak inovija dosti- kompletnog pitanja
kratkih dlanaka i radova to;e Glass -..iof"gi;.
fbb.".?i-F*S!ed koji sam vicleo. To je zbirka
gttut'a. Oni iak idrr toliko clalcko da kaZu da su slike u redu, sve dok ne trolite ;L pisao i prikupljao (pl. plau8er j; jedan
saradnika), a odraZava od
prcviie vrelltenit gleditjtrii ih i sprernni su da ih izbace. (Zapaz.iCeIe da ova knjiga
na koncanta ricniri,.ltcc'At ll\41,') Mogu da zantislim da se odluka o radu u :i:gor9j. vlsegodiSnle'prouLavanye ove te"me. Sa drlaj 1c
zabavan i opSiran samo koliko n"oihod.,o da bi se saopstira susrina ne skade
ttt'kottt ptt'tluzct'tt riortosi sanro na oslrovu toga cla li sc tamo koristi XP Mala s teme na temu i nije dosadan. Ne samo -
da rasteruje magru, nego i Jalc srorinc
krtjiga, krittka poglitvlju, i'ita sc [rr:z na])ora, uzbudljive teme z-a razmi5ljanje. referenci na druge radove i studije. Trebalo bi au sri programeri
procitaju ovu knjigu pre nego ito zakorade i rukovodioci
Pociinjt'te cla zurniiljatc kako ruclite tr takrroj okolini i to vam stvara slike sasvim u modvaru n"t
no\'og s\,(,tit. SofyTg Runaways: Monumental Software Disasters," -.tnaotogi;..
.^
(Prentice-Hall, autor: Robcrr Glass
"""; k",;;;l;:,;';;;;,;;rri
tf ML Distilled, ;rrrlor: \,lartin []ou,lcr (drugo iz.danje, Addison-We sley, 2000). t 997). Velika stvar
u vezi s
tlost dana ono o demu ne govorimo: koliko no ,r._
[)rvi srrsrct s lJ\JL-orn jc obcshrabrrrjuii z.ltog velik<tg broja dijagrama i detalja. projekata doZivi neuspeh, i to
l)renta l:rtnlcrLt, r'cc'uta ovilt stvan nije neopl-rodna, tako da on izdvaja samo tragidan. Mislim da veiina nas i darje misli:,,Tose
me.,i ne moze-Jogooiti,, rili
sitS(itttt. I'n izratli rrajvt'icg broja projckata, treba poznavati samo nekoliko ,,To mi se ne moZe dogoditi ponori,l i da nas
to dovodi u nepovoljan poloiaj.
aiatki za pravljetrlr'tlrjagrarlit, a Irorvlerrtv cilj 1e da dodete do dobrog projekta, Ako imate na umu da stvari uvek mogu
urlt('slr) ria blrnctt'o svirrr vcitacikinr clctaljima. [)obra, tanka, ditlliva knjiga -
krenutr nizbrdo, taau
boljem poloZaju da ih usmerite na pravi"nadin. sie . mnogo
prva kojrr bi vallalo ltrocttati ako trcba da raztrrnete [JML. Object Lessons, autor: Tom l.orre (SIGS Books,
1993). kl5 jertna dobra knjiga
Thc llnified Software f)evelopment Process, autori: Ivar Jacobsen, Grady koja daje ,,globalni pregled,,.
Ilooch i lantes Ilrrnrltitrrgh (r\ddison-Wcslcy, l!)99). Zapodeo sam ditanje, pot- Peopleware, autori: Tom Demarco i limothy
l.ister (Dorset Housc, clnrgo
lltttlo priprt'ttrljt:n tlir rni sc krrjiga rrc svicli. [)clor,ala jc kao da sadrZi sve ele- izdanje, t99g)' Iako autori imaju iskustvo,..uruo;u
softvera, ova knjiga;c o pro-
tttettteclosircjttogttnivcrzitetskogucl2bcnika. Iliosamprijatnoiznenaden-samo iettllS i.timovima ,op.]": U centru paZnje su ljudii
n;ifrorepoi.e,UE]u n. ,.n
neki rnali tlelorri sadr7e objainjcnja koja ostavljaju utisak da nisu sasvim jasna ni nologija i njeni zahtevi. oni govore o rtuu.u.rlu.udnog
arrlorir.r.rii. Najvcii cico knjigc jc ijasan izanimljir,r Najbolje od svega je 5to biti zadovoljni i produktivn-i, a ne o prurriri-, kojihokruZenja u kome ie rjudi
drZavaju da bi postali podobni delovi masineriie. po
ti liudi treba da sc pri-
oltisitt.ti ltostttpak rno2c cia se prirncni ir prakticnom radu.'lo nije baS ekstremno mom
je glavni mi.rjenju, ovo drugo
progratrirart jc (i ncnra lasno definisano testiranje), ali je to takode deo UML sti- uzr:ok Sto se program.erismeskaju i t<rimalu gravama aot se uwa,a
neta
hijc iak i ako nc ntoZere da prihvatitc XII mnogi su se ukrcali u vagon s narpi- metodologija, azatim nastavljaju da rade
kao Sto uvek radili.
sont,,[]\'11. jc dobar" (ltez obzira na.srr/arr?r nivo iskustva), tako da ga ivi Complexity, auror: M. MitchellWaldrop (Simon
& Schusrer, 1992). Knjiga hro-
\r(,roYarno nro7L.r0 rrsvojiti. \lislinr da ova knjiga treba da bude vodid kroz UML i prati okupljanje grupe naudnika iz- razliditih
::t,"s$
Meksiku, da bi razmotrili postojeie probreme
oblasti u Sanra lreu, tr Novom
ttrrrZctc jc prit'itati poslc Irorvlcrovc knjige tlL,lL Disrillerl, kada vam zatrebaju ko,i nrsu reseni-,, p"iliir.eri*
rloclatni cictalji. :l1T'i,.3.(ekonomski p.otr.- t.rr., triotostl problem nasra,ka zivora, soci.-
I'rt'trt'go Sto izabt'rctt'[rilo kojrr rretoclologiju, korisno je da saznate miSljenja loSki problem ljudskog ponaianja itd).
Ukr.tanjem fizike, ekonomije, hemijc,
rrjiltovilt ltrotivnikit. \'1t'torlologrju lako ntoZete trsvo.jiti bez stvarnog razurrre- matematike, radunarsrva, sociorogije i drugih
nuuio, razvija se ,,-,,,ttrJilciptina.ni
vittt jit ottogit (1rt oioktrictc otl nle iliSta ona rnoZc rrCinitt za vas. Dnrgi je koriste pristup ovim problemima. sto.je;os vaznr,e,
i .,aitale drugaiiji na(.in razttiirjart ja
lo rzglcrla kao tlovoljno pt.ivliriarr raz.log. I\lcclrrtim, ljudska biia imaju jednu o ovim, veoma sloZenim,.problemima: aatli
oa mutem"atiikog 0.,.r.'inirrnu i
ttt'obit'tttt osobitttt:rtko verrrjrr cla tc ncito reSiti njihove problcme, oni ie to pro- privida da moZete napisati jed.nadinu
koja piedvida svako ponasanje, a brizi po.s-
[rati. ( Iir;r't'kspcrirncntisanjc, ito 1c tlobro.)Ali, ako to ne rc5i njihove probleme, ma-t.ranju i traZenju obrasca i poku.aju
da se ta pravilnost opona.a no .nrn"
ttrlvostrttiit'c napol iglasrro objavrti do kakvog srr velikog otkriia doSli. (To 1e nadine' (Na primer, kniiga hronoloski prati
nastanak genetidkih argoritarna.)
otlltaci,,'anjt', ito nije tioblo.) l)rct[)ostavka je da, ako moZete pril.uii idruge na verujem da je ovaj nadin razmisrjanja koiistan
kaoa posmarramo upravljanje sve
isti Itrocl, nedt:tt bitr usarnljeni, cak iako on ne plovi nigdc (ili tone). sloZenijim softverskim projektima.

You might also like