C++/Referencje
Czym jest referencja?
edytujReferencja w swym działaniu przypomina wskaźniki. Różnica polega jednak na tym, że do referencji można przypisać adres tylko raz, a jej dalsze używanie niczym się nie różni od używania zwykłej zmiennej. Operacje jakie wykona się na zmiennej referencyjnej, zostaną odzwierciedlone na zmiennej zwykłej, z której pobrano adres.
Można by pokusić się o stwierdzenie, że:
Referencja jest inną nazwą danej zmiennej. |
Deklaracja referencji
edytujReferencje deklaruje się jak zmienne z podaniem znaku &:
TypDanych & referencja
Taki zapis byłby możliwy w liście argumentów funkcji, jednak w ciele funkcji referencja musi być od razu zainicjalizowana. Zapisujemy do niej adres innej zmiennej (robi się to trochę inaczej niż w wypadku wskaźników):
TypDanych & referencja = innaZmienna;
Od tej pory można używać obu tych zmiennych zamiennie.
Poniższe przypisania dadzą więc ten sam efekt:
innaZmienna = 9; referencja = 9;
Zobaczmy działanie referencji na konkretnym przykładzie:
int i = 0;
int &ref_i = i;
cout << i; // wypisuje 0
ref_i = 1;
cout << i; // wypisuje 1
cout << ref_i; // wypisuje 1
Porównajmy to z sytuacją, gdybyśmy użyli wskaźników:
int i=0;
int *wsk_i=&i;
cout << i; // wypisuje 0
*wsk_i = 1;
cout << i; // wypisuje 1
cout << *wsk_i; // wypisuje 1
Zauważmy, o ile wygodniejsze jest użycie referencji. Nie musimy ani pobierać adresu zmiennej (&i) by przypisać go do referencji ani też używać gwiazdki by dostać wskazywaną wartość.
Jeszcze jedną różnicą ze wskaźnikami jest ograniczenie, że referencji po przypisaniu nie można przestawić na inną zmienną. Referencja musi też być zainicjalizowana w momencie utworzenia:
int a,b;
int *wsk_a = &a, *wsk_b = &b;
int &ref_a = a, &ref_b = b;
int &ref_c; // kompilator nie zezwoli na to - referencja niezainicjalizowana
wsk_b = &a; // ok
ref_b = &a; // tak się nie da
Przykład przypomina też, że analogicznie jak w przypadku wskaźników znak & nie łączy się z typem tylko ze zmienną i przy deklarowaniu kilku referencji na raz trzeba wstawiać & przed każdą z nich:
int &ref_x = x, &ref_y = y; // referencje
char *wsk_1, *wsk2; // wskazniki
Stałe referencje
edytujMożliwe jest zadeklarowanie referencji do obiektów stałych - wtedy obiektu, do którego odnosi się referencja nie będzie można zmienić.
int i=0;
const int &ref_i = i;
cout << ref_i; // wypisze 0
ref_i = 1; // kompilator nie pozwoli na to i zgłosi błąd
Powody, dla jakich możemy chcieć używać stałych referencji są analogiczne jak dla stałych wskaźników.
Przekazywanie argumentów przez referencję
edytujAby w C zmodyfikować parametr przekazywany do funkcji, musieliśmy używać wskaźników. C++ proponuje bezpieczniejszą i wygodniejszą w użyciu metodę - przekazywanie przez referencję.
Różnica między przekazywaniem przez referencję a przekazywaniem przez wskaźnik jest taka jaka miedzy referencjami i wskaźnikami, nie ma tu żadnej rewolucji. Przykład zastosowania pokazany jest poniżej:
void nie_zwieksz (int i)
{
++i; // tak naprawdę funkcja nie robi nic, bo zmieniona zostaje tylko lokalna kopia
}
void zwieksz_c (int *i)
{
++(*i); // ta funkcja jest napisana w stylu C
}
void zwieksz_cpp (int& i)
{
++i; // ta funkcja wykorzystuje możliwości C++
}
int main ()
{
int a = 0, b = 0, c = 0;
nie_zwieksz (a);
zwieksz_c (&b);
zwieksz_cpp (c);
cout << a << " " << b << " " << c;
// wypisze "0 1 1"
return 0;
}