Ciobanu Stanislav CR221fr POO Lab2

Descărcați ca pdf sau txt
Descărcați ca pdf sau txt
Sunteți pe pagina 1din 15

MINISTERUL EDUCAŢIEI ȘI CERCETĂRII AL REPUBLICII MOLDOVA

UNIVERSITATEA TEHNICĂ A MOLDOVEI

FACULTATEA CALCULATOARE, INFORMATICĂ ŞI MICROELECTRONICĂ

DEPARTAMENTUL INFORMATICĂ ȘI INGINERIA SISTEMELOR

Raport
Lucrarea de laborator nr. 2
la disciplina “Programarea orientată pe obiecte”

A efectuat: Stanislav Ciobanu


gr. CR-221FR

A verificat: Mihail Kulev


dr., conf. univ.

CHIŞINĂU 2024
Lucrarea de laborator nr. 2

Tema: Supraîncărcarea operatorilor

Sarcina (condiția problemei):


Varianta 7
Să se creeze clasa numerelor mari întregi Long. Să se definească operatorii "+" şi "*" ca
metode ale clasei, iar "-" şi "/" - ca funcţii prietene. Să se supraîncarce operatorii de
incrementare şi de decrementare în ambele forme (prefixă şi postfixă). Operatorii trebuie să
permită realizarea operaţiilor atît cu variabilele clasei date, cît şi cu variabilele de tip
predefinit long. Să se definească operatorii "<<" şi ">>".

Partea teoretică și explicativă:

La elaborarea lucrării de laborator respective au fost utilizate clasele friend (prieten), şi


