Sunteți pe pagina 1din 49

REFERAT DE LABORATOR Nr.

REFERAT DE LABORATOR NR. 3


TEMA: Suprancrcarea operatorilor.

NOIUNI TEORETICE
Suprancrcarea (supradefinirea, termenul overloading) operatorilor permite atribuirea de noi semnificaii operatorilor uzuali (operatorilor ntlnii pentru tipurile de date predefinite). Aa cum am subliniat n numeroase rnduri, clasa reprezint un tip de date (o mulime de valori pentru care s-a adoptat un anumit mod de reprezentare i o mulime de operaii care pot fi aplicate acestora). Astfel, operatorul + folosete la adunarea a dou date de tip int, float sau double, ns aceluiai operator i se poate atribui semnificaia de alipire a dou obiecte de tipul ir, sau de adunare a dou obiecte de tipul complex, vector sau matrice. Prin suprancrcarea operatorilor, operaiile care pot fi executate asupra instanelor(obiectelor) unei clase pot fi folosite ca i n cazul tipurilor de date predefinite. Declaraia i definiia unui operator suprancrcat, sunt similare cu declaraiile i definiiile de funcii: [<tip_val_ret>] operator <simbol_op> (<lista_declar_par>) { // . . . . corpul funciei } n situaia n care, pentru o clas, suprancrcarea unui operator unar se realizeaz printr-o funcie membr, aceasta primete ca parametru implicit adresa obiectului curent (pentru care este apelat), adic pointerul cptre obiectul curent (this). n cazul suprancrcrii prin funcii prietene (friend), deoarece acestea nu primesc ca argument implicit pointerul ctre obiectul curent, astfel c funcia va primi un parametru explicit. Operatorii binari pot fi supradefinii printr-o funcie membr cu un parametru implicit (pointerul this) si parametru explicit sau printr-o funcie prieten cu doi parametri explicii de tipul clas.

REFERAT DE LABORATOR Nr. 3

1. Restricii la suprancrcarea operatorilor

Suprancrcarea operatorilor se poate realiza, deci, prin funcii membre sau funcii prietene. Dac suprancrcm acelai operator printr-o metod i printr-o funcie prieten, funcia prieten va avea, ntotdeauna, un parametru n plus fa de metod (deoarece funciei prietene nu i se transmite ca parametru implicit pointerul this). Totui, suprancrcarea operatorilor este supus urmtoarelor restricii: Se pot suprancrca doar operatorii existeni; nu se pot crea noi operatori. Nu se poate modifica aritatea (numrul de operanzi) operatorilor limbajului (operatorii unari nu pot fi supraincrcai ca operatori binari, i invers). Nu se poate modifica precedena i asociativitatea operatorilor. Dei operatorii suprancrcai pstreaz aritatea i precedena operatorilor predefinii, ei nu motenesc i comutativitatea acestora. Nu pot fi suprancrcai operatorii . (operatorul selector al unui membru), .* (operatorul de defereniere, selecie indirect a unui membru), :: (de rezoluie, de apartenen, scop) i ?: (operatorul condiional).

Observaii: Dac operatorul = (de atribuire) nu este suprancrcat, el are o semnificaie implicit. Operatorii , new delete [] -> i de conversie explicit impun restricii suplimentare care vor fi discutate ulterior. Funcia operator trebuie s aib cel puin un argument (implicit sau explicit) de tipul clasei pentru care s-a suprancrcat operatorul. Se poate atribui unui operator orice semnificaie, ns este de dorit ca noua semnificaie s fie ct mai apropiat de semnificaia natural. De exemplu, pentru adunarea a dou obiecte se poate suprancrca operatorul * , dar este mai natural folosirea operatorului + cu semnificaia de adunare.

2. Membrii constani ai unei clase

O clas poate avea metode constante. O metod este declarat constant prin utilizarea modificatorului const n antetul ei, dup lista parametrilor formali. Metodele constante nu modific obiectul pentru care sunt apelate. Ca oricror variabile de tip predefinit, i obiectelor de tip definit de utilizator li se poate aplica modificatorul const. Pentru un obiect constant este permis doar apelul metodelor constante, a constructorilor i a destructorilor.

REFERAT DE LABORATOR Nr. 3

3. Suprancrcarea operatorilor insertor i extractor

Operatorul << se numete operator insertor, deoarece insereaz date n stream-ul (fluxul) de ieire. Operatorul >> se numete operator extractor, deoarece extrage date din stream-ul (fluxul) de intrare. n exemplul urmtor, aceti operatori sunt suprancrcai pentru clasa complex, astfel nct s poat fi folosii ca pentru obiectele de tip predefinit. Deoarece ntotdeauna operandul stng este de tip istream (cin este obiect predefinit, de tip istream) sau ostream (cout este obiect predefinit, de tip ostream), i nu de tipul introdus prin clas, operatorii << i >> pot fi suprancrcai numai prin funcii prietene. Prototipurile operatorilor sunt: Prototipurile funciilor operator << i >> pentru un tip abstract tip, sunt: friend ostream &operator<<(ostream &,const tip&); friend istream &operator >> (istream &,tip&);

4. Suprancrcarea operatorului de atribuire =

n cazul n care operatorul de atribuire nu este suprancrcat explicit, compilatorul genereaz unul implicit (ca n exemplul clasei punct sau segment). n absena unei suprancrcri explicite, operatorul copie valorile datelor membre ale operandului drept n datele membre ale operandului stng. Exemplu: punct a(8,9), b; b=a; /* operator atribuire implicit: zona de memorie ocupata de obiectul a se copie, bit cu bit, n zona de memorie ocupat de b: b.x=a.x i b.y=a.y */ Operatorul de atribuire implicit este nesatisfctor n situaiile n care obiectele clasei au ca date membre pointeri, sau n situaiile n care memoria este alocat n mod dinamic. O suprancrcare explicit a operatorului (ambii operanzi de tipul clasei) poate fi fcut fie prin metod, fie prin funcie prieten. O modalitate de a suprancrca operatorul de atribuire prin metod a clasei, este aceea prin care funcia primete ca parametru implicit operandul stng (pointerul this), ca parametru explicit o referin constant (pentru a nu putea fi modificat acest operand) ctre operandul drept, i returneaz o referin (adresa operandului stng). Deasemenea, operatorul binar de atribuire poate fi suprancrcat prin funcie prieten (n acest caz, nu primete parametrul implicit this, deci are doi operanzi).
3

REFERAT DE LABORATOR Nr. 3

Deoarece ntotdeauna operandul stng al operatorului de atribuire este de tipul clasei pentru care se suprancarc, este preferabil ca suprancrcarea s se realizeze prin metod a clasei. Reamintim c asociativitatea operatorului este de la dreapta la stnga. Operatorul poate apare n expresii de forma: a=b=c=d;

5. Suprancrcarea operatorului de indexare [ ]

Operatorul de indexare este un operator binar, utilizat sub forma: <nume>[<expresie>] S considerm clasa vector, definit astfel: class vector{ private: int nrcomp; //nr. componente double *tabcomp; //tabloul componentelor; //adresa de inceput public: double &operator[](int); } Pentru tipul abstract vector, operatorul de indexare poate fi supradefinit, astfel nct s permit accesarea elementului de indice n. n acest caz, operatorul de indexare se poate supradefini printr-o funcie membr a clasei (deoarece operandul stng este de tipul clasei), i poate fi folosit sub forma: v[n] (unde v este obiect al clasei vector; n-expresie ntreag). Expresia v[n] este echivalent cu v.operator[ ](n) (apelul explicit al funciei operator []). Transferul parametrului ctre funcia care suprancarc operatorul se poate face prin valoare sau prin referin. n mod obligatoriu, funcia trebuie s returneze referina ctre elementul aflat pe poziia n (pentru a permite eventualele modificri ale elementului, deoarece vector[n] este lvalue). Pentru un tip abstract, prototipul funciei membre care supradefinete operatorul de indexare este (const protejeaz argumentul la modificrile accidentale): <tip_element> & <tip>::operator [ ] (const int); n cazul n care operatorul se suprancarc printr-o funcie prieten, prototipul funciei este: <tip_elem> & operator [ ] (<tip>, const int);

REFERAT DE LABORATOR Nr. 3

6. Suprancrcarea operatorilor new i delete

Avantajul alocrii dinamice a memoriei i a eliberrii acesteia cu ajutorul operatorilor new i delete, fa de utilizarea funciilor malloc, calloc sau free, const n faptul c operatorii aloc (elibereaz) memorie pentru obiecte, date de tip abstract. Acest lucru este posibil deoarece aceti operatori au o suprancrcare global, standard. n cazul n care suprancrcarea standard este insuficient, utilizatorul poate suprancrca operatorii prin metode (implicit!) statice. Pentru operatorul new, funcia membr care suprancarc operatorul new are prototipul: void * <nume_clasa>::operator new (size_t <lungime>); Funcia returneaz un pointer generic a crui valoare este adresa de nceput a zonei de memorie alocate dinamic. Tipul size_t este definit n stdlib.h. La aplicarea operatorului, nu se indic nici o valoare pentru parametrul lungime (mrimea zonei de memorie necesare obiectului pentru care se aloc dinamic memorie), deoarece compilatorul o determin, automat. Modul de utilizare al operatorului new: <nume_clasa> *<p> = new <nume_clasa>; Sau: <nume_clasa> *<p> = new <nume_clasa>(<p1>, <p2>, <p3>);

Aplicarea operatorului new supradefinit de utilizator determin, automat, apelul constructorului corespunztor clasei, sau al constructorului implicit. n a doua form, la alocarea dinamic a memoriei apar i parametrii constructorului (p1, p2, p3). Operatorul delete se supradefinete printr-o funcie membr cu prototipul: void <nume_clasa>::operator delete (void *); La aplicarea operatorului delete se apeleaz, automat, destructorul clasei.

7. Suprancrcarea operatorului ( )

Operatorul apel de funcie, utilizat sub forma <nume> (<lista_param_efectivi>) poate fi interpretat ca o operaie binar, avnd ca operand stng nume, iar ca operand drept lista_param_efectivi. Suprancrcarea acestui operator binar, nestatic, va permite utilizarea sub forma: a (b, ), sau (apelul explicit): a.operator() (b, ).
5

REFERAT DE LABORATOR Nr. 3

Avantajele unui astfel de operator sunt: Evaluarea i verificarea listei de argumente n mod similar unei funcii obinuite; Mecanismului de apel: dei operatorul este binar, cel de-al doilea operand fiind o list de argumente (chiar vid), funcia operator poate avea orici parametri.

n cazul n care numele funciei este un pointer ctre o anumit funcie (vezi pointeri ctre funcii), apelul funciei se realizeaz prin: (*<point_f>) (<lista_param_efectivi>); Funcia care suprancarc operatorul trebuie s fie metod nestatic. Suprancrcarea operatorului ( ) se utilizeaz n mod frecvent la definirea aa-numitului iterator. Iteratorii se utilizeaz n legtur cu tipuri abstracte de date, care conin colecii de elemente (liste, arbori, tabele de dispersie, etc.). Pe lng protecia datelor, iteratorii ofer un mijloc simplu de acces la elementele unei colecii (traversarea unei coleciei), fr a intra n detaliile legate de implementarea coleciei (independen a utilizrii unei colecii i implementrii unei colecii). n principiu, un iterator se implementeaz printr o clas ataat unui tip abstract care conine o colecie de elemente.

8. Suprancrcarea operatorului ->

Suprancrcarea operatorului unar -> (de selecie indirect, prin intermediul pointerului) se realizeaz printr-o metod nestatic. Expresia obiect -> expresie va fi interpretat ca (obiect.operator->())->expresie. De aceea, funcia care suprancarc operatorul trebuie s returneze fie un pointer la un obiect al clasei, fie un obiect de un tip pentru care este supradefinit operatorul ->.

9. Conversii

Exist urmtoarele tipuri de conversii: Conversii implicite; Conversii explicite.

Conversiile implicite au loc n urmtoarele situaii: n cazul aplicrii operatorului de atribuire: operandul drept este convertit la tipul operandului stng. La apelul unei funcii: Dac tipul parametrilor efectivi (de apel) difer de tipul parametrilor formali, se ncearc conversia tipului parametrilor efectivi la tipul parametrilor formali.
6

REFERAT DE LABORATOR Nr. 3

La revenirea dintr-o funcie: Dac funcia returneaz o valoare n programul apelant, la ntlnirea instruciunii return expresie; se ncearc conversia tipului expresiei la tipul specificat n antetul funciei.

Conversiile explicite pot fi : a) b) c) d) tip_predefinit_1 -> tip_predefinit_2 tip_predefinit -> tip_definit_de_utilizator (clas) clas -> tip_predefinit clas_1 -> clas_2

