You are on page 1of 5

Reference

http://web.math.pmf.unizg.hr/nastava/opepp/Ch1/reference.html

Reference
Definicija
Referenca na neki objekt je novo ime za taj objekt. Osnovna uloga reference je omoguiti prijenos parametara po referenci, dakle prijenos u kojem nema kopiranja parametra ve funkcija dobiva referencu na objekt. Referenca spada u tzv. sloeni tip (compound type), tip koji se gradi pomou drugih tipova. tu spadaju jo pokazivai (na neki tip) i polja (nekog tipa). Budui da referenca uvijek mora referirati na neki objekt slijedi pravilo: Prilikom deklaracije referenca mora biti inicijalizirana.
int n=100; int& rn = n; float ℞

// greka pri kompilaciji. Neinicijalizirana referenca

Uoimo da se pri deklaraciji reference koristimo ampersandom ispred imena varijable kao oznakom za referencu (posve analogno kao to se sluimo zvjezdicom pri deklaraciji pokazivaa). Na jedan objekt moemo imati vie referenci, a kako je svaka referenca samo novo ime za objekt svaka promjena objekta putem jedne reference vidljiva je i kroz sve druge. Sljedei kod e pokazati da su obje varijable n i rn promijenjene nakon rn++.
int n = 100; int& rn = n; std::cout << " n= "<< n << ", rn = "<< rn << std::endl; rn++; std::cout << " n= "<< n << ", rn = "<< rn << std::endl;

Referenca moe biti konstantna i tada moe referirati na konstantan objekt. Obina referenca ne moe referirati na konstantu:
char &ra = 'a'; // greka pri kompilaciji. // Nekonstantna referenca, konstantan objekt. // o.k.

const char &rb = 'b';

Konstantna referenca nam garantira da kroz nju ne moemo promijeniti objekt na koji referira. Referenca je dakle isto to i pokaziva koji se automatski dereferencira. Za razliku od pokazivaa referenca koja referira na jedan objekt nikad ne moe referirati na neki drugi objekt.

Implicitne konverzije
Koritenjem referenci donekle ograniavamo prirodan nain koritenja implicitnih konverzija. Na primjer, sljedei kod javlja greku pri kompilaciji.
double x = 2.71; int &rx = x;

1 od 5

23.11.2013. 2:21

Reference

http://web.math.pmf.unizg.hr/nastava/opepp/Ch1/reference.html

dok sljedei javlja samo upozorenje o konverziji double u int:


double const int x = 2.71; &rx = x;

Razlog za takvo ponaanje je sljedei: Kada prevodilac treba referencu na jedan tip inicijalizirati objektom nekog drugog, kompatibilnog, tipa, on kreira privremeni objekt istog tipa kao i referenca, vri konverziju i inicijalizira referencu tim privremenim objektom. U naem konkretnom sluaju prevodilac stvara privremenu varijablu tipa int koju inicijalizira varijablom x i zatim inicijalizira referencu s privremenim objektom. Kod koji prevodilac generira izgleda, dakle, ovako:
double int const int x = 2.71; tmp = x; &rx = tmp;

Sada e dakle svaka promjena putem reference rx mijenjati samo privremeni objekt tmp, a ne i varijablu x to obino nije ono to je programer htio. Stoga C++ zahtijeva da referenca rx bude konstantna. Time dolazimo do ovog pravila: Nekonstantna referenca nekog tipa moe biti inicijalizirana jedino objektom egzaktno tog istog tipa.

Referenca na pokaziva
Referencu moemo definirati i na pokaziva. Sintaksa je pokazana u sljedeem primjeru:
int n = 100; int *pn = &n; int *&rpn = pn;

// Referenca a pokaziva

std::cout << "*rpn = "<< *rpn << std::endl;

Uoimo da se deklaracija reference na pokaziva ita s desna na lijevo. S druge strane, nije dozvoljeno deklarirati pokaziva na referencu (jer to nema puno smisla), a isto tako i referencu na referencu.

Polje referenci
Ne postoji! Deklaracija
double &x[8]; // Polje referenci nije dozvoljeno

je neispravna. Razlog je taj to svaka referenca mora biti inicijalizirana nekim objektom, to pri definiciji polja nije mogue.

Referenca kao parametar funkcije


U programskom jeziku C kada ne elimo prijenos parametara po vrijednosti (buduu da su argumenti ili suvie veliki ili ih elimo promijeniti) funkcija treba uzeti pokaziva na objekt, koji se zatim u tijelu funkcije dereferencira kako bi se objekt dohvatio. U C++ u tu svrhu koristimo reference. Ako je formalni argument funkcije deklariran kao referenca nekog tipa, onda prilikom poziva funkcije nee doi do kopiranja stvarnog argument u formalni ve e formalni argument (koji je referenca) biti inicijaliziran stvarnim. Formalni argument tako postaje alias za stvarni

