Professional Documents
Culture Documents
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 ℞
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.
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
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
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.
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.
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; }
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