Conversii din tip predefinit1 n tip predefinit2 Pentru realizarea unor astfel de conversii, se folosete operatorul unar de conversie explicit (cast), de forma: (<tip>) <operand> Conversii din tip predefinit n clas Astfel de conversii se pot realiza att implicit, ct i explicit, n cazul n care pentru clasa respectiv exist un constructor cu parametri implicii, de tipul predefinit. Conversii din clas n tip predefinit Acest tip de conversie se realizeaz printr-un operator special (cast) care convertete obiectul din clas la tipul predefinit. Operatorul de conversie explicit se suprancarc printr-o funcie membr nestatic. <nume_clasa>:: operator <nume_tip_predefinit>( ); La apelarea operatorului se folosete una din construciile: (<nume_tip_predefinit>)<obiect>; <nume_tip_predefinit> (<obiect>); Conversii din clas1 n clas2 Conversia din tip_abstract_1 n tip_abstract_2 (din clas1 n clas2), se realizeaz cu ajutorul unui constructor al clasei2, care primete ca parametri obiecte din clasa1.

REFERAT DE LABORATOR Nr. 3

PROBLEME REZOLVATE
1. S se defineasc tipul de date complex, cu datele membru parte real (re) i
parte imaginar (im). Pentru tipul de date complex s se defineasc un constructor, un constructor de copiere i un destructor. Operaiile care pot fi realizate asupra datelor de acest tip, vor fi: calculul modulului unui complex functia modul( ); calculul argumentului unui complex functia arg( ); adunarea a dou numere complexe, precum si adunarea unui complex cu o valoare real, realizate prin suprancrcarea operatorului +; diferena a dou numere complexe, realizat prin suprancrcarea operatorului -; produsul a dou numere complexe, realizat prin suprancrcarea operatorului *; negativarea, respectiv pozitivarea unui numr complex, realizate prin suprancrcarea operatorilor unari -, respectiv +; suprancrcarea operatorului =; suprancrcarea operatorilor compui +=, -=, *= i /=; incrementarea prii reale, n form prefixat i postfixat, realizat prin suprancrcarea operatorului ++; decrementarea prii reale n form prefixat, realizat prin suprancrcarea operatorului --; testarea egalitii i a inegalitii dintre dou numere complexe, realizate prin suprancrcarea operatorilor ==, respectiv !=; citirea de la tastatur, respectiv afiarea pe ecran a unui numr complex, realizate prin suprancrcarea operatorilor extractor >>, respectiv insertor <<;

//Fiierul Complex.cpp
#include <iostream> #include <math.h> using namespace std; class complex { double re,im; public: complex (double r=0,double i=0); complex (const complex&); ~complex() {} double modul(); double arg(); //constructor //constructor copiere //destructor

//metoda care returneaza modulul unui complex //metoda care returneaza argumentul unui complex

friend complex operator+(const complex&,const complex&); // complex + complex friend complex operator+(const double,const complex &); 8

REFERAT DE LABORATOR Nr. 3 // real + complex friend complex operator +(const complex&,const double); // complex + double complex operator - (const complex &) const; complex operator *(const complex ) const; complex operator + () const; //operator + unar; metoda constanta complex operator - () const; //operator - unar complex &operator=(const complex &); complex complex complex complex & operator += (const complex &z); operator += (const double); operator -= (const complex&); & operator /= (const complex &z); //forma prefixata //forma postfixata //decrementarea partii reale

complex & operator ++ (); complex operator ++ (int); complex operator--();

int operator == (complex &z); //compara doi complecsi si returneaza 1 n caz de egalitate friend int operator != (complex &, complex &); //compara doi complecsi si returneaza 1 n caz ca sunt diferiti friend ostream& operator << (ostream &,const complex&); //operator afisare complex friend istream& operator >> (istream &,complex&); //operator citire complex }; inline complex::complex(double r,double i) { re=r; im=i; } complex::complex(const complex & z) { re=z.re; im=z.im; } inline double complex::modul() { return sqrt(re*re+im*im); } double complex::arg() { double a; if (re==0 && im==0) return 0.0; if (im==0) if (re>0) return 0.0; else return M_PI; if (re==0) if (im==0) return M_PI/2; else return (3*M_PI)/2; a=atan(im/re); if (re<0) 9

REFERAT DE LABORATOR Nr. 3 return M_PI+a; if (im<0) return 2*M_PI+a; return a; } complex operator +(const complex &a, const complex &b) { complex z; z.re=a.re+b.re; z.im=a.im+b.im; return z; } complex operator +(const double d, const complex &a) { complex z; z.re=d+a.re; z.im=a.im; return z; } complex operator +(const complex &a, const double d) { complex z; z.re=d+a.re; z.im=a.im; return z; } complex complex::operator-(const complex &a) const { complex z; z.re=re-a.re; z.im=im-a.im; return z; } complex complex::operator *(const complex x) const { complex z; z.re=re*x.re-im*x.im; z.im=re*x.im+im*x.re; return z; } complex complex::operator +() const { return *this; } complex complex::operator -() const { complex z; z.re=-re; z.im=-im; return z; } complex & complex::operator=(const complex &a) { re=a.re; im=a.im; return *this; } // returneaza obiectul curent complex & complex::operator+=(const complex &x) { re += x.re; im += x.im; 10

