Podręcznik
Wersja podręcznika: 1.0
Data publikacji: 01.01.2022 r.
4. Typy pochodne
4.2. Referencje
Pojęciem związanym z pojęciem wskaźnika jest referencja. W pierwszym przybliżeniu możecie ją rozumieć jako inną nazwę obiektu – czyli faktycznie dostajemy pewną analogię do wskaźników – możliwość odwołania się do jednego obiektu poprzez kilka nazw.
W praktyce możemy tworzyć wiele zmiennych odpowiadających temu samemu obszarowi pamięci, takich „zmiennych wirtualnych” - istniejących w kodzie programu jako nazwa, lecz nie posiadających własnej tożsamości – i to są właśnie referencje. W przeciwieństwie do wskaźników referencje nie są rzeczywistymi zmiennymi, i obszar ich zastosowań jest zdecydowanie bardziej ograniczony w stosunku do wskaźników. Ich główne zastosowanie to specyfikowanie argumentów funkcji – o tym będzie mowa w dalszej części podręcznika. Fachowo często się mówi o referencjach jako o stałym wskaźniku z niejawnym operatorem adresowania pośredniego. Brzmi skomplikowanie, ale dużo nam mówi o charakterze referencji, między innymi o jej podobieństwie do stałych. Przy czym pamiętajcie - w przypadku referencji stały oznacza tylko że nie można zmienić wskazywanego obiektu - jego tożsamości. Natomiast wartość przechowywaną we wskazywanym obiekcie można zmieniać.
Korzystając z referencji pamiętajcie by trzymać się kilku zasad:
- Każda referencja musi zostać zainicjowana w momencie definicji – podobnie jak stałe
- Wskazywanego obiektu dla referencji nie da się zmienić – raz zdefiniowana wskazuje ciągle na tą samą zmienną.
- Operatory zawsze działają na wartości – nigdy na referencji – inaczej niż we wskaźnikach, ale dokładnie jak w przypadku stałych wskaźników
- Optymalizacja we współczesnych kompilatorach często prowadzi do usunięcia obiektów reprezentujących referencje – podobnie jak w przypadku stałych
- Referencja bez modyfikatora const musi zostać zainicjowana L-wartością - stała referencja może być inicjowana wartością stałą (nie l-wartością).
Przykłady definiowania referencji:
int s1 = 5, s2;
int& r1{s1};
s2 = r1;
r1 = 6;
r1++;
// źle !
int& r3 = 1;
int& r4;
// dobrze
extern int& r2;
const double& r5=1;