Professional Documents
Culture Documents
C++ (Deo Udzbenika)
C++ (Deo Udzbenika)
C++ (Deo Udzbenika)
Katedra za raunarstvo
Maj, 2005
Recenzenti:
Dr ivko Toi.
Dr Dragan Jankovi
Pretampavanje ili umnoavanje ove knjige nije dozvoljeno bez pismene dozvole
izdavaa.
Tira: 300 primeraka
tampa: Mikops, Ni
SADRAJ
SADRAJ
vi
1.
1.1
1.2
Apstrakcija
1.3
Definicija objekta
1.4
Zatvaranje (Inkapsulacija)
1.5
Definicija klase
2.
C++ KLASE
2.1
2.2
Kreiranje objekata
2.3
Konstruktori
10
2.4
14
2.5
16
2.6
18
2.7
Operatorske funkcije
20
2.8
24
3.
NASLEIVANJE KLASA
3.1
Generalizacija
26
3.2
Nasleivanje
26
26
3.3
Polimorfizam
30
3.4
Viestruko nasleivanje
35
3.5
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
51
6.2
Sintaksa
51
7.
55
8.
98
8.1
Prevoenje programa
98
8.2
98
8.3
99
9.
100
10.
103
10.1
103
10.2
106
10.3
108
38
41
50
11.
KLASE U JAVI
112
11.1
Definicija klase
112
11.2
113
11.3
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
122
12.
12.1
Apstraktne klase
124
12.2
Interfejsi
125
13.
PAKETI
129
13.1
Korienje paketa
129
13.2
129
14.
14.1
Paket java.lang
132
14.2
Paket java.io
134
14.3
137
15.
144
16.
LITERATURA
165
iii
124
132
iv
PREDGOVOR
vi
I deo
viii
1.
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
Nezavisni su,
2.
C++ KLASE
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
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
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-
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
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
13
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
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
C++ KLASE
{
vozilo bmw(230), ferrari(340);
if (uporediBrzine(bmw, ferrari))
brzi");
else printf ("Ferrari je brzi");
}
printf("Bmw
je
19
%f\n",
20
C++ KLASE
{
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
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
25
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.
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
27
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
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
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.
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
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
NASLEIVANJE KLASA
Osnovna2
Izvedena
A { };
B1: public A { };
B2: public A { };
C: public B1, public B2 { };
35
A { };
B1: public virtual A { };
B2: public virtual A { };
C: public B1, public B2 { };
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
4.
++ ABLONI
ULAZ/IZLAZ
// eksplicitni zahtev za
// generisanje
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;
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:
41
ULAZ/IZLAZ
ios::ate
ios::in
ios::out
ios::nocreate
ios::noreplace
ios::trunc
ios::binary
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
ULAZ/IZLAZ
oct
hex
ws
endl
ends
flush
48
ULAZ/IZLAZ
"."
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
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
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
CTest izuzetak.\n";
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