respectiv supraîncărcarea operatorilor.
Funcțiile friend (prieten) sunt funcţii asociate unor clase care au acces la datele şi
metodele protejate ale acelor clase deşi nu sunt funcţii membre ale acelei clase. Există două
tipuri de astfel de funcții, și anume funcții prieten globale și funcții membre ale altor clase. O
cauză esențială de utilizare a acestora este necesitatea accesării datelor protejate. Declararea unei
funcții friend globale pentru o clasă se face incluzând prototipul ei, precedat de cuvântul cheie
friend, în acea clasă, pe când însăși definiţia funcţiei se face deja în afara clasei. Sunt funcţii
membre ale unei clase ce au acces la datele membru protejate ale unei alte clase. Declararea unei
funcții friend se face incluzând prototipul ei, precedat de cuvântul cheie friend, în clasa în care se
dorește accesul. Astfel de obicei declarăm clasa din care vrem să efectuăm accesul înaintea
definirii clasei în care se află datele/metodele protejate. Dacă dorim ca toate metodele dintr-o
clasă IdClasaB să aibă acces asupra tuturor datelor/funcţiilor membre protejate ale unei alte clase
IdClasaA atunci declarăm clasa IdClasaB ca fiind clasă friend (prieten) pentru clasa IdClasaA
prin intermediul sintaxei declarative corespunzătoare. Relaţia de prietenie dintre două clase nu
este reflexivă, adică dacă clasa IdClasaA este clasă prieten a clasei IdClasaB, atunci nu şi
reciproca este valabilă. Relaţia de prietenie nu este tranzitivă, adică dacă clasa IdClasaA este
clasă prietenă clasei IdClasaB, iar IdClasaB este clasă prietenă clasei IdClasaC, asta nu implică
faptul că IdClasaA este clasă prietenă a clasei IdClasaC. La fel, relaţia de prietenie nu se
moşteneşte în clasele derivate [1].
Un tip de date (predefinit) definește un set de valori și o mulțime de operații ce se pot
efectua cu acestea, cum ar fi de exemplu: adunarea (+), scăderea (-), etc. Problema constă în
faptul că în cazul tipurilor de date definite prin intermediul claselor, cum am putea defini
anumite operații cu ajutorul operatorilor? Acest lucru se realizează prin așa numita
supraîncărcare (overloading) a operatorilor care este procesul de atribuire a două sau mai multe
operații aceluiași operator și se poate realiza prin intermediul funcțiilor membru sau funcțiilor
friend globale. Aplicarea acestuia permite o exprimare mai elegantă a operațiilor. Totuși este
însoțită de un șir de restricții, astfel prin supraîncărcarea operatorilor nu se poate modifica
aritatea operatorilor, asociativitatea și prioritatea. Aritatea descrie numărul operanzilor asupra
cărora se aplică un operator. Astfel, operatorii unari nu pot fi supraîncărcați ca operatori binari și
invers. Se pot supraîncărca numai operatori existenți și oricum există un șir de operatori ce nu
pot fi supraîncărcați precum ".*", "::", "?:" și sizeof [1].
Supraîncărcarea operatorilor are loc prin intermediul cuvântului-cheie operator urmat de
simbolul operatorului dorit și lista de parametri (operanzi asupra cărora acționează operatorul). În
cazul supraîncărcării operatorilor cu funcții membru, numărul de parametri este cu 1 mai mic
decât aritatea operatorului, iar primul operand este obiectul curent pentru care se apelează
operatorul. Pe când, la supraîncărcarea operatorilor cu funcții friend numărul de parametri este
deja egal cu aritatea operatorului. Operatorul este o funcţie cu un nume predefinit şi o sintaxă
specială la apelare. Operatorii se definesc cu ajutorul cuvîntului cheie operator, urmat de
simbolul operaţiei. În rest, este o funcţie obişnuită, care are parametri şi returnează un rezultat. În
continuare, operatorul dat poate fi utilizat ca şi un operator predefinit, dar se poate de utilizat şi
forma funcţională de apelare [2].
Avantajul utilizării operatorilor (reducerea codului) în acelaşi timp complică înţelegerea
codului, deoarece nu este posibil întotdeauna sau este complicat să se urmărească dacă se
utilizează un operator predefinit sau supraîncărcat. Însă supraîncărcarea operatorilor este
necesară. Sunt probleme care se soluţionează numai prin supraîncărcarea operatorilor,cum ar fi
operatorul de atribuire. Desigur, compilatorul poate să genereze codul necesar, dar această
soluţie nu este ideală, deoarece neajunsul metodei date constă în utilizarea copierii bit cu bit,
ceea ce este satisfăcător doar atît timp cît în clasă nu se utilizează pointerii. Pentru evitarea
ambiguităților cel puţin un operator este strict necesar [2].
Toţi operatorii se divizează în două grupuri: unari şi binari. Operatorii unari se numesc
operatorii cu un singur operand, precum de exemplu, operatorul & - de referenţiere, ++ - de
incrementare, ! – de negare, etc. Operatorii binari au doi operanzi: + - adunarea, * - înmulţirea,
etc. Unii operatori unari au două forme, de exemplu, operatorul ++ poate fi scris ca i++, sau ++i.
Pentru ca compilatorul să deosebească care realizare să o apeleze, a fost introdusă regula:
operatorul postfix are un parametru suplimentar de tip întreg. Trebuie de menţionat că operatorii
de atribuire "=", de indexare "[]", de apel funcţie"()" şi operatorul "->" pot fi definiţi numai ca
funcţii membru. Un specific aparte îl are operatorul ->, la supraîncărcarea lui variabila se
comportă ca şi un pointer, ceea ce induce tipul pointerilor inteligenţi. Operatorul de apel funcţie
se utilizează pentru definirea obiectelor funcţionale [3].
Pentru tipurile predefinite nu pot fi definiţi operatori, dar ei pot fi utilizaţi. Unul şi acelaşi
operator nu poate fi definit şi ca funcţie membru, şi ca funcţie prieten. Toţi operatorii trebuie să
returneze un tip diferit de void, excepţie fiind operatorul (). La supraîncărcare prioritatea
operatorilor nu se schimbă. Operatorul () poate avea un număr arbitrar de parametri, el nu face
parte din clasificarea obişnuită a operatorilor [4].