2 od 5

23.11.2013. 2:21

Reference

http://web.math.pmf.unizg.hr/nastava/opepp/Ch1/reference.html

argument i kroz njega moemo stvarni argument dohvatiti. Na taj se nain postie prijenos parametara po referenci.
void swap(int& x, int& y) { int tmp = x; x = y; y = tmp; }

U principu imamo dva razloga zbog kojih elimo prijenos po referenci. Ili elimo mijenjati stvarni argument (tipian primjer je swap funkcija) ili je argument suvie velik za kopiranje. U ovom drugom sluaju kada samo elimo izbjei kopiranje stvarnog argumenta formalni argument treba deklarirati kao konstantnu referencu. Na taj se nain izbjegava mogunost da se stvarni argument promijeni unutar tijela funkcije. S druge strane, kako je mogue konstantnu referencu inicijalizirati nekonstantnim objektom (const je samo obeanje da referenca nee sluiti za mijenjanje objekta) funkcija koja deklarira konstantnu referencu moe uvijek uzeti nekonstantan argument (koji, naravno, ne moe u svom tijelu promijeniti). Na primjer, za funkciju
void print(std::string& text) { std::cout << text << std::endl; }

bismo imali
std::string a("...");

print(a); print("...");

// o.k. // greka

Drugi poziv bi dao greku pri kompilaciji. Oba poziva bi bila korektna ukoliko bismo funkciju deklarirali na sljedei nain:
void print(const std::string& text) { std::cout << text << std::endl; }

Druga je verzija fleksibilnija i treba ju koristiti uvijek kada funkcija ne namjerava mijenjati argument iju referencu dobiva. Kako nekonstantnu referencu na neki tip moemo inicijalizirati samo objektom tog tipa dolazimo do vane posljedice za konverziju tipova pri pozivu funkcije: Ako je argument funkcije dekariran kao nekonstantna referenca, onda pri pozivu funkcije nije dozvoljena konverzija tipova za taj argument. Formalni i stvarni argument moraju biti istog tipa. Kada je referenca konstantna, onda je, kao to smo vidjeli, konverzija dozvoljena. Treba imati pri tome na umu da e prevodilac generirati privremeni objekt i da e formalni argument referirati na njega.

Referenca na polje
Funkcija koja uzima polje kao argument dobiva pokaziva na prvi element polja. Takva funkcija moe uzeti polje bilo koje dimenzije. S druge strane, mogue je deklarirati funkciju koja uzima referencu na

3 od 5

23.11.2013. 2:21

Reference

http://web.math.pmf.unizg.hr/nastava/opepp/Ch1/reference.html

polje. Na primjer,
int count(int (&arr)[4]) { int x = 0; for(int i=0; i< 4; ++i) x += arr[i]; return x; }

U toj definiciji ne smijemo zaboraviti dimenziju polja, jer su polja razliite dimenzije, ustvari, razliitog tipa. Sad moemo pisati,
int arr[]={0,1,2,3}; std::cout << count(arr) << std::endl

No funkcija count e uzimati samo polja dimenzije 4, jer nema implicitnih konverzija izmeu polja razliite veliine. Sljedei kod se stoga ne bi kompilirao:
int arr[]={0,1,2,3,4}; std::cout << count(arr) << std::endl; // greka

Referenca na polje je dakle manje fleksibilna od pokazivaa na polje, pa se stoga rijetko koristi kao parametar funkcije.

Funkcije koje vraaju referencu


Ako funkcija vraa referencu tada ne dolazi do kopiranja vrijednosti, ve samo do kopiranja reference. Za velike objekte to moe biti velika uteda. Referenca kao povratna vrijednost ima jo i tu prednost da predstavlja vrijednost koja se moe nai na lijevoj strani znaka jednakosti (lvalue). To ilustrira ovaj primjer:
char& get(std::string& s, unsigned i) { assert(i < s.size()); return s[i]; }

Sada mogu promijeniti element u stringu na sljedei nain:


std::string s1("abc"); get(s1,2)='z';

Rezultat je string "abz". (to bi se desilo da smo s prenijeli po vrijednosti u funkciji get?) Ta mogunost vraanja reference vrlo je vana kod definicije operatora. Pri tom moramo paziti da nikad ne vratimo referencu na lokalnu varijablu jer e ona nakon vraanja reference na nju biti unitena. Isto naravno vrijedi i za pokaziva na lokalnu varijablu. Na primjer,
// Neispravan kod std::string& ccn(const std::string& s1, const std::string& s2) { std::string tmp = s1+s2; return tmp; }

Funkcija ne smije nikada vratitit referencu ili pokaziva na lokalnu varijablu.

4 od 5

23.11.2013. 2:21

Reference

http://web.math.pmf.unizg.hr/nastava/opepp/Ch1/reference.html

5 od 5

23.11.2013. 2:21

You might also like