Documente Academic
Documente Profesional
Documente Cultură
4 Supraîncărcarea
operatorilor
matematici
Pointerul this
Funcţii prieten
Supraîncărcarea operatorilor matematici
Aplicaţii propuse pentru studiu în laborator
Probleme propuse pentru studiu individual
Pointerul this
Atunci când este apelată o funcţie membru, acesteia i se pasează în mod
automat un argument implicit, care este pointer către obiectul care a generat apelarea
(obiectul care a invocat funcţia – obiectul curent pentru acea funcţie). Acest pointer
este pointerul this. Pentru a înţelege utilitatea pointerului this, vom scrie în exemplul
următor un program care creează clasă ce calculează rezultatul dat de ridicarea unui
număr real la o putere ilustrată printr-un exponent întreg.
putere::putere(double x, short y)
{
2 Supraîncărcarea operatorilor matematici
a=x;
b=y;
n=1;
if(!b)
return;
for(;b>0;b--)
n*=a;
}
double putere::rezultat()
{
return n;
}
int main()
{
putere a(5,3);
putere b(4.89,0);
putere c(8.5,1);
cout<<"Rezultatul 1 este: "<<a.rezultat()<<'\n';
cout<<"Rezultatul 2 este: "<<b.rezultat()<<'\n';
cout<<"Rezultatul 3 este: "<<c.rezultat()<<'\n';
system("pause");
return (0);
}
putere::putere(double x, short y)
{
(*this).a=x; //o prima varianta de scrire
this->b=y; //o a doua varianta de scriere
this->n=1;
if(!this->b)
return;
for(;this->b>0;(this->b)--)
((*this).n)*=this->a;
După cum se poate observa, datele şi funcţiile membru ale unei clase, pot fi
accesate atât prin varianta lungă, cea prin pointerul this, care ne duce la obiectul
curent pentru respectivul caz, cât şi prin partea prescurtată, cea prin accesibilitate
directă.
În mod sigur, niciun programator de C++ nu va scrie funcţia putere(...) aşa
cum a fost prezentată în Exerciţiul 2, deoarece nu se câştigă nimic, iar forma
prescurtată, cea de la Exerciţiul 1, este mai uşoară.
Totuşi, pointerul this este foarte important la supraîncărcarea operatorilor şi
ori de câte ori o funcţie membru trebuie să utilizeze un pointer către obiectul care a
3 Supraîncărcarea operatorilor matematici
apelat-o. Pointerul this este transmis automat către toate funcţiile membru. Ca atare,
funcţia rezultat(...) se poate scrie astfel:
double putere::rezultat()
{
return this->n;
}
În acest caz, dacă rezultat() este apelată astfel: a.rezultat(); atunci this va
indica spre obiectul a.
Exerciţiul 3. Aplicație pentru utilizarea pointerului this.
#include<iostream>
using namespace std;
class test
{
int a;
public:
test(int a)
{
this->a = a;
}
void afis()
{
cout << a;
}
};
int main()
{
test ob(5);
ob.afis();
system("pause");
return 0;
}
Funcţii prieten
O proprietate de bază a tipurilor abstracte este protecţia datelor membru ale
tipului respectiv. Elementele protejate constituie aşa numita implementare a tipului
abstract.
Tipurile abstracte de date se definesc cu ajutorul claselor. Datele protejate ale
unui tip abstract sunt încapsulate în clasa care defineşte tipul respectiv.
Protecţia datelor se realizează prin aceea că la ele au acces numai funcţiile
membru ale clasei. De asemenea, dacă o funcţie membru este protejată, atunci ea
poate fi apelată numai prin intermediul unei funcţii membru a clasei.
Acest mod de lucru, deşi asigură o protecţie bună a elementelor membru
protejate ale clasei, uneori este considerat prea rigid. O funcţie membru se apelează
4 Supraîncărcarea operatorilor matematici
putere::putere(double x, short y)
{
a=x;
b=y;
n=1;
if(!b)
return;
for(;b>0;b--)
n*=a;
}
double rezultat(putere x)
{
return x.n;
}
int main()
{
5 Supraîncărcarea operatorilor matematici
putere a(5,3);
putere b(4.89,0);
putere c(8.5,1);
cout<<"Rezultatul 1 este: "<<rezultat(a)<<'\n';
cout<<"Rezultatul 2 este: "<<rezultat(b)<<'\n';
cout<<"Rezultatul 3 este: "<<rezultat(c)<<'\n';
system("pause");
return (0);
}
Observaţii:
1) Funcţiile friend nu sunt membri ai clasei şi, de aceea, a nu li plasa pointeri this.
2) Constructorii unei clase nu pot fi funcţii prieten.
3) Funcţiile membre static (despre care sa va discuta într-unul din cursurile
următoare) nu au pointer this.
4) Modificatorii de protecţie nu au nici un fel de influenţă asupra unei funcţii
prieten. De aceea, specificarea faptului că o funcţie este prieten pentru o clasă,
poate fi scrisă în orice punct din interiorul definiţiei clasei respective.
5) Funcţia prieten nu este protejată şi deci poate fi utilizată fără nici o restricţie ca
orice funcţie obişnuită.
class test
{
int a;
public:
test(int a=0)
{
this->a = a;
}
void afis()
{
cout << a<<'\n';
}
//ridicam numarul din data membru la patrat (vom folosi o functie
prieten)
friend void patrat(test b, test& c)
{
c.a=b.a*b.a;
}
};
int main()
{
test ob(5);
ob.afis(); //apel al unei metode
patrat(ob,ob); //apel al unei functii prieten, acelasi ca al unei
functii obisnuite
ob.afis();
6 Supraîncărcarea operatorilor matematici
system("pause");
return 0;
}
Supraîncărcarea operatorilor
Tipurile abstracte de date se definesc în limbajul C++ cu ajutorul claselor. Ar
fi ideal ca tipurile abstracte să se comporte ca cele predefinite. Există o serie de
asemănări între tipurile abstracte şi cele predefinite. Datele de tip abstract (obiectele)
se declară la fel ca şi cele predefinite. De asemenea, ele pot fi iniţializate la declarare.
Operaţiile care se pot executa asupra obiectelor sunt bine precizate ca şi în
cazul tipurilor predefinite. În cazul tipurilor abstracte, operaţiile se definesc cu
ajutorul funcţiior membru şi prieten.
În laboratorul anterior am realizat operaţii matematice (adunare, scădere,
înmulţire, împărţire, …) folosind funcţii membru sau prieten.
Se pune problema dacă nu s-ar putea realiza aceste operaţii prin simpla
folosire a operatorilor asemenea datelor reprezentative pentru tipurile standard de
date, adică să scriem, de exemplu, o expresie de forma c=a+b, unde c, a, b sunt
obiecte.
Ei bine, acest lucru este posibil prin mecanismul de supraîncărcare a
operatorilor.
Limbajul C++ permite supraîncărcarea numai a operatorilor existenţi în
limbaj. Dintre aceştia nu pot fi supraîncăraţi operatorii: . :: ? şi :
De asemenea, prin supraîncărcarea operatorilor nu se poate schimba n-
aritatea, prioritatea sau asociativitatea operatorilor, acestea fiind elemente
predefinite pentru tipuri predefinite şi deci ele se vor menţine şi pentru tipuri
abstracte.
Prin n-aritate se înţelege că operatorul este unar sau binar. Supraîncărcarea
operatorilor se realizează cu ajutorul unor funcţii membru sau prieten speciale.
Specificul lor constă în numele acestora. El se compune din cuvântul cheie operator şi
unul sau mai multe caractere care definesc operatorul care se supraîncarcă. Între
cuvântul cheie operator şi caracterele care definesc operatorul care se supraîncarcă se
află cel puţin un spaţiu alb.
În cazul tipului complex, vom folosi pentru supraîncărcarea operatorilor + şi –,
funcţiile definite mai jos:
//FUNCTIE MEMBRU (METODA)
7 Supraîncărcarea operatorilor matematici
//FUNCTIE PRIETEN
complex operator - (compex& z1, complex& z2)
// supraîncărcarea operatorului – pentru obiecte de tip complex
{
complex temp;
temp.real=z1.real-z2.real;
temp.imag=z1.imag-z2.imag;
return temp;
}
Din cele de mai sus se poate observa că operatorii pot fi supraîncărcaţi prin
funcţii membre sau funcţii prieten. O diferenţă între cele două tipuri de funcţii constă
în numărul de parametri. Astfel, funcţiile membru care supraîncarcă operatorii unari
nu au parametri, iar cele care supraîncarcă operatori binari au un singur parametru.
În cazul funcţiilor prieten, numărul parametrilor este egal cu n-aritatea
parametrului care se supraîncarcă.
La supraîncărcarea operatorilor pentru obiecte de tip abstract nu se poate face
diferenţă între formele prefixate şi postfixate.
#include<iostream>
#include<string>
using namespace std;
class complex
{
double a, b;
string s;
public:
complex(double = 0, double = 1, string="");
void afisare();
complex operator+(complex); //adunarea a doua numere complexe
complex operator-(complex); //diferenta a doua nr. complexe
8 Supraîncărcarea operatorilor matematici
complex complex::operator+(complex z)
{
complex r;
r.a = a + z.a;
r.b = b + z.b;
r.s = s + '+' + z.s;
return r;
}
complex complex::operator-()
{
complex r;
r.a = -a;
r.b = -b;
return r;
}
complex complex::operator-(complex z)
{
complex r;
r = (*this) + (-z); //apel al doua functii (suma a doua nr. complexe
si negativul unui nr. complex)
r.s = s + '-' + z.s;
return r;
}
complex complex::operator*(complex z)
{
complex r;
r.a = a * z.a - b * z.b;
r.b = a * z.b + b * z.a;
r.s = s + '*' + z.s;
return r;
}
complex complex::operator*(int x)
{
complex r;
r.a = a * x;
r.b = b * x;
9 Supraîncărcarea operatorilor matematici
complex complex::operator~()
{
complex r;
r.a = a;
r.b = -b;
return r;
}
double complex::operator!()
{
return sqrt(a * a + b * b);
}
complex complex::operator/(complex z)
{
complex r;
complex t;
t = (*this)*(~z);
double m;
m = pow(!z, 2);
r.a = t.a / m;
r.b = t.b / m;
r.s = s + '/' + z.s;
return r;
}
double& complex::parte_re()
{
return a;
}
double& complex::parte_im()
{
return b;
}
//COMPLEX.cpp
#include"Complex.h"
int main()
{
complex z1(4, 7, "A"), z2(0, -2, "B");
z1.afisare();
z2.afisare();
//operatii
10 Supraîncărcarea operatorilor matematici
system("pause");
return 0;
}
//VECTOR.h
#include<iostream>
using namespace std;
class vector2
{
float a,b;
public:
vector2(float, float); //constructor de initializare
vector2(){} //contructorul implicit rescris
vector2(const vector2 &); //constructor de initializare prin copiere
float& first(); //intoarce primul element din vector
float& second(); //intoarce al doilea element din vector
vector2 operator+(vector2 &); //v1+v2
vector2 operator-(); //-v1
vector2 operator-(vector2 &); //v1-v2
vector2 operator*(int); //v1*5
11 Supraîncărcarea operatorilor matematici
//*****************************************************************//
vector2 vector2::operator+(vector2& v)
{
vector2 r;
r.a=a+v.a;
r.b=b+v.b;
return r;
}
vector2 vector2::operator-()
{
vector2 r;
r.a=-a;
r.b=-b;
return r;
}
vector2 vector2::operator-(vector2& v)
{
return (*this)+(-v); //linia aceasta face apel al celor doua functii
descrise mai sus
}
vector2 vector2::operator*(int x)
{
vector2 r;
r.a=a*x;
r.b=x*b;
return r;
}
double vector2::operator*(vector2& v)
{
double d;
d=a*v.a+b*v.b;
12 Supraîncărcarea operatorilor matematici
return d;
}
void vector2::read()
{
cout<<"\tprimul element: ";
cin>>a;
cout<<"\tal doilea element: ";
cin>>b;
}
void vector2::write(char* s)
{
cout<<"Sirul "<<s<<" este: ("<<a<<','<<b<<")\n";
}
//VECTOR.cpp
#include"Vector.h"
int main()
{
//Introducerea datelor in vectori
cout<<"Vectorul 1 il introduc prin initializare direct la declarare\n";
vector2 v1(3,-4);
cout<<"Vectorul 2 il introduc prin atribuire\n";
vector2 v2;
v2.attrib(6,-8);
cout<<"Vectorul 3 va fi citit de la consola\n";
vector2 v3;
v3.read();
cout<<"Vectorul 4 va avea informatiile direct transferate\n";
vector2 v4;
v4.first()=0;
v4.second()=7;
cout<<'\n';
((((-v1)*6)-(5*v4))*(int)(v2*v3)).write("Expresie");
system("pause");
13 Supraîncărcarea operatorilor matematici
return (0);
}
//MATRICE.h
class matrice
{
int m,n; //m = nr. de linii, n = nr. de coloane
int a[10][10];
public:
matrice(); //constructor de iniţializare
void constructie(int,int,char); //crearea unei matrice
matrice operator+(matrice&); //adunarea adoua matrice
matrice operator-(); //negativarea unei matrice
matrice operator-(matrice&); //diferenta a doua matrice
matrice operator~(); //transpusa unei matrice
void afisare(char* s); //afişarea unei matrice
};
inline matrice::matrice()
{
m=n=0;
}
matrice matrice::operator - ()
{
matrice R;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
R.a[i][j]=-a[i][j];
R.m=m;
R.n=n;
return R;
}
matrice matrice::operator ~ ()
{ matrice R;
R.m=n;
R.n=m;
for(int i=0;i<R.m;i++)
for(int j=0;j<R.n;j++)
R.a[i][j]=a[j][i];
return R;
}
//MATRICE.cpp
#include"Matrice.h"
int main()
{
matrice a,b;
int m,n;
cout<<"Introduceti dimensiunele matricelor:\n";
cout<<"\tnumarul de linii= ";
cin>>m;
cout<<"\tnumarul de coloane= ";
cin>>n;
a.constructie(m,n,'A');
b.constructie(m,n,'B');
cin.get();
system("cls");
a.afisare("A");
b.afisare("B");
cin.get();
15 Supraîncărcarea operatorilor matematici
system("cls");
(a+b).afisare("A+B");
(a-b).afisare("A-B");
(~a).afisare("A transpus");
(~b).afisare("B transpus");
system("pause");
return (0);
}
#include<iostream>
using namespace std;
#define dim 512
typedef int vector[dim];
bool prim(int n)
{
bool x=true;
if(n==2)
{
return x;
16 Supraîncărcarea operatorilor matematici
}
if(!(n%2))
{
x=false;
return x;
}
for(int i=3;i*i<=n;i+=2)
if(!(n%i)) //n%i==0
{
x=false;
return x;
}
return x;
}
/***************************************************************/
int main()
{
vector x;
int n;
system("pause");
return (0);
}
class vector
{
int n;
sir a;
//verificarea daca un intreg este numar prim
bool prim(int);
public:
//citirea unui sir
void citire();
//afisarea unui sir
void afisare();
//suma numerelor prime
int operator+();
//extragerea elementelor non-prime din sir
vector operator!();
};
bool vector::prim(int n)
{
bool x=true;
if(n==2)
{
return x;
}
if(!(n%2))
{
x=false;
return x;
}
for(int i=3;i*i<=n;i+=2)
if(!(n%i)) //n%i==0
{
x=false;
return x;
}
return x;
}
void vector::citire()
{
cout<<"Introduceti vectorul\n";
do{
cout<<"\tdati dimensiunea: ";
cin>>n;
}while(n<1 || n>512);
cout<<"\tdati elementele:\n";
for(int i=0;i<n;i++)
{
cout<<"\t\telementul "<<i+1<<"= ";
cin>>a[i];
}
}
void vector::afisare()
{
cout<<"Vectorul este: ";
for(int i=0;i<n;i++)
cout<<a[i]<<' ';
cout<<'\n';
}
18 Supraîncărcarea operatorilor matematici
int vector::operator+()
{
int s=0;
for(int i=0;i<n;i++)
if(prim(a[i])==true)
s+=a[i];
return s;
}
vector vector::operator!()
{
vector v;
int m=0; //numarul de elemente care nu sunt prime
for(int i=0;i<n;i++)
if(prim(a[i])==false)
v.a[m++]=a[i];
v.n=m;
return v;
}
/***************************************************************/
int main()
{
vector x;
system("pause");
return (0);
}