Sunteți pe pagina 1din 6

Mihai TOGAN

Cap. 8 – Supraîncărcarea operatorilor

Obiective:
 Supraîncărcarea operatorilor (operator overloading)
 Exemple

1
Mihai TOGAN
Sunt facilităţi puse la dispoziţie de limbajele OOP. Pot fi realizate folosind următoarele
mecanisme:
 Supraîncărcarea funcțiilor
o funcții cu acelaşi nume dar cu parametrii și funcționalitate diferită.
 Supraîncărcarea operatorilor (standard)
o operatori cu acelaşi nume, dar cu operanzi (parametrii) și funcționalitate probabil
diferită.

Supraîncărcarea operatorilor
 Extinderea unui operator pentru a putea lucra cu tipuri de operanzi definiţi de utilizator
(clase, structuri).
 La nivelul unei clase/structuri utilizatorul poate defini un operator care să implementeze o
operaţie asupra unui obiect din acea clasă.
 Nu pot fi definiți (supraîncărcaţi) decât operatorii standard (built-in).

Exemplu:
#include <iostream>
using namespace std;

class Complex {
public:
Complex(double re,double im) :real(re),imag(im) {};
void print() {printf ("(%lf, %lf)", real, imag);}

Complex operator+ (const Complex& C);

private:
double real;
double imag;
};

Complex Complex::operator+ (const Complex& C)


{
double result_real = real + C.real;
double result_imaginary = imag + C.imag;
return Complex(result_real, result_imaginary);
}

/****************************************************************************/
void main ()
{
Complex a(1.2,1.3);
Complex b(2.1,3);

Complex c = a+b; //aici, operatorul + trebuie redefinit (supraincarcat)

a.print();cout << " + "; b.print(); cout << " = "; c.print();
cout << endl;
}
/*****************************************************************************/

2
Mihai TOGAN

Fără această facilitate, am fi putut rezolva operaţia de adunare de două numere complexe
definind o funcție dedicată la nivelul clasei Complex:

Complex Add (const Complex& C);

Complex c = a.Add(b);

Observaţie: singura diferenţă între cele două abordări este cea de claritate a secvenţelor de
cod. Este mult mai intuitiv și mai lizibil utilizarea operatorului „+” ȋn această situaţie.

Un operator poate fi definit (supraîncărcat) ȋn mai multe variante, schimbând lista de


parametrii:
/*************************************************************************/
class Complex
{
public:
Complex operator+ (const Complex& C);
Complex operator+ (int k);
//..
};

Complex Complex::operator+ (int k)


{
double result_real = real + k;
double result_imaginary = imag + k;
return Complex(result_real, result_imaginary);
}

/*************************************************************************/
void main ()
{
Complex a(1.2,1.3);

Complex d = a + 2;
d.print();
}
/*************************************************************************/

Câteva observaţii privind supraîncărcarea operatorilor în C++:


 Operatorii de asignare „=”, adresare „&” și secvenţiere ",” au implementări implicite
pentru orice tip nou de date (class sau struct). Aceste implementări implicite pot fi însă
supraîncărcate. Orice alt operator trebuie declarat și definit pentru a putea fi aplicat.

 Aproape toţi operatorii standard (built-in la nivelul limbajului) pot fi supraîncărcaţi:

 Operatorii işi păstrează întotdeauna tipul (operator unar, binar, etc.) și precedenţa.
 Operatorul de scop „::” și cel de selectare de membrii „ .” nu pot fi supraîncărcaţi.
 Toţi operatorii, cu excepţia operatorului de atribuire „=”, se moştenesc.
3
Mihai TOGAN
Secvenţa următoare de cod prezintă un exemplu de supraîncărcare pentru operatorul de
asignare „=”
class Complex
{
public:
//..
Complex& operator= (const Complex& C);
};

Complex& Complex::operator= (const Complex& C)


{
if (this != &C)
{
this->real = C.real;
this->imag = C.imag;
}

return *this;
}
/***************************************************************************/
void main ()
{
Complex a(1.2,1.3);

Complex c (0, 0);


c = a; //aici, este apelat operatorul = (cel supraincarcat)

// ATENTIE !!
Complex d = a; //aici, este invocat constructorul de copiere și nu operatorul =

}
/***************************************************************************/

Observaţie: operatorul se putea declara și defini fără a se utiliza referinţa la tipul de return al
funcţiei (discuţie în sală):
class Complex {
//..
Complex operator= (const Complex& C);
};

La nivelul unei clase (poate fi şi struct) operatorii pot fi supraîncărcaţi ȋn 2 moduri:


 Ca metode ale clasei (exemplul de mai sus)
 Ca funcții standalone, însă friend cu clasa respectivă.
Exemplul anterior modificat (operatorii definiți ca funcții friend la nivelul clasei Complex):
class Complex
{
public:
Complex(double re,double im):real(re),imag(im) {};
void print() {printf ("(%lf, %lf)", real, imag);}

private:
double real;
double imag;

friend Complex operator+(const Complex& C1, const Complex& C2);


friend Complex operator+ (const Complex& C1, int k);
};
4
Mihai TOGAN
Complex operator+(const Complex& C1, const Complex& C2)
{
double result_real = C1.real + C2.real;
double result_imaginary = C1.imag + C2.imag;
return Complex(result_real, result_imaginary);
}

Complex operator+ (const Complex& C1, int k)


{
double result_real = C1.real + k;
double result_imaginary = C1.imag + k;
return Complex(result_real, result_imaginary);
}

/****************************************************************************/
void main ()
{
Complex a(1.2,1.3);
Complex b(2.1,3);

Complex c = a + b;
a.print();cout << " + "; b.print(); cout << " = "; c.print();

Complex d = a + 2;
d.print();
}
/****************************************************************************/

Există situaţii când numai aşa putem obţine un caz particular de supraîncărcare a unui
operator.

Exemplu: în cazul în care dorim să putem realiza operaţia de mai sus păstrând proprietatea
de comutativitate specifică operatorului „+” :
Complex d = 2 + a;

Ȋn acest caz, singura variantă de implementare este cea bazată pe funcții friend:

/****************************************************************************/
class Complex
{
public:
Complex operator+ (const Complex& C);
Complex operator+ (int k);

friend Complex operator+ (int k, const Complex& C1);


//..
};

Complex operator+ (int k, const Complex& C1)


{
double result_real = C1.real + k;
double result_imaginary = C1.imag + k;
return Complex(result_real, result_imaginary);
}

5
Mihai TOGAN

/****************************************************************************/
void main ()
{
Complex a(1.2,1.3);

Complex d = 2 + a;
d.print();
}

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

Supraîncărcarea operatorilor de intrare/ieșire (<< , >>)


class Complex
{
//..
friend ostream &operator<<(ostream &out, Complex c); //output
friend istream &operator>>(istream &in, Complex &c); //input
};

ostream &operator<<(ostream &out, Complex c) //output


{
out<<"real part: "<<c.real << ", ";
out<<"imag part: "<<c.imag<<"\n";
return out;
}

istream &operator>>(istream &in, Complex &c) //input


{
cout<<"enter real part:\n";
in>>c.real;
cout<<"enter imag part: \n";
in>>c.imag;
return in;
}

/****************************************************************************/
void main ()
{
Complex a(1.2,1.3);
Complex b(2.1,3);

cout<<a<<b;

cin>> b;
cout << b;
}
/****************************************************************************/