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;