5615 afișări Candale Silviu (silviu) 01.06.2021 www.pbinfo.ro
Etichete: nicio etichetă

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, unde F și G sunt de tip fracție;
    • F = n, unde F este fracție și n este întreg;
    • F += G, unde F și G sunt de tip fracție;
    • F += n, unde F este fracție și n 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.


5615 afișări Candale Silviu (silviu) 01.06.2021 www.pbinfo.ro