Skocz do zawartości
  • 👋 Witaj na MPCForum!

    Przeglądasz forum jako gość, co oznacza, że wiele świetnych funkcji jest jeszcze przed Tobą! 😎

    • Pełny dostęp do działów i ukrytych treści
    • Możliwość pisania i odpowiadania w tematach
    • System prywatnych wiadomości
    • Zbieranie reputacji i rozwijanie swojego profilu
    • Członkostwo w jednej z największych społeczności graczy

    👉 Dołączenie zajmie Ci mniej niż minutę – a zyskasz znacznie więcej!

    Zarejestruj się teraz

Rekomendowane odpowiedzi

Opublikowano

Referencje

 

Dwie lekcje temu omówiłem wskaźniki. W tej lekcji będziemy mówić o czymś, co jest jakby odwrotnością wskaźnika. Mam na myśli referencję. Referencja to jakby zmienna, która "podszywa się" pod inną zmienną. Do czego może się nam taki "oszust" przydać? Narazie do niczego, lecz gdy dojdziemy do funkcji to okaże się, że referencja to bardzo przydatna rzecz. Ale narazie zakończmy tą podróż do przyszłości. Zobacz na poniższy kod:

 

 

 

int Jasio = 10;

int & Rudy = Jasio;

 

 

 

 

Pierwsza linijka pewnie nie sprawia ci trudności ;-). To jest zwyczajne zadeklarowanie zmiennej Jasio, którą od razu inicjujemy wartością 10 [liczbą lat małego Jasia]. Druga linijka wygląda natomiast dość ciekawie. Co tam robi ten operator adresu? [inaczej zwany operatorem referencji]. :-/ To jest właśnie deklaracja tej specjalnej zmiennej zwanej referencją. Taka deklaracja oznacza, że zmienna Rudy jest typu referencyjnego i może "podszywać się" pod zmienną typu int. Zmienną referencyjną musimy od razu zainicjować, inaczej kompilator zgłosi błąd, bo musi przecież wiedzieć, jaką zmienną udaje nasza referencja. Jak widzisz, przypisujemy referencji Rudy zmienną Jasio. Co to daje? No to zobacz kolejne linijki:

 

 

 

cout << "Poznajcie Jasia. Jasio ma " << Jasio << " latek\n";

cout << "Jasia przezywaja Rudy. Rudy ma " << Rudy << " latek\n";

 

 

 

 

Czy już łapiesz, o co chodzi? :-) Zmienna referencyjna to jakby "przezwisko". Na przykład możemy Jasia przezwać Rudy i powiedzieć, że Rudy ma 10 latek :-). Jak działa taka referencja? Po prostu kompilator nie rezerwuje dla niej nowego miejsca w pamięci, lecz korzysta z miejsca już zarezerwowanego wcześniej dla innej zmiennej. Dla nas wygląda to więc po prostu jak inna nazwa pewnego miejsca w pamięci, czyli inna nazwa [synonim, przezwisko] jakiejś zmiennej.

 

Sprawdźmy więc, czy rzeczywiście chodzi o tą samą zmienną, tylko pod inną nazwą. Zmienimy wartość jednej z nich i zobaczymy, czy druga też się zmieni.

 

 

 

Jasio = 7; cout << "Rudy ma " << Rudy << " latek\n";

Rudy = 14; cout << "Jasio ma " << Jasio << " lat\n";

 

 

 

 

Widzisz więc, że zmiana referencji powoduje też zmianę tej drugiej zmiennej. Gdy kompilator chce coś zrobić z referencją, to wskazuje mu ona miejsce w pamięci, gdzie przechowywana jest ta druga zmienna. Poniższy kawałek kodu powinien wszystko wyjaśnić:

 

 

 

cout << "Adres zamieszkania Jasia: " << (&Jasio) << endl;

cout << "Adres zamieszkania Rudego: " << (&Rudy) << endl;

 

 

 

 

Jak widzisz, nie ma znaczenia, że na Jasia czasem mówią Rudy, bo chodzi o tą samą osobę.

 

Spójrzmy na to znów od strony kompilatora. Dla niego każda nazwa zmiennej to coś na kształt wskaźnika, bo jest odpowiednikiem jakiegoś adresu w pamięci. Zwykła zmienna "zamieszkuje" wyłącznie swoje miejsce. Referencja jest jakby "bezdomną" zmienną, która korzysta z cudzego adresu zamieszkania. Natomiast wskaźnik, podobnie jak zwykła zmienna, ma swoje własne miejsce zamieszkania, ale jest kimś w rodzaju informatora, który może wskazać nam adres kogoś innego gdy go o to zapytamy. Referencja i wskaźnik, mimo że wydają się być tym samym, są jednak całkowitymi przeciwieństwami. Dlatego operator & [referencji] i operator * [dereferencji] znoszą się nawzajem. Zobacz:

 

 

 

int zmienna = 7; int *wskaznik = &zmienna;

cout << (*&zmienna) << "\t\t" << zmienna << endl;

cout << (&*wskaznik) << "\t\t" << wskaznik << endl;

 

 

 

 

W pierwszej linijce deklarujemy zmienną i wskaźnik do niej. W drugiej linijce zawartość nawiasu działa tak, że najpierw operator referencji zwraca adres zmiennej, po czym operator dereferencji zwraca to, co jest pod tym adresem, czyli zawartość zmiennej. Widzisz więc, że oba operatory działają całkowicie odwrotnie do siebie, co powoduje że kasują się nawzajem. Dowodem na to jest dalsza część linijki. Nawias w drugiej linijce działa tak, że najpierw operator dereferencji wyciąga to, co jest pod adresem wskazywanym przez wskaźnik, po czym operator referencji zwraca adres tego czegoś [czyli to samo, co zawiera zmienna wskaźnikowa]. Czyli podobnie jak w linijce pierwszej. Łapiesz już, czym się różni pojęcie REFERENCJI od pojęcia DEREFERENCJI? :-J Liczę na to, że tak, więc na tym zakończę tą lekcję. W kolejnej lekcji poznasz funkcje i zobaczysz wreszcie, do czego może nam się przydać referencja.

×
×
  • Dodaj nową pozycję...