Operatorul de atribuire apare în C++ în forma V = E
, unde V
este o variabilă (dată de tip left value
) iar E
este o expresie, sau în forma V op= E
, ca prescurtare pentru V = V op E
, unde op
este un operator binar (+
, -
, *
, etc.).
Am văzut deja că atribuirea (=
) este posibilă implicit pentru obiecte de același tip. Ea funcționează corect doar dacă datele membre ale clasei sunt alocate static, deoarece se face bit cu bit.
Este un operator binar, care se implementează ca metodă. Obiectul curent reprezintă primul operand, în timp ce al doilea operand va fi transmis ca parametru.
Rezultatul său este o referință la obiectul curent, cel care se modifică.
În continuare avem trei exemple:
- primul tratează atribuirea unei valori pentru un obiect de tip fracție; sunt implementați următorii operatori:
F = G
, undeF
șiG
sunt de tip fracție;F = n
, undeF
este fracție șin
este întreg;F += G
, undeF
șiG
sunt de tip fracție;F += n
, undeF
este fracție șin
este întreg;- similar se pot implementa operatorii
-=
,*=
,/=
, etc.
- celelalte două tratează operatorul de atribuire în cazul obiectelor care alocă memoria dinamic. Mai precis, este implementată o listă alocată dinamic și operatorul de atribuire între două obiecte de tip listă.
- pentru al doilea exemplu se folosește operatorul de atribuire implicit. Gestionarea memoriei este greșită!
- pentru al doilea exemplu se supraîncarcă operatorul de atribuire. Memoria se gestionează corect!
Exemplul 1
#include <iostream> using namespace std; class Fractie{ private: int numarator, numitor; public: void afiseaza() /// metodă pentru afișarea fractiei { cout << numarator << "/" << numitor << endl; } Fractie(int a = 0, int b = 1) /// constructor { if(b < 0) a = -a, b = -b; numarator = a, numitor = b; } Fractie & operator = (const Fractie & F) { this->numarator = F.numarator; this->numitor = F.numitor; return * this; } Fractie & operator = (const int & n) { this->numarator = n; this->numitor = 1; return * this; } Fractie & operator += (const Fractie & F) { int a = numarator * F.numitor + numitor * F.numarator; int b = numitor * F.numitor; this->numarator = a; this->numitor = b; return * this; } Fractie & operator += (const int & n) { int a = numarator * 1 + numitor * n; int b = numitor * 1; this->numarator = a; this->numitor = b; return * this; } }; int main(){ Fractie X(1 , 4), Y(2, 3); X += Y; X.afiseaza(); // 11/12 X = Fractie(1 , 4); X.afiseaza(); // 1/4 X += 2; X.afiseaza(); // 9/4 X = Fractie(1 , 4) , Y = Fractie(2 , 3); swap(X , Y); X.afiseaza(); // 2/3 Y.afiseaza(); // 1/4 X = Fractie(1 , 4) , Y = Fractie(2 , 3); X = (Y += 1); X.afiseaza(); // 5/3 Y.afiseaza(); // 5/3 return 0; }
Exemplul 2 – greșit
#include <iostream> using namespace std; class Lista{ private: struct nod{ int info; nod * urm; nod(int x = 0){ info = x; urm = NULL; } } * prim, * ultim; public: Lista(){ prim = ultim = NULL; } void adaugare(int x = 0){ if(prim == NULL) { prim = ultim = new nod(x); } else { ultim->urm = new nod(x); ultim = ultim->urm; } } void afisare() { nod * p = prim; while(p) cout << p->info << " ", p = p->urm; cout << endl; } }; int main(){ Lista L; L.adaugare(4); L.adaugare(3); L.afisare(); Lista M; M = L; L.adaugare(5); M.afisare(); return 0; }
În exemplul de mai sus, atribuirea M = L;
folosește operatorul de atribuire implicit. În obiectele M
și L
, membrii prim
și ultim
au aceeași valoare, adică adresele acelorași noduri din listă. Practic obiectele M
și L
prelucrează aceeași listă:
Exemplul 3 – corect
#include <iostream> using namespace std; class Lista{ private: struct nod{ int info; nod * urm; nod(int x = 0){ info = x; urm = NULL; } } * prim, * ultim; public: Lista(){ prim = ultim = NULL; } void adaugare(int x = 0){ if(prim == NULL) { prim = ultim = new nod(x); } else { ultim->urm = new nod(x); ultim = ultim->urm; } } void afisare() { nod * p = prim; while(p) cout << p->info << " ", p = p->urm; cout << endl; } Lista & operator = (const Lista & S) { // se sterg elementele existente în lista curentă // TO DO // se adauga in lista curentă elementele din S prim = NULL; nod * p = S.prim; while(p) { this->adaugare(p->info), p = p->urm; } return * this; } }; int main(){ Lista L; L.adaugare(4); L.adaugare(3); L.afisare(); Lista M; M = L; L.adaugare(5); M.afisare(); return 0; }
Față de exemplul anterior, am supraîncărcat operatorul de atribuire =
. Astfel, în obiectul M
se crează o nouă listă, care conține însă aceleași valori ca cele din L
, încapsulate în alte noduri. Adăugarea unui nou nod în L
nu afectează în niciun fel lista M
.