REFERAT DE LABORATOR Nr. 3 return *this; } complex complex::operator+=(const double d) { re += d; return *this; } complex complex::operator-=(const complex &x) { re -= x.re; im -= x.im; return *this; } complex &complex::operator /= (const complex &z) { double numitor=z.re*z.re+z.im*z.im; double re1=(double)(re*z.re+im*z.im)/numitor; double im1=(double)(im*z.re-re*z.im)/numitor; re=re1; im=im1; return *this; } complex & complex::operator++() //forma prefixata { re++; return *this; } complex complex::operator ++ (int) //forma postfixata { complex z=*this; re++; return z; } complex complex::operator--() { re--; return *this; } int complex::operator==(complex &x) { return re==x.re && im==x.im; } int operator!=(complex &x, complex &y) { return !(x.re==y.re && x.im==y.im); } ostream &operator<<(ostream &ecran, const complex &z) { ecran<<"("<<z.re; if (z.im>=0) ecran<<'+'; ecran<<z.im<<"*i)"; return ecran; }

11

REFERAT DE LABORATOR Nr. 3 istream &operator>>(istream &tastatura, complex &z) { cout << "\nParte reala: "; tastatura >> z.re; cout << "Parte imaginara: "; tastatura >> z.im; return tastatura; }

Dup definirea tipului de date complex, vom realiza un fiier de test n care vom testa operaiile pe care le putem face asupra numerelor complexe. //Fiierul TestComplex.cpp
#include "Complex.cpp" #include <conio.h> int main() { complex a(2,3), b(1,1), c, d; cout cout cout cout cout cout << << << << << << "Numerele complexe definite prin instructiunea: "; "complex a(2,3), b(1,1), c, d;\n"; "a = " << a << endl; "b = " << b << endl; "c = " << c << endl; "d = " << d << endl;

cout << "\nCitim numarul c de la tastatura: "; cin >> c; cout << "\nNumarul c citit este: " << c << endl; d = b; cout cout cout cout cout cout cout << << << << << << << "\nDupa operatia de atribuire d=b, numarul d este: " << d; "\n\n Testarea operatorilor logici:\n"; d << " == " << b << " ?: " << (d==b) << endl; a << " == " << b << " ?: " << (a==b) << endl; d << " != " << b << " ?: " << (d!=b) << endl; a << " != " << b << " ?: " << (a!=b) << endl; endl;

cout << "#######################################\n"; cout << "## Apasa o tasta pentru continuare ##\n"; cout << "#######################################\n"; getch(); cout << c = a + cout << c = a + cout << c = 2 + cout << c = a cout << c = a * cout << "\n Testarea operatorilor binari:\n\n"; b; a << " + " << b << " = " << c << endl; 2; a << " + 2 = " << c << endl; a; "2 + " << a << " = " << c << endl; b; a << " - " << b << " = " << c << endl; b; a << " * " << b << " = " << c << endl;

cout << "\n Operatorul - unar:\n\n"; c = -a; cout << "-" << a << " = " << c << endl; 12

REFERAT DE LABORATOR Nr. 3 cout << "\n Testarea operatorilor binari compusi:\n\n"; cout << "Rezultatul " << c << " += " << b << " este: "; c += b; cout << c << endl; cout << "Rezultatul " << c << " += 2 este: "; c += 2; cout << c << endl; cout << "Rezultatul " << c << " -= " << b << " este: "; c -= b; cout << c << endl; cout << "Rezultatul " << c << " /= " << b << " este: "; c/=b; cout << c << endl; cout << endl; cout << "#######################################\n"; cout << "## Apasa o tasta pentru continuare ##\n"; cout << "#######################################\n"; getch(); cout cout cout cout cout cout } << << << << << << "\n Testarea operatorilor de incrementare si decrementare:\n\n"; "a = " << a << endl << endl; "a++: " << a++ << endl; "a = " << a << endl << endl; "++a: " << ++a << endl; "a = " << a << endl << endl;

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

13

REFERAT DE LABORATOR Nr. 3

2.

n exemplul urmtor se implementeaz clasa fracie. Ea are ca date membre private nrt i nmt (numrtorul i numitorul). Tot ca metod privat este definit metoda simplifica(), metod care simplific o fracie pentru evitarea unor calcule cu numere mari. Funcia cmmdc (care implementeaz algoritmul lui Euclid pentru aflarea celui mai mare divizor comun a dou numere) nu este nici funcie membr a clasei fracie, nici funcie prieten. Ea este apelat de funcia simplifica.

Ca metode publice sunt definite: un constructor, un destructor, funcia numarator care returneaz valoarea datei membre nrt, funcia numitor care returneaz valoarea datei membre nmt, funcia valoare care returneaz valoarea real obinut prin mprirea numrtorului la numitor. Se suprancarc operatorii +, -, *, / prin funcii prietene ale clasei fractie. Semnificaia dat este cea de realizare a operaiilor de adunare, scdere, nmulire i mprire a obiectelor din clasa fracie. Se suprancarc operatorii +=, -=, *=, /= prin funcii membre ale clasei fractie. Se suprancarc operatorii extractor >> i insertor << pentru realizarea de operaii de intrare/ieire (citire de la tastatur i afiare pe ecran).
14

REFERAT DE LABORATOR Nr. 3

//Fiierul Fractie.cpp
#include <iostream> using namespace std; class fractie { int nrt, nmt; void simplifica();

// numarator,numitor //metoda de simplificare a fractiei

public: fractie(int nrti=0, int nmti=1); //constructor cu parametri impliciti ~fractie() {}; //destructor int numarator() {return nrt;} int numitor() {return nmt;} double valoare() {return (double)nrt/(double)nmt;} friend friend friend friend fractie fractie fractie fractie operator+(const operator-(const operator*(const operator/(const +=(const -=(const *=(const /=(const fractie&, fractie&, fractie&, fractie&, const const const const fractie&); fractie&); fractie&); fractie&);

fractie& fractie& fractie& fractie&

operator operator operator operator

fractie&); fractie&); fractie&); fractie&);

friend ostream& operator <<(ostream &, const fractie &); friend istream& operator >>(istream &, fractie &); }; int cmmdc(int x,int y) //calculeaza si returneaza cmmdc pentru x, y { int z; if (x==0 || y==1) return 1; if (x<0) x=-x; if (y<0) y=-y; while (x!=0) { if (y>x) { z=x; x=y; y=z; } x%=y; } return y; } void fractie::simplifica() { int cd; if (nmt<0) { nrt=-nrt; nmt=-nmt; } 15

REFERAT DE LABORATOR Nr. 3 if (nmt>1) { cd=cmmdc(nrt,nmt); if (cd>1) { nrt/=cd; nmt/=cd; } } } fractie::fractie(int nri, int nmi) { nrt=nri; nmt=nmi; simplifica(); } fractie operator +(const fractie &f1, const fractie &f2) { int dc; fractie f; dc=cmmdc(f1.nmt,f2.nmt); f.nmt=(f1.nmt/dc)*f2.nmt; f.nrt=f1.nrt*(f2.nmt/dc)+f2.nrt*(f1.nmt/dc); f.simplifica(); return f; } fractie operator -(const fractie &f1, const fractie &f2) { int dc; fractie f; dc=cmmdc(f1.nmt,f2.nmt); f.nmt=(f1.nmt/dc)*f2.nmt; f.nrt=f1.nrt*(f2.nmt/dc) - f2.nrt*(f1.nmt/dc); f.simplifica(); return f; } fractie operator * (const fractie &f11, const fractie &f22) { int dc; fractie f, f1=f11, f2=f22; dc=cmmdc(f1.nrt,f2.nmt); if (dc>1) { f1.nrt/=dc; f2.nmt/=dc; } dc=cmmdc(f2.nrt,f1.nmt); if (dc>1) { f2.nrt/=dc; f1.nmt/=dc; } f.nrt=f1.nrt*f2.nrt; f.nmt=f1.nmt*f2.nmt; return f; } fractie operator / (const fractie & f11, const fractie & f22) { int dc; fractie f, f1=f11, f2=f22; 16

REFERAT DE LABORATOR Nr. 3 dc=cmmdc(f1.nrt,f2.nrt); if (dc>1) { f1.nrt/=dc; f2.nrt/=dc; } dc=cmmdc(f2.nmt,f1.nmt); if (dc>1) { f2.nmt/=dc; f1.nmt/=dc; } f.nrt=f1.nrt*f2.nmt; f.nmt=f1.nmt*f2.nrt; return f; } fractie& fractie::operator+=(const fractie &f1) { int dc=cmmdc(nmt,f1.nmt); nmt=(nmt/dc)*f1.nmt; nrt=nrt*(f1.nmt/dc)+f1.nrt*(nmt/dc); simplifica(); return *this; } fractie& fractie::operator-=(const fractie &f1) { int dc=cmmdc(nmt,f1.nmt); nmt=(nmt/dc)*f1.nmt; nrt=nrt*(f1.nmt/dc)-f1.nrt*(nmt/dc); simplifica(); return *this; } fractie& fractie::operator *=(const fractie &f11) { fractie f1=f11; int dc; dc=cmmdc(nrt,f1.nmt); if (dc>1) { nrt/=dc; f1.nmt/=dc; } dc=cmmdc(f1.nrt,nmt); if (dc>1) { f1.nrt/=dc; nmt/=dc; } nrt=nrt*f1.nrt; nmt=nmt*f1.nmt; simplifica(); return *this; } fractie& fractie::operator /=(const fractie &f11) { fractie f1=f11; int dc; dc=cmmdc(nrt,f1.nrt); if (dc>1) { nrt/=dc; f1.nrt/=dc; 17

REFERAT DE LABORATOR Nr. 3 } dc=cmmdc(f1.nmt,nmt); if (dc>1) { f1.nmt/=dc; nmt/=dc; } nrt=nrt*f1.nmt; nmt=nmt*f1.nrt; return *this; } ostream& operator<<(ostream &ecran, const fractie &f) { ecran << '(' << f.nrt << '/' << f.nmt << ')'; return ecran; } istream& operator>>(istream &tastatura, fractie &f) { cout << "\nNumarator: "; tastatura >> f.nrt; cout << "Numitor: "; tastatura >> f.nmt; f.simplifica(); return tastatura; }