Listingul programului:

// Implementarea bibliotecilor necesare


#include <iostream>

// Importam spatiul de nume std


using namespace std;

// Cream clasa numerelor mari intregi Long


class Long
{
long n;
public:
Long(long n=0)
{
this->n=n;
}
// Supraincarcam operatorul de incrementare (forma prefixa)
Long& operator++();

// Supraincarcam operatorul de incrementare (forma postfixa)


// (conform regulei are un parametru suplimentar de tip intreg)
Long operator++(int);

// Supraincarcam operatorul de decrementare (forma prefixa)


Long& operator--();
// Supraincarcam operatorul de decrementare (forma postfixa)
// (conform regulei are un parametru suplimentar de tip intreg)
Long operator--(int);

// Definim operatorul "+" ca metoda a clasei

// Operator ce permite realizarea operatiilor


// cu variabilele clasei date
Long operator+(Long& a);

// Operator ce permite realizarea operatiilor


// cu variabilele de tip predefinit long
Long operator+(long b);

// Definim operatorul "*" ca metoda a clasei


// analogic operatorul adunarii definit mai sus
Long operator*(Long& a);
Long operator*(long b);

// Definim operatorul "-" ca functie prieten


friend Long operator-(Long& a, Long& b);
friend Long operator-(Long& a, long b);
friend Long operator-(long a, Long& b);

// Definim operatorul "/" ca functie prieten


friend Long operator/(Long& a, Long& b);
friend Long operator/(Long& a, long b);
friend Long operator/(long a, Long& b);

// Definim operatorii de citire/afisare "<<" si ">>"


friend ostream& operator<<(ostream& os, const Long& ob);
friend istream& operator>>(istream& os, Long& ob);
};

Long& Long::operator++() {
++n;
return *this;
}

Long Long::operator++(int) {
n++;
return *this;
}

Long& Long::operator--() {
--n;
return *this;
}

Long Long::operator--(int) {
n--;
return *this;
}

Long Long::operator+(long b)
{
Long r;
r.n=n+b;
return r;
}

Long Long::operator+(Long& a)
{
Long r;
r.n=n+a.n;
return r;
}

Long Long::operator*(Long& a)
{
Long r;
r.n=n*a.n;
return r;
}

Long Long::operator*(long b)
{
Long r;
r.n=n*b;
return r;
}

Long operator-(Long& a, Long& b)


{
Long r;
r.n=a.n-b.n;
return r;
}

Long operator-(Long& a, long b)


{
Long r;
r.n=a.n-b;
return r;
}

Long operator-(long a, Long& b)


{
Long r;
r.n=a-b.n;
return r;
}

Long operator/(Long& a, Long& b) {


Long r;
// Verificare daca impartitorul este diferit de
// zero pentru a evita impartirea la zero
if(b.n!=0)
r.n=a.n/b.n;
else
cerr<<"Eroare: Impartire la zero!\n";
return r;
}

Long operator/(Long& a, long b) {


Long r;
// Verificare daca impartitorul este diferit de
// zero pentru a evita impartirea la zero
if(b!=0)
r.n=a.n/b;
else
cerr<<"Eroare: Impartire la zero!\n";
return r;
}

Long operator/(long a, Long& b) {


Long r;
// Verificare daca impartitorul este diferit de
// zero pentru a evita impartirea la zero
if(b.n!=0)
r.n=a/b.n;
else
cerr<<"Eroare: Impartire la zero!\n";
return r;
}

ostream& operator<<(ostream& os,const Long& ob)


{
os<<"Valoare: "<<ob.n<<endl;
return os;
}

istream& operator>>(istream& os, Long& ob)


{
cout<<"Introduceti valoarea: ";
os>>ob.n;
return os;
}

