C++ (Deo Udzbenika)

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 68

ELEKTRONSKI FAKULTET U NIU

Katedra za raunarstvo

Milena Stankovi, Suzana Stojkovi,


Milo Radmanovi, Ivan Petkovi

OBJEKTNO ORIJENTISANI JEZICI


C++ i JAVA
sa reenim zadacima

Maj, 2005

OBJEKTNO ORIJENTISANI JEZICI


C++ I JAVA
sa reenim zadacima

Dr Milena Stankovi, Mr Suzana Stojkovi, Milo Radmanovi, Ivan Petkovi


PROGRAMSKI JEZICI C++ I JAVA
SA REENIM ZADACIMA
Izdava:

Elektronski fakultet u Niu


P. fah 73, 18000 Ni
http://www.elfak.ni.ac.yu

Recenzenti:

Dr ivko Toi.
Dr Dragan Jankovi

Glavni i odgovorni urednik: Doc.dr Zoran Peri


Odlukom Nastavno-naunog vea Elektronskog fakulteta u Niu, br. 1/05-151/05002 od 20.06.2005., rukopis je odobren za tampu kao pomoni udbenik.
ISBN 86-85195-08-X
CIP -
,
004.432.2.C++(075.8)
004.438JAVA(075.8).
OBJEKTNO orjentisani jezici C++ i Java
: sa reenim zadacima / STANKOVI, Milena
...[et. al.]. Ni : Elektronski
Fakultet, 2005 (Ni : Mikops). VI, 165 str.
: graf. Prikazi ; 24 cm. (Edicija
Pomoni udbenici / [Elektronski fakultet, Ni])
Na vrhu nasl. str.: Univerzitet u Niu,
Katedra za raunarstvo. - Tira 300.
Bibliografija: str. 165.
ISBN 86-85195-08-X
1. ,
) C++ b)
Java
COBISS.SR-ID 123772172

Pretampavanje ili umnoavanje ove knjige nije dozvoljeno bez pismene dozvole
izdavaa.
Tira: 300 primeraka

tampa: Mikops, Ni

SADRAJ
SADRAJ

Kako koristiti udbenik ?

vi

1.

UVOD U OBJEKTNO ORIJENTISANO PROGRAMIRANJE 1

1.1

Objektno orjentisana paradigma

1.2

Apstrakcija

1.3

Definicija objekta

1.4

Zatvaranje (Inkapsulacija)

1.5

Definicija klase

2.

C++ KLASE

2.1

Definisanje klase u jeziku C++

2.2

Kreiranje objekata

2.3

Konstruktori

10

2.4

Unitavanje (brisanje) objekata

14

2.5

Pristup funkcijama i atributima klase

16

2.6

Prijateljske funkcije klase

18

2.7

Operatorske funkcije

20

2.8

Zajedniki lanovi klasa

24

3.

NASLEIVANJE KLASA

3.1

Generalizacija

26

3.2

Nasleivanje

26

26

3.3

Polimorfizam

30

3.4

Viestruko nasleivanje

35

3.5

Virtualne osnovne klase

35

4.

++ ABLONI

4.1

Generisanje funkcija

39

4.2

Generisanje klasa

39

5.

ULAZ/IZLAZ

5.1

Ulazni tok

42

5.2

Izlazni tok

46

6.

OBRADA IZUZETAKA

6.1

Koncept obrade izuzetaka

51

6.2

Sintaksa

51

7.

++ - PRIMERI REENIH ZADATAKA

55

8.

UVOD U PROGRAMSKI JEZIK JAVA

98

8.1

Prevoenje programa

98

8.2

Put JAVA programa od sors-koda do izvrenja

98

8.3

Istorijat razvoja programskog jezika Java

99

9.

OSNOVNI KONCEPTI PROGRAMIRANJA U JAVI

100

10.

ELEMENTI PROGRAMSKOG JEZIKA JAVA

103

10.1

Leksiki elementi programskog jezika Java

103

10.2

Promenljive i tipovi podataka

106

10.3

Upravljake strukture u Javi

108

38

41

50

11.

KLASE U JAVI

112

11.1

Definicija klase

112

11.2

Kreiranje Java aplikacije

113

11.3

Metodi sa preklopljenim imenima

116

11.4

Konstruktori u Javi

118

11.5

Zavrni metodi

120

11.6

Preklopljeni metodi

120

11.7

Modifikator final

121

11.8

Modifikatori pristupa

122

11.9

Konverzija tipova podataka

122

12.

APSTRAKTNE KLASE I INTERFEJSI

12.1

Apstraktne klase

124

12.2

Interfejsi

125

13.

PAKETI

129

13.1

Korienje paketa

129

13.2

Kreiranje novog paketa

129

14.

JAVA - BIBLIOTKA KLASA

14.1

Paket java.lang

132

14.2

Paket java.io

134

14.3

Klase za rad sa character-tokovima podataka

137

15.

JAVA - PRIMERI REENIH ZADATAKA

144

16.

LITERATURA

165

iii

124

132

SPISAK REENIH ZADATAKA


Zadatak 7.1 Klasa Vektor ................................................................................... 55
Zadatak 7.2 Matrica - klasa.................................................................................... 57
Zadatak 7.3 Lanana lista (dokument) - klasa ....................................................... 61
Zadatak 7.4 Dvostruko spregnuta lanana lista klasa ......................................... 66
Zadatak 7.5 Vektor izvedena klasa ..................................................................... 70
Zadatak 7.6 Studenti izvedena iz apstraktne klase .............................................. 72
Zadatak 7.7 Krug izvodjenje u vie koraka ........................................................ 75
Zadatak 7.8 Radnici dve izvedene klase ............................................................. 76
Zadatak 7.9 Fuzija nizova objekata generika funkcija .................................. 81
Zadatak 7.10 Stek (vektor) generika klasa ........................................................ 84
Zadatak 7.11 Matrica generika klasa ................................................................ 86
Zadatak 7.12 Zamena elementa u matrici binarna datoteka................................ 90
Zadatak 7.13 ifriranje teksta tekstualna datoteka, obrada izuzetaka ................. 94
Zad atak 11.1 Rad sa datumima ....................................................................... 113
Zad atak 11.2 Izraunavanje vremena za koje se puni telo valjkastog oblika ... 117
Zad atak 11.3 Izraunavanje povrine krunog prstena ................................... 120
Zad atak 12.1 Izraunavanje povrine i zapremine rogljastih tela ................... 124
Zad atak 12.2 Implementacija iteratora ........................................................... 126
Zad atak 13.1 R ad s a mag acino m ............................................................... 129
Zad atak 14.1 Sortiranje vektora (rad sa datotekama) ..................................... 138
Zad atak 14.2 Sumiranje elemenata niza (rad sa tekstualnim tokovima podataka)
...................................................................................................................... 141
Zad atak 15.1 Rad sa linernom i kvadratnom funkcijom.................................. 144
Zad atak 15.2 Nalaenje izvoda polinoma ....................................................... 148
Zad atak 15.3 Sabiranje brojeva proizvoljne duine u brojnom sistemu
proizvoljne osnove ........................................................................................ 151
Zad atak 15.4 Rad sa displejima ...................................................................... 155
Zad atak 15.5 Nalaenje nule funkcije metodom polovljenja intervala ........... 158
Zad atak 15.6 Kreiranje platnog spiska ........................................................... 160

iv

PREDGOVOR

Objektno orijentisano programiranje je iroko prihvaena tehnika programiranja


koja se danas standardno primenjuje u razvoju softvera. Izuavanje objektno
orijentisanih programskih jezika je sastavni deo nastavnih programa na svim
kolama u kojima se pripremnaju kadrovi iz oblasti raunarstva. Objektno
orijentisani jezici se izuavaju na Smeru za raunarsku tehniku i infomatiku
Elektronskog fakulteta u Niu ve vie od deset godina. Kako je literatura iz ove
oblasti oskudna autori su se prihvatili zadatka da materijal koji je dugo godina
korien u odravanju predavanja, raunskih i laboratorijskih vebi iz ove oblasti
pripreme u vidu udbenika.
Ovaj udbenik se praktino sastoji iz dva dela od kojih se prvi odnosi na
programski jezik C++, a drugi na programski jezik Java. Ova dva jezika su
izabrana zbog toga to su zastupljena u nastavnom programu iz predmeta
Programski jezici ali i zbog toga to su to u praksi veoma zastupljeni programski
jezici.
Ovaj udbenik je prvenstveno namenjen studentima III godine Elektronskog
fakulteta u Niu koji izuavaju objektno orijentisane jezike u okviru predmeta
Programski jezici, a koriste ih i u okviru nekoliko drugih predmeta. Kako je novim
programom studija na Elektronskom fakultetu predvien predmet Objektno
orijentisano programiranje, ovaj udbrnik e moi da se koristi i u nastavi iz ovog
predmeta. Nadamo se da e udbenik takoe biti od koristi i svima onima koji
izuavaju objektno orijentisane programske jezike na drugim fakultetima ili su
odluili da samostalno savladaju neki od ovih jezika.
Posebno elimo da zahvalimo recenzentima prof. dr ivku Toiu i docentu dr
Draganu Jankoviu, na uloenom trudu da detaljno proitaju rukopis udbenika i
korisnim predlozima i primedbama.
Takoe, emo iskreno biti zahvalni svim korisnicima udbenika koji nam budu
ukazali na propuste i tamparske greke, kojih sigurno ima, i pored naeg
nastojanja da ih svedemo na minimum.

Kako koristiti udbenik ?


Ovaj udbenik je pripremljen u vidu tutorijala, i ne objanjava sve karakteristike
jezika C++ i Java. Cilj je da polaznik na praktinim i konciznim primerima ovlada
osnovnim konceptima objektno orijentisanog programiranja, kao i programiranja
primenom jezika C++ i Java. Za potpuniju listu karakteristika ovih jezika poeljno
je koristiti dodatnu literaturu koja je navedena na kraju udbenika.
Uz deo udbenika koji se odnosi na programski jezik C++ idu i dodatni primeri gotovi projekti realizovani u Microsoft Visual Studio 6 okruenju, koji su dostupni
na sajtu Katedre za raunarstvo Elektronskog fakulteta u Niu
http://cs.elfak.ni.ac.yu.
Radi lakeg korienja udbenika, neki njegovi delovi su drugaije formatirani.
Programski kod u primerima i reenim zadacima je predstavljen Courier
fontom.
Naredbe koje su pridodate postojeem kodu u skladu sa nekim prethodnim
objanjenjem bie oznaene Courier fontom, bold.
Tekst ispisan masnim slovima i uokviren na sivoj pozadini predstavlja vanu
napomenu.
Referenciranje na kompletan projekat koji se nalazi na sajtu http://cs.elfak.ni.ac.yu
bie predstavljeno pravougaonikom sledeeg oblika:
Poglavlje 2 - 01 - Kreiranje objekta

vi

I deo

Programski jezik C++

viii

UVOD U OBJEKTNO ORIJENTISANO PROGRAMIRANJE

1.

UVOD U OBJEKTNO ORIJENTISANO


PROGRAMIRANJE

1.1 Objektno orjentisana paradigma


U svakodnevnom ivotu esto upotrebljavamo pojam objekat, a da pri tome ni ne
pokuavamo da ga definiemo. ovek na svom putu do posla ulazi u kafi,
naruuje kafu, sedne, popije je, i zatim nastavi put. U kafiu postoji vie objekata:
sam lokal, sto, kafemat, kafa, itd. Svaki objekat ima vie razliitih karakteristika
(atributa) koje ga opisuju: kafi moe da bude otvoren ili zatvoren; kafa moe da
bude gorka, srednje slatka ili veoma slatka i da ima odreenu cenu; stolovi mogu
da budu zauzeti ili slobodni. Takoe, neki objekti mogu da vre i odreene
funkcije, npr. kafemat moe da pravi kafu, konobarica moe da donosi kafu.
Objektna orijentacija je tehnika modelovanje sistema; gde je sistem softverski
sistem ili sistem u optem smislu, npr. kafi iz prethodnog primera. Objektna
orijentacija opisuje, ili modeluje, sistem kao skup objekata koji su u meusobnoj
interakciji. Objektna orjentacija je slina nainu na koji ljudi doivljavaju okolinu.
Objektno orjentisana paradigma (ili OO) je savremeni pristup programiranju i
sastoji se od nekoliko koncepata, relativno novih u svetu programiranja, kao to su
smanjenje sloenosti razdvajanjem programa na manje module, smanjenje
sloenosti kroz apstrakciju (vidi 1.2), i korienje koncepta ponovne upotrebljivosti
(reuseability) radi lakeg i breg razvoja aplikacija.