Dup definirea tipului de date fracie, vom realiza un fiier de test n care vom testa operaiile pe care le putem face asupra fraciilor. //Fiierul TestFractie.cpp
#include "Fractie.cpp" int main() { fractie f(1,1), f1, f2; cout << "Introduceti prima fractie:\n"; cin >> f1; cout << "\nIntroduceti a doua fractie:\n"; cin >> f2; cout << "\nf1=" << f1; cout << "\nf2=" << f2 << "\n\n"; cout cout cout cout cout << << << << << f1 << f1 << f1 << f1 << endl; " " " " + * / " " " " << << << << f2 f2 f2 f2 << << << << " " " " = = = = " " " " << << << << (f1+f2) (f1-f2) (f1*f2) (f1/f2) << << << << endl; endl; endl; endl;

cout << f1+=f; cout << cout << f1-=f; cout << cout << f1*=f; cout << cout <<

f1 << " += " << f << " : "; f1 << endl; f1 << " -= " << f << " : "; f1 << endl; f1 << " *= " << f << " : "; f1 << endl; f1 << " /= " << f << " : "; 18

REFERAT DE LABORATOR Nr. 3 f1/=f; cout << f1 << endl; f1=f2; cout << "\nDupa instructiunea f1=f2, f1 = " << f1; f1=5; cout << "\nDupa instructiunea f1=5, f1 = " << f1; }

Observaii: Nu a fost necesar definirea unui constructor de copiere i nici suprancrcarea operatorului de atribuire, deoarece clasa fracie nu contine pointeri ctre date alocate dinamic. n ambele situaii se face o copiere bit cu bit, conform procedurii standard de copiere a structurilor din limbajul C. ntr-o atribuire cum ar fi: f4=f; (unde f4, f de tip fractie), se realizeaz copierea bit cu bit a fraciei f n fracia f4. Operatorii binari simpli +, -, *, / au fost suprancrcai prin funcii prietene, pentru a putea fi folosii n expresii de tipul n+f, n care n este operand de tip int i f este operand de tip fracie. Dac aceti operatori ar fi fost suprancrcai prin metode ale clasei fracie, ar fi putut fi utilizai doar n expresiile n care operandul stng era de tip fracie. Operatorii binari compui +=, -=, *=, /= au fost suprancrcai prin funcii membre, deoarece operandul stng este ntotdeauna de tip fracie. n programul de test fraciia f au fost iniializate cu valorile 1 si 1. Fraciile f1 i f2 a fost iniializat cu 0 i 1, datorit parametrilor implicii ai constructorului clasei. n cazul unei atribuiri de forma f=n;, unde f este fracie i n este de tip int, nainte de atribuirea propriu-zis are loc o conversie a lui n n fracie. ntregul n este convertit automat n fracie (n,1). Acelai efect s-ar fi obinut n urma unei conversii explicite, de forma: (fractie)n. Pentru un obiect din clasa fracie, constructorul poate fi apelat explicit: f=fractie(1,1); //(n loc de fractie f(1,1); ).

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

19

REFERAT DE LABORATOR Nr. 3

3. Se definete clasa vector, care are ca date membre (private):


int nrcomp; - numrul elementelor vectorului int err; - indice de eroare double *tabcomp; - adresa de nceput a tabloului componentelor

Metode: vector(int nrc=0); - Constructor iniializare cu parametru implicit: numr elemente 0. Creaz dinamic un vector de elemente reale (double) i iniializeaz elementele cu valoarea 0. vector(const vector&); - Constructor de copiere: Pe baza vectorului primit ca argument, creaz un nou vector (de aceeai dimensiune, cu aceleai valori ale componentelor). virtual ~vector(); - Destructor: elibereaz memoria alocat dinamic la crearea unui obiect din clasa vector. int dimens() const; - Returneaz dimensiunea (numrul elementelor) pentru obiectul curent. double &operator[](int); - Suprancarca operatorul de indexare [] prin funcie membr (metod). Returneaz referina ctre elementul cu numrul de ordine indicat ca argument. vector &operator=(const vector&); - Suprancarcarea operatorului de atribuire printr-o funcie membr. A fost necesar suprancarcarea operatorului de atribuire datorit faptului c aceast clas conine pointeri ctre datele membre. int nrerori() const; - Metod constant (nu poate modifica obiectul curent) care returneaz valoarea datei membre err; void anulari(); - Metoda care anuleaz indicele de eroare. int comparare(const vector&) const; - Metoda constant care compar obiectul curent (operand stng, argument implicit) cu obiectul primit ca parametru (tot vector). Returneaz o valoare ntreag, care este: 2 dac vectorii au numr de componente diferit; 0 dac obiectul curent are 0 elemente sau dac vectorii comparai au aceleai elemente; 1 dac vectorii au cel puin un element diferit. Metoda nu modific operandul stng. Mod de apelare: a.comparare(b); //(unde a, b vectori). friend int prodscal(const vector& v1,const vector& v2, double& p); - Funcie prieten a clasei vector care calculeaz i returneaz valoarea produsului scalar pentru vectorii v1 i v2, transmii ca argumente: [ ] [ ]

friend int suma(const vector& v1, const vector& v2, vector& v); - Funcie prieten care calculeaz vectorul sum v: [ ] [ ] [ ] Returneaz o valoare ntreag: 1 dac numrul de elemente din v1 este diferit de numrul elementelor din v2; 0 dac v2 are 0 elemente, sau dac s-a calculat suma; 3 dac v are 0 elemente friend int diferenta(const vector&v1,const vector& v2,vector& v); - Funcie prieten care calculeaz vectorul diferen v: [ ] [ ] [ ]
20

REFERAT DE LABORATOR Nr. 3

Returneaz o valoare ntreag: 1 dac numrul de elemente din v1 este diferit de de numrul elementelor din v2; 0 dac v2 are 0 elemente, sau dac s-a calculat diferena; 3 dac v are 0 elemente. friend ostream &operator<<(ostream &ies, const vector&); Operator de afiare suprancarcat prin funcie prieten. Apeleaz metoda privat constant. virtual void afisare(ostream &)const; - Cuvntul virtual care apare n antetul funciei indic faptul c metoda este o funcie virtual. Ea poate fi eventual redefinit (cu acelai prototip) i n clasele derivate din clasa vector. n cazul unei redefiniri, funcia ar fi supus "legrii dinamice", ceea ce nseamn c selecia ei se va face abia n momentul execuiei. double operator *(const vector& v1) const; - Operator de nmulire suprancrcat prin metod constant care returneaz o valoare real reprezentnd produsul scalar dintre obiectul curent i cel primit ca argument. n funcie nu se creaz o copie a lui v1, se lucreaz cu v1 din programul apelant (parametru transmis prin referin). vector operator+(const vector&) const; - Operator de adunare suprancrcat prin metod constant care returneaz un vector (ntoarce o copie care poate fi utilizat n programul apelant) reprezentnd suma dintre obiectul curent i cel primit ca argument. vector operator-(const vector&) const; - Operator de scdere suprancrcat prin metoda constant care returneaz un vector (ntoarce o copie care poate fi utilizat n programul apelant) reprezentnd diferena dintre obiectul curent i cel primit ca argument. v[ k ] = v1[ k ] + v 2[ k ] v[ k ] = v1[ k ] v 2[ k ] vector &operator+=(const vector& b); - Operator suprancrcat prin metod, deoarece ntotdeauna operandul stng este de tipul vector. Este folosit n expresii cum ar fi: a+=b (a i b de tipul vector). vector &operator-=(const vector&); - Operatorul -= suprancrcat prin metod, deoarece ntotdeauna operandul stng este de tipul vector. int sort(char='A'); - Metod care testeaz argumentul primit. Dac acesta este valid ('A' sau 'D') apeleaz metoda quicksort, pentru ordonarea cresctoare sau descresctoare a alementelor unui vector. void quicksort(int, int, char); - Metoda este protejat i realizeaz ordonarea cresctoare (argumentul 'A') sau descresctoare (argumentul 'D').

//Fiierul Vector.cpp
#include <iostream> #include <string.h> using namespace std; class vector { private: int nrcomp; int err; double *tabcomp;

