De ce contează?
Imaginează-ți doi colegi care lucrează pe ACEEAȘI foaie de pe tablă. Când unul șterge un cuvânt și scrie altul, celălalt vede pe loc schimbarea — pentru că nu sunt două foi diferite, e una singură. Asta este o referință: nu o copie a foii pe care s-o pui în buzunar, ci chiar foaia originală, la care funcția primește acces direct.
Ce este
Când transmiți un parametru prin valoare (int x), funcția primește o copie. Lucrează pe copie, iar la întoarcere copia dispare — originalul rămâne neatins.
Când transmiți un parametru prin referință (int &x), funcția NU mai primește o copie. Parametrul devine un alias: un al doilea nume pentru exact aceeași variabilă din apelant. Tot ce schimbi prin x se schimbă în original.
La ce folosește?
- Întorci mai multe rezultate —
returndă o singură valoare; cu referințe „scrii înapoi" în mai multe variabile deodată. - Eviți copierea structurilor mari — un vector cu un milion de elemente, copiat la fiecare apel, e lent; o referință e doar un alias, deci legarea e instantanee.
Singura diferență dintre o copie și un alias este simbolul & din declararea parametrului. Fără &, funcția se joacă într-o cutie izolată. Cu &, funcția pune mâna direct pe variabila ta. Ține minte: & la parametru înseamnă „același obiect, alt nume".
Cum arată
Hai să urmărim funcția care interschimbă două valori:
void interschimba(int &a, int &b) {
int aux = a;
a = b;
b = aux;
}În apelant avem x = 3 și y = 7 și chemăm interschimba(x, y). Pentru că parametrii sunt referințe, a este alt nume pentru x, iar b este alt nume pentru y. Tot ce face funcția se întâmplă, de fapt, pe x și y.
3 | 7 |
x | y |
a |
7 | 7 |
x | y |
a=b |
7 | 3 |
x | y |
b=aux |
Observă esențialul: funcția nu a întors nimic cu return, dar x și y din apelant s-au modificat. Asta este puterea referinței — efectul rămâne după ce funcția se termină.
Implementare C++
Program complet care arată și interschimbarea, și întoarcerea a două rezultate prin referință:
#include <iostream>
using namespace std;
// a si b sunt referinte: alias-uri pentru variabilele din apelant
void interschimba(int &a, int &b) {
int aux = a; // salvam valoarea lui a
a = b; // a (deci x in apelant) ia valoarea lui b
b = aux; // b (deci y in apelant) ia vechea valoare a lui a
}
// intoarcem DOUA rezultate: scriem direct in cat si rest
void impartire(int deimpartit, int impartitor, int &cat, int &rest) {
cat = deimpartit / impartitor;
rest = deimpartit % impartitor;
}
int main() {
int x = 3, y = 7;
cout << "Inainte: x = " << x << ", y = " << y << "\n"; // 3, 7
interschimba(x, y); // trimitem variabilele, nu valori
cout << "Dupa: x = " << x << ", y = " << y << "\n"; // 7, 3
int c, r;
impartire(17, 5, c, r); // c si r se umplu in interiorul functiei
cout << "17 / 5 = " << c << " rest " << r << "\n"; // 3 rest 2
return 0;
}Observă apelul interschimba(x, y): trimiți variabilele x și y, nu doar niște numere. Funcția se leagă de ele și le modifică. La fel la impartire: nu folosești niciun return, dar după apel c și r conțin câtul și restul, fiindcă funcția le-a scris direct.
Trei capcane frecvente cu referințele:
-
Uiți
&. Scriivoid interschimba(int a, int b)în loc deint &a, int &b. Codul compilează, dar funcția lucrează pe copii —xșiydin apelant rămân3și7. Schimbarea „se pierde" la întoarcerea din funcție. Dacă vrei efect în apelant, parametrul TREBUIE să aibă&. -
Legi referința de o valoare, nu de o variabilă.
interschimba(3, 7)nu compilează: un literal precum3nu are o adresă proprie pe care funcția s-o modifice. O referință (ne-const) are nevoie de o variabilă reală, deci scrieinterschimba(x, y). -
Uiți
constla parametrii mari doar de citit. Dacă dai un vector imens doar ca să-l citești, foloseșteconst vector<int> &v:&evită copia costisitoare, iarconstte oprește să-l modifici din greșeală. Fărăconst, oricine citește semnătura crede că funcția poate schimba vectorul.