1.2 Apstrakcija
Ljudi gledaju na fiziki svet sa razliitim nivoima apstrakcije. Voza vidi kola kao
transportni mehanizam sa tokovima, seditima i rezervoarom (neki nisu uli ni da
postoji ulje i da treba da se menja). Sa druge strane, automehaniar shvata kola
detaljnije: kao skup raznih mehanikih delova koji pokreu kola.
Telefon apstrakuje detalje o nainu uspostavljanja veze jednostavno, korisnika ne
interesuje ta se deava pri uspostavljanju veze njemu je vano da on moe da
razgovara.
Apstrakcija je proces ignorisanja detalja radi koncentrisanja na vanim, sutinskim
karakteristikama. Apstrakcija se fokusira na najvanijim svojstvima nekog objekta,
kao to je njegova svojstva ili funkcije, i ignorie nepotrebne detalje.
Na primer, motor ima dva toka i jedno sedite, dok automobil ima etiri toka i
etiri sedita. Ali, i motor i automobili su u sutini prevozna sredstva. Do ovog
zakljuka smo doli apstrakcijom detalja.
1

PROGRAMSKI JEZIK C++

1.3 Definicija objekta


Recimo da hoemo da napravimo prodavanicu automobila. Zapaamo da
automobil ima skup atributa koji ga opisuju (snaga motora, boja, klima, ...) kao i
skup funkcija koje on moe da izvrava (startovanje motora, grejanje sedita,
ubrzavanje,...). Sve te karakteristike emo staviti u katalog performansi
automobila. Meutim, osim gore navedenih atributa, ovaj automobil ima i XYZ
rafova i X metara ica. Da li je to potencijalnom kupcu automobila bitno?
Naravno da nije. Zbog toga ignoriemo nebitne detalje, a zadravamo samo nama
bitne. Kao rezultat ove apstrakcije dobijamo objekat. Taj objekat je apstrakovana
predstava automobila zato to zanemaruje nama nebitne detalje.
Objekti su apstrahovane predstave stvari.
Objekti je definisan atributima i funkcijama.
Meutim, ovako apstrakovan objekat je dobar samo u kontekstu prodavnice
automobila. ta ako hoemo da napravimo prodavnicu automobilskih delova? Da li
bi nam u tom sluaju takav objekat bio adekvatan. Ne, jer smo zanemarili detalje
koji su u ovom sluaju bitni!
Glavni problem u objektno-orjentisanom razvoju je nalaenje pravih objekata da bi
se modelovao predstavljeni sistem. Identifikovanje objekata u kontekstu problema
je umetnost, a ne nauka, tj. ne postoji jednoznano reenje.
Objekti imaju sledee karakteristike:

Objekti mogu da budu realni (stvarni) ili imaginarni (izmiljeni),

Objekti mogu da budu jednostavni ili sloeni,

Sastoje se od atributa i funkcija,

Nezavisni su,

Odgovaraju kontekstu problema.

Na primer, automobil je sloeni i realan objekat. Meutim, objekat ne mora uvek


da ima fiziku predstavu, to moe da bude i koncept. Na primer, bankovni raun
je vie koncept nego fiziki objekat.

1.4 Zatvaranje (Inkapsulacija)


Da li, da bi obavili tevefonski razgovor, morate da znate kako se uspostavlja sama
telefonska veza?
Ne, potrebno je samo da razumete kako da koristite telefon, tj. da razumete
interfejs (interface def. stanje ili taka preko koje razliite stvari interaguju) koji
se sastoji od dugmia, zvunika i mikrofona. Moete ignorisati interni proces
uspostavljanja veze koja moda prolazi i kroz nekoliko zemalja. Ukoliko se
2

UVOD U OBJEKTNO ORIJENTISANO PROGRAMIRANJE

tehnologija u uspostavljanju veze promeni, ili promenite operatera, vi ete i dalje


telefonirati na isti nain.
Inkapsulacija razdvaja spoljanje aspekte objekta, koji su dostupni drugim
objektima, od internih (unutranjih) implementacionih detalja objekta, koji su
skriveni od ostalih objekata.
Kupili smo automobil. Njegova implementacija su sva tehnika reenja smetena
ispod haube. Nas ne interesuje kako motor radi. Njegov interfejs su volan, kvailo,
gas, konica i ostale sitnice u kabini. Mi koristimo objekat (automobil) preko
interfejsa.
Meutim, u nekom trenutku odluimo da ugradimo sistem za alternativno gorivo
(plin). Menja se samo implementacioni deo, dok interfejs ostaje isti. Poto je
interfejs ostao isti, mi (drugi objekat koji koristi objekat automobil) ne moramo da
ponovo uimo kako da koristimo automobil (drugi objekti koji koriste promenjeni
objekat se ne menjaju).
Prednost inkapsulacije, koja krije implementacione detalje, je u tome da se objekat
moe promeniti. Ukoliko se samo dese promene u implementaciji, koja je inae
skrivena, i ukoliko je novi interfejs (deo dostupan ostalim objektima) ostao isti kao
original, objekti koji koriste promenjeni objekat ostaju isti.
Recimo da voza hoe da zaustavi automobil pritiskom papuice za koenje
(operacija interfejsa) koja pomou hidraulinog sistema (implementacija) smanjuje
brzinu automobila (privatni atribut, deo internih informacija). Voza uopte ne
mora da zna da postoji hidraulini sistem za koenje da bi ukoio automobil.
Objekat se sastoji iz tri dela tj. aspekta:

Javno dostupnog interfejsa: spoljanji deo koji ostali objekti koriste za


interakciju sa tim objektom (papuice za koenje, gas, volan
automobila,...)

Implementacije: interne funkcije i ostali implementacioni detalji; svrha


objekta (motor i ostala mehanika automobila)

Interne informacije: ta bi objekat trebalo da zna da bi izvrio funkciju.


(brzina automobila,...)

Funkcije i atributi nekog objekta se obino nazivaju lanovima objekta. lanovi


mogu da budu javni (public), privatni (private) ili zatieni (protected).
Ukoliko je lan definisan kao javni, bez obzira da li se radi o atributu ili operaciji,
on postaje deo interfejsa, to znai da je javno dostupan.
Ukoliko je lan definisan kao privatni, onda je on lan implementacije i nije javno
dostupan.

PROGRAMSKI JEZIK C++

U potpuno objektno orjentisanim sistemima, svi atributi su privatni i mogu biti


promenjeni ili dostupni samo preko javnih funkcija interfejsa.

1.5 Definicija klase


Na Slici 1.1 su prikazani razliiti objekti: automobil, brod, mlaznjak, motor,
jedrilica, voz, dvokrilni avion i raketa. Ovaj skup objekata je mogue klasifikovati
(grupisati) po nekim zajednikim karakteristikama. Na primer, motor, automobil i
lokomotiva se mogu svrstati u kopneni transport. Raketa, mlaznjak i dvokrilni
avion bi predstavljali vazduni transport. Brod i jedrilica predstavljaju vodeni
transport.

Slika 1.1 Prevozna sredstva


Objekti sa istim skupom karakteristika se grupiu u klase. Klase su abloni kojima
se opisuje struktura objekata. Kaemo da objekti pripadaju klasi koja ih opisuje, da
predstavljaju primerke (uzorke, istance) klase.
Mogue je sledee poreenje: Ukoliko je klasa nacrt zgrade na papiru, onda su
objekti sve zgrade izgraene po tom nacrtu.
Moe se rei da klasa predstavlja logiku apstrakciju, dok objekat poseduje fiziku
reprezentaciju.
U naem primeru bi to znailo da objekti motor, automobil i lokomotiva pripadaju
klasi kopneniTransport, raketa, mlaznjak i dvokrilni avion klasi

UVOD U OBJEKTNO ORIJENTISANO PROGRAMIRANJE

vazdusniTransport, i brod i jedrilica klasi morskiTransport, Slika


1.2.

Slika 1.2 Tri klase: za kopeneni, morski i vazduni transport

PROGRAMSKI JEZIK C++

2.

C++ KLASE

2.1 Definisanje klase u jeziku C++


U programskom jeziku C++ klase su strukture kojima se opisuju objekti. Klasa
opisuje svojstva objekata, njihove atribute i funkcije koje definiu ponaanje
objekata.
Na primer, kamion, autobus, automobil, motor i bicikal pored oiglednih razlika
imaju jednu zajedniku karakteristiku to su sve prevozna sredstva. Po tome se
mogu svrstati u klasu vozilo koja e predstavljati skup svih (kopnenih) prevoznih
sredstava.
Deklariemo klasu vozilo :
class vozilo {
};
Kada upotrebimo termin prevozno sredstvo, pozivamo se na klasu vozilo, jer se
misli na bilo koji primerak klase koji se klasifikuje kao vozilo (nije bitno da li je to
bicikal, automobil ili neko drugo prevozno sredstvo).
U okviru bloka klase ( izmeu zagrada{ i }) deklariu se atributi i funkcije klase
(umesto termina funkcije koriste se i termini: metodi ili operacije). U ovom
udbeniku bie korien termin funkcije.
class vozilo {
// atributi
// funkcije
};
Atributi i funkcije mogu da budu deklarisani kao private, protected ili
public. Privatni atributi klase su dostupni samo unutar klase u kojoj su
deklarisani dok su atributi deklarisani kao public javni i moe im se pristupiti od
strane drugih objekata koji su izvan klase. Atributi deklarisani kao protected su
takoe privatni u odnosu na klasu u kojoj su deklarisani ali su dostupni i iz klasa
koje su njeni potomci, o emu e biti rei kasnije.
Obino se atributi klase deklariu kao private ili protected ime se
ograniava direktan pristup ovim atributima spolja, a za promenu njihovih
vrednosti se moraju koristiti eksplicitno definisane funkcije deklarisane kao
public.
Recimo, u klasi vozilo moemo da deklariemo atribut stanje kojim emo
oznaavati da je motor ukljuen ili iskljuen (1 ukljuen, 0 iskljuen).

C++ KLASE

class vozilo {
private:
int stanje;
};
Klasi emo dodati dve funkcije, ukljuci() i iskljuci(), za paljenje i
gaenje motora, respektivno. Prva funkcija atributu stanje klase vozilo
dodeljuje vrednost 1, a druga vrednost 0.
Ove dve funkcije emo deklarisati unutar klase vozilo kao public, da bi ih
mogli pozivati izvan klase. U okviru deklaracije klase bie navedeno samo
zaglavlje ovih funkcija, interfejs preko kojeg ih pozivamo, ali ne i telo funkcija.
Deklaracija funkcija se daje prema sledeoj sintaksi:
<tip promenjive koji operacija vraa> <ime funkcije> (
<lista argumenata>);
Na primer:
int promeniBrzinu ( int brzina );
Unutar jedne klase mogue je definisati i vei broj funkcija sa istim imenom koje
se razlikuju po broju i tipovima argumenata. Tako u klasi vozilo moe da postoji
i druga funkcija promeniBrzinu koja brzinu poveava, na primer, uvek za 1 i
ija bi deklaracija imala sledei izgled.
int promeniBrzinu ( );
Parametri funkcije u programskom jeziku C++ mogu da imaju i svoje
podrazumevane vrednosti. Pretpostavimo da u prvoj funkciji argument nije nova
brzina vozila ve korak promene brzine. Druga funkcija bi takoe vrila promenu
brzine za zadati korak, ali u ovom sluaju bi korak bio unapred poznat i nema
smisla navoditi ga. U tom sluaju funkcija za promenu brzine bila bi deklarisana na
sledei nain:
int promeniBrzinu ( int korak = 1 );
Ovo znai da, ukoliko u pozivu funkcije nije naveden korak promene brzine,
njegova podrazumevana vrednost je 1.
Kada funkcija ima vei broj parametara, parametri koji imaju podrazumevane
vrednosti se piu na kraju liste argumenata.
Npr.
int f1( float a, float b, int c=0, int d=200 );
Funkcija f1 moe da se poziva navoenjem 2, 3 ili 4 stvarna argumenta. Ukoliko
je funkcija pozvana sa 3 argumenta, podrazumeva se da je u pozivu navedena
vrednost parametra c, dok se za parametar d uzima njegova podrazumevana
7

PROGRAMSKI JEZIK C++

vrednost. Nikako u pozivu ne moe da bude izostavljena vrednost parametra c, a