//nr. componente //indice eroare //tabloul componentelor; adresa de nceput

21

REFERAT DE LABORATOR Nr. 3 public: vector(int nrc=0); //constructor initializare pentru un vector vid vector(const vector&); //constr. copiere ~vector(); //destructor int dimens() const { return nrcomp; } double &operator[](int); vector& operator=(vector); //metoda constanta

//supraincarcare operator indexare //supraincarcare operator de atribuire

int nrerori() const { return err; } void anulari() { err=0; } int operator ==(const vector&) const; //compara 2 vectori friend ostream& operator<<(ostream &ies, const vector&); double operator *(const vector&) const; vector operator+(const vector&) const; vector operator-(const vector&) const; vector &operator+=(const vector&); //a+=b vector &operator-=(const vector&); int sort(char='A'); private: void afisare(ostream &)const; void quicksort(int,int,char); }; vector::vector(int nrc) { err=0; if (nrc>0) { nrcomp=nrc; tabcomp=new double[nrcomp]; if (tabcomp==0) nrcomp=0; else for (int i=0;i<nrcomp;i++) tabcomp[i]=0; //initializare elemente vector cu 0 } else { nrcomp=0; tabcomp=0; } } vector::vector(const vector &v) { err=v.err; if (v.nrcomp>0) { nrcomp=v.nrcomp; tabcomp=new double[nrcomp]; if (tabcomp==0) { nrcomp=0; tabcomp=0; err=1; } 22

REFERAT DE LABORATOR Nr. 3 else for(int k=0;k<nrcomp;k++) tabcomp[k]=v.tabcomp[k]; } else { nrcomp=0; tabcomp=0; } } vector::~vector() { if (tabcomp!=0) delete[] tabcomp; } double &vector::operator[ ](int i) { if (i<0 || i>=nrcomp) { err++; return tabcomp[nrcomp]; } else return tabcomp[i]; } int vector::operator==(const vector&v) const { if (nrcomp!=v.nrcomp) return 2; if (nrcomp==0) return 0; for (int k=0;k<nrcomp && tabcomp[k]==v.tabcomp[k];k++) if (k<nrcomp) return 1; //vectorii au cel putin un elem. diferit return 0; } ostream& operator<<(ostream &ies, const vector &v) { ies<<'['; for (int i=0; i<(v.nrcomp-1); i++) ies<<v.tabcomp[i]<<", "; if (v.nrcomp>0) ies<<v.tabcomp[v.nrcomp-1]; ies<<']'; return ies; } vector& vector::operator=(vector v) { if (tabcomp!=0) delete[] tabcomp; nrcomp=0; err=0; tabcomp=0; if (v.nrcomp>0) { tabcomp=new double[v.nrcomp]; if (tabcomp!=0) { nrcomp=v.nrcomp; 23

REFERAT DE LABORATOR Nr. 3 err=v.err; for (int k=0;k<nrcomp;k++) tabcomp[k]=v.tabcomp[k]; } } return *this; } double vector::operator*(const vector&b)const //z=a*b; a-operandul din stnga { double z=0.0; if (nrcomp!=b.nrcomp) { cout<<"Nr. componente diferit!\n"; cout<<"Nu se poate face produs scalar!\n"; return 4; } else if (nrcomp>0) for (int k=0;k<nrcomp;k++) z+=tabcomp[k]*b.tabcomp[k]; return z; } vector vector::operator+(const vector &b) const //c=a+b { if (nrcomp!=b.nrcomp) { vector c; c.err=1; return c; } if (nrcomp==0) { vector c; return c; } vector c(nrcomp); for (int k=0; k<nrcomp; k++) c.tabcomp[k] = tabcomp[k] + b.tabcomp[k]; return c; } vector vector::operator-(const vector &b) const //c=a-b { if (nrcomp!=b.nrcomp) { vector c; c.err=1; return c; } if (nrcomp==0) { vector c; return c; } vector c(nrcomp); for (int k=0; k<nrcomp; k++) c.tabcomp[k] = tabcomp[k] - b.tabcomp[k]; return c; }

24

REFERAT DE LABORATOR Nr. 3 vector &vector::operator+=(const vector &b) { if (nrcomp!=b.nrcomp) err++; else if (nrcomp>0) for (int k=0;k<nrcomp;k++) tabcomp[k]+=b.tabcomp[k]; return *this; } vector &vector::operator-=(const vector &b) { if (nrcomp!=b.nrcomp) err++; else if (nrcomp>0) for (int k=0;k<nrcomp;k++) tabcomp[k]-=b.tabcomp[k]; return *this; } void vector::quicksort(int i1,int i2,char modsort) { int i,j; double a,y; i=i1; j=i2; a=tabcomp[(i1+i2)/2]; do { switch (modsort) { case 'A': while (tabcomp[i]<a) i++; while (tabcomp[j]>a) j--; break; case 'D': while (tabcomp[i]>a) i++; while (tabcomp[j]<a) j--; } if (i<=j) { y=tabcomp[i]; tabcomp[i]=tabcomp[j]; tabcomp[j]=y; i++; j--; } } while (i<=j); if (i1<j) quicksort(i1,j,modsort); if (i<i2) quicksort(i,i2,modsort); } int vector::sort(char modsort) { modsort=toupper(modsort); if (modsort!='A' && modsort!='D') return 1; if (nrcomp==0) return 2; if (nrcomp==1) 25

REFERAT DE LABORATOR Nr. 3 return 0; quicksort(0,nrcomp-1,modsort); return 0; }

Dup definirea tipului de date vector, vom realiza un fiier de test n care vom testa operaiile pe care le putem face asupra vectorilor. //Fiierul TestVector.cpp
#include "Vector.cpp" int main() { int nr_elem; cout << "Numarul de elemente: "; cin >> nr_elem; vector v1(nr_elem), v2; v2 = vector(nr_elem); cout << "Introduceti primul vector:\n"; for (int i=0; i<nr_elem; i++) { cout << "v1[" << i+1 << "]= "; cin >> v1[i]; } cout << "\nIntroduceti al doilea vector:\n"; for (int i=0; i<nr_elem; i++) { cout << "v2[" << i+1 << "]= "; cin >> v2[i]; } cout << "\nv1: " << v1 << endl; cout << "v2: " << v2 << endl; cout << "\nv1+v2: " << (v1+v2) << endl; cout << "v1-v2: " << (v1-v2) << endl; cout << "v1*v2: " << (v1*v2) << endl; cout << "\nv1+=v2: " << (v1+=v2) << endl; cout << "v1-=v2: " << (v1-=v2) << endl; v1.sort(); cout << "\nv1 ordonat crescator: " << v1 << endl; v1.sort('D'); cout << "v1 ordonat descrescator: " << v1 << endl; }

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

26

REFERAT DE LABORATOR Nr. 3

4. Fie clasa Sir, pentru care se suprancarc operatorul de indexare printr-o funcie
membr. Funcia returneaz o referin ctre caracterul de indice n (transmis ca argument explicit).

#include <iostream> #include <string.h> using namespace std; class Sir { char *sptr; public: Sir(char *); ~Sir() { delete sptr; } void afisare() { cout << sptr; } char& operator[] (int n) { return *(sptr + n); } }; Sir::Sir(char *s) { sptr = new char[strlen(s)+1]; strcpy(sptr, s); } int main() { Sir s1("Acesta este un sir"); cout <<"Sirul s1: \n"; s1.afisare(); 27

REFERAT DE LABORATOR Nr. 3 cout <<"\n\nElementul de indice 4 din sir: "<< s1[4]; s1[4] = '1'; s1[5] = '5'; s1[6] = 't'; s1[7] = 'h'; cout <<"\n\nDupa ce s-au modificat elementele de indici 4,5,6 si 7: \n"; s1.afisare(); strncpy(&s1[4], "21st", 4); cout <<"\n\nDupa ce s-au modif. din nou elementele de indici 4,5,6,7:\n"; s1.afisare(); }

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

5. Se definete tipul sir, cu date membre (private):


int lung lungimea propriu-zis (nr. de caractere din ir), fr terminator; char *sirul adresa nceput ir (irul-pointer ctre nceput ir);

Metode: sir(); constructor vid; sir (char *); constructor de iniializare care primete ca parametru un pointer ctre un ir de caractere (alocare dinamic); sir(const sir&); constructor de copiere: primete ca argument o referin ctre un obiect din clasa ir i realizeaz copierea. ~sir(); destructor care elibereaz memoria alocat dinamic. int lungime(); returneaz valoarea datei membre lung (nr. de carctere din ir). const char *continut(); returneaz coninutul unui obiect de tip ir. sir &operator=(const sir&); suprancrcarea operatorului de atribuire printro funcie membr. A fost necesar suprancarcarea operatorului de atribuire datorit faptului c aceast clas conine ca date membre, pointeri.
28

REFERAT DE LABORATOR Nr. 3