// Functia programului principal


int main() {
// Variabila optiunii selectate
int opt;

// Am fost nevoit sa scot initializarile obiectelor in afara


// switch-ului pentru a evita eroarea crosses initialization
Long a,b,rezultat;
long c;

// Implementarea meniului
do {
menu:

cout<<"==========================[Meniu]=======================
===\n"<<endl;
cout<<"1. Adunare intre doua obiecte Long"<<endl;
cout<<"2. Adunare intre un obiect Long si un long"<<endl;
cout<<"3. Inmultire intre doua obiecte Long"<<endl;
cout<<"4. Inmultire intre un obiect Long si un long"<<endl;
cout<<"5. Scadere (diferenta) intre doua obiecte Long"<<endl;
cout<<"6. Scadere (diferenta) intre un obiect Long si un long"<<endl;
cout<<"7. Incrementare prefixata a unui obiect Long"<<endl;
cout<<"8. Incrementare postfixata a unui obiect Long"<<endl;
cout<<"9. Decrementare prefixata a unui obiect Long"<<endl;
cout<<"10. Decrementare postfixata a unui obiect Long"<<endl;
cout<<"11. Citirea de la tastiera a unui obiect Long"<<endl;
cout<<"12. Iesire din program\n"<<endl;
cout<<"Selectati optiunea: ";
cin>>opt;
system("clear");
switch(opt) {
case 1:
cout<<"Prima valoare:"<<endl;
cin>>a; // de ex. 337085435895643930

cout<<"A doua valoare:"<<endl;


cin>>b; // de ex. -4109992949012952954

// Realizam adunarea (sumarea) celor doua


rezultat = a+b;

// Afisam rezultatul
cout<<"Rezultatul adunarii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 2:
cout<<"Prima valoare (obiect Long):"<<endl;
cin>>a; // de ex. 337085435895643930

cout<<"A doua valoare (tip predefinit long): ";


cin>>c; // de ex. 6156966818670483016

// Realizam adunarea (sumarea) celor doua


rezultat = a+c;

// Afisam rezultatul
cout<<"Rezultatul adunarii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 3:
cout<<"Prima valoare:"<<endl;
cin>>a; // de ex. 337085435895643930
cout<<"A doua valoare:"<<endl;
cin>>b; // de ex. -4109992949012952954

// Realizam inmultirea celor doua


rezultat = a*b;

// Afisam rezultatul
cout<<"Rezultatul inmultirii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 4:
cout<<"Prima valoare (obiect Long):"<<endl;
cin>>a; // de ex. 337085435895643930

cout<<"A doua valoare (tip predefinit long): ";


cin>>c; // de ex. 1826319561324603557

// Realizam inmultirea celor doua


rezultat = a*c;

// Afisam rezultatul
cout<<"Rezultatul inmultirii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 5:
cout<<"Prima valoare:"<<endl;
cin>>a; // de ex. 337085435895643930

cout<<"A doua valoare: "<<endl;


cin>>b; // de ex. -4109992949012952954

// Realizam scaderea (diferenta) celor doua


rezultat = a-b;

// Afisam rezultatul
cout<<"Rezultatul scaderii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 6:
cout<<"Prima valoare (obiect Long):"<<endl;
cin>>a; // de ex. 337085435895643930

cout<<"A doua valoare (tip predefinit long): ";


cin>>c; // de ex. 3746099921384830993

// Realizam scaderea (diferenta) celor doua


rezultat = a-c;

// Afisam rezultatul
cout<<"Rezultatul scaderii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 7:
cout<<"Incrementarea (forma prefixata):"<<endl;
cin>>a; // de ex. 337085435895643930

// Realizam incrementarea valorii


rezultat = ++a; //pre-incrementare

// Afisam rezultatul
cout<<"Rezultatul incrementarii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 8:
cout<<"Incrementarea (forma postfixata):"<<endl;
cin>>a; // de ex. 337085435895643930

// Realizam incrementarea valorii


rezultat = a++; // post-incrementare

// Afisam rezultatul
cout<<"Rezultatul incrementarii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 9:
cout<<"Decrementarea (forma prefixata):"<<endl;
cin>>a; // de ex. 337085435895643930

// Realizam incrementarea valorii


rezultat = --a;

// Afisam rezultatul
cout<<"Rezultatul decrementarii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 10:
cout<<"Decrementarea (forma postfixata):"<<endl;
cin>>a; // de ex. 337085435895643930

// Realizam incrementarea valorii


rezultat = a--;

// Afisam rezultatul
cout<<"Rezultatul decrementarii:\n"<<rezultat;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 11:
cout<<"Introduceti valoarea obiectului Long:"<<endl;
cin>>a; // de ex. 337085435895643930

// Realizam afisarea la ecran a valorii prin operatorul ">>"


cout<<"Ati introdus:\n"<<a;

// Pauza pana la apasarea oricarei taste


cin.get(); cin.get();
system("clear");

// Revenirea la meniu
goto menu;
break;
case 12:
exit(1);
default:
cout<<"Eroare! Optiune invalida, alegeti alta optiune."<<endl;
// Pauza pana la apasarea oricarei taste
cin.get(); cin.get();
system("clear");
// Revenirea la meniu
goto menu;
}
} while(opt!=12);

// Finisarea executarii
return 0;
}
Testarea și verificarea programului și rezultatele obținute:

1. Meniul principal:

2. Adunarea între două obiecte Long (opțiunea 1):

3. Adunarea între un obiect Long și un long (opțiunea 2):

4. Înmulțirea între două obiecte Long (opțiunea 3):

5. Înmulțirea între un obiect Long și un long (opțiunea 4):


6. Diferența (scăderea) între două obiecte Long (opțiunea 5):

7. Diferența (scăderea) între un obiect Long și un long (opțiunea 6):

8. Incrementare (forma prefixată) a unui obiect Long (opțiunea 7):

9. Incrementare (forma postfixată) a unui obiect Long (opțiunea 8):

10. Decrementare (forma prefixată) a unui obiect Long (opțiunea 9):

11. Decrementare (forma postfixată) a unui obiect Long (opțiunea 10):


12. Citirea de tastieră a unui obiect Long (opțiunea 11):

13. Introducerea unei opțiuni invalide (caz particular):

14. Ieșirea din program (opțiunea 12):

Analiza rezultatelor si concluzii:

Realizând această lucrare de laborator ne-am creat obişnuinţe de lucru cu supraîncărcarea


operatorilor, pentru a putea efectua mai multe operații în cadrul unui operator. Mi-au fost de
folos pozele tablei cu explicații oferite de prof. Mantaluța Marius în cadrul cursurilor (exemplu
asemănător cu varianta 8 – supraîncărcarea operatorilor clasei Bool). Precum și exemplele de
program oferite ca exemple pe platforma ELSE, mai ales cel unde e explicată varianta 1 a
laboratorului 2 (clasa Int), deoarece este asemănătoare cu varianta mea 7 (clasa Long) și am
preluat de acolo codul ce ține de operatorii “>>”, “<<”, “+” și “-”. Despre supraîncărcarea
operatorilor de incrementare și decrementare în ambele forme m-am documentat suplimentar.
Bibliografie:

1. „Clase și funcții friend. Supraîncărcarea operatorilor” (.pdf), Mihail Kulev

2. Teoria sarcinii laboratorului 2 pe tema „Supraîncărcarea operatorilor” (.pdf)

3. „Programarea orientată pe obiecte. Cursul 04-05” (.pdf). Mihail Kulev

4. Stroustrup, Bjarne. "The C++ Programming Language". Addison-Wesley Professional, 2013.

S-ar putea să vă placă și