Supraîncărcarea operatorilor

Noţiuni generale

Supraîncărcarea operatorilor permite utilizarea operatorilor standard ai limbajului pentru clasele proprii. Aceasta se poate realiza prin definirea unor funcţii cu denumire specială (se foloseşte cuvântul cheie operator).

 

La supraîncărcarea operatorilor există unele restricţii:

 

Operatorii pot fi supraîncărcaţi prin funcţii membre în clasă sau prin funcţii normale. În cazul în care se folosesc funcţii membre numărul parametrilor funcţiei ca fi cu 1 mai mic decât cardinalitatea operatorului (primul operand este considerat pointerul this).

 

Pentru detalii, vezi cartea „Programarea orientată obiect în limbajul C++”, paginile 52-78.

 

Aplicaţie

 

Să se construiască o clasă Colectie memorată sub formă de listă simplu înlănţuită pentru stocarea numerelor întregi care să permită efectuarea principalelor operaţii folosind operatori şi care să permită parcurgerea colecţiei folosind un iterator. Să se scrie un program principal pentru demonstrarea funcţionării clasei.

 

Pentru rezolvare vom avea nevoie de trei clase:

 

Implementarea C++ a claselor şi a programului principal pentru testare:

 

#include <iostream>

using namespace std;

 

/********************************************************************

 * Clasa Colectie

 * --------------------------

 * Implementeaza o colectie de numere intregi sub forma de lista

 * simplu inlantuita.

 ********************************************************************/

class Colectie

{

       struct Nod;   // anuntare clasa Nod (pentru Iterator)

 

       /*** Interfata publica ***/

 

public:

 

       // Constructori

       Colectie() : cap(NULL) {}  // constructorul implicit

       Colectie(const Colectie& c) // constructorul de copiere

       {

              cap = NULL;

 

              // parcurgem colectia cu un iterator

              for (Iterator i = c.Inceput(); i != c.Sfarsit(); i++)

                     // si adaugam nodurile in colectia noastra

                     Adaugare(*i);

       }

 

       // operatorul de atribuire

       const Colectie& operator=(const Colectie& c)

       {

              // stergem colectia curenta

              GolireColectie();

 

              // si copiem elementele noi

              for (Iterator i = c.Inceput(); i != c.Sfarsit(); i++)

                     Adaugare(*i);

 

              return (*this);

       }

 

       // destructorul

       ~Colectie()

       {

              GolireColectie();

       }

 

       // operatorul pentru acces direct la elemente

       int& operator[] (int k) const

       {

              // presupunem ca indicele este in interiorul colectiei

              Nod *p = cap;

              for (int i = 0; i < k; i++)

                     p = p->Urmator;

             

              return p->Valoare;

       }

 

       // operatii cu elemente

       void Adaugare(int valoare) // adaugare element la sfarsit

       {

              // cazul 1: lista vida

              if (cap == NULL)

                     cap = new Nod(valoare);

              else

              {

                     // cazul 2: lista nu este vida

                     Nod *p = cap;

                     while (p->Urmator != NULL)

                           p = p->Urmator;

 

                     p->Urmator = new Nod(valoare);

              }

       }

 

       const Colectie& operator +=(int valoare)

       {

              Adaugare(valoare);

              return (*this);

       }

 

       void Inserare(int poz, int val)   // inserare element 

       {

              // cazul 1: inserare la inceputul colectiei

              if (poz == 0)

              {

                     cap = new Nod(val, cap);

                     return;

              }

 

              // cazul 2: inserare in interiorul colectiei

             

              // cautam pozitia de inserare

              Nod *p = cap;

              for (int i = 0; i < poz-1; i++)

                     p = p->Urmator;

 

              // si inseram nodul

              p->Urmator = new Nod(val, p->Urmator);

       }

 

       void Stergere(int poz)                   // sterge elementul de pe pozitia specificata

       {

              // cazul 1: stergere la inceputul colectiei

              if (poz == 0)

              {

                     Nod *temp = cap;

                     cap = cap->Urmator;

                     delete temp;

 

                     return;

              }

 

              // cazul 2: stergere din interiorul colectiei

             

              // cautam pozitia de sters

              Nod *p = cap;

              for (int i = 0; i < poz-1; i++)

                     p = p->Urmator;

 

              // si stergem nodul

              Nod *temp = p->Urmator;

              p->Urmator = p->Urmator->Urmator;

              delete temp;

       }

 

       void GolireColectie()             // sterge toate elementele din colectie

       {

              while (cap != NULL)

                     Stergere(0);

       }

 

       // concatenare colectii

       const Colectie& operator +=(const Colectie &c)

       {

              // adaugam elementele noi

              for (Iterator i = c.Inceput(); i != c.Sfarsit(); i++)

                     Adaugare(*i);

       }

 

       const Colectie operator + (const Colectie &c)

       {

              Colectie rezultat = (*this);

 

              // adaugam elementele noi

              for (Iterator i = c.Inceput(); i != c.Sfarsit(); i++)

                     rezultat.Adaugare(*i);

 

              return rezultat;

       }

 

       // operatii diverse

       int NumarElemente() const         // obtine numarul de elemente

       {

              Nod *p = cap;

              int i = 0;

 

              while (p != NULL)

              {

                     p = p->Urmator;

                     i++;

              }

 

              return i;

       }

 