sir &operator+=(const sir&); operator suprancarcat prin funcie membr care realizeaz concatenarea obiectului curent (operandul implicit, de tip ir) cu obiectul de tip ir primit ca parametru. friend sir operator+(const sir& s1, const sir& s2); suprancarc operatorul de adunare printro funcie prieten. Acesta concateneaz obiectele de tip ir primite ca parametri. Returneaz irul obinut n urma concatenrii. friend ostream &operator<<(ostream &, const sir&); suprancarc operatorul insertor printro funcie prieten a clasei ir. friend istream &operator>>(istream &, sir&); suprancarc operatorul extractor printro funcie prieten a clasei ir.

//Fiierul Sirul.cpp
#include <string.h> #include <iostream> using namespace std; class sir { int lung; char *sirul;

//lungimea propriu-zisa, fara terminator //adresa inceput sir (sirul-pointer catre inceput sir)

public: sir(); //constructor vid: construieste un sir vid sir (char *); //constructor initializare primeste ca argument //un sir standard sir(const sir&); // constructor copiere: primeste ca argument //o referinta catre un obiect din clasa sir si //trebuie sa faca o copiere ~sir(); //destructor int lungime(); //metoda care returneaza numarul de caractere //din componenta sirului const char *continut(); //metoda inline-returneaza continutul //sirului curent sir &operator=(const sir&); //supraincarcare operator atribuire //(necesar datorita faptului ca, in cls sir, exista un //pointer catre data membra "sirul" supraincarcat prin functie //membra, deoarece intotdeauna membrul stang este un obiect //din clasa sir sir &operator+=(const sir&); //concateneaza argumentul primit la sirul curent friend sir operator+(const sir&, const sir&); //concateneaza argumentele intr-un sir nou friend ostream &operator<<(ostream &,const sir&); //supraincarcare operator insertor friend istream &operator>>(istream &,sir&); //supraincarcare operator extractor }; sir::sir() { sirul = 0; lung = 0; } 29

REFERAT DE LABORATOR Nr. 3 sir::sir(char *s) { lung = strlen(s); if (lung>0) { sirul = new char[lung+1]; if (sirul != 0) strcpy(sirul,s); else lung = 0; } else sirul = 0; } sir::sir(const sir &s) { if (s.lung>0) { sirul = new char[s.lung+1]; if (sirul != 0) { strcpy(sirul,s.sirul); lung = s.lung; } else lung = 0; } else { lung = 0; sirul = 0; } } sir::~sir() { if (sirul != 0) delete sirul; } int sir::lungime() { return lung; } const char *sir::continut() { return sirul; } sir &sir::operator=(const sir&s) { if (sirul != 0) delete sirul; if (s.lung>0) { sirul = new char[s.lung+1]; if (sirul != 0) { strcpy(sirul,s.sirul); lung = s.lung; } 30

REFERAT DE LABORATOR Nr. 3 else lung = 0; } else { sirul = 0; lung = 0; } return *this; } sir & sir::operator+=(const sir &s) { if (s.lung>0) { char *ps; int lung1; lung1 = lung + s.lung; ps = new char[lung1+1]; if (ps != 0) { strcpy(ps,sirul); strcat(ps,s.sirul); delete sirul; sirul = ps; lung = lung1; } } return *this; } sir operator+(const sir &s1, const sir &s2) { sir s; s.lung = s1.lung + s2.lung; s.sirul = new char[s.lung+1]; if (s.sirul != 0) { if (s1.lung>0) strcpy(s.sirul,s1.sirul); else strcpy(s.sirul,""); if (s2.lung>0) strcat(s.sirul,s2.sirul); } else { s.lung = 0; s.sirul = 0; } return s; } ostream &operator<<(ostream &ies, const sir &s) { if(s.lung>0) ies<<s.sirul; return ies; } istream &operator>>(istream &intr, sir &s) { char s1[100]; cin>>s1; 31

REFERAT DE LABORATOR Nr. 3 s=s1; return intr; }

Dup definirea tipului de date sir, vom realiza un fiier de test n care vom testa operaiile pe care le putem face asupra sirurilor. //Fiierul TestSirul.cpp
#include "Sirul.cpp" int main() { const char *p; sir s1("SIR INITIALIZAT!"), s2(s1), s3, s4; cout<<"\nAfisari\n"; cout<<"s1="<<s1<<'\n'; cout<<"s2="<<s2<<'\n'; cout<<"s3="<<s3<<'\n'; cout<<"s4="<<s4<<'\n'; s3=s2; cout<<"\nAtribuire s3=s2: s3="<<s3<<'\n'; s4="Proba de atribuire"; cout<<"\nTest atribuire sir de caractere lui s4: s4="<<s4<<'\n'; cout<<"\nConcatenare s1 (ob. curent) cu s4:\n"; s1+=s4; cout<<"s1="<<s1<<'\n'; cout<<"\nConcatenare s1 cu s4, rezultat in s3:\n"; s3=s1+s4; cout<<"s3="<<s3<<'\n'; sir q; cout<<"\nAstept caractere din sirul q:"; cin>>q; cout<<"Nr caractere introduse in sir:"<<q.lungime()<<'\n'; cout<<"Continutul sirului:"<<q.continut()<<'\n'; }

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

32

REFERAT DE LABORATOR Nr. 3

6. Se implementeaz clasa matrice. Matricea este privit ca un vector de linii.


Date membre (protected): int Dim1,Dim2; - nr. linii, nr. coloane double *tab; - pointer ctre tabloul componentelor int err; - indice de eroare

Metode: matrice (int dim1=0, int dim2=0); - Constructor matrice, cu alocare dinamic. matrice(const matrice&); - Constructor de copiere ~matrice(); - Destructor, cu rolul de a elibera memoria alocat dinamic. int pune(int ind1, int ind2, double elem); - Iniializeaz elementul de indici (ind1, ind2) cu valoarea transmis ca argument (al treilea parametru). ntoarce valoarea ntreag 1 dac indicii sunt incoreci. int dim1()const; - Metod constant care returneaz numrul de linii. int dim2() const; - Metod constant care returneaz numrul de coloane. int nrerori() const; - Metod constant (nu poate modifica obiectul curent), returneaz valoarea datei membre err; void anulari(); - Metod care anuleaz indicele de eroare. double elem(int ind1, int ind2) const; - Metod constant care returneaz valoarea elementuluilui de indici (ind1,ind2). friend ostream &operator<<(ostream &, const matrice&); Suprancrcarea operatorului de inserie printr-o funcie membr. Apeleaz metoda afiare. void afiare(ostream &)const;

33

REFERAT DE LABORATOR Nr. 3

matrice &operator=(const matrice&); Suprancrcarea operatorului de atribuire printr-o funcie membr. A fost necesar suprancrcarea operatorului de atribuire datorit faptului c aceast clas conine pointeri ctre datele membre. int dimtab()const; - Metod constant care returneaz numrul de elemente din matrice (Dim1*Dim2). virtual int comparare(const matrice&) const; - Metod constant care compar obiectul curent cu obiectul primit ca argument. matrice operator+(const matrice&) const; - Operator de adunare suprancrcat prin metod constant care returneaz o matrice (ntoarce o copie care poate fi utilizat n programul apelant) reprezentnd suma dintre obiectul curent i cel primit ca argument. matrice operator-(const matrice&) const; - Operator de scdere suprancrcat prin metod constant care returneaz o matrice (ntoarce o copie care poate fi utilizat n programul apelant) reprezentnd suma dintre obiectul curent i cel primit ca argument. matrice &operator+=(const matrice&); - Operator suprancrcat prin metod, deoarece ntotdeauna operandul stng este de tipul matrice. Este folosit n expresii cum ar fi: a+=b (a i b de tipul matrice). matrice &operator-=(const matrice&); Operatorul -= suprancrcat prin metod, deoarece ntotdeauna operandul stng este de tipul matrice. Este folosit n expresii cum ar fi: a-=b (a i b de tipul matrice). friend matrice operator*(double, const matrice&); Operator suprancrcat prin funcie prieten, pentru a putea fi utilizat n expresii n*M, unde n este de tip real sau ntreg i M de tipul matrice. matrice operator*(const matrice&) const; Operator suprancrcat prin funcie membr, care nmulete obiectul curent (tip matrice) cu obiectul primit ca argument (tot tip matrice). int indtab(int i,int j) const; - Metod care returneaz indicele din tabloul unidimensional (matricea este privit ca un tablou unidimensional, cu elementele memorate ntr-un tablou unidimensional, nti elementele primei linii, n continuare elementele celei de-a doua linii, etc.) pentru elementul[i][j]. int erind(int, int) const; - Metod care testeaz eventualele erori de indexare. matrice transp() const; - Metoda calculeaz i returneaz matricea transpus pentru obiectul curent. Nu modific obiectul curent. double operator ( ) (int i, int j); - Suprancrcarea operatorului ( ) prin metod a clasei care returneaz valoarea elementului de indici i i j pentru obiectul curent, sau 0 n cazul n care apare o eroare de indexare (vezi i metoda elem). Apelul metodei elem: A.elem(1, 3) este echivalent cu apelul A(1, 3).

//Fiierul Matrice.cpp
#include <iostream> using namespace std; class matrice{ int Dim1,Dim2; double *tab; int err; 34

