Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
POO - Curs Doc-1.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
868.86 Кб
Скачать

§9. Definirea şi utilizarea referinţelor

Toate programele utilizate până în prezent utilizau doar două tipuri de variabile şi anume variabile obişnuite şi variabile de tip adresă sau pointeri. Limbajul C++ mai adaugă la aceste tipuri şi variabile de tip referinţă. O variabilă de tip referinţă este precedată la definire de simbolul ampersend (&). Iată cum este definită o referinţă,

tip & nume_var_ref=nume_var;

unde nume_var_ref este un identificator, care reprezintă numele variabilei de tip referinţă, iar nume_var este numele unei variabile, care trebuie să aibă o definire anterioară referinţei. Această definire poate fi generalizată pentru cazul mai multor variabile, după cum urmează:

tip &nume_var_ref1=nume_var1, . . .,

&nume_var_refk=nume_vark;

Pentru a observa unele proprietăţi ale referinţelor este propus un program în care sunt definite referinţe şi sunt efectuate o serie de operaţii atât asupra variabilelor simple cât şi asupra variabilelor de tip referinţă.

#include <iostream.h>

void main()

{

int i=10, j=20;

int &ri=i, &rj=j;

cout <<i<<’ ’<<ri<<endl;

i=j;

cout <<i<<’ ’<<ri<<endl;

ri+=rj;

cout <<i<<’ ’<<ri<<endl;

}

Programul anterior va produce următoarele afişări:

10 10

20 20

40 40

Se observă că orice transformare efectuată asupra variabilei i se răsfrânge asupra referinţei corespunzătoare ri şi de asemenea orice transformare efectuată asupra referinţei ri se răsfrânge asupra variabilei corespunzătoare i. De aici este trasă concluzia că o referinţă este ca un nume nou pentru variabila cu care este legată, adică ar fi ca un alias sau poreclă. Crearea unui nume nou pentru o variabilă nu este un mare avantaj fiindcă ar putea doar să genereze dificultate de a urmări ideea programului şi ar putea fi şi o sursă de erori.

Totuşi referinţele sunt de un real folos în cadrul funcţiilor şi anume în calitate de parametri fictivi şi ca valoare returnată de funcţie. Sunt cunoscute deja metodele de transmitere a parametrilor în funcţie prin valoare şi prin adresă. La aceste metode se mai alătură şi metoda de transmitere a parametrilor prin referinţă. Pentru o comparare a acestor metode vor fi realizate trei funcţii menite să schimbe cu locurile valorile aflate în două variabile.

1) Transmitere prin valoare

void schimb1(

int a, int b)

{

int t=a;

a=b;

b=t;

}

2) Transmitere prin adresă

void schimb2(

int*a, int*b)

{

int t=*a;

*a=*b;

*b=t;

}

3) Transmitere prin referinţă

void schimb3(

int&a, int&b)

{

int t=a;

a=b;

b=t;

}

Aceste funcţii vor fi apelate în funcţia main(), cu scopul realizării operaţiei de schimb a valorilor variabilelor.

#include<iostream.h>

void main()

{

int a=30, b=60;

int &ra=a, &rb=b;

schimb1(a,b);

cout<<a<<’ ’<<b<<endl;

schimb2(&a,&b);

cout<<a<<’ ’<<b<<endl;

schimb3(ra,rb);

cout<<a<<’ ’<<b<<endl;

}

Programul dat va produce următoarele afişări:

30 60

60 30

30 60

Urmărind afişările produse se poate trage concluzia că prima funcţie face un schimb local, care nu afectează nicicum variabilele a şi b, iar funcţiile a doua şi a treia realizează un schimb care afectează valorile variabilelor a şi b, precum şi era necesar. Deci transmiterea parametrilor prin adresă şi prin referinţă sunt asemănătoare prin faptul că schimbarea valorii în cadrul funcţiei a unui parametru din lista parametrilor fictivi se produce neapărat şi asupra parametrului real transmis în funcţie în locul acestui parametru fictiv. Aşadar parametrii fictivi de tip referinţă sunt asemănători cu parametrii de tip pointer. Adică referinţele sunt un fel de adrese.

Pe de altă parte comparând funcţiile se poate observa că modul de prelucrare a referinţelor în cadrul funcţiei este asemănător cu modul de prelucrare a variabilelor obişnuite, adică nu sunt necesare careva simboluri adăugătoare ataşate variabilelor ca în cazul pointerilor (*). Deci parametrii de tip referinţă sunt asemănători atât cu parametrii de tip adresă cât şi cu parametrii de tip valoare.

În programul anterior funcţia schimb3() a fost apelată utilizând variabilele de tip referinţă ra şi rb, corespunzătoare variabilelor a şi b:

schimb3(ra,rb);

Poate fi realizat un apel echivalent al funcţiei, utilizând direct variabilele a şi b după cum urmează.

schimb3(a,b);

Un exemplu interesant de funcţie este o funcţie care are un parametru fictiv de tip referinţă şi returnează o valoare de tip referinţă. Fie următorul tip de funcţie:

int patrat(int i)

{

i=i*i;

return i;

}

Această funcţie se comportă bine în partea dreaptă a unei egalităţi returnând pătratul unui număr. De exemplu:

int k=12;

j=patrat(k);

Plasarea unei astfel de funcţii în partea stângă a egalităţii ar genera o eroare.

patrat(k)=j; //eroare

În continuare funcţia anterioară este schimbată puţin, utilizând referinţe, şi este obţinută următoarea funcţie:

int& patrat(int&i)

{

i=i*i;

return i;

}

Plasată în partea dreaptă a egalităţii ea de asemenea returnează pătratul unei valori, insă ea capătă proprietatea neaşteptată de a putea fi plasată şi în partea stângă a egalităţii:

j=25;

patrat(k)=j; //corect

Drept rezultat valoarea 25 din variabila j va fi plasată în variabila k. Astfel de proprietate poate fi de un real folos în procesul de supraîncărcare a unor operatori.

Există o serie de restricţii de utilizare a referinţelor:

  1. Referinţa trebuie iniţializată la definire şi rămâne neschimbată pe parcursul execuţiei programului;

  2. Nu poate fi determinată adresa unei referinţe;

  3. Referinţele pot fi comparate, dar nu la nivel de adrese, ci la nivel de valori asociate cu ele.

În continuare va fi menţionată o posibilă eroare legată de referinţe şi care poartă denumirea de pierdere a referinţei. O astfel de eroare se produce atunci când tipul referinţei nu coincide cu tipul variabilei cu care este asociată referinţa:

tip1 var;

tip2 &r=var;

tip1≠tip2;

În baza ideii anterioare este propus următorul exemplu:

int i=10;

int &ri=i;

long j=10;

int &rj=j;

cout <<i<<’ ’<<ri<<endl;

cout <<j<<’ ’<<rj<<endl;

i++;

j++;

cout <<i<<’ ’<<ri<<endl;

cout <<j<<’ ’<<rj<<endl;

Fragmentul dat va produce următoarele afişări:

10 10

10 10

11 11

11 10

De aici se observă că variabilele i şi ri, fiind definite corect, sunt asociate şi se schimbă sincron, pe când valorile variabilelor j şi rj arată că ele de fapt nu sunt asociate, deci referinţa rj nu este legată corect de variabila j.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]