Quentin , spróbuję wyjaśnić całe zagadnienie referencji w kilku zdaniach.
-
[*:1lcxf02d] “Pod spodem” czyli od strony “kuchni” wskaźnik i referencja to jedno i to samo. Czyli kilka bajtów pamięci stanowiących słowo w danym komputerze w którym zapisany fizyczny adres innej komórki pamięci. Różni się jedyne sposobem zapisu.
double zmienna,x;
double *wsk1=zmienna; // inicjalizacja wskaźnika przy dekłaracji
double ref1=zmienna; // dokładnie to samo co wyżej, tylko że inny PROSTSZY zapis
*wsk1=0; wsk1[0]=0; // dwa sposoby na zmianę wskazywanej przez wskaźnik zmiennej
ref1=0; // sposób na zmianę “wskazywanej” przez referencje zmiennej, tylko że inny PROSTSZY zapis
wsk1=x; // sposób na zmianę wskazywanej zmiennej, nie ma odpowiednika dla referencji
double *wsk2; // już gdzieś tam wskazuje, można nawet pod ten adres coś zapisać (ze złym skutkiem)
//double ref2; // nie skompiluję się ponieważ musi zacząć “referować” tuż przy deklaracji
[*:1lcxf02d] Wskaźniki mogą być podwójne, potrójne i nawet więcej.
long ***** w;
[*:1lcxf02d] Można zadeklarować referencję na wskaźnik
short *w;
short *r=w; // r jest referencją na w
[*:1lcxf02d] Nie da się nawet zadeklarować wskaźnika na referencję jak również referencji na referencję. Wynika to właśnie z “kuchni”, czyli z tego czym właściwie jest referencja. [*:1lcxf02d] Referencja przeważnie jest stosowana dla przekazywania parametrów do funkcji.
int a=3,b=4;
void swap(int *x,int *y) { int t=*x; *x=*y; *y=t; } // zamiana wartości przez wskaźniki
void swap(int x,int y) { int t=x; x=y; y=t; } // zamiana wartości przez referencje
swap(a,b); // wywołanie funkcji zamiany wartości przez wskaźniki
swap(a,b); // wywołanie funkcji zamiany wartości przez referencje
Chyba widać czemu z referencją lepiej. [*:1lcxf02d] Ponieważ od “kuchni” referencja jest tym samym co wskaźnik to twierdzenie “nie da się przestawić referencji na inny obiekt” nie jest do końca prawdą. Można zmienić ale nie wprost, przez “mazanie po pamięci” czasami używa się kontrolowanego mazania dla takiej zmiany, ale to jest bardzo nie elegantske. Przykłady zmiany referencji:
#include
using std::cout;
using std::endl;
using std::cin;
struct z_ref { long r; };
long A=123456789,B=987654321,R1=A;
z_ref z={A};
int main()
{
long R2=A,Q=0;
{
cout"Przestawienie referencji bazujace na wiedzy:"endl;
cout"struktura zr ma ten sam adres co jej pierwsza składowa."endlendl;
cout"POCZATEK: z.r jest referencja na A, "endl;
cout"adresy z.r i A sa identyczne "z.r'='A" A="z.rendlendl;
long **w=reinterpret_castlong ** (z); // zmienna w - właściwie jest wskaźnikiem na referencję
*w=B; // zmieniamy referencje
cout"A TERAZ: z.r jest referencja na B, "endl;
cout"adresy z.r i B sa identyczne "z.r'='B" B="z.rendlendl;
long *r=*reinterpret_castlong **(z); // zmienna r - właściwie jest referencją na referencję
r=A; // zmieniamy referencje
cout"I ZNOWU: z.r jest referencja na A, "endl;
cout"adresy z.r i A sa identyczne "z.r'='A" A="z.rendlendlendl;
}
{
cout"Przestawienie referencji bazujace na wiedzy:"endl;
cout"zmienne globalne rozmieszczane w pamieci po kolei."endlendl;
cout"POCZATEK: R1 jest referencja na A, "endl;
cout"adresy R1 i A sa identyczne "R1'='A" A="R1endlendl;
long **w=reinterpret_castlong ** (B+1); // zmienna w - właściwie jest wskaźnikiem na referencję
*w=B; // zmieniamy referencje
cout"A TERAZ: R1 jest referencja na B, "endl;
cout"adresy R1 i B sa identyczne "R1'='B" B="R1endlendl;
long *r=*reinterpret_castlong **(B+1); // zmienna r - właściwie jest referencją na referencję
r=A; // zmieniamy referencje
cout"I ZNOWU: R1 jest referencja na A, "endl;
cout"adresy R1 i A sa identyczne "R1'='A" A="R1endlendlendl;
}
{
cout"Przestawienie referencji bazujace na wiedzy:"endl;
cout"zmienne lokalne rozmieszczane w pamieci w odwrotnej kolejnosci."endlendl;
cout"POCZATEK: R2 jest referencja na A, "endl;
cout"adresy R2 i A sa identyczne "R2'='A" A="R2endlendl;
long **w=reinterpret_castlong ** (Q-1); // zmienna w - właściwie jest wskaźnikiem na referencję
*w=B; // zmieniamy referencje
cout"A TERAZ: R2 jest referencja na B, "endl;
cout"adresy R2 i B sa identyczne "R2'='B" B="R2endlendl;
long *r=*reinterpret_castlong **(Q-1); // zmienna r - właściwie jest referencją na referencję
r=A; // zmieniamy referencje
cout"I ZNOWU: R2 jest referencja na A, "endl;
cout"adresy R2 i A sa identyczne "R2'='A" A="R2endlendlendl;
}
cin.get();
return 0;
} [/code]
Nie są to jedyne sposoby na zmianę referowanej zmiennej, ale najprostsze. Jeżeli w strukturze z_ref dodamy jakąś składową przed składową r to pierwszy przykład natychmiast się załamie. Drugi i trzeci przykład załamią się po zwykłej zmianie kolejności deklarowanych zmiennych, lub nawet po przenoszeniu zmiennych lokalnych do globalnych albo na odwrót.