REFERAT DE LABORATOR Nr. 3 public: matrice (int dim1=0,int dim2=0); matrice(const matrice&); ~matrice(); int pune(int ind1, int ind2, double elem); //pune elementul elem pe pozitia de indici (ind1, ind2) //intoarce 1 daca indicii sunt incorecti friend ostream &operator<<(ostream &, const matrice&); matrice &operator=(const matrice&); matrice transp() const; int dim1()const {return Dim1;} int dim2() const {return Dim2;} int dimtab() const; int nrerori() const {return err;} void anulerori() {err=0;} double elem(int ind1, int ind2) const; //intoarce valoarea elementului de indici (ind1,ind2) int comparare(const matrice&) const; matrice operator+(const matrice&) const; matrice operator-(const matrice&) const; matrice &operator+=(const matrice&); matrice &operator-=(const matrice&); friend matrice operator*(double, const matrice&); private: int indtab(int i,int j) const { return i*Dim2+j; } //indicele din tab al unui elem. int erind(int, int) const; //test er. de indexare void afisare(ostream &)const; }; matrice::matrice (int d1,int d2) // constructor matrice { int k,dtab; err=0; if (d1<=0 || d2<=0) { Dim1=0; Dim2=0; tab=0; } else { dtab=d1*d2; tab=new double[dtab]; if (tab!=0) { Dim1=d1;Dim2=d2; for (k=0;k<dtab;k++) tab[k]=0; } else { Dim1=0; Dim2=0; err=1; 35

REFERAT DE LABORATOR Nr. 3 } } } matrice::matrice(const matrice &M) //constructor copiere { err=0; int k, dtab; if (M.Dim1<=0 || M.Dim2<=0) { Dim1=0; Dim2=0; tab=0; } else { dtab=M.Dim1*M.Dim2; tab=new double[dtab]; if (tab!=0) { Dim1=M.Dim1; Dim2=M.Dim2; for (k=0;k<dtab;k++) tab[k]=M.tab[k]; } else { Dim1=0; Dim2=0; } } } matrice::~matrice() { if (tab!=0) delete [] tab; } int matrice::pune(int i, int j, double val) { int iret; iret=erind(i,j); if (iret!=0) return iret; tab[indtab(i,j)]=val; return 0; } int matrice::erind(int i,int j) const { if (Dim1==0 ||Dim2==0) return 2; if (i<0 || i>=Dim1 || j<0 || j>=Dim2) return 1; return 0; } void matrice::afisare(ostream & ies) const { int i,j; if (tab!=0) { ies<<'\n'; for (i=0;i<Dim1;i++) 36

REFERAT DE LABORATOR Nr. 3 { for (j=0;j<Dim2;j++) ies<<tab[indtab(i,j)]<<" "; cout<<'\n'; } } } ostream &operator<<(ostream &ies, const matrice &M) { M.afisare(ies); return ies; } matrice &matrice::operator=(const matrice &M) { int k, dtab, vdtab; err=M.err; dtab=M.Dim1*M.Dim2; //dimens. M if (dtab==0) { Dim1=0;Dim2=0; if (tab==0) { delete [] tab; tab=0; } } else { vdtab=Dim1*Dim2; if (vdtab!=dtab) { delete [] tab; tab=new double [dtab]; if (tab!=0) { Dim1=0; Dim2=0; err=1; } } if (tab!=0) { Dim1=M.Dim1; Dim2=M.Dim2; for (k=0; k<dtab; k++) tab[k]=M.tab[k]; } } return *this; } int matrice::comparare(const matrice &M) const { int k,dtab; if (M.Dim1!=Dim1 || M.Dim2!=Dim2) return 2; dtab=Dim1*Dim2; for (k=0;k<dtab;k++) if (M.tab[k]!=tab[k]) return 1; return 0; } 37

REFERAT DE LABORATOR Nr. 3 matrice matrice::operator+(const matrice &B) const { matrice C; int k, dtab; if (Dim1!=B.Dim1 || Dim2!=B.Dim2) C.err=1; else { dtab=Dim1*Dim2; C.tab=new double [dtab]; if (C.tab==0) { C.Dim1=0; C.Dim2=0; C.err=2; } else { C.Dim1=Dim1; C.Dim2=Dim2; if (dtab!=0) for (k=0;k<dtab;k++) C.tab[k]=tab[k]+B.tab[k]; } } return C; } matrice matrice::operator-(const matrice &B) const { matrice C; int k, dtab; if (Dim1!=B.Dim1 || Dim2!=B.Dim2) C.err=1; else { dtab=Dim1*Dim2;C.tab=new double [dtab]; if (C.tab==0) { C.Dim1=0; C.Dim2=0; C.err=2; } else { C.Dim1=Dim1; C.Dim2=Dim2; if (dtab!=0) for(k=0;k<dtab;k++) C.tab[k]=tab[k]-B.tab[k]; } } return C; } matrice &matrice::operator+=(const matrice &B) { int dtab; if (Dim1!=B.Dim1 || Dim2!=B.Dim2) err++; else { dtab=Dim1*Dim2; if (dtab!=0) for (int k=0;k<dtab;k++) 38

REFERAT DE LABORATOR Nr. 3 tab[k]+=B.tab[k]; } return *this; } matrice &matrice::operator-=(const matrice &B) { int dtab; if (Dim1!=B.Dim1 || Dim2!=B.Dim2) err++; else { dtab=Dim1*Dim2; if (dtab!=0) for (int k=0;k<dtab;k++) tab[k]-=B.tab[k]; } return *this; } matrice operator*(double a, const matrice &B) { if (B.tab==0) { matrice C; C.err=B.err; return C; } int k, dtab; matrice C(B.Dim1, B.Dim2); if (B.tab==0) { C.err=3; return C; } dtab=C.Dim1*C.Dim2; for (k=0; k<dtab; k++) C.tab[k]=a*B.tab[k]; return C; } matrice matrice::operator*(const matrice &B) const { if (Dim2!=B.Dim2) { matrice C; C.err=1; return C; } if (tab==0 && B.tab==0) { matrice C; return C; } if (tab==0 || B.tab==0) { matrice C; C.err=2; return C; } int i,j,k; double S; matrice C(Dim1, B.Dim2); 39

REFERAT DE LABORATOR Nr. 3 if (C.tab==0) { C.err=3; return C; } for (i=0;i<Dim1;i++) for (j=0;j<B.Dim2;j++) { double S=0; for (k=0;k<Dim2;k++) S+=tab[indtab(i,k)]*B.tab[B.indtab(k,j)]; C.tab[C.indtab(i,j)]=S; } return C; } matrice matrice::transp() const { int i,j,dtab; dtab=Dim1*Dim2; if (dtab==0) { matrice C; C.err=err; return C; } matrice C(Dim2,Dim1); if (C.tab==0) { C.err=1; return C; } for (i=0;i<C.Dim1;i++) for (j=0;j<C.Dim2;j++) C.tab[C.indtab(i,j)]=tab[indtab(j,i)]; return C; } double matrice::elem(int i,int j) const { if (erind(i,j)) return 0; return tab[indtab(i,j)]; } int matrice::dimtab() const { return Dim1*Dim2; }

Dup definirea tipului de date vector, vom realiza un fiier de test n care vom testa operaiile pe care le putem face asupra vectorilor. //Fiierul TestMatrice.cpp
#include "Matrice.cpp" #include <conio.h> int main() { int nr_elem; double val; 40

REFERAT DE LABORATOR Nr. 3 cout << "Numarul de linii si de coloane: "; cin >> nr_elem; matrice a(nr_elem, nr_elem), b(nr_elem, nr_elem), c; cout << "\nElementele matricii a: " << endl; for (int i = 0; i < nr_elem; i++) for (int j = 0; j < nr_elem; j++) { cout << "A[" << i+1 << "][" << j+1 << "]= "; cin >> val; a.pune(i, j, val); } cout << "\nMatricea A:" << a; cout << "\nA transpus:" << a.transp(); cout << "\nDimensiunile matricii a: " << a.dim1() << ", " <<a.dim2(); cout << "\n\n------Apasa o tasta pentru continuare-------\n"; getch(); cout << "\nElementele matricii b: " << endl; for (int i = 0; i < nr_elem; i++) for (int j = 0; j < nr_elem; j++) { cout << "B[" << i+1 << "][" << j+1 << "]= "; cin >> val; b.pune(i, j, val); } cout << "\nMatricea A:" << a; cout << "\nMatricea B:" << b; cout << "\nA+B:" << (a+b); cout << "\nA-B:" << (a-b); cout << "\nA*B:" << (a*b); cout << "\n\n------Apasa o tasta pentru continuare-------\n"; getch(); cout << "\nMatricea A:" << a; cout << "\nMatricea B:" << b; a+=b; cout << "\nA+=B:" << a; a-=b; cout << "\nA-=B:" << a; }

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

41

REFERAT DE LABORATOR Nr. 3

42

REFERAT DE LABORATOR Nr. 3

43

REFERAT DE LABORATOR Nr. 3

7. S se urmreasc urmtorul program care ilustreaz conversiile din tip predefinit n


clas i din clas n tip predefinit. Pentru clasa fracie, se va suprancrca operatorul de conversie explicit, care s realizeze conversii fracie -> int.