navedena vrednost parametra d. Zbog toga je kod navoenja argumenata sa
podrazumevanim vrednostima veoma vano voditi rauna o njihovom redosledu.
Definisanje funkcije podrazumeva ispisivanje tela (koda) funkcije i uglavnom se
vri van deklaracije klase. Najee su deklaracije i definicije u razliitim
datotekama. Uobiajeno je da se definicija klase nalazi u datoteci sa nastavkom .h
(u naem primeru to e biti datoteka vozilo.h), a definicija u datoteci sa
nastavkom .cpp (vozilo.cpp, u naem primeru).
(vozilo.h)
class vozilo {
private:
int stanje;
public:
void ukljuci();
void iskljuci();
}
Definisanje funkcija:
(vozilo.cpp)
void vozilo::ukljuci()
{
this->stanje = 1;
}
void vozilo::iskljuci()
{
this->stanje = 0;
}
U ovom primeru this je pokaziva na sam objekat klase ija je funkcija pozvana (u
ovom sluaju je to klasa vozilo).
Nije obavezno da se pokaziva this eksplicitno navodi. Mogue je navesti samo
ime atributa klase. U primerima koji slede operator this e biti korien isto radi
lakeg razumevanja koda.

2.2 Kreiranje objekata


Poto smo deklarisali i definisali klasu vozilo (i to zapisali u dve datoteke,
vozilo.h i vozilo.cpp), kreiraemo novu datoteku, main.cpp (ime je
proizvoljno) u kojoj emo iskoristiti klasu vozilo. U te svrhe potrebno je sa
8

C++ KLASE

definiemo globalnu funkciju main()koju emo smestiti u ovu datoteku. Sve tri
datoteke treba da budu u istom projektu.
(main.cpp)
void main()
{
}
Da bi funkcija main() videla klasu vozilo, treba da, korienjem include
direktive, ukljuimo header (zaglavlje) datoteku vozilo.h.
(main.cpp)
#include vozilo.h
void main()
{
}
U okviru funkcije main vrimo kreiranje (stvaranje, konstruisanje) objekata,
pravljenje primerka klase vozilo. To se moe uraditi na dva naina: statiki i
dinamiki:
(main.cpp)
#include vozilo.h
void main()
{
vozilo bmw;
vozilo *yugo;
yugo = new vozilo();
}
Prvi nain, statiki:
vozilo bmw;
Klasa vozilo se koristi kao apstraktni tip podataka i kreira se objekat kao njen
uzorak koji ima strukturu (atribute) opisanu klasom. Taj objekat se naziva stalni
objekat.
Drugi nain, dinamiki:
vozilo *yugo;
U ovom sluaju yugo je pokaziva na objekat klase vozilo, objekat nije kreiran,
ve to treba eksplicitno da se uradi pomou operatora new.
yugo = new vozilo();
9

PROGRAMSKI JEZIK C++

Operator new slui za dinamiko alociranje (dodeljivanje) memorije (kao malloc


u C-u). Tako napravljeni objekti su dinamiki objekti.
Sada u memoriji postoje dva objekta klase vozilo kojima moemo manipulisati:
mw i yugo.
U programu je mogue definisati i referencu (upuiva) na objekat klase vozilo.
Referenca je drugo ime za neki podatak (objekat). Zbog toga reference moraju da
se inicijalizuju prilikom definisanja:
vozilo& strano = bmw;
vozilo& domae = *yugo;
Parametri funkcija i atributi klase takoe mogu da budu objekti, pokazivai i
reference.
Ukoliko se objekat pojavi kao parametar funkcije u trenutku poziva funkcije pravi
se kopija objekta koji se pojavio kao stvarni argument, a na kraju izvravanja
funkcije taj objekat se brie iz memorije. Kada se referenca pojavi kao parametar
funkcije, od trenutka poziva funkcije to je drugo ime za objekat koji predstavlja
odgovarajui stvarni argument. To znai da se referenca u praksi najee koristi
da se omogui da se vrednosti stvarnih argumenata funkcije promene u njenom
telu. Drugi razlog zato se referenca koristi pri prenosu parametara je i uteda u
memoriji. Objekti mogu sadrati veliki broj atributa i veoma kompleksne atribute
pa je pravljenje njihovih kopija prilikom poziva funkcije krajnje neekonomino.
Ako se parametar u funkciji nee menjati iako je prenet po referenci, to se
eksplicitno navodi pomou kljune rei const ispred njegove deklaracije:
void f1( const vozilo& automobil)
Kada je referenca atribut klase onda se njena inicijalizacija vri u konstruktoru
(vidi sledee poglavlje).

2.3 Konstruktori
Proiriemo prethodni primer zahtevom da klasa vozilo ima i sledee atribute:
maksimalnu brzinu i trenutnu brzinu kao i funkcije: ubrzaj (kojom ubrzava) i
uspori (kojom usporava). Takoe emo obraditi sluajeve kada vozilo pri
ubrzavanju dostigne maksimalnu brzinu i kad pri usporavanju stane.
(vozilo.h)
class vozilo
{
private:
int stanje;
int max_brzina;
int brzina;
10

C++ KLASE

public:
void
void
void
void

ukljuci();
iskljuci();
ubrzaj();
uspori();

}
(vozilo.cpp)
void vozilo::ukljuci()
{
this->stanje = 1;
}
void vozilo::iskljuci()
{
this->stanje = 0;
}
void vozilo::ubrzaj()
{
if (this->brzina < this->max_brzina)
>brzina++;
}
void vozilo::uspori()
{
if (this->brzina > 0) this->brzina--;
}

this-

Meutim, u naem primeru javlja se problem jer nismo definisali maksimalnu


brzinu. To se moe reiti uvoenjem nove funkcije koja e dodeliti neku vrednost
za maksimalnu brzinu. Ovo reenje je dobro ukoliko svako vozilo (objekat tipa
vozilo) ima razliitu maksimalnu brzinu. Ali, ta ako hoemo da napravimo
stotinak vozila (objekata) identine maksimalne brzine? Ispisivanje stotinak
naredbi nije ba efikasno reenje.
Najbolje reenje bi bilo kada bi definisali inicijalnu (default) vrednost za
maksimalnu brzinu svih vozila, tako da nije potrebno eksplicitno zadavati
maksimalne brzine za svaki od ojekata klase vozilo.
To je mogue korienjem konstruktora. Konstruktor je posebna funkcija klase
koja ima isto ime kao i klasa ( T() za klasu T), a slui da se definiu poetne
vrednosti podataka klase. Konstruktor se poziva u trenutku kreiranja objekta klase.
Moe da bude bez argumenata ili da ima jedan ili vie argumenata. Takoe,
11

PROGRAMSKI JEZIK C++

mogue je da postoji vie od jednog konstruktora, pri emu svaki mora da ima
razliitu listu argumenata.
U zaglavlju klase vozilo deklarisaemo konstruktor bez argumenata i u okviru
njega definisati poetne vrednosti atributa klase:
(vozilo.h)
class vozilo
{
private:
int stanje;
int max_brzina;
int brzina;
public:
vozilo();
void ukljuci();
void iskljuci();
void ubrzaj();
void uspori();
}
U izvornu (.cpp) datoteku treba dodati:
vozilo::vozilo()
{
this->brzina = 0;
this->max_brzina = 180;
this->stanje = 0;
}
Time e pri inicijalizaciji objekata klase vozilo vrednost atributa max_brzina
biti 180.
Poglavlje 2 - 01 - Kreiranje objekta

ta ako bi hteli da postoji mogunost navoenja i druge maksimalne brzine


prilikom kreiranja objekta? Reenje bi bilo u uvoenju drugog konstruktora koji bi
imao argument preko kojeg bi se manjala vrednost atributa max_brzina.
(vozilo.h)
class vozilo
{
private:
int stanje;
int max_brzina;
int brzina;
public:
12

C++ KLASE

vozilo();
vozilo(int max);
void ukljuci();
void iskljuci();
void ubrzaj();
void uspori();
}
Inicijalizacija atributa moe da se navede u telu konstruktora, ali i u delu za
inicijalizaciju. Deo za inicijalizaciju se pie iza zagrlvavlja konstruktora, a pre
njegovog tela i od zaglavlja je odvojen simbolom :. U delu za inicijalizaciju
pozivaju se konstruktori atributa kao ikonstruktor roditeljske klase (o tome e
kasnije biti rei). Tu se obavezno inicijalizuju reference i konstantni atriburi.
(vozilo.cpp)
...
vozilo::vozilo(int max)
: brzina(0), max_brzina(max), stanje(0)
{
}
Koji e konstruktor biti pozvan odreuje se na osnolu liste argumenata. Ukoliko
kreiramo objekat korienjem prvog konstruktora (bez argumenata):
vozilo bmw;
ili
vozilo *yugo = new vozilo;
vrednost atributa max_brzina objekta bmw i yugo e biti 180. Ali, ukoliko
kreiramo novi objekat korienjem drugog konstruktora (sa navoenjem eljene
maksimalne brzine):
vozilo bmw(300);
ili
vozilo yugo = new vozilo(150);
vrednost atributa max_brzina objekta bmw e biti 300, a objekta jugo 150.
Poglavlje 2 - 02 - Klasa sa vie konstruktora

Ukoliko u klasi nije definisan ni jedan konstruktor prevodilac e sam definisati


konstruktor bez argumenata (takozvani podrazumevani konstruktor).

13

PROGRAMSKI JEZIK C++

Posebna vrsta konstruktora su konstruktori za kopiranje. Konstruktori za kopiranje


prave kopiju postojeeg objekta. Konstruktor za kopiranje klase vozilo izgledao
bi:
vozilo::vozilo(vozilo& v)
{
this->brzina = v.brzina;
this->max_brzina = v.max_brzina;
this->stanje = v.stanje;
}
Postojei objekat se konstruktoru za kopiranje obavezno prenosi po referenci. To je
razumnljivo jer, ukoliko se parametar prenosi po vrednosti, u trenutku poziva
funkcije se poziva konstruktor za kopiranje za sve objekte koji se prenose po
vrednosti. Tako bi se dobila jedna beskonana rekurzija koja bi na kraju dovela do
pada aplikacije.
Konstruktor za kopiranje se obavezno pravi kada klasa sadri dinamike atribute.
Ukoliko nije napravljen konstruktor za kopiranje, kada treba praviti kopiju objekta
svi atributii postojeeg objekta se jednostavno prepiu u atribute novog. Ako su
atributi postojeeg objekta pokazivai na druge objekte, kada se napravi novi
objekat, vrednosti pokaziva e se prepisati, tako da e i stari i novi objekat
ukazivati na iste dinamike lanove. To e dovesti do problema pri promenama
takvih lanove (ako se u starom objekat neto izmeni, promena e se odraziti i na
novi objekat, i obrnuto), ali e najvei problem biti pri brisanju objekata. Ako se
obrie, recimo, novi objekat i on ispravno obrie i sve svoje dinamike lanove,
aplikacija e ponovo da padne ukoliko se iz starog objekta pokua da pristupi
tom dinamikom lanu, ili u trenutku kada se brie stari objekat pa i on pokua da
obrie svoje dinamike lanove (koji su ve obrisani).

2.4 Unitavanje (brisanje) objekata


Ukoliko nam neki objekti vie nisu potrebni, preporuljivo je njihovo brisanje kako
bi oslobodili zauzeti memorijski prostor. Specijalna funkcija klase koja se
implicitno poziva u trenutku kada se objekat klase brie iz memorije je destruktor
Destruktor je funkcija bez argumenata i u klasi moe da postoji samo jedan
destruktor.
Identifikator destruktora je isti kao identifikator klase, sa prefiksom ~ na poetku
(~T() za klasu T). Dodaemo naem primeru sledei kod:
(vozilo.h)
~vozilo();
(vozilo.cpp)
vozilo::~vozilo()
{
14

C++ KLASE

// telo desktruktora
}
Ukoliko se ne definie destruktor, podrazumeva se destruktor sa praznim telom.
Kada i zato koristiti destruktor? Ukoliko smo u okviru nekog objekta kreirali
dinamike strukture (lanane liste, stabla, ...) ili objekte, moramo radi oslobaanja
memorije, pre unitavanja tog objekta da unitimo i te strukture i objekte. U praksi
se deava da doe do gomilanja neunitenih dinamikih struktura i objekata ako se
objekat u kome se kreiraju vie puta kreira i unitava a da se pri tome ne unitavaju
uredno kreirane strukture. To dovodi do toga da sistem ostane bez memorije i
aplikacija pada (memory leak). Takve greke se veoma teko otkrivaju jer
aplikacija neko vreme radi stabilno, a onda u nekom proizvoljnom trenutku
padne. To se takoe, deava nezavisno od procesorske i memorijske snage
raunara. to raunar ima veu memoriju, to je ovu greku tee otkriti (jer e
sistem ree padati)!
Kada se destruktor automatski poziva?
Vratimo se naem primeru u kome je istanciran objekat bmw:
void main()
{
vozilo bmw(250);
// proizvoljan kod
}
Vreme ivota objekta bmw e biti sve dok se funkcija main izvrava. Onog
trenutka kad se main zavri, destruktor se automatski poziva i unitava objekat.
To znai da ukoliko neka funkcija statiki inicijalizuje objekat, taj objekat e
postojati sve do zavretka izvravanja funkcije.
Operator delete slui za dinamiko dealociranje (oslobaanje) memorije (nalik na
free u programskom jeziku C). Pomou njega se mogu eksplicitno unititi
dinamiki kreirani objekti, kao i sve ostale dinamike strukture (element lanane
liste moemo unititi sa delete(<pokazivac_na_element>)). Na primer,
dinamiki kreirani objekat jugo se moe unititi sa:
void main()
{
vozilo *yugo;
yugo = new vozilo();
delete yugo;
}
Poglavlje 2 - 03 Unitavanje objekata

