Documente Academic
Documente Profesional
Documente Cultură
Curs10 Supra Op
Curs10 Supra Op
Programare n C / C++
Suprancrcarea operatorilor.
1. Suprancrcare.
2. Funcii prieten.
3. Modaliti de suprancrcare a operatorilor.
4. Operatori redefinii ca funcii prieten.
5. Operatori redefinii ca funcii membri.
6. Suprancrcarea operatorului de atribuire.
7. Suprancrcarea operatorului de indexare.
8. Suprancrcarea operatorilor new i delete.
9. Suprancrcarea operatorului apel de funcie.
10. Suprancrcarea operatorilor de conversie.
11. Suprancrcarea operatorilor << i >>.
12. Probleme.
Operatorii sunt notaii concise, infixate, pentru operaii matematice uzuale. Limbajul C++, ca
orice limbaj de programare asigur un set de operatori pentru tipurile primitive. n plus, fa de
limbajul C, C++ ofer posibilitatea asocierii operatorilor existeni cu tipurile definite de utilizator .
Astfel, prezint interes extinderea operatorilor n aritmetic complex, algebra matricial, n lucrul cu
iruri de caractere, etc. Un operator poate fi privit ca o funcie, n care termenii sunt argumentele
funciei (n lipsa operatorului +, expresia a+b s-ar calcula apelnd funcia aduna(a,b)).
Limbajul C++ introduce urmtorii operatori noi: new i delete- pentru gestiunea
memoriei dinamice, operatorul de rezoluie (::) i operatorii de acces la membri: .* i ->*.
1. Suprancrcare.
Prin suprancrcarea unui operator, acesta este utilizat n contexte diferite, avnd aceeai
semnificaie sau o semnificaie diferit. Astfel operatorul + este suprancrcat pentru adunarea
ntregilor i a realilor; operatorul << este suprancrcat cu semnificaia de deplasare la stnga, dac
termenii sunt ntregi sau inserare n flux, dac un termen este un flux de date, iar cellalt un obiect.
Programatorul poate asocia noi semnificaii operatorilor existeni prin suprancrcarea
operatorilor. Vom evita folosirea termenului redefinire, cruia i vom da o semnificaie diferit, n
contextul motenirii.
Anumii operatori pot fi utilizai cu orice tip de termeni (sunt deja suprancrcai global de
ctre compilator). Acetia sunt: new, delete, sizeof, ::, =, &, ->*, .*, ., ->.
Pot fi suprancrcai urmtorii operatori:
+
&
| ~
<
>
+=
-=
*=
/=
%=
^=
&=
|=
>>=
&&
||
++
--
->*
->
<<
>>
new
new[]
delete
<<=
[]
==
!=
<=
>=
()
delete[]
Valeriu Iorga
Programare n C / C++
2. Funcii prieten.
n afara funciilor membre, datele private i cele protejate mai pot fi accesate de funciile
prieten (friend) ale clasei. O funcie este considerat prieten al unei clase, dac declararea funciei
precedate de specificatorul friend, apare n declararea clasei,. Definiia funciei prieten se face
global, n afara clasei.
Dac o funcie are ca parametri obiecte aparinnd la dou clase diferite, atunci ea poate fi
declarat ca funcie membru a unei clase i prieten al celeilalte clase, sau ca funcie prieten ambelor
clase.
De exemplu fie o funcie de nmulire a unei matrice cu un vector. Parametrii funciei vor fi
dou obiecte o matrice i un vector. Clasele respective Mat i Vec pot declara fiecare, funcia
MatVec() ca prieten:
class Mat{
int n;
double **m;
public:
Mat();
Mat(Mat&);
. . .
friend Vec MatVec(Mat&, Vec&);
};
class Vec{
int n;
double *v;
public:
Vec();
Vec(Vec&);
. . .
friend Vec MatVec(Mat&, Vec&);
};
De asemenea funciile prieten se utilizeaz n contextual suprancrcrii operatorilor.
Declararea unei funcii prieten poate fi fcut n orice parte a clasei (public, privat sau
protejat).
O funcie prieten a unei clase poate accesa toi membrii clasei. Dac o clas este prieten cu
alt clas, membrii ei pot accesa membrii celeilalte clase.
3. Modaliti de suprancrcare a operatorilor.
O funcie operator suprancrcat poate fi introdus ca funcie membr (n general nestatic)
sau funcie prieten (funcie nemembr).
Declararea unei funcii membr nestatic specific urmtoarele:
1) funcia poate accesa partea privat a declaraiei clasei
2) funcia este n domeniul clasei
3) funcia trebuie apelat dintr-un obiect
O funcie membr static satisface numai primele dou condiii, n timp ce o funcie prieten a
unei clase satisface numai prima condiie.
O funcie operator avnd ca prim argument un tip primitiv nu poate fi funcie membru.
Funciile care modific reprezentarea unui obiect necesit acces la datele membri, deci trebuie
s aparin clasei. Ele sunt funcii membrecu argumente referine neconstante.
Dac se doresc conversii implicite pentru termenii funciei operator, aceasta va fi funcie
nemembr cu argumente referine constante. Aceste funcii implementeaz operatorii care nu necesit
operanzi L-valori (adic se aplic tipurilor fundamentale). Acetia sunt n general operatorii binari.
Necesitatea accesului la reprezentare determin definirea lor ca funcii prieten.
Valeriu Iorga
Programare n C / C++
Operatorii care produc o nou valoare din valorile argumentelor (de exemplu operatorul+) se
definesc n afara clasei.
Dac nu sunt necesare conversii de tip, alegerea ntre funcie membru i funcie prieten
rmne la latitudinea programatorului.
O funcie nemembr folosete numai argumente explicite, n timp ce o funcie membr
folosete argumentul implicit this.
Argumentele clase, transmise prin valoare se copiaz n stiv neeconomic. Se prefer n acest
caz argumentele referine constante.
Dac valoarea ntoars de funcie este o referin, atunci aceasta nu poate fi o variabil
automatic (local funciei). Ea nu poate fi nici o variabil static local, deoarece operatorul poate fi
folosit de mai multe ori ntr-o expresie. Valoarea de ntoarcere trebuie s fie alocat n memoria liber
(heap) sau s fie preluat dintr-un buffer de obiecte statice.
ntoarcerea unei referine la obiectul modificat se realizeaz prin return *this.
Se caut minimizarea numrului de funcii care au acces la reprezentarea intern a unei clase,
prevzndu-se funcii de acces.
n mod obligatoriu sunt funcii membre: constructorii, destructorii, funciile virtuale, etc.
4. Operatori suprancrcai ca funcii prieten.
Operatorii folosii n mod uzual pot fi unari sau binari. Utilizarea unui operator binar sub
forma a#b este interpretat ca operator#(a,b)
Aadar, un operator binar va fi reprezentat printr-o funcie nemembr cu dou argumente, iar
un operator unar, printr-o funcie nemembr cu un singur argument.
Argumentele se iau clase sau referine constante la clase (pentru o preluare economic,
asigurnd protecia datelor)
Vom exemplifica pentru clasa Cplx:
class Cplx{
double re, im;
public:
Cplx(double x=0, double y=0);
Cplx(const Cplx& z);
//operatori
friend Cplx
friend Cplx
friend Cplx
friend Cplx
binari
operator+(const
operator-(const
operator*(const
operator/(const
Cplx&
Cplx&
Cplx&
Cplx&
s,
s,
s,
s,
const
const
const
const
Cplx&
Cplx&
Cplx&
Cplx&
d);
d);
d);
d);
//operatori de comparatie
friend int operator==(const Cplx& s, const Cplx& d);
friend int operator!=(const Cplx& s, const Cplx& d);
//operatori unari
friend Cplx operator-(const Cplx& z);
friend Cplx operator!(const Cplx& z); //conjugat
friend Cplx& operator++(Cplx& z);
//prefix
friend Cplx operator-(Cplx& z,int); //postfix
};
//definitii operatori n afara domeniului clasei
Cplx operator+(const Cplx& s, const Cplx& d){
return Cplx(s.re+d.re,s.im+d.im);
};
Cplx operator-(const Cplx& s, const Cplx& d){
return Cplx(s.re-d.re,s.im-d.im);
};
Valeriu Iorga
Programare n C / C++
//prefix
//postfix
Pentru a face deosebirea ntre semnturile funciilor operatori de incrementare prefix i postfix
s-a introdus un argument fictiv pentru cel din urm.
Incrementarea prefix ntoarce valoarea incrementat, deci trebuie s fie o L-valoare (rezultatul
ntors va fi o referin), n timp ce postincrementarea ntoarce valoarea dinaintea incrementrii.
5. Operatori suprancrcai ca funcii membri.
Funciilor membru li se transmite un argument implicit (ascuns) this (adresa obiectului, care
poate reprezenta primul termen), motiv pentru care un operator binar poate fi implementat printr-o
funcie membru nestatic cu un singur argument (termenul din dreapta operatorului). a#b este
interpretat ca a.operator#(b)
O funcie membru operator unar ca o funcie membru nestatic fr argumente ( #a se
interpreteaz ca a.operator#();
pentru operatorul postfixat a# convenia este
a.operator#(int) ).
n acest context, operatorii clasei Cplx se scriu:
Class Cplx{
double re, im;
public:
Cplx operator+(const Cplx& d);
Cplx operator-(const Cplx& d);
Cplx operator*(const Cplx& d);
Cplx operator/(const Cplx& d);
Cplx& operator+=(const Cplx& d);
Cplx& operator-=(const Cplx& d);
Cplx& operator*=(const Cplx& d);
Cplx& operator/=(const Cplx& d);
Valeriu Iorga
Programare n C / C++
Valeriu Iorga
Programare n C / C++
};
Cplx& Cplx::operator-(){
re=-re;
im=-im;
return *this;
};
Cplx& Cplx::operator!(){
im=-im;
return *this;
};
Cplx& Cplx::operator++(){
re++;
return *this;
};
Cplx Cplx::operator++(int){
Cplx t(re,im);
re++;
return t;
};
6. Suprancrcarea operatorului de atribuire.
Operaia de atribuire simpl, dac nu este suprancrcat, realizeaz o copiere membru cu
membru.
Pentru obiectele care nu conin date alocate dinamic la iniializare, atribuirea prin copiere
membru cu membru funcioneaz corect, motiv pentru care nu se suprancarc operatorul de atribuire.
Pentru clasele ce conin date alocate dinamic, copierea membru cu membru, executat n mod
implicit la atribuire conduce la copierea pointerilor la datele alocate dinamic, n loc de a copia datele.
Operatorul de atribuire poate fi redefinit numai ca funcie membr, el fiind legat de obiectul
din stnga operatorului =, o L-valoare, motiv pentru care va ntoarce o referin la obiect.
O prim cerin la scrierea funciei operator= este evitarea autoatribuirii a=a. n acest
scop se efectueaz testul this != &d (unde d este parametrul funciei -obiectul din dreapta
operatorului = .
Urmeaz apoi curirea membrului stng (eliberarea memoriei alocate dinamic). Copierea
propriu zis este fcut de obicei folosind constructorul de copiere.
Funcia operator returneaz o referin la obiectul modificat (return *this).
Exemplificm pentru clasa String, definit astfel:
class String{
char* s;
int n;
public:
String();
//c(onstruc)tor implicit
String(const char* p);
//ctor de initializare
String(const String& r);
//cr de copiere
~String();
//dtor
String& operator=(const String& d);
String& operator=(const char* p);
};
//ctor de copiere
String::String& operator=(const String& d){
if(this != &d){
//evitare autoatribuire
if(s)
//curatire
delete [] s;
Valeriu Iorga
Programare n C / C++
n=d.n;
//copiere
s=new char[n];
strncpy(s, d.s, n);
};
return *this;
};
Valeriu Iorga
Programare n C / C++
//y1=5.5
//y2=2*1.5+3=6
Definii un obiect funcie (functor) care genereaz termenul de rang n din irul lui Fibonacci.
class Fibo{
public:
Fibo():x(0),y(1){};
//constructor
long operator()(int n); //supraincarcare operator functie
Valeriu Iorga
Programare n C / C++
private:
long x, y;
};
long Fibo::operator ()(int n){
for(int i=2; i<=n; i++){
long z=x+y;
x=y;
y=z;
};
return x;
};
10. Suprancrcarea operatorilor de conversie.
n C++ la evaluarea unei expresii se efectueaz conversii implicite pentru tipurile predefinite.
Deoarece nu exist conversii implicite de la o clas la un tip predefinit, programatorul i poate defini
conversii explicite prin suprancrcarea unui operator de conversie al clasei. Astfel pentru clasa C,
funcia membru nestatic de conversie C::operator T() unde T este un nume de tip primitiv
realizeaz conversia de la tipul C la tipul T. Aceasta nu specific nici un tip de rezultat ntors, deoarece
se returneaz implicit valoarea obiectului convertit la tipul pentru care este definit conversia i nu are
parametri.
Funcia operator primete ca prim parametru implicit adresa obiectului i ntoarce valoarea
convertit de tipul numelui funciei operator de conversie.
Apelul explicit al funciei de conversie de la un obiect din clasa C la tipul primitiv T se
specific prin T(obiect) sau (T) obiect.
Pentru conversia unui obiect ntre dou clase C1 i C2,C1->C2 se definete funcia membru
operator de conversie C1::operator C2(); Pentru ca aceast funcie s aib acces la membrii
clasei C2, se declar funcie prieten clasei C2.
Sunt premise astfel conversii ntre o clas i un tip predefinit sau ntre dou clase, dar nu de la
un tip predefinit la o clas.
Constructorii cu un singur argument pot fi folosii ca funcii de conversie de la tipul
argumentului la clasa constructorului. Acest efect nu este ntotdeauna dorit, i pentru a-l evita,
constructorul se declar precedat de cuvntul cheie explicit.
Dac o metod a unei clase folosete parametri care sufer conversii implicite, metoda se va
defini ca funcie prieten, nu ca funcie membr.
Definim ca exemplu clasa Inch:
class Inch{
double inch;
double cm;
public:
explicit Inch(double i=0.) : inch(i){}; //ctor
void Inch_cm(){ cm=2.54*inch;};
operator int() const {return int(inch+0.5);}; //fctie conversie
}
11. Suprancrcarea operatorilor << i >>.
Operatorii de intrare / ieire pot fi suprancrcai. Operatorul de extracie >>, membru al clasei
istream servete pentru extragerea datelor de tipuri predefinite din fluxul de intrare cin. Prin
suprancrcarea operatorului putem extrage din fluxul de intrare f, obiecte ob, scriind f >> ob;
Funcia operator corespunztoare are semntura:
istream& operator >> (istream& f, clasa & ob);
Valeriu Iorga
Programare n C / C++
Operatorul de inserie <<, membru al clasei ostream servete pentru depunerea datelor de
tipuri predefinite n fluxul de ieire cout. Suprancrcarea operatorului permite depunerea de obiecte
ob n fluxul de ieire f cu f << ob;
ostream& operator << (ostream& f, const clasa & ob);
ntruct ambele funciile operatori ntorc referine la fluxuri (prin return f), operatorii pot
fi nlnuii.(f << o1 << o2;)
Funciile operator pentru suprancrcarea operatorilor de intrare / ieire se declar funcii
prieten al clasei care interacioneaz cu fluxul.
Exemplificm cu clasele Cplx i String:
class Cplx{
double re,im;
public:
friend ostream& operator<<(ostream& os, const Cplx& z);
friend istream& operator>>(istream& is, Cplx& z);
};
ostream& operator<<(ostream& os, const Cplx& z){
os << ( << z.re <<, << z.im << ) << endl;
return os;
};
istream& operator>>(istream& is, Cplx& z){
is >> z.re >> z.im;
return is;
};
class String{
int n;
char *s;
public:
. . .
friend ostream& operator<<(ostream&os,const String& w);
friend istream& operator>>(istream& is, String& w);
};
ostream& operator<<(ostream& os,const String& w){
for(int i=0; i<w.n; i++)
os << w.s[i];
return os;
};
istream& operator>>(istream& is, String& w){
char zona[100];
is.get(zona,100);
w=zona;
return is;
};
12. Probleme.
1. O expresie ptratic de o variabil are forma: ax2+bx+c n care numerele a,b,c (coeficienii)
au valori fixate, iar variabila x poate lua diferite valori.
Specificai,proiectai i implementai clasa Patrat, care poate pstra informaii
asupra unei expresii ptratice.
Un constructor implicit seteaz cei 3 coeficieni la zero.
Se vor prevedea funcii membru pentru:
- schimbarea coeficienilor
- aflarea valorii curente a coeficienilor
- evaluarea unei expresii ptratice pentru un x dat
10
Valeriu Iorga
Programare n C / C++
11
Valeriu Iorga
Programare n C / C++
12