#include <iostream> using namespace std; class fractie { long nrt, nmt; public: fractie(int n=0, int m=1) { nrt=n; nmt=m; } friend ostream &operator<<(ostream &,const fractie&); operator int( ) { return nrt/nmt; } //conversie fractie -> int }; ostream &operator<<(ostream &ies, const fractie &f) { ies << f.nrt << '/' << f.nmt; return ies; } int main() { cout << "Conversia numarului intreg 23 in fractie: "; cout << (fractie)23<< endl; cout << "\nConversia explicita fractie -> intreg\n"; fractie a(5,4); cout << "Fractia a: " << a << endl; 44

REFERAT DE LABORATOR Nr. 3 cout << "(int)" << a << " = " << (int)a << endl; //conversie explicita cout << "int(" << a << ") = " << int(a) << endl; //conversie explicita int x=a; //conversia se face implicit, inainte de atribuire cout << "\nConversia implicita fractie -> intreg\n"; cout << "int x = " << a << endl; cout << "x = " << x << endl; }

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

8. S se urmreasc urmtorul program care ilustreaz conversiile dintr-o clas n alt


clas. Conversia se realizeaz cu ajutorul unui constructor al clasei2, care primete ca parametri obiecte din clasa1 (fracie -> complex).

#include <iostream> using namespace std; class fractie { int nrt, nmt; public: fractie(int nr=0, int nm=1) {nrt=nr; nmt=nm;} operator int() const {return nrt/nmt;} //conversie fractie -> int friend ostream &operator<<(ostream&, const fractie&); int intreg() {return nrt/nmt;} friend class complex; //clasa complex este clasa prietena pentru clasa fractie, //fiecare functie din complex este prietena pentru fractie }; ostream &operator <<(ostream &ostr, const fractie &f) { ostr << f.nrt << '/' << f.nmt; return ostr; } 45

REFERAT DE LABORATOR Nr. 3 class complex { double re, im; public: complex (double r=0, double i=0) { re=r; im=i; } complex (fractie &f) { re=(double)f.nrt/f.nmt; im=0; } // conversie fractie->complex operator double() const {return re;} //conversie complex->double friend ostream &operator<<(ostream &, const complex &); }; ostream &operator<<(ostream &ies, const complex &z) { ies << z.re; if (z.im >=0 ) ies << '+' ; ies << z.im << "*i"; return ies; } int main() { complex a(6.98, 3.2), b; int i = 12, j = 5, k; double x = 1234.699, y = 74.9897, z; fractie r(7, 3), r1(9); cout cout cout cout cout cout cout cout << << << << << << << << "Numerele complexe: \n"; " a=" << a << " b=" << b << endl; "Numerele intregi: \n"; " i=" << i << " j=" << j << endl; "Numerele reale: \n"; " x=" << x << " y=" << y << endl; "Fractiile: \n"; " r=" << r << " r1=" << r1 << endl;

b=i; //conversie int->complex cout << "\nconversie int->complex: b = i = " << b << endl; b=x; //conversie double->complex //(constructor complex cu argument double) cout << "\nconversie double->complex: b = x = " << b << endl; b=complex(y,j); //apel explicit al constructorului complex; cout << "\nconstructor complex: b = complex(y,j) = " << b << endl; k=a; //conversie complex->double->int cout << "\nconversie complex->int: k = a = " << k << endl; z=(double)a; //conversie complex->double cout << "\nconversie complex->double: z = a = " << z << endl; //conversie fractie->int cout << "\nconversie fractie->int: int(r) = "; cout << int(r) << " (int)r1 = " << (int)r1 << endl; //conversie fractie->int cout<<"\nconversie fractie->int: r.intreg() = "<<r.intreg()<<endl; // conversie fractie->complex cout<<"\nconversie fractie->complex:(complex)r = "<<(complex)r<<endl; } 46

REFERAT DE LABORATOR Nr. 3

n continuare, am introdus capturi de ecran din timpul execuiei programului, pentru a se putea urmri execuia programului de test.

PROBLEME PROPUSE SPRE REZOLVARE


1. Fie clasa complex, cu datele membre parte_r i parte_i.
a) S se suprancarce operatorul + binar care realizeaz operaii de forma d+c, unde d este ntreg, c este complex, iar rezultatul complex; b) S se suprancarce operatorul de nmulire a dou numere complexe printr-o metod membr.

2. Pentru clasa punct, cu datele membre A (abscisa) i O (ordonata) s se suprancarce


operatorii:
a) unar, care negativeaz valorile abscisei i ordonatei pentru un punct; b) Funcie prieten de afiare.

47

REFERAT DE LABORATOR Nr. 3

3. Pentru clasa complex cu datele membre p_real i p_imag, s se suprancarce


operatorii:
a) ==, care compar 2 complexi, prin metod a clasei; b) + binar care realizeaz operaii de forma d+c, unde d este real, c este complex, iar rezultatul complex

4. Pentru clasa complex, cu datele membre pr i pi, s se suprancarce operatorii:


a) * binar care realizeaz operaii de forma d+c, unde d este real, c este complex, iar rezultatul complex; b) binar, prin metod (realizeaz operaii de forma C-D, unde C i D sunt complexi).

5. Pentru clasa fractie cu datele membre numit i numar, s se suprancarce operatorii:


a) extractor; b) != binar, prin metod, care realizeaz operaii de forma f!=r, unde f este de tip fracie i r de tip real.

6. Pentru clasa fracie cu datele membre nm (numitor) i nt (numartor), s se


suprancarce operatorii:
a) ! unar care schimb ntre ele valorile datelor membre; b) binar, care relizeaz operaii de forma d-f, unde d este real, iar f fracie.

7. Fie clasa complex, cu datele membre part_r i part_i.


a) S se suprancarce operatorul += binar, care realizeaz operaii de forma c1+=c2, unde c1 i c2 sunt complexi. b) S se implementeze o funcie prieten de afiare a unui complex.

8. Fie clasa fracie, cu datele membre nm (numitor) si nr (numrtor).


a) S se suprancarce operatorul != , care realizeaz operaii de forma f != a, unde f este fracie, iar a este real, prin metod a clasei; b) S se suprancarce operatorul binar, printr-o funcie prieten, astfel ncat s realizeze operaii de forma f1-f2, unde f1 si f2 sunt fracii.

9. Pentru clasa ir, s se suprancarce operatorii:


a) <, care compar lexicografic coninutul a dou obiecte de tip ir; b) operatorul +, care concateneaz coninutul a dou obiecte de tip ir; c) operatorul !, care transform literele mari din coninutul unui obiect de tip ir n litere mici

10.

Fie clasa ir.

a) S se implementeze metoda caut_nr_apariii care caut de cte ori apare un caracter transmis ca argument ntr-un ir i returneaz numrul de apariii sau 0 n cazul n care acel caracter nu este gsit;
48

REFERAT DE LABORATOR Nr. 3

b) S se suprancarce operatorul ! care transform caracterele din coninutul irului din litere mari n litere mici; c) S se defineasc destructorul pentru ir; d) S se suprancarce operatorul binar I logic (pe cuvnt) care din dou iruri s1 i s2, construiete un alt ir, care conine caracterele comune lui s1 si s2; e) S se suprancarce operatorul != care testeaz existena unui caracter (dat ca argument) ntr-un ir. Dac acel caracter este coninut n ir, se returneaz valoarea 1, altfel valoarea 0; f) S se suprancarce operatorii relaionali care compar lexicografic coninutul a dou iruri; g) S se suprancarce operatorul unar care realizeaz conversia tuturor caracterelor alfabetice din coninutul unui obiect de tip ir, din litere mari n litere mici.

11.

S se defineasc tipul dat calendaristic. Data calendaristic se va introduce sub forma zz/ll/aaaa, fiind validat (se va ine cont de anii biseci). Se vor suprancrca operatorii: a) b) c) d) e) f) g) h) i) insertor; extractor; += (adun la dat un numr de zile); -= (scade dintr-o dat un numr de zile); == (compar 2 date); - (returneaz numrul de zile dintre dou date); + (adun dou date); ++ (incrementeaz luna); -- (decrementeaz luna).

12. 13. 14. 15.

Pentru clasa ir, sa se suprancarce operatorul <=, care compar lexicografic coninutul a dou obiecte de tip ir. Pentru clasa ir, s se suprancarce operatorul ^ binar, care realizeaz operaii de forma s^n, unde s ir. Operatorul multiplic de n ori coninutul irului. Pentru clasa ir, s se suprancarce operatorul !, care schimb literele mari din coninutul unui obiect de tip ir, n litere mici. Pentru clasa ir, s se suprancarce operatorul ^ care primete ca argument un ir (C) de caractere i elimin din coninutul unui obiect de tipul ir caracterele din irul C transmis ca argument. Pentru clasa ir, s se suprancarce operatorul -, care primete ca argument un numr ntreg n i elimin din contnutul unui obiect de tipul ir ultimele n caractere. Pentru clasa vector, s se implementeze o funcie prieten care calculeaz i returneaz suma tuturor elementelor vectorului.

16. 17.

49