15

PROGRAMSKI JEZIK C++

2.5 Pristup funkcijama i atributima klase


Da bi se pristupilo funkciji nekog objekta, potrebno je navesti ime objekta,
propraeno takom (.) i zatim ime funkcije sa odgovarajuom sintaksom (stvarni
parametri u okviru zagrada funkcije, ukoliko postoje). Navedena funkcija mora da
bude deklarisana u okviru klase korienog objekta.
<objekat>.<operacija>
<pokazivac_na_objekat> -> <operacija>
Ukoliko navodimo pokaziva na objekat, onda koristimo strelicu (->) umesto
take.
Recimo da hoemo da ukljuimo motor prvog vozila. To emo uraditi na sledei
nain:
bmw.ukljuci();
Vano je napomenuti da je motor drugog vozila i dalje ostao iskljuen, tj. operacija
ukljuci() je promenila samo atribut stanje objekta nad kojim je primenjena.
Uzimajui primer sa vozilo, ukljuiemo motore oba vozila, a zatim iskljuiti
motor prvog vozila.
(main.cpp)
#include vozilo.h;
void main()
{
vozilo bmw;
vozilo *yugo;
yugo = new vozilo();
bmw.ukljuci();
yugo->ukljuci();
}
Ista sintaksa vai i za pristup atribitima klase ako su deklarisani kao javni (public),
Na primer:
bmw.stanje = 1;
Meutim, poeljno je izbegavati direktno pristupanje atributima klase pomou
funkcija drugih klasa. Time se naruava koncept inkapsulacije. Zbog toga se
obino atributi klase deklariu kao privatni, a za pristup atributima koristite se
public funkcije klase za postavljanje i preuzimanje vrednosti atributa (u
engleskoj literaturi poznate kao set i get funkcije).
16

C++ KLASE

Funkcije za pristup atributima se obino prave kao inline funkcije. Telo inline
funkcija se pie direktno u definiciji klase, ili se u definiciji klase ispred deklaracije
funkcije navede kljuna re inline, a implementacija se navodi iza definicije
klase (u .h fajlu). Inline funkcije tede vreme izvrenja programa na taj nain to
prevodilac njihov kod umee u kod u svakoj taki njihovog poziva. Zbog toga se
kao inline definiu samo funkcije koje se veoma esto pozivaju, a ije je telo
veoma klatko. Neki kompilatori ak nameu ogranienje da funkcije koje sadre
cikluse ne mogu biti definisane kao inline funkcije.
Klasi vozilo dodaemo funkcije za postavljanje i preuzimanje vrednosti brzine.
(vozilo.h)
class vozilo
{
private:
int stanje;
int max_brzina;
int brzina;
public:
vozilo();
vozilo(int max);
void ukljuci();
void iskljuci();
void ubrzaj();
void uspori();
const int uzmiBrzinu() const {
return brzina;
}
inline void postaviBrzinu( int brzina );
};
void vozilo::postaviBrzinu( int brzina) {
this->brzina = brzina;
}
U ovom primeru moe se uoiti jo jedna novina. Ispred povratnog tipa funkcije
navedena je kljuna re const, to znai da je vrednost koju funkcija vraa
konstantna (ne sme se menjati dalje u programu). Iza zaglavlja funkcije navedena
je takoe kluna re const. To oznaava da je funkcija konstantna, tj. da funkcija
ne menja objekat nad kojim je pozvana. Kad god funkcija ne menja vrednosti
atributa treba je definisati kao konstantnu jer se nad konstantnim objektima klase
mogu pozivati samo konstantne funkcije. To znai da u programu moemo
definisati konstanti objekat:
const voziloNaIzlozbi(200);
Nad ovako definisanim objektom dozvoljeno je pozvati samo funkciju
uzmiBrzinu jer je trenutno u klasi samo ona definisana kao konstantna.
17

PROGRAMSKI JEZIK C++

2.6 Prijateljske funkcije klase


Klasi vozilo emo pridruiti funkciju koja e uporeivati maksimalne brzine dva
vozila. Na poetku deklaracije funkcije emo dodati modifikator friend koji
oznaava da ovoj operaciji mogu pristupati prijateljske funkcije.
Prijateljska funkcija klase je funkcija koja nije lan klase, ali ima pristip privatnim
lanovima te klase. To mogu da budu obine funkcije ili funkcije neke druge
(prijateljske) klase.
(vozilo.h)
class vozilo
{
private:
int stanje;
int max_brzina;
int brzina;
public:
vozilo();
vozilo(int max);
void ukljuci();
void iskljuci();
void ubrzaj();
void uspori();
friend bool uporediBrzine(vozilo& v1, vozilo& v2){
if (v1.max_brzina > v2.max_brzina) return 1;
else return 0;
}
};
Definicija prijateljske funkcije moe da se izvi na dva naina. U oba sluaja e se
smatrati globalnom funkcijom!
Prvi je inline, tj. u definiciji klase.
Argumenti funkcije uporediBrzine su reference na objekte klase vozilo.
Recimo da hoemo da u funkciji main uporedimo maksimale brzine dva
automobila koristei funkciju uporediBrzine. U tom sluaju funkcija main
predstavlja prijateljsku funkciju.
(main.cpp)
#include <stdio.h>
#include "vozilo.h"
void main()
18

C++ KLASE

{
vozilo bmw(230), ferrari(340);
if (uporediBrzine(bmw, ferrari))
brzi");
else printf ("Ferrari je brzi");
}