       bool EGoala() const                      // testare colectie vida

       {

              return cap == NULL;

       }

       bool operator!() const

       {

              return !EGoala();

       }

 

       // operatori de verificare egalitate

       bool operator == (const Colectie& c) const

       {

              Iterator i1 = Inceput();

              Iterator i2 = c.Inceput();

 

              while (i1 != Sfarsit() && i2 != c.Sfarsit())

              {

                     if ((*i1) != (*i2))

                           return false;

                    

                     i1++;

                     i2++;

              }

 

              // daca nu au aceeasi lungime sunt diferite

              if ((i1 == Sfarsit() && i2 != c.Sfarsit()) || (i1 != Sfarsit() && i2 == c.Sfarsit()))

                     return false;

 

              // au toate elementele egale si aceeasi dimensiune

              return true;

       }

 

       bool operator != (const Colectie& c) const

       {

              return !((*this) == c);

       }

 

       // implementare iterator

       class Iterator

       {            

       public:

              // operatorul de dereferentiere

              int& operator *() const

              {

                     return nodCurent->Valoare;

              }

 

              // operatorul de avansare in colectie (postincrementare)

              const Iterator& operator++(int)

              {

                     nodCurent = nodCurent->Urmator;

                     return (*this);

              }

 

              // operatorul de atribuire

              const Iterator& operator=(const Iterator& iterator)

              {

                     nodCurent = iterator.nodCurent;

                     return (*this);

              }

 

              // operatorii de comparatie

              bool operator==(const Iterator& iterator)

              {

                     return nodCurent == iterator.nodCurent;

              }

 

              bool operator != (const Iterator& iterator)

              {

                     return !((*this) == iterator);

              }

 

       private:

              // clasa colectie trebuie sa aiba acces la

              // sectiunea privata a Iteratorului

              friend class Colectie;           

             

              // constructor privat (va fi apelat doar

              // de catre clasa Colectie)

              Iterator(Nod *nod)

                     : nodCurent(nod) {}

 

              Nod *nodCurent;

       };

 

       // functii pentru iteratori

       // intoarce un iterator la inceputul colectiei

       Iterator Inceput() const

       {

              return Iterator(cap);

       };

 

       // intoarce un iterator dupa sfarsitul colectiei

       Iterator Sfarsit() const

       {

              return Iterator(NULL);

       };

 

       /*** Sectiunea privata ***/

 

private:

 

       // clasa folosita intern pentru memorarea unui nod al listei

       struct Nod

       {

              // constructor

              Nod(int valoare, Nod *urmator = NULL)

                     : Valoare(valoare), Urmator(urmator) {}

 

              // date membru

              int Valoare;

              Nod *Urmator;

       };

 

       // capul listei

       Nod *cap;

};

 

// operatorii de I/E pentru Colectie

ostream& operator << (ostream& out, const Colectie& c)

{

       for (Colectie::Iterator i = c.Inceput(); i != c.Sfarsit(); i++)

              out << (*i) << " ";

 

       return out;

}

 

void main()

{

       // creare colectie

       Colectie c1;

 

       // adaugare elemente in colectie

       c1.Adaugare(7);

       c1.Adaugare(8);

       c1 += 23;

       c1 += 72;

 

       // afisare colectie folosind operatorul <<

       cout << "Elemente dupa adaugare: " << c1 << endl;

 

       // inserare elemente

       c1.Inserare(0, 2);

       c1.Inserare(5, 22);

       c1.Inserare(5, 21);

       cout << "Elemente dupa inserare: " << c1 << endl;

 

       // stergere elemente

       c1.Stergere(3);

       cout << "Elemente dupa stergere: " << c1 << endl;

 

       // accesare elemente folosind operatorul []

       cout << "Primul element este:" << c1[0] << endl;

       cout << "Ultimul element este:" << c1[c1.NumarElemente() - 1] << endl;

 

       // test coada vida

       if (c1.EGoala())

              cout << "Colectia este goala." << endl;

       else

              cout << "Colectia nu este goala." << endl;

 

       // construim o colectie noua folosind constructorul de copiere

       Colectie c2 = c1;

 

       // stergere colectie

       c1.GolireColectie();

       cout << "Dupa golire:" << endl;

       if (c1.EGoala())

              cout << "Colectia este goala." << endl;

       else

              cout << "Colectia nu este goala." << endl;

 

       // afisare colectia 2

       cout << "Colectia 2:" << c2 << endl;

 

       cout << "Inainte de operator =" << endl;

 

       // verificare egalitate

       if (c1 == c2)

              cout << "Colectiile sunt egale" << endl;

       if (c1 != c2)

              cout << "Colectiile nu sunt egale" << endl;

 

       // testare operator =

       c1 = c2;

 

       cout << "Dupa de operator =" << endl;

       // verificare egalitate

       if (c1 == c2)

              cout << "Colectiile sunt egale" << endl;

       if (c1 != c2)

              cout << "Colectiile nu sunt egale" << endl;

 

       // afisare colectia 1

       cout << "Colectia 1 dupa atribuire:" << c1 << endl;

 

       // test concatenare

       cout << "Concatenare: " << c1 + c2 << endl;

}