28. SUPRADEFINIREA OPERATORILOR Pentru un tip clasă se poate defini un set de operatori asociaţi prin supradefinirea operatorilor existenţi, ceea ce permite realizarea de operaţii specifice cu noul tip la fel cum se pot realiza şi operaţii cu tipurile standard. Operatorii care pot fi supradefiniţi sunt : + - *? = < > += -= *= /= << >> <<= >>= ==!= <= >= ++ -- % & ^! ~ &= ^= = && %= [] () new delete *= -> ->* Forma generală a funcţiei pentru supradefinirea operatorilor este: tip_rezultat operator simbol (parametri); unde simbol este unul dintre operatorii din tabela precedentă, parametri reprezintă parametrii funcţiei (în principiu pot fi operanzii care se prelucrează) şi tip_rezultat este tipul rezultatului obţinut în urma operaţiei şi returnat de funcţie. Un operator poate fi supradefinit printr-o variantă din următoarele două posibile: -ca funcţie membră a clasei respective. -ca funcţie prietenă a clasei cu care se asociază operatorul; Problema 28.1. Să se definească o clasă reprezentând numere complexe în formă trigonometrică pentru care să se supradefinească operatorii '*' (înmulţire) şi '/' (împărţire), astfel încât aceştia să opereze asupra obiectelor aparţinând acestei clase (numere complexe în formă trigonometrică). class CompTrig { float modul, arg; CompTrig (); //constructor vid CompTrig (float, float); //constructor void afiseaza (); //afiseaza un numar complex int este_zero () { //test daca modul nul return modul==0; CompTrig operator * (CompTrig); //supradefinirea operatorului * CompTrig operator / (CompTrig); //supradefinirea operatorului / ; CompTrig::CompTrig () { //constructor modul=0; arg=0; CompTrig::CompTrig (float m, float a) { //constructor modul=m; arg=a; void CompTrig::afiseaza () { cout<<"modul="<<modul<<" argument="<<arg<<"\n"; 1
CompTrig CompTrig::operator * (CompTrig param) { CompTrig temp; temp.modul=modul*param.modul; temp.arg=arg+param.arg; return temp; CompTrig CompTrig::operator / (CompTrig param) { CompTrig temp; temp.modul=modul/param.modul; temp.arg=arg-param.arg; return temp; void main () { CompTrig a(4.5,0.983), b(-2.5,0.452), c, d; cout<<"primul numar este:\n"; a.afiseaza(); cout<<"aldoilea numar este:\n"; b.afiseaza(); c=a*b; //apel al functiei operator* cout<<"produsul lor este:\n"; c.afiseaza(); if (b.este_zero()) { cout<<"nu se poate face impartirea!\n"; else { d=a/b; //apel al functiei operator/ cout<<"catul lor este:\n"; d.afiseaza(); În cadrul acestei soluţii s-a definit clasa CompTrig pentru reprezentarea unui număr complex sub formă trigonometrică: z = ρ(cosα + isinα) unde ρ este modulul numarului complex, α este argumentul numarului şi i = 1. În acest scop clasa are ca date membre modul şi arg, pentru modulul, respectiv argumentul unui numar complex în formă trigonometrică. Ca funcţii membre, clasa conţine: -doi constructori, primul vid, fără argumente şi al doilea pentru iniţializarea unui obiect (număr complex) cu anumite valori; -funcţia afiseaza permite afişarea valorilor modulului şi argumentului unui număr complex; -funcţia este_zero permite testarea modulului unui număr complex (întoarce valoarea adevărat dacă modulul este zero), pentru a evita operaţia de împărţire cu zero; -funcţii pentru supradefinirea operatorilor '*' şi '/'. Supradefinirea operatorilor se face sub forma unor funcţii membre ale clasei. O funcţie membră primeşte în mod implicit adresa obiectului pentru care este apelată, deci aici, fiecare funcţie are câte un singur parametru, reprezentând al doilea operand (primul operand fiind reprezentat de obiectul pentru care se face apelul). Astfel, expresia: a*b este interpretată de compilator ca un apel a.operator*(b). Problema 28.2. Să se definească o clasă reprezentând vectori de numere reale, pentru care să se supradefinească operatorul '+', astfel încât să permită adunarea a doi vectori de aceeaşi lungime, prin adunarea perechilor de componente de acelaşi rang. #include <stdlib.h> #include <conio.h> 2
class CVector { int lung, v[100]; CVector (int); //constructor CVector (int, int); //constructor void afiseaza (); friend int operator == (CVector, CVector); friend CVector operator + (CVector, CVector); ; CVector::CVector (int param) { lung=param; for (i=0;i<lung;i++) v[i]=0; CVector::CVector (int param1, int param2) { lung=param1; for (i=0;i<lung;i++) v[i]=random(param2); void CVector::afiseaza () { for (i=0;i<lung;i++) cout<<" v["<<i<<"]="<<v[i]; cout<<endl; CVector operator + (CVector a, CVector b) { CVector c(a.lung); for (i=0;i<a.lung;i++) c.v[i]=a.v[i]+b.v[i]; return c; int operator == (CVector a, CVector b) { return a.lung == b.lung; void main () { randomize(); CVector x(5,100),y(5),z(5,100),rez(5); cout<<"vectorul x:\n"; x.afiseaza(); cout<<"vectorul y:\n"; y.afiseaza(); cout<<"vectorul z:\n"; z.afiseaza(); if (x==y) { rez=x+y; cout<<"vectorul x+y:\n"; rez.afiseaza(); else cout<<"vectorii au lungimi diferite!"; if (x==z) { rez=x+z; cout<<"vectorul x+z:\n"; rez.afiseaza(); 3
else cout<<"vectorii au lungimi diferite!"; getch(); Clasa CVector are ca date membre variabila intreaga lung si vectorul de numere intregi v. De asemenea, conţine doi constructori: -primul are un singur parametru reprezentând lungimea vectorului şi realizează iniţializarea tuturor componentelor cu valoarea 0; -al doilea are doi parametri, lungimea vectorului şi parametrul funcţiei random care permite iniţializarea componentelor vectorului cu valori aleatoare cuprinse intre 0 şi al doilea parametru al constructorului. Operatorul '+' este supradefinit ca funcţie prietenă a clasei CVector cu prototipul: CVector operator + (CVector, CVector); astfel că expresia x+y este interpretată de compilator ca un apel al funcţiei sub forma: operator + (x,y) Varianta: #include <stdlib.h> #include <conio.h> class CVector { int lung, v[10]; CVector (); //constructor CVector (int); //constructor void afiseaza (); friend CVector operator + (CVector, CVector); ; CVector::CVector () { for (i=0;i<10;i++) v[i]=0; CVector::CVector (int param) { randomize(); for (i=0;i<10;i++) v[i]=random(param); void CVector::afiseaza () { for (i=0;i<10;i++) cout<<" v["<<i<<"]="<<v[i]; cout<<endl; CVector operator + (CVector a, CVector b) { CVector c; for (i=0;i<10;i++) c.v[i]=a.v[i]+b.v[i]; return c; 4
void main () { randomize(); CVector x(100),y,z(100),rez; cout<<"vectorul x:\n"; x.afiseaza(); cout<<"vectorul y:\n"; y.afiseaza(); cout<<"vectorul z:\n"; z.afiseaza(); rez=x+y; cout<<"vectorul x+y:\n"; rez.afiseaza(); rez=x+z; cout<<"vectorul x+z:\n"; rez.afiseaza(); getch(); Problema 28.3. Pentru o clasă reprezentând o stivă de numere întregi (vezi problema 27.2) să se supradefinească operatorul '=' pentru atribuirea de obiecte de tip Stiva. class Stiva { int vector[201]; int indicator; int push (int); //adauga un element în vârful stivei int pop (int&); //extrage elementul din vârful stivei void afiseaza(); int full () { return indicator==0; int empty () { return indicator==200; Stiva () { //constructor indicator=200; ; Stiva operator = (Stiva); int Stiva::push (int a) { if (!full()) { indicator--; vector[indicator]=a; return 1; else { cout<<"stiva este plina!\n"; return 0; int Stiva::pop (int &a) { if (!empty()) { a=vector[indicator]; indicator++; 5
return 1; else { cout<<"stiva este vida!\n"; return 0; void Stiva::afiseaza() { cout<<endl<<"adresa stivei: "<<&vector; cout <<" Stiva contine:"; if (!empty()) for (i=indicator; i<200; i++) cout<<" "<<vector[i]; else cout<<"...continut vid..."; Stiva Stiva::operator = (Stiva s) { indicator=s.indicator; if (!s.empty()) for (i=indicator; i<200; i++) vector[i]=s.vector[i]; return *this; void main () { int a; Stiva stv1, stv2; stv1.push(11); stv1.push(22); stv1.push(33); cout<<endl<<"aici se face atribuirea de stive!"; stv2=stv1; stv1.pop(a); cout<<endl<<"elementul extras din prima stiva este "<<a; stv1.push(44); În această soluţie, spre deosebire de soluţia de la problema 27.2, s-a definit un constructor pentru iniţializarea obiectelor de tip Stiva. De remarcat supradefinirea operatorului '=' pentru efectuarea operaţiei de atribuire de obiecte din această clasă. Operaţia de atribuire stv2=stv1 este echivalentă cu apelul funcţiei stv2.operator=(stv1). În funcţia main se efectuează mai multe operaţii push şi pop, numai cu obiectul stv1, iar la un moment dat se face operaţia de atribuire între obiectele de tip Stiva, acestea devenind egale. 6
Pentru a putea urmări evoluţia celor două stive, în program, se execută după fiecare operaţie afişarea conţinuturilor acestora. Problema 28.3a. Sa se supradefineaca operatorii == pentru compararea lungimilor a doi vectori si + pentru adunarea vectoriala a doi vectori, in cadrul unei clase corespunzatoare vectorilor de numere intregi. #include <conio.h> class vector { int lung, v[100]; void citeste (); void afis (); int operator == (vector); vector operator + (vector); ; void vector::citeste () { cout<<"lungime vector:"; cin>>lung; for (i=0; i<lung; i++) { cout<<"v{"<<i<<"]="; cin>>v[i]; void vector::afis() { for (i=0; i<lung; i++) cout<<v[i]<<' '; cout<<endl; int vector::operator == (vector x) { return lung==x.lung; vector vector::operator + (vector x) { vector y; y.lung=lung; for (i=0; i<lung; i++) y.v[i]=v[i]+x.v[i]; return y; void main () { vector alfa, beta, gama; alfa.citeste(); alfa.afis(); beta.citeste(); beta.afis(); if (alfa==beta) { else //alfa.operator == (beta) gama=alfa+beta; //gama=alfa.operator + (beta) cout<<"\nsuma vectorilor: "; gama.afis(); cout<<"vectorii au lungimi diferite si nu se pot aduna!"; 7
cout<<"\napasati o tasta!"; getch(); Probleme propuse 28.4. Pentru clasa definită în problema 27.4 să se supradefinească operatorii '+' şi '=' în vederea realizării operaţiilor de adunare şi atribuire de matrici. În funcţia main se va utiliza clasa pentru adunarea unei matrici (citită de la tastatură) cu transpusa sa şi afişarea rezultatului obţinut. 28.5. Pentru clasa definită în problema 27.4 să se supradefinească operatorul '*' pentru înmulţirea de matrici. În funcţia main se va utiliza clasa pentru înmulţirea a două matrici, având componentele citite de la tastatură şi afişarea rezultatului. 28.6. Având în vedere clasa definită în problema 27.6 să se supradefinească operatorul '=' pentru atribuirea de cozi. În funcţia main se va utiliza un obiect de tip coadă, în care se vor face o serie de adăugări de elemente, apoi o a doua coadă va fi iniţializată cu elementele primei cozi, prin operaţia de atribuire, iar în final se vor executa o serie de operaţii de extragere din coadă, afişând după fiecare operaţie efectuată conţinuturile celor două cozi. 28.7. Pentru clasa definită în problema 27.7 să se supradefinească operatorul '%' pentru operaţia de concatenare a două liste dublu înlănţuite, evident, fiind necesar, ca după această operaţie, lista dublu înlănţuită obţinută să conţină, de asemenea, elementele în ordine crescătoare. 8