printf("Bmw

je

Funkcija uporediBrzine vraa true ukoliko je maksimalna brzina prvog


objekta vea od maksimalne brzine drugog (to u gornjem primeru nije sluaj).
Drugi nain je da se prijateljska funkcija deklarie u zaglavlju (vozilo.h) ali bez
bloka naredbi (tela funkcije):
friend void ispisiKarakteristike(vozilo& v);
a zatim da se u nekom implementacionom fajlu (recimo vozilo.cpp) definie kao
globalna funkcija:
void ispisiKarakteristike(vozilo& v)
{
printf ("max. brzina: %d \n", v.max_brzina);
printf ("trenutna brzina: %d \n", v.brzina);
printf ("stanje motora: %d \n", v.stanje);
}
Zato koristiti prijateljske funkcije klase?
Njihova najea upotreba je pri preklapanju operatora (operator overloading) o
emu e biti vie reeno kasnije. Moe se rei da se njihovom upotrebom poveava
efikasnost jer direktno pristupaju privatnim elementima, izbegavajui indirektni
pristup preko funkcija klase. Jo jedna od pogodnosti je i to to je upotreba tih
funkcija prirodnija onima koji su navikli na proceduralno programiranje. Umesto
bmw.uporediBrzine(ferrari) moemo pisati uporediBrzine(bmw,
ferrari). Taj efekat ne moemo postii definisanjem proizvoljne globalne
funkcije jer ona ne bi mogla da pristupi privatnim lanovima klase.
Zato NE koristiti prijateljske funkcije klase?
to se tie negativnih strana korienja prijateljskih funkcija, one predstavljaju
bone veze u hierarhiji klasa. Vodi se polemika da li one kre koncept
inkapsulacije, ili samo proiruju javni interfejs. Programski kod koji ih koristi e
generalno biti tei za razumevanje i podloniji grekama. Zbog toga, treba biti
oprezan pri korienju prijateljskih funkcija.
Poglavlje 2 - 04 Prijateljske funkcije

19

PROGRAMSKI JEZIK C++

2.7 Operatorske funkcije


Definiimo klasu za kompleksan broj. Ona bi trebalo da ima dva atributa: za realan
i imaginaran deo, i jedan konstruktor koji e imati dva argumenta (za realni i
imaginarni deo):
(Complex.h)
class Complex
{
public:
double real;
double imag;
public:
Complex(double r, double i);
};
(Complex.cpp)
#include "Complex.h"
Complex::Complex(double r, double i)
{
real = r;
imag = i;
}
Dodajemo i globalnu funkciju main u kojoj emo inicijalizovati objekat klase
Complex:
(main.h)
#include <stdio.h>
#include "Complex.h"
void main()
{
Complex c(10,5);
printf ("realni deo = %f, imaginarni deo =
c.real, c.imag);
}

%f\n",

Naredbom Complex c(10,5) inicijalizuje se objekat klase Complex sa


realnim delom 10 i imaginarnim delom 5.
Meutim, ta ako hoemo da saberemo dva kompleksna broja? Kako za sada
nemamo nikakav mehanizam za sabiranje kompleksnih brojeva, morali bi da

20

C++ KLASE

saberemo prvo njihove realne, a zatim i njihove imaginarne delove. To bi se


ponavljalo kod svakog sabiranja. Oigledno da je ovo vrlo neefikasno.
Mnogo efikasnije reenje bi bilo kada bi za sabiranje kompleksnih brojeva mogli
da napiemo naredbu kao i za sabiranje celih ili realnih brojeva:
c = a + b;
gde su a, b i c kompleksni brojevi. Tako neto moe da se postigne korienjem
operatorskih funkcija.
Dodaemo jednu operatorsku funkciju, i to za oduzimanje (-). Deklarisaemo je u
zaglavlju:
(Complex.h)
Complex operator- (Complex& a);
Ovu funkciju definiemo u implementacionom fajlu (Complex.cpp):
(Complex.cpp)
Complex Complex::operator- (Complex& a)
{
// b = t - a
Complex b;
b.real = this->real - a.real;
b.imag = this->imag - a.imag;
return b;
}
Poziv ove operatorske funkcije, po pravilu koje vai za bilo koju funkciju klase, bi
bio:
b = c.operator-(a);
Kako se radi o operatorskoj funkciji, moe se pisati i kao:
b = c a;
U prethodnoj naredbi iskorien je i operator = kojim se objektu b dodeljuje
objekat koji predstavlja rezultat operacije c-a. Na taj nain se svi atributi objekta
koji se nalazi sa desne strane operatora dodele dodeljuju odgovarajuim atributima
objekta koji se nalazi sa njegove leve strane. Ovo je, opet, prihvatljivo samo
ukoliko objekti ne sarde dinamike atribute. U suprotnom, i operator = mora biti
implementiran. Problemi koji nastaju pri realizaciji operatora = bi'e pokazani na
primeru klase Vector.
(Vector.h)
class Vector
21

PROGRAMSKI JEZIK C++

{
private:
int size;
int* elements;
public:
Vector ( int max )
{
size = max;
elements = new int[max];
}
~Vextor()
{
delete [] elements;
}
Vector& operator=( const Vector& v);
};
Prvi problem koji se javlja pri implementaciji operatora = je da vektori sa leve i sa
desne strane operatora ne moraju biti iste duine. Zbog toga u vektoru kojem se
dodeljuje vrednost treba obrisati prethodni niz elemenata i kreirati novi
odgovarajue duine. Drugi problem koji se odmah uoava je da e ovo brisanje
dovesti do problema ukoliko se sa leve strane operatora nae isti taj vektor. Zbog
toga je najkorektnije operator = u ovom sluaju realizovati na sledei nain:
(Vector.cpp)
Vector& Vector::operator=( const Vector& v )
{
if ( this != &v )
{
size = v.size;
delete [] elements;
elements = new int[size];
for( int i=0; i<size; i++ )
elements[i] = v.elements[i];
}
return *this;
}
Operatorske funkcije su ili lanovi (funkcije) klase ili obine funkcije (prijateljske)
koje imaju opti oblik:
operator op
gde je op simbol odgovarajueg operatora (npr. operator+, operator--).
Poglavlje 2 - 05 Operatorske funkcije

22

C++ KLASE

U jeziku C++ za operatorske funkcije postoje ogranienja:


Ne mogu da se piu operatorske funkcije za operatore pretprocesora.
Ne mogu da se piu operatorske funkcije za operatore ?:(ternarni), .(*lan
od), .*(pokaziva na lana) ili ::(razreenje dosega).
Ne mogu da se izmiljaju novi operatori.
Ne mogu da se menjaju asocijativnost, prvenstvo ili vrsta (binarni ili unarni)
operatora.
Operatorske funkcije, u zavisnosti kako se postupa sa prvim operandom, mogu biti:
operatorske funkcije lanice klase
samostalne operatorske funkcije.
Pravila za pisanje operatorskih funkcija kao funkcija lanica klase su:
Unarni operatori - Funkcija lanica nema argumente. Jedan jedini argumet
je objekat koji se koristi za poziv funkcije lanice
Binarni operatori - Funkcija lanica ima jedan argument. Levi operand je
objekat koji se koristi za poziv funkcije, a desni operand je argument
funkcije lanice.
Unarni i binarni operatori - Operatorska funkcija mora da se pozove
objektom ispravnog tipa. Prevodilac e izvriti konverziju levog (za binarne
operatore) ili jedinog operanda (za unarne operatore). Uobiajena pravila za
konverziju se primenjuju na desni operand (za binarne operatore).
Osobine samostalnih operatorskih funkcija:
Za binarne operatore samostalne operatorske funkcije se ponaaju
simetrino. I levi i desni operand podleu uobiajnoj konverziji i nije nuno
da levi operand bude objekat.
Samostalne operatorske funkcije mogu da se piu i za klase iz biblioteka
(klase koje niste sami kreirali).
Meutim, ne mogu sve operatorske funkcije da budu samostalne. Tako, sledee
funkcije moraju da se piu iskljuivo kao funkcije lanice klase: operator=(),
operator()(), operator[](), operator->().
Izbor povratnih tipova operatorskih funkcija:
Operatori koji menjaju levi operand (npr. =) treba da vrate referencu na levi
operand.
Operatori koji biraju ili isporuuju operande (npr. [], ->, ()) obino treba da
vrate referencu na izabranu vrednost.
Operatori koji izraunavaju novu vrednost, a ne menjaju svoje operande
(operatori nad bitovima, +, -, *, /, %, &, \, ^, &&, ||, unarni (-, +), !~) obino
treba da vrate kopiju lokalno kreiranog objekta, tj. Da lokalne objekte vrate
po vrednosti.
Preinkrement i predekrement - obino treba da vrate referencu na operand.
Postinkrement i postdekrement - obino treba da sauvaju kopiju svog
operanda, izmene operand i zatim vrate kopiju.
23

PROGRAMSKI JEZIK C++

U sledeem primeru je isti operator realizovan na dva naina, kao prefiksni i


postfiksni.
class demo{
privat:
int val;
public:
demo& operator++()
// prefiks
{
val++;
return *this;
}
demo operator++(int)
// postfiks
//da bi se realizovao kao postfiksni, uvodi se
// formalni argument koji se u telu
// funkcije i ne koristi
{
demo tmp;
tmp.val=val;
val++;
return tmp;
//vraa objekat po vrednosti
}
};

2.8 Zajedniki lanovi klasa


Recimo da hoemo da napravimo lananu listu u kojoj svaki element sadri
podatak o ukupnom broju elemenata te liste u tom trenutku. Ukoliko bi obrisali
jedan element liste, morali bi, prolaskom kroz celu listu, da auriramo podatak o
broju elemenata u svakom elementu liste. To je prilino neefikasno i loe reenje.
Idealno bi bilo ukoliko bi svi elementi liste itali vrednost tog podatka sa jednog
mesta.U tom sluaju ne bi bilo problema sa aururanjem liste. Zajedniki atributi
klase upravo to i rade. Ukoliko je broj elemenata liste zajedniki podatak,
postojae samo jedna kopija tog podatka za sve elemente te liste. Isti prtincip vai i
za zajednike funkcije klase.
Stavljanjem modifikatora static na poetak definicije ili deklaracije nekog lana
date klase, taj lan postaje zajedniki za sve objekte te klase.
Zajedniki atibuti su slini globalnim podacima, ali se njihove vrednosti mogu
menjati samo na nain koji odgovara opisu klase.
Definisaemo klasu Abc koja e imati jedan zajedniki i jedan obian
(pojedinaan) atribut, i jednu zajedniku i dve pojedinane funkcije.
(Abc.h)
class Abc
24

C++ KLASE

{
static int a;
atributa
int b;
public:
static int getA();
int getB();
void incA();
1
};

//

deklarisanje

zajednickog

// pojedinacni atribut
// uzima vrednost a
// uzima vrednost b
// increase a, povecaj a za

Zajedniki atribut je samo deklarisan, ali nije i deifinisan. Da bi smo ga definisali,


u implementacionom fajlu (Abc.cpp) emo dodati:
int Abc::a = 10;
Definicija atributa mora obavezno da se izvri pre kreiranja bilo kog objekta te
klase, ili pre pozivanja funkcije main().
Definisanje funkcija bi izgledalo ovako:
(Abc.cpp)
int Abc::getA()
{
return Abc::a;
}
int Abc::getB()
{
return b;
}
void Abc::incA()
{
Abc::a ++;
}
Funkcija getA() je zajednika, i kao takva moe pristupati samo zajednikim
atributima, a ne i pojedinanim. Sa druge strane, pojedinana funkcija moe
pristupati i pojedinanim i zajednikim atributima.
Pri pristupanju zajednikim lanovima, izriito se preporuuje korienje izraza
oblika Klasa::lan (iako to nije jedini nain).
Poglavlje 2 - 06 Zajedniki lanovi klasa

25

PROGRAMSKI JEZIK C++

3.

NASLEIVANJE KLASA

3.1 Generalizacija
Pri razmatranju skupa objekata, pogodno je grupisati ih po slinim atributima i
zajednikim funkcijama. Na primer, hoemo da napravimo klasu koja e
predstavljati sve objekte koji slue za transport. Ona bi ukljuivala objekte aviona,
objekte automobila ili ak objekte brodova. Drugim reima, ona bi objedinjavala
klase
kopneniTransport,
vazdusniTransport
i
morskiTransport. Nazovimo tu klasu Transport. Ovu klasu smo dobili
procesom generalizacije.
Generalizacija je proces kojim se identifikuju i definiu zajedniki atributi i
funkcije u skupu objekata.
Identifikovanjem zajednikih delova sistema, generalizacija smanjuje redundansu
(viak) u razvoju i omoguava ponovno korienje pojedinih delova.

3.2 Nasleivanje
Klasa Transport je na vrhu hierarhije. Ona se zove superklasa (roditeljska
klasa), dok se klase vazdusniTransport, morskiTransport i
kopneniTransport nazivaju podklase. Hierarhija je prikazana na donjoj slici.

Slika 3.1 Hierarhija klasa


26

NASLEIVANJE KLASA

Atribute klase Transport (npr. maksimalan broj putnika) kao i funkcije te klase
(transportuj, stani, kreni) su nasledile podklase. Moe se takoe rei da su
podklase izvedene iz roditeljske klase.
Nasleivanje je mehanizam definisanja novih klasa od ve postojeih klasa. Tako
napravljene klase dele, tj. nasleuju lanove roditeljske klase.
Zbog ega je nasleivanje korisno? Ukoliko izvrimo bilo kakvu izmenu meu
lanovima roditeljske klase (promena ili dodavanje nekog atributa ili funkcije), ta
izmena e se automatski (tj. bez ikakve nae intervencije) odraziti i na sve podklase
(potomke) koje su izvedene iz roditeljske klase.
Nasleivanje se esto predstavlja pomou stabla. Kretanjem niz stablo, klase
postaju sve vie specijalizovane. Kretanjem uz stablo, klase postaju mnogo
generalnije.

Specijalizacija

Generalizacija

Slika 3.2 Specijalizacija i generalizacija


Objekti veoma retko pripadaju totalno razliitim grupama esto postoji znaajno
preklapanje funkcija meu grupama objekata.
Radi ilustracije, deklarisaemo klasu Transport. Posedovae par atributa
trenutnu brzinu i stanje rezervoara vozila. Ovaj atribut spada u interne informacije
klase (vidi 1.4).
Ova klasa e imati i dve privatne funkcije, koje predstavljaju implementacioni deo
klase. To bi bile funkcije za poveanje dotoka goriva u motor (ime se poveava
brzina)
(povecajDotokGoriva())
i
za
koenje
ukljuciSistemKocenja()). Ove dve funkcije su zajednike za sva
(motorna) prevozna sredstva.
Interfejs klase bi se sastojao od dve funkcije: za ubrzavanje vozila (ubrzaj()) i
za usporavanje vozila (uspori()).

27

PROGRAMSKI JEZIK C++

Vozaa ne treba da brinu implementacioni detalji, tj. kako i zbog ega se poveava
brzina vozila.
(transport.h)
class Transport
{
int brzina;
int stanje_rezervoara;
protected:
void povecajDotokGoriva();
void ukljuciSistemKocenja();
public:
void ubrzaj();
void uspori();
};
(transport.cpp)
void Transport::povecajDotokGoriva(){
}
void Transport::ukljuciSistemKocenja(){
}
void Transport::ubrzaj(){
povecajDotokGoriva();
}
void Transport::uspori(){
ukljuciSistemKocenja();
}
Prvo
emo
iz
roditeljske
klase
Transport
izvesti
podklase
vazdusniTransport, morskiTransport i kopneniTransport. Svaka
od ovih klasa e sadrati i neke dodatne atribute i funkcije svojstvene samo
njima. Radi ilustracije e biti prikazane samo .h datoteke.
Nasleivanje se vri tako to se pri deklaraciji klase, posle navoenja imena klase
stavi znak : (dve take), zatim tip nasleivanja (private, protected ili public, vidi
tabelu 1) i ime klase iz koje se vri nasleivanje:
class vazdusniTransport : public Transport
{
public:
28

NASLEIVANJE KLASA

povecajVisinu();
smanjiVisinu();
}
Ova klasa e sadrati sve atribute i funkcije svoje roditeljske klase, kao i dodatne
dve funkcije koje su dodatno deklarisane. Na primer:
void main()
{
vazdusniTransport avion;
avion.povecajVisinu();
avion.ubrzaj();

// nasledjena funkcija

}
Poglavlje 3 - 01 Nasleivanje klasa

Postoji nekoliko vrsta nasleivanja: private, protected i public. Zavisno od vrste


nasleivanja e se menjati i pristupanost lanova izvedene klase. Na primer,
ukoliko je pristupnost nekog lana roditeljske klase public, i ukoliko se podklasa
privatno izvede (private), onda e pristupnost tog istog lana u izvedenoj klasi
biti private.
Tabela 3.1 Vrste nasleivanja i pristupanost izvedenih klasa
Pravo pristupa
lanovima u
osnovnoj klasi

Pravo pristupa
istim lanovima u
privatno izvedenoj
klasi

Pravo pristupa
istim lanovima u
zatieno
izvedenoj klasi

Pravo pristupa
istim lanovima u
javno izvedenoj
klasi

(private)

(protected)

(public)

nepristupaan

nepristupaan

nepristupaan

nepristupaan

private

nepristupaan

nepristupaan

nepristupaan

protected

Private

protected

protected

public

Private

protected

public

Odnos sastoji se od znai da izvedena klasa sadri kopiju osnovne i svu njenu
funkcionalnost, ali objekti izvedene klase ne mogu da se koriste u sluajevima
kada se zahtevaju objekti osnovne klase.

29

PROGRAMSKI JEZIK C++

Kod privatno izvedene klase javni lanovi osnovne klase postaju privatni u
izvedenoj klasi.

3.3 Polimorfizam
Normalno, svaki tip vozila funkcionie na drugaiji nain brod, avion i automobil
usporavaju na sasvim drugaiji nain. To znai da im se menjaju i implementacioni
detalji, tj. svaki od njih bi trebalo da ima razliite funkcije za poveanje dotoka
goriva i sistema koenja. Sa druge strane, interfejs bi ostao isti usporavanje i
ubrzavanje vozila.
Polimorfizam omoguava da klasa saopti da ima isti interfejs kao i osnovna klasa,
ali da je ponaanje izvedene klase razliito od ponaanja osnovne klase.
Na primer, avion usporava na sasvim drugi nain od automobila. Samim tim bi
trebalo da je drugaija i njegova funkcija ukljuciSistemKocenja. Ustvari,
svaka od izvedenih klasa (vazdusniTransport, morskiTransport i
kopneniTransport) trebalo bi da ima drugaije definisanu funkciju
ukljuciSistemKocenja. Polimorfizam omoguava upravo to da izvedene
klase imaju svoje verzije funkcija deklarisanih u osnovnoj klasi.
Polimorfizam se postie deklarisanjem eljenih funkcija osnovne klase virtualnim.
Ako izvedena klasa ne definie virtualnu funkciju osnovne klase, ona jednostavno
usvaja ponaanje osnovne klase.

3.3.1 Virtualne funkcije


Virtualna funkcija je funkcija lanica za koju se oekuje da bude redefinisana u
nasleenim klasama.
Da bismo omoguili polimorfizam funkcije ukljuciSistemKocenja u
gornjem primeru, potrebno je da u deklaraciji te funkcije u osnovnoj klasi dodamo
prefix virtual kako bi naznaili da je ta funkcija virtualna:
virtual void ukljuciSistemKocenja();
(transport.h)
class Transport
{
int brzina;
int stanje_rezervoara;
public:
void povecajDotokGoriva();
virtual char* ukljuciSistemKocenja() {return
Ukljucen;}
void ubrzaj() {povecajDotokGoriva();}
char* uspori() {return ukljuciSistemKocenja();}
};
30

NASLEIVANJE KLASA

(vazdusniTransport.h)
class vazdusniTransport : public Transport
{
public:
virtual char* ukljuciSistemKocenja(){
return Vazdusne kocnice podignute;
}
}
(kopneniTransport.h)
class kopneniTransport : public Transport
{
public:
virtual char* ukljuciSistemKocenja(){
return Kocioni diskovi rade;
}
};
(morskiTransport.h)
class kopneniTransport : public Transport
{
public:
virtual char* ukljuciSistemKocenja(){
return Propeler koci;
}
};
U glavnom programu bie kreirani objekti definisanih klasa. U ovom primeru to
emo izvriti dinamikim putem, pomou pokazivaa (kreiranje objekata se moe
vriti i statiki (videti 2.2)).
(main.cpp)
void main()
{
Transport *vozilo;
vozilo = new vazdusniTransport;
vozilo->koci();
// ispisuje: Vazdusne kocnice podignute
delete vozilo;
vozilo = new kopneniTransport;
vozilo->koci();
// ispisuje: Kocioni diskovi rade};
31

PROGRAMSKI JEZIK C++

delete vozilo;
vozilo = new morskiTransport;
vozilo->koci();
// ispisuje: Propeler koci
delete vozilo;
}
Nepisano je pravilo da se destruktori klasa prave kao virtuelne funkcije. U
prethodnom primeru definisan je pokaziva tipa Transport. U trenutku brisanja
objekta (delete vozilo), kada destruktor nije definisan kao virtuelna funkcija,
poziva se destruktor klase Transport. U tom sluaju, da su u izvedenim klasama
postojali podaci smeteni u dinamikoj zoni memorije, oni bi ostali neobrisani, tj.
taj deo memorijskog prostora bi bio blokiran do kraja izvrenja programa. Kada se
destruktor osnovne klase definie kao virtuelan, onda se u trenutku brisanja
objekta, proverava stvarni tip objekta i poziva se destruktor odgovarajue izvedene
klase. Destruktor izvedene klase na kraju implicitno poziva destruktor osnovne
klase. Tako e u tom sluaju biti obrisani svi dinamiki atributi i izvedene i
osnovne klase.
Iz prethodnog razmatranja zakljuujemo da desturktori osnovih (roditeljskih) klasa
treba da budu virtuelni. Medjutim, stablo nasledjivanja nikada nije konano.
Verovatno e u nekoj drugoj primeni i izvedene klase biti dalje nasledjene. ak i
ako u postojeim klasama nema dinamikih podataka (to je bilo i u naem
primeru), to ne znai da ih nee biti ni u izvedenim klasama. Zato destruktor u
klasi treba uvek definisati kao virtuelnu funnkciju.
Nad objektom izvedene klase se ne moe pozvati funkcija roditeljske klase koja je
u izvedenoj klase predefinisana. Meutim, u funkcijama izvedene klase se moe
koristiti funkcija osnovne klase koja je u izvedenoj predefinisana. U tom sluaju
funkcija roditeljske klase se poziva na sledei nain:
<imeRodKlase>::<imeFunkcije>( <stvarniArgumenti> )
Ovaj mehanizam poziva funkcije roditeljske klase bie pokazan na primeru
kreiranja klase Krug i iz nje izvedene klase Valjak. Funkcija povrsina()
definisana u klasi Krug bie koriena u funkcijama za zrauvnavanje povrine i
zapremine u klasi Valjak.
(Krug.h)
class Krug
{
float r;
public:
Krug( float r );
32

NASLEIVANJE KLASA

float obim();
float povrsina();
};
(Krug.cpp)
Krug::Krug( float r )
{
this->r = r;
}
float Krug::obim()
{
return 2*3.14*r;
}
float Krug::povrsina()
{
return 3.14*r*r;
}
(Valjak.h)
class Valjak :: public Krug
{
float H;
public:
Valjak( float r, float H );
float zapremina();
float povrsina();
};
(Valjak.cpp)
Valjak::Valjak( float r, float H )
: Krug( r )
{
this->H = H;
}
float Krug::zapremina()
{
return ( Krug::povrsina()*H);
}
float Krug::povrsina()
{
return ( 2*Krug::povrsina() + obim()*H );
}
33

PROGRAMSKI JEZIK C++

Polimorfizam igra znaajnu ulogu u projektovanju objektno orjentisanih aplikacija,


pogotovu u primeni projektnih obrazaca (design patterns).
Poglavlje 3 - 02 Polimorfizam

3.3.2 iste virtualne funkcije, apstraktne klase


Izvedena klasa preiava i proiruje ponaanje osnovne klase. U mnogim realnim
aplikacijama, izvedene klase pored svojeg ponaanja, koriste osobine i ponaanje
osnovnih (roditeljskih) klasa. Ali postoje situacije kada je osnovna klasa
jednostavno skelet ili okvir, dok se funkcionalnost dobija tek kod izvedenih klasa.
U primeru transporta, funkcija povecajDotokGoriva() klase Transport
nema telo, zato to se implementacija razlikuje od vozila do vozila. Ona samo
ukazuje na zajedniki oblik i naziv funkcije, dok telo funkcije varira zavisno od
implementacije. Svako pisanje tela funkcije povecajDotokGoriva() u klasi
Transport bi bilo beskorisno, s obzirom da bi ionako bilo zamenjeno u
izvedenoj klasi. U takvim sluajevima treba koristiti iste virtualne funkcije.
ista virtualna funkcija je virtualna funkcija kojoj nije potrebno telo. Ona u
deklaraciji iza imena sadri notaciju =0.
U tom sluaju bi deklaracija funkcije povecajDotokGoriva() izgledala
ovako:
void povecajDotokGoriva()=0;
im klasa ima makar jednu istu virtualnu funkciju, ona se naziva apstraktnom.
Apstaktna klasa je klasa koja sadri istu virtualnu funkciju ili klasa koja nasleuje
virtualnu funkciju ali je ne definie. Ne moe da se kreira primerak apstaktne klase,
mada moe da postoji pokaziva ili referenca na apstaktnu klasu.
Pokaziva ne moe stvarno da pokae na neki objekat osnovne (apstraktne) klase,
uvek e pokazivati na neki objekat jedne od klasa izvedenih iz osnovne. Nije
dozvoljeno raditi nita to e kreirati pravi objekat osnovne klase. To ilustruje
sledei primer:
Osnovna *pok;
//pokazivac
na
objekat
klase Glavna
pok = new Osnovna;
//nije ispravno
pok = new Izvedena;
//ispravno
void uradiNesto(Osnovna & ref); //funkcija koja uzima
//referencu na objekat klase Glavna
U primeru transporta, klasa Transport nije funkcionalno upotrebljiva jo uvek
se ne zna o kom tipu vozila je re, nema sve potrebne funkcije, itd. Meutim, ona
34

NASLEIVANJE KLASA

prua zajedniku osnovu za ostale izvedene klase (vazdusniTransport,


morskiTransport i kopneniTransport). Moda su i te izvedene klase
previe neodreene da bi se koristile moda tek kad bi recimo iz klase
kopneniTransport izveli klasu Automobil, onda bi zadnje navedena klasa
bila upotrebljiva, i onda bi mogli da pravimo objekte te klase. U tom sluaju, klase
Transport,
vazdusniTransport,
morskiTransport
i
kopneniTransport nisu direktno primenljive, ne mogu se kreirati objekti ovih
klasa. Takoe, one mogu da sadre i iste virtualne funkcije, to ih ini idealnim
kandidatima na apstraktne klase.

3.4 Viestruko nasleivanje


Jednostruko nasleivanje podrazumeva da izvedena klasa nasleuje osobine jedne
osnovne klase. Viestruko nasleivanje znai nasleivanje osobina od vie
osnovnih klasa, Slika 3.3. Time se omoguava da se u izvedenoj klasi kombinuju i
proiruju karakteristika nekoliko osnovnih klasa.
class Izvedena : public Osnovna1, public Osnovna2
{
...
}
Osnovna1

Osnovna2

Izvedena

Slika 3.3 Viestruko nasleivanje

3.5 Virtualne osnovne klase


Klase B1 i B2 su izvedene iz A, a klasa C je izvedena iz B1 i B2. Klasa A se
pojavljuje dva puta, po jednom preko svake od osnovnih klasa klase C. Ako je
klasa A integralni deo B1 i B2, tada su verovatno potrebne dve kopije A u klasi C,
Slika 3.4
class
class
class
class

A { };
B1: public A { };
B2: public A { };
C: public B1, public B2 { };
35

PROGRAMSKI JEZIK C++

Slika 3.4 Viestruko nasleivanje klasa izvedenih iz iste klase


U nekim sluajevima je potrebno da imate samo jednu kopiju A, Slika 3.5. Zato je
potrebno da se A uini virtualnom osnovnom klasom. Kada prevodilac gradi klasu,
on uzima sve virtualne primerke klase koji spaja u jedinstveni primerak.
class
class
class
class

A { };
B1: public virtual A { };
B2: public virtual A { };
C: public B1, public B2 { };

Mogue je i da bude ukljuena i virtualna i nevirtualna verzija klase. Kada se to


dogodi svi virtualni primerci se kombinuju u jedan primerak, dok se nevirtualni
primerci tretiraju normalno i unose odvojeno.

Slika 3.5 Viestruko nasleivanje sa jednom kopijom klase A


Kada je klasa obina osnovna a ne virtualna osnovna, konstruktori izvedene klase
kontroliu koji konstruktori osnovne klase se pozivaju. Ali kada je osnovna klasa
virtualna stvari postaju nejasne zato to ima mnogo izvedenih klasa od kojih svaka
polae jednaka prava na osnovnu klasu. Poto virtualna osnovna klasa treba da se
inicijalizuje jednom, potrebno je pravilo za odreivanje izvedene klase koja zaista
kontrolie aktiviranje konstruktora virtualne osnovne. U jeziku C++ je usvojeno
36

NASLEIVANJE KLASA

reenje da kontrolu ima klasa stvarnog objekta, koja se ponekad zove i najvie
izvedena klasa.
Na primer, ako Z na neki nain ima virtualnu osnovnu klasu koja se zove A, tada je
na Z konstruktorima da kontroliu koji e A konstruktori biti pozvani. Ako A ima
standardni konstruktor i Z konstruktor se ne odnosi eksplicitno na A u listi
inicijalizacije, tada e biti upotrebljen standardni konstruktor klase A. Meutim,
ako A ima samo konstruktore koji uzimaju argumente, tada Z mora eksplicitno da
izabere jedan od konstruktora klase A.
Iako je pravilo da kontrolu ima najvie izvedena klasa, podrazumeva se da
konstruktori svake izvedene klase moraju da odrede koji od A konstruktora treba
pozvati, jer ne moete da znate koja e od izvedenih klasa biti kreirana tokom
izvravanja. Tako, ako A ima samo konstruktore koji uzimaju argumente, svaka
klasa koja ima A kao virtualnu osnovnu klasu, bez obzira na udaljenost u
naslednom stablu, mora eksplicitno da obezbedi konstruktore koji u
inicijalizacionoj listi pozivaju A konstruktore.
Ako u hijerahiji klasa postoji A kao virtualna osnovna, tada e se koristiti samo
inicijalizacija A koju odredi najvia izvedena klasa, a sve druge se preskau. Npr.
ako se kreira objekat klase B, koristie se njegova inicijalizacija virtualne osnovne
klase A. Ali ako se klasa C izvede iz B i kreira se objekat klase C, bie preskoena
inicijalizacija virtualne osnovne A od strane B i koristie se inicijalizacija iz klase
C.

37

PROGRAMSKI JEZIK C++

4.

++ ABLONI

Recimo da je potrebno da napiemo funkciju koja odreuje koji je od data dva


broja vei. Ukoliko se radi o celim brojevima, funkcija bi izgledala:
int max (int i, int j)
{
return i>j ? i : j;
}
Meutim, ta ako ista funkcija treba za realne brojeve? Onda bi funkcija izgledala
ovako:
float max (float i, float j)
{
return i>j ? i : j;
}
Razlike izmeu ove dve funkcije se svode na sistematsko zamenjivanje oznake tipa
unutar cele definicije fukcije. To je rutinski posao, i on se moe automatizovati
korienjem generikih funkcija. Primer generike funkcije za gornji primer bi
bio:
template <class T>
T max (T i, T j)
{
return i>j ? i : j;
}
Poglavlje 4 - 01 Generike funkcije

Prvi red u gornjem kodu:


template <class T>
definie klasu T kao formalni argument koji e biti zamenjen stvarnim
argumentom u trenutku korienja ablona. Na primer, ukoliko se pozove
max(5,8) T e biti tipa int.
Funkcije ili klase opisane pomou ablona nazivaju se generike funkcije ili
generike klase. Na osnovu njih se kasinje generiu konkretne funkcije ili klase.
Opti oblik za ablone generikih funkcija ili klasa je:
template < argument, argument, ... > opis
Argumenti mogu da oznaavaju tipove ili konstante. Opti oblik argumenata je:
38

ULAZ/IZLAZ

class identifikator_tipa (npr. class T)


ili
oznaka_tipa identifikator_konstante (npr. int k)
Opis moe da bude deklaracija (prototip) ili definicija generike funkcije (odnosno
klase) iji se ablon opisuje.
abloni mogu znaajno da poveaju fleksibilnost i da smanje veliinu koda.

4.1 Generisanje funkcija


Funkcije na osnovu zadatog ablona se generiu:

automatski - kad se naie na poziv generike funkcije sa stvarnim


argumentima koji mogu da se uklope u ablon bez konverzije tipova
argumenata.

na zahtev programera - navoenjem deklaracije (prototipa) za datu


generiku funkciju sa eljenim argumentima.

Zaobilaenje generisanja funkcija na osnovu ablona postie se navoenjem


definicije odgovarajue obine funkcije koju prevodilac mora da nae pre nego to
izvri generisanje na osnovu ablona.
Primer:
float max (float, float);

// eksplicitni zahtev za
// generisanje

float g = max (i, f);

4.2 Generisanje klasa


Konkretna klasa (tip) se generie na osnovu ablona generike klase u trenutku kad
naie na prvu definiciju objekta u kojoj se koristi identifikator generike klase.
Tada se generiu i sve funkcije lanice generisane klase. Oznaka generisane klase
treba za sadri stvarne argumente za ablon.
Koristi se sledea sintaksa:
naziv_klase <argument, argument, ...> naziv_objekta;
Na primer:
Vektor<int, 12> vek;
Sledi primer generike klase, uz korienje konstante argumenata ablona:
Definicija klase:
template <class T, int k>
39

PROGRAMSKI JEZIK C++

class Vektor
{
T element [k];
public:
int duzina;
public:
Vektor();
T& operator[] (int i);
};
Definicije funkcija klase:
template <class T, int k>
Vektor<T, k>::Vektor ()
{
duzina = k;
}
template <class T, int k>
T& Vektor<T, k>::operator[] (int i)
{
return element[i];
}
Ukoliko bi eleli da napravimo vektor realnih brojeva duine 12, napisali bi:
Vektor<float, 12> vek;
Pristupanje elementima vektora (atribut element) se vri pomou operatora []:
vek[3] = 4.2;

Poglavlje 4 - 02 Generike klase

Poglavlje 4 - 03 Primer genericke klase Matrica

40

ULAZ/IZLAZ

5.

ULAZ/IZLAZ

Ulaz i izlaz podataka nije deo jezika C++, ve postoji odgovarajua biblioteka
klasa za rad sa ulazom/izlazom.
Datoteke u C++-u su samo dugaki nizovi bajtova i nazivaju se tokovima. Nema
sutinske razlike izmeu toka na disku (datoteke) i toka u operativnoj memoriji.
Rad sa tokovima u C++ realizuje se odgovarajuim klasama, Slika 5.1. Konkretni
tokovi su primerci (objekti) tih klasa. Veina funkcija nad tokovima je ista, bez
obzira gde su oni smeteni.
Sa slike se moe videti da je klasa ios osnovna klasa za sve klase za ulazni/izlazni
tok. Iako ios tehniki nije apstraktna klasa, obino se ne kreiraju objekti ove klase,
niti se klase izvode direktno iz ios. Za nasleivanje se koriste klase iostream ili
ostream, ili druge izvedene klase.
Klasa istream slui za ulazne tokove, a klasa ostream za izlazne tokove. Klasa
iostream nasleuje obe klase (istream i ostream).
Dve najvanije klase koje se izvode iz klase iostream su:

fstream, za rad sa tokovima na disku (datoteke)

strstream, za rad sa nizovima (eng. strings, tj. tokovima u operativnoj


memoriji)

Generalno, za rad sa datotekama postoje tri klase:

ifstream, samo za ulazne datoteke

ofstream, samo za izlazne datoteke

fstream, za kombinovani ulaz i izlaz

Nalik na prethodni sluaj, za rad sa nizovima postoje tri klase:

istrstream, za uzimanje podataka iz tokova

ostrstream, za smetanje podataka u tokove

strstream, za uzimanje i smetanja podataka u/iz tokova

Postoje 4 standardna toka (primerka klase ostream i istream) koji se automatski


formiraju na poetku izvravanja svakog programa:

cin glavni (standardni) ulaz tipa istream (preciznije objekat klase


istream_withassign) . Standardno predstavlja tastaturu, ukoliko se drugaije ne
specificira (da se izvri skretanje glavnog ulaza unutar samog programa ili u
komandi operativnog sistema za izvravanje programa).

41

PROGRAMSKI JEZIK C++

Slika 5.1 Hierarhija klasa za ulazni/izlazni tok

cout glavni (standardni) izlaz tipa ostream (preciznije objekat klase


ostream_withassign). Predstavlja ekran, koristi se za ispisivanje podataka koji
ine rezultate izvravanja programa.

cerr standardni izlaz za poruke tipa ostream. Predstavlja ekran, obino se


koristi za ispisivanje poruka o grekama.

clog standardni izlaz za zabeleke tipa ostream. Predstavlja ekran, koristi se


za voenje dnevnika o dogaajima za vreme izvrenja programa.

Biblioteka stdio.h jezika C i dalje moe da se koristi za ulaz/izlaz podataka, ali


su ipak C++ klase efikasnije. Nikako se ne preporuuje da se koriste obe vrste
ulazno-izlaznih biblioteka.

5.1 Ulazni tok


Tri najvanije klase za ulazne tokove su istream, ifstream, i istrsteam. Klasa
istream je najbolja za rad sa sekvencijalnim tekstualnim ulazom. Klasa ifstream
podrava ulaz iz datoteke.
42

ULAZ/IZLAZ

5.1.1 Konstruisanje objekata ulaznih tokova


Ukoliko koristite cin objekat, ne treba da se napravi ulazni tok. Ulazni tok se mora
napraviti ukoliko koristite:

tok iz datoteke (File stream)

tok iz niza (String stream)

5.1.1 Konstruktori ulaznih tokova datoteka


Postoji tri naina da se napravi ulazni tok iz datoteke:
1. korienjem konstruktora bez argumenata
2. navoenjem naziva datoteke i odgovarajuih parametara
3. navoenjem deskriptora datoteke.
Tabela 5.1 Parametri iosmode i dosmode
ios::app

upisivanje na kraj datoteke

ios::ate

pozicioniranje na kraj datoteke posle otvaranja

ios::in

otvara ulaznu datoteku

ios::out

otvara izlaznu datoteku

ios::nocreate

otvara datoteku ukoliko ve postoji

ios::noreplace

otvara datoteku ukoliko ve ne postoji

ios::trunc

otvara datoteku i brie stari sadraj

ios::binary

binarna datoteka. Ako se nita ne kae, podrazumeva se rad sa tekstualnom


datotekom.

Korienjem konstruktora bez argumenata kreira se objekat klase ifstream, a zatim


se poziva funkcija open koja otvara navedenu datoteku:
ifstream f;
// na steku
f.open ( "test.txt", iosmod);
ili
ifstream* f = new ifstream; // na heap-u
f->open("test.txt", iosmode);
Navoenje naziva datoteke i odgovarajuih parametara (mode flags) se vri na
sledei nain:
43

PROGRAMSKI JEZIK C++

ifstream f("test.txt", iosmode);


Navoenje deskriptora datoteke se vri za datoteku koja je ve otvorena.
Standardni (default) nain za postizanje navedenog je:
int fd = _open("test.txt", dosmode);
ifstream f(fd);
Za parametre iosmode i dosmode se koriste vrednosti date u Tabeli 5.1.

5.1.2 Konstruktori ulaznih tokova niza


Konstruktor ulaznog toka niza zahteva adresu prethodno alocirane (dodeljene) i
inicijalizovane memorije:
char s[] = "123.45";
double amt;
istrstream myString( s );
myString >> amt; // Amt = 123.45

5.1.3 Funkcije ulaznog toka


Operator ekstrakcije (>>) je programiran za sve standardne C++ tipove podataka, i
predstavlja najlaki nain da se preuzmu bajtovi iz objekta ulaznog toka.
char ime[20];
cin >> ime;
Operator >> pamti ulazne podatke samo do prvog uneenog blanko znaka. Za unos
"Marko Markovic" e se dobiti samo "Marko".
Poglavlje 5 01 Operator ekstrakcije.

Funkcija get se ponaa kao i operator >>, osim to pamti i blanko znakove. Postoji
vie prototipova ove funkcije, naveemo samo najee koriene.
istream &get(char& znak); - uzima sledei znak iz ulaznog toka i smeta
ga u promenljivu znak (npr. cin.get(c)).
istream &get(char* niz, int max); - ita max broj znakova (ukoliko
postoji toliko znakova) i smeta ih u niz (npr. cin.get(ime, 20) ).
istream &get(char* niz, int max, char kraj); - ita sve
znakove do prvog pojavljivanja znaka kraj. Pored toga, moe da proita najvie
max broj znakova (npr. cin.get(ime, 20, '\n') ).
Funkcija getline je veoma slina operaciji get, jedino to uklanja znak prekida
(npr. '\n') koji get ne uklanja.
Poglavlje 5 02 Operacija get

44

ULAZ/IZLAZ

Funkcija read ita bajtove iz toka u odreeni deo memorije. Mora se navesti
lokacija gde se upisuju proitani podaci, kao i broj proitanih bajtova. Na primer,
ukoliko imamo sledeu strukturu:
struct Radnik
{
char ime[20];
double plata;
};
i hoemo da proitamo iz (ve napravljene) datoteke "plata.dat" jedan slog
(strukture Radnik), prvo bi otvorili tok iz te datoteke:
ifstream is( "plata.dat", ios::binary | ios::nocreate
);
Ukoliko je datoteka uspeno otvorena, vri se itanje podataka iz toka koji se
upisuju u strukturu r, i odmah zatim i tampanje strukture r:
if( is ) {
Radnik r;
is.read( (char *) &r, sizeof(r) );
cout << r.ime << ' ' << r.plata << endl;
}
Konano, otvoreni tok treba zatvoriti:
is.close();
Poglavlje 5 03 Operacija read

Ukoliko se ne navede broj bajtova koji treba proitati, itanje e prestati kada se
doe do kraja datoteke.
Funkcije get i getline se koriste za ulazne tokove tekstualnih datoteka, a read i za
ulazne tokove binarnih datoteka.
Tokovi datoteka pamte pokaziva na poziciju u datoteci koja e sledea biti
proitana. Vrednost tog pokazivaa moe se odrediti pomou funkcije seekg:
ifstream is( "plata.dat", ios::binary | ios::nocreate
);
is.seekg (8);
// 8 bajtova
Vrednost pokazivaa se moe dobiti pomou funkcije tellg (npr. is.tellg() ).

45

PROGRAMSKI JEZIK C++

5.1.4 Preklapanje operatora ekstrakcije


Preklapanjem (overloading) operatora >> za neku klasu,
promenie se
funkcionalnost tog operatora u sluaju upotrebe te klase. Primer, imamo klasu za
datum:
class Datum
{
public:
int dan, mesec, godina;
friend istream& operator>> ( istream& is, Datum& dt
);
};
gde je operator>> prijateljska funkcija koja je definisana na sledei nain:
istream& operator>> ( istream& is, Datum& dt )
{
is >> dt.dan >> dt.mesec >> dt.godina;
return is;
}
operator>> mora biti definisan kao prijateljska funkcija jer funkcija definisana
u klasi se poziva nad levim operandom. Kako je uobiajeno da na levoj strani ove
funkcije bude objekat klase istream, to bi znailo da ta funkcija mora da bude
lanica klase istream. Kako mi nemamo pravo da menjamo biblioteke klase,
jedino nam ostaje da ovu funkciju definiemo na globalnom nivou (kao
samostalnu).
Sada se operator >> moe koristiti na sledei nain:
Datum dt;
cin >> dt;
Poglavlje 5 04 Preklapanje operatora ekstrakcije

5.2 Izlazni tok


Tri najvanije klase za izlazne tokove su ostream, ofstream i ostrstream. Veoma
retko se konstruiu objekti klase ostream, ve se koriste predefinisani objekti
(cout, cerr, clog). Klasa ofstream podrava rad sa datotekama. Za kreiranje niza u
memoriji treba koristiti klasu ostrstream.

5.2.1 Konstruisanje objekata izlaznih tokova


Konstruisanje objekata izlaznih tokova se vri potpuno isto kao i kod ulaznih
tokova (isto postoje tri naina), jedino to se koristi klasa ofstream.
46

ULAZ/IZLAZ

5.2.2 Upotreba operatora umetanja


Operator umetanja (<<) je programiran za sve standardne C++ tipove podataka, i
slui za slanje bajtova objektu izlaznog toka.
cout << "Ovo je test";
On takoe radi sa predefinisanim manipulatorima (elementima koji menjaju
formatiranje, npr. endl);
cout << "Ovo je test" << endl;
U ovom primeru manipulator endl predstavlja znag za prelazak u novi red.

5.2.3 Formatiranje izlaza


Za odreivanje jednake irine izlaza, koristi se manipulator setw ili funkcija width.
double values[] = { 1.23, 35.36, 653.7, 4358.24 };
for( int i = 0; i < 4; i++ )
{
cout.width(10);
cout << values[i] << '\n';
}

U gornjem primeru se pri ispisivanju vrednosti svaki red dopunjava blanko


znakovima do 10 znakova. Ukoliko elimo da se vri popuna nekim drugim
znakom, onda se koristi funkcija fill.
for( int i = 0; i < 4; i++ )
{
cout.width( 10 );
cout.fill( '*' );
cout << values[i] << endl
}

Ukoliko se koristi setw sa argumentima, vrednosti se tampaju u poljima iste


duine. U tom sluaju se mora ukljuiti i IOMANIP.H datoteka.
double values[] = { 1.23, 35.36, 653.7, 4358.24 };
char *names[] = { "Zoot", "Jimmy", "Al", "Stan" };
for( int i = 0; i < 4; i++ )
cout << setw( 6 ) << names[i]
<< setw( 10 ) << values[i] << endl;
Ovim bi se dobile dve kolone, u jednoj bi bila ispisana imena, a u drugoj vrednosti.
U tabeli 5.2 dati su neki predefinisani manipulatori.
47

PROGRAMSKI JEZIK C++

Tabela 5.2 Predefinisani manipulatori


dec

ukljuivanje decimalne konverzije

oct

ukljuivanje oktalne konverzije

hex

ukljuivanje heksadecimalne konverzije

ws

izbacivanje blanko znakova na poetku

endl

umetanje znaka \n u izlazni tok i pranjenje bafera


izlaznog toka

ends

umetanje znaka \0 u izlazni tok

flush

pranjenje bafera izlaznog toka

Poglavlje 5 05 Formatiranje izlaza

5.2.4 Funkcije izlaznog toka


Kao i kod ulaznog toka, i ovde se koriste iste funkcije za otvaranje i zatvaranje
toka (open i close).
Za rad sa znakovnim podacima koristi se funkcija put. Ona smeta zadati znak u
izlazni tok. Na primer:
cout.put ('A');
daje isti rezultat kao i
cout << 'A';
Funkcija write se koristi za upis bloka memorije u izlazni tok. Ona ima dva
argumenta: prvi, char pokaziva i drugi, broj bajtova za upis. Treba napomenuti da
je obavezna konverzija u char* pre adrese strukture ili objekta.
Funkcija write se koristi i za binarne datoteke.
Primer za upis strukture Radnik (vidi 5.1.4) u binarnu datoteku:
Radnik r;
ofstream os("plata.dat", ios::binary);
os.write((char*) &r, sizeof(r));
os.close();
Funkcije seekp i tellp su gotovo identine funkcijama seekg i tellg, jedino to se
koriste za izlazne tokove.
Poglavlje 5 06 Operacija write

48

ULAZ/IZLAZ

5.2.5 Preklapanje operatora umetanja


Preklapanje operatora umetanja (<<) za neku klasu dovodi do drugaijeg formata
ispisivanja u izlazni tok. Moe se koristiti kao sredstvo za formatiranje izlaza.
Koristi se zajedno sa manipulatorima.
Primer preklapanja operatora << za klasu Datum:
class Datum
{
public:
int dan, mesec, godina;
Datum (int d, int m, int g){
dan = d; mesec = m; godina = g;
}
friend ostream& operator<< ( ostream& os, Datum& dt
);
};
ostream& operator<< ( ostream& os, Datum& dt )
{
os << dt.dan <<
dt.godina;
return os;
}
void main()
{
Datum dt(4,11,2004);
cout << dt;
}

"."

49

<<

dt.mesec

<<

"."

<<

6.

OBRADA IZUZETAKA

Tokom izvrenja programa, raunar moe da naie na dva tipa situacija: na one
koje je spreman da obradi i na one koje nije spreman da obradi.
Sledi primer jednostavnog programa za mnoenje dva broja:
#include <iostream>
using namespace std;
int main()
{
double a, b, c;
cout << "Unesite dva broja \n";
cout << "Prvi broj: ";
cin >> a;
cout << "Drugi broj: ";
cin >> b;
// Mnozenje dva broja i prikaz rezultata
c = a * b;
cout << "\n" << a << " * " << b << " = " << c <<
"\n\n";
return 0;
}
Sve radi kako treba ukoliko korisnik ne napravi greku pri unoenju parametara i
recimo unese niz znakova umesto broja. ta onda?
Pre nego to je uveden sistem obrade izuzetaka, programi definitivno nisu bili bez
greaka. Postoji nekoliko metoda za obradu greaka koje su se tada koristile, a
objasniemo samo jednu da bi mogli videti prednost sistema obrade izuzetaka.
U starijim programima, svaka vanija funkcija vraa neku vrednost kojom se
oznaava kako je izvravanje prolo. Kod koji je pozvao funkciju proverava
vraenu vrednost i zavisno od toga sprovodi odreene akcije. Posledica
programski kod je prepun dodatnim ifnaredbama i delovima koda za obradu
greke. Takoe, povratna vrednost funkcije ne moe da se koristi za vraanje nieg
drugog sem koda greke.

50

OBRADA IZUZETAKA

6.1

Koncept obrade izuzetaka

Globalni koncept obrade izuzetaka je jednostavan. Ideja je da se postave "zastavice


za greke" (error flags) svaki put kada neto krene naopako. Takoe postoji sistem
koji non-stop nadgleda te zastavice. Ukoliko je zastavica postavljena, taj sistem
poziva kod za obradu greke. Postavljanje zastavice za greku se naziva
generisanje (eng. raising, throwing) greke.
Kad se generie greka, ceo sistem reaguje hvatanjem (eng. catching) greke.
Uokviravanje bloka (dela) koda osetljivog na greke kodom za obradu izuzetaka
se naziva pokuavanje (eng. trying) izvrenja bloka. Kod za obradu izuzetaka se
naziva try-kod.
Jedna od najmonijih osobina obrade izuzetaka je to to greka moe da se
generie i van granica funkcije. To znai da ukoliko jedna od najdubljih funkcija na
steku (npr. rekurzivni pozivi funkcije) generie greku, ta greka moe da se
prosledi do funkcija iznad u hierarhiji, ukoliko postoji try-kod. To omoguava
programerima da postave kod za obradu greke samo na jednom mestu, npr. u
glavnoj (main) funkciji.

6.2 Sintaksa
Sistem za obradu izuzetaka u C++ jeziku koristi try, catch i throw naredbe.
try
{
// kod osetljiv na greke
}
catch (Exception &e)
{
// obrada izuzetka
}
Kompletna sintaksa korienja sistema za obradu izuzetaka:

try-block :
try compound-statement handler-list
handler-list :
handler handler-listopt
handler :
catch ( exception-declaration ) compound-statement
exception-declaration :

51

PROGRAMSKI JEZIK C++

type-specifier-list declarator
type-specifier-list abstract-declarator
type-specifier-list
...
throw-expression :
throw assignment-expressionopt
Blok koda posle try naredbe (compound-statement) je tieni deo koda. Blok
pod nazivom throw-expression generie izuzetak.
Tok izvrenja programa izgleda ovako:
1. Kontrola se predaje try naredbi. tieni deo koda u okviru try bloka se
izvrava.
2. Ukoliko ni jedan izuzetak nije generisan tokom izvrenja, catch blok se ne
izvrava.
3. Ukoliko se generie izuzetak tokom izvrenja tienog dela ili u okviru
bilo koje rutine, podprograma koji je pozvan u tom delu (direktno ili
indirektno), kreira se objekat izuzetka i to iz objekta kreiranog od strane
throw operanda. Kompajler trai odgovarajuu catch klauzulu koja ume da
obradi izuzetak (u pogledu tipa izuzetka). Catch handler-i (klauzule koje
odbrauju izuzetke) se ispituju onim redom kojim se javljaju i u try bloku.
Ukoliko se ne nae odgovarajui handler, ispituje se try blok koji obuhvata
trenutni try blok (ukoliko postoji).
4. Ukoliko se ne nae ni jedan handler, poziva se predefinisana funkcija
terminate.
5. Ukoliko se nae odgovarajui catch handler, memorijska (stek) se
oslobaa automatski generisanih objekata, kreiranih izmeu poetka
aktuelnog try bloka i mesta podizanja izuzetka. Destruktori se pozivaju u
obrnutom redu u odnosu na konstruisanje (prvo se unitava zadnje
napravljeni objekat). Zatim se izvrava catch handler, a potom se nastavlja
sa izvrenjem programa, i to od od prve naredbe napisane ispod svih catch
handlera.

Primer:
#include <iostream>
using namespace std;
int main()
{
char *buf;
try
{
52

OBRADA IZUZETAKA

buf = new char[512];


if( buf == 0 )
throw "Greska u alokaciji memorije!";
}
catch( char * str )
{
cout << "Aktiviran izuzetak: " << str << '\n';
}
// ...
return 0;
}
Primer : Korienje klasa i vie catch handlera:
#include <iostream>
using namespace std;
void MyFunc( void );
class CTest {
public:
CTest(){};
~CTest(){};
const char *ShowReason() const { return "Izuzetak u
CTest klasi."; }
};
class CDtorDemo {
public:
CDtorDemo();
~CDtorDemo();
};
CDtorDemo::CDtorDemo() {
cout << "Konstruise se objekat CDtorDemo.\n";
}
CDtorDemo::~CDtorDemo() {
cout << "Unistava se CDtorDemo.\n";
}
void MyFunc() {
CDtorDemo D;
cout<< "U MyFunc(). Aktivira se
throw CTest();
}
53

CTest izuzetak.\n";

PROGRAMSKI JEZIK C++

int main() {
cout << "U main.\n";
try {
cout << "U try bloku, poziva se MyFunc().\n";
MyFunc();
}
catch( CTest E ) {
cout << "U catch bloku.\n";
cout << "Uhvacen CTest izuzetak: ";
cout << E.ShowReason() << "\n";
}
catch( char *str )
{
cout << "Uhvacen neki drugi izuzetak: " << str
<< "\n";
}
cout << "Povratak u main. \n";
return 0;
}
Rezultat programa:
U main.
U try bloku, poziva se MyFunc().
Konstruise se objekat CDtorDemo.
U MyFunc(). Aktivira se CTest izuzetak.
Unistava se CDtorDemo.
U catch bloku.
Uhvacen CTest izuzetak: Izuzetak u CTest klasi.
Povratak u main.

54

You might also like