Sunteți pe pagina 1din 149

Clase si obiecte

Clase si obiecte
Clasa = tip de date definit de utilizator, care incapsuleaza atat partea de
structura (date) cat si partea procedurala (metode = functii +
operatori de prelucrare)
= are la baza abstractizarea unei “entitati” (concept),
reprezerntand formalizarea computationala a acesteia
Obiect = variabila (instantiere) care are ca tip de date o clasa
Sintaxa declaratiei: class numeClasa;
Sintaxa definitiei: class numeClasa
(caz clasa nederivata) { declaratii/defintii date/metode (private)
specificator de acces:
declaratie/defintie date/metode
specificator de acces:
declaratie/defintie date/metode
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
}[lista_obiecte];
Clase si obiecte
Specificatori de acces

public = date / functii membre la care exista acces SI DIN exteriorul


clasei (si din interior).
private = date / functii membre la care exista acces NUMAI din
interiorul clasei
protected = membri privati (fara acces din exteriorul clasei), dar la
care AU ACCES clasele derivate

Obs.: - specificatorul de acces stabileste tipul de acces asupra


tuturor membrilor declarati / definiti dupa el, pana la aparitia
urmatorului specificator de acces.

- la inceputul blocului de definitie al clasei, in lipsa unui


specificator de acces, membri au tip de acces implicit private
Clase si obiecte
Specificatori de acces

Ex.: class nr_complex


{ [ private: ]
double re; Zona membri private
double im;
public:
nr_complex adunare(nr_complex n1)
{ nr_complex rez;
rez.re=n1.re+re;
rez.im=n1.im+im; Zona membri public
return rez;
};

nr_complex inmultire(nr_complex);

};
Clase si obiecte
Specificatori de acces

Ex.: class nr_complex


{ [ private: ]
double re; Zona membri private
double im;
public:
nr_complex adunare(nr_complex n1)
{ nr_complex rez;
rez.re=n1.re+re;
Defintitie functie rez.im=n1.im+im; Zona membri public
return rez;
}

nr_complex inmultire(nr_complex);

};

Declaratie functie
Clase si obiecte. Date si functii membre.

Date si functii membre

Datele membre trebuie, in general, protejate (private, protected),


cf. mecansimul de ascundere a datelor (discutat deja)

Functiile membre sunt publice, in general, pentru a putea fi apelate in


prelucrarea datelor clasei respective.
dar:
In cazul in care algoritmul de implementat este complex, se
recomanda o abordare procedurala - impartirea implementarii
in blocuri functionale - functiile ajutatoare avand acces privat,
neavand utilitate externa.
Clase si obiecte. Date si functii membre.

Membri privati ai unei clase


domeniu de definite = domeniul clasei
(sunt cunoscuti in interiorul clasei)

Membri publici ai unei clase


domeniu de definite = domeniul de definitie al clasei
(sunt cunoscuti acolo unde este
definita/cunoscuta clasa)
#include . . . . . .
. . . . . . . . . . .
Domeniul de definitie al clasei class nume
{. . . D e f i n i t i e c l a s a . . .
};
incepe cu definirea clasei . . . . . . . . . . .
int main()
{
se termina la sfarsitul fisierului . . . . . . . . . . .
}
. . . . . . . . . . .
Clase si obiecte. Date si functii membre.

Functiile membre pot fi definite:


in interiorul definitiei clasei, cu sintaxa clasica:
class nume_clasa
{ . . . . . . . Definitie Clasa . . . . . . .

tip_returnat nume_functie(lista argumente)


{
. . . . . . . Corpul Functiei . . . . .
}
};

in exteriorul definitiei clasei, cu sintaxa:

tip_returnat nume_clasa :: nume_functie(lista argumente)


{
. . . . . . . . Corpul Functiei . . . . . . .
}
Clase si obiecte. Date si functii membre.
Exemplu:
class cl
{ int a; //membri private
float b;
public:
void init() // definitie in interior
{ a = b = 0;
}
void set(int,float); //delaratie fct. membra
void afisare();
};
void cl::afisare() //definitie in exteriorul clasei
{ cout << “a=” << a << endl;
cout << “b=” << b << endl;
}
void cl::set(int a1, float b1)
{ a = a1;
b = b1;
}
Clase si obiecte. Date si functii membre.
Exemplu:
class cl
{ int a; //membri private
float b;
public:
void init() // definitie in interior
{ a = b = 0;
}
void set(int,float); //delaratie fct. membra
void afisare();
};
void cl::afisare() //definitie in exteriorul clasei
{ cout << “a=” << a << endl;
cout << “b=” << b << endl;
}
Diferenta intre lista
void cl::set(int a1, float b1) argumente de la
{ a = a1; declaratie si definitie
b = b1;
}
Clase si obiecte. Date si functii membre.

Accesul la membri publici ai unui obiect se face cu operatorii:

. cu sintaxa: Nume_Obiect.membru
-> cu sintaxa: Nume_PointerObiect -> membru

Exemplu:
int main()
{ cl ob1; //definitie obiect
ob1.init(); // acces/apel functie membra
ob1.afisare();
ob1.set(2,3.5);
ob1.afisare();
cl *p_ob; //definitie pointer obiect
p_ob=&ob1;
p_ob->set(20,13.5);// acces/apel functie membra
p_ob->afisare();
}
Clase si obiecte. Date si functii membre.

Obs.: Cat timp o clasa NU a fost definita , ci doar declarata,


NU se pot defini obiecte din clasa respectiva, dar
se pot defini pointeri avand tip de baza clasa respectiva

Exemplu:
class K; // declaratie clasa

K ob; // eroare, trebuie cunoscuta


// dimensiunea memoriei de alocat

K* p_ob; // corect, se aloca memorie


// pentru un pointer
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Pointerul this
Mecanismul de administrarea a apelurilor de functie membra
Exemplu: class cl
{ int a;
float b;
public:
void SetData(int a1, float b1)
{ a = a1;
b = b1;
}
void Afisare()
{ cout << “a=” << a << endl;
cout << “b=” << b << endl;
}
};
int main()
{ . . . . . . . . . .
cl ob1,ob2;
ob1.SetData(2,3.5);
ob2.SetData(5,1.7);
. . . . . . . . . .
}
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Cum se aloca memoria obiectelor?
La definirea unui obiect:
- se aloca spatiu de memorie pentru intreaga structura de date proprie
(obiectele diferite contin valori diferite),
- partea de procesare a datelor se pastreaza intr-o zona de memorie
comuna, alocata la definirea clasei
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Cum se aloca memoria obiectelor?
La definirea unui obiect:
- se aloca spatiu de memorie pentru intreaga structura de date proprie
(obiectele diferite contin valori diferite),
- partea de procesare a datelor se pastreaza intr-o zona de memorie
comuna, alocata la definirea clasei Zona memorie
Exemplu:
class cl
{ int a; cl
float b; SetData Implementare
public: functie
void SetData(int a1, float b1) Afisare Implementare
{ . . . . . . . . } functie
void Afisare()
{ . . . . . . . . } ob1
}; a 2
int main() b 3.5
{ . . . . . . . . . .
cl ob1,ob2; ob2
ob1.SetData(2,3.5); a 5
ob2.SetData(5,1.7);
b 1.7
. . . . . . . . . .
}
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Cum se aloca memoria obiectelor?
La definirea unui obiect:
- se aloca spatiu de memorie pentru intreaga structura de date proprie
(obiectele diferite contin valori diferite),
- partea de procesare a datelor se pastreaza intr-o zona de memorie
comuna, alocata la definirea clasei Zona memorie
Exemplu:
class cl
{ int a; cl
float b; SetData Implementare
public: functie
void SetData(int a1, float b1) Afisare Implementare
{ . . . . . . . . } functie
void Afisare()
{ . . . . . . . . } ob1
}; a 2
int main() b 3.5
{ . . . . . . . . . .
cl ob1,ob2; ob2
ob1.SetData(2,3.5); a 5
ob2.SetData(5,1.7);
b 1.7
. . . . . . . Cum
. . se.face apelul de functie daca exista o
} singura implementare, obiecte/date diferite ?
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Cum se face apelul de functie daca exista o singura implementare,
obiecte/date diferite ?
In implementare exista variabilele a si b care, la apel, trebuie particularizate
cu datele membre ale fiecarui obiect:
ob1.a ob1.b ob2.a ob2.a
Zona memorie
Exemplu:
class cl
{ int a; cl
float b; SetData
void SetData(int a1, float b1)
public: { a = a1;
void SetData(int a1, float b1) b = b1;
{ . . . . . . . . } }
void Afisare() Afisare
{ . . . . . . . . } void Afisare()
}; { cout << “a=” << a << endl;
int main() cout << “b=” << b << endl;
}
{ . . . . . . . . . .
cl ob1,ob2;
ob1.SetData(2,3.5);
ob2.SetData(5,1.7);
. . . . . . . . . .
}
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Cum se face apelul de functie daca exista o singura implementare,
obiecte/date diferite ?
In implementare exista variabilele a si b care, la apel, trebuie particularizate
cu datele membre ale fiecarui obiect:
ob1.a ob1.b ob2.a ob2.a
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Cum se face apelul de functie daca exista o singura implementare,
obiecte/date diferite ?
In implementare exista variabilele a si b care, la apel, trebuie particularizate
cu datele membre ale fiecarui obiect:
ob1.a ob1.b ob2.a ob2.a

Solutie: La apelul functiilor membre se transmite in plus un argument


ascuns, ponterul la obiectul curent, care se numeste this
this  este un pointer constant la obiectul curent (nu se poate modifica),
care are tipul de date:
nume_clasa* const this
 este cuvant cheie al limbajului, se foloseste strict numai pentru
transmiterea / accesarea adresei obiectului curent
 se defineste implicit in momentul definirii obiectului
 se poate apela/utiliza si in mod explicit, desi utilizarea implicita este
suficienta
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Exemplu:
void cl::SetData(int a1,float b1)
{ a = a1;
b = b1;
}

In realitate mecanismul de apel (ascuns) este

void cl::SetData(int a1,float b1, cl* const this)


{ this->a = a1;
this->b = b1;
}

Apelarea standard echivalenta cu


ob1.SetData(2, 3.5) ob1.SetData(2, 3.5, &ob1)
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Exemplu:
void cl::SetData(int a1,float b1)
{ a = a1;
b = b1;
}

In realitate sintaxa (ascunsa este)

void cl::SetData(int a1,float b1, cl* const this)


{ this->a = a1;
this->b = b1;
} NU se foloseste niciodata aceasta
Modul de apelare EXPLICITA a sintaxa, este scrisa numai in scop
datelor membre, este corecta didactic, de a explica modul de
transmitere a pointerului la
Totusi scrierea IMPLICITA este obiectul curent, pentru a identifica
cea dorita/utilizata datele membre

Apelarea standard echivalenta cu


ob1.SetData(2, 3.5) ob1.SetData(2, 3.5, &ob1)
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Problema: Nu se pot apela functiile membre pentru argumentele transmise prin
pointer/referinta constanta la un obiect

void fct_afisare_obiect(const cl* ob)


{ . . . . . . . .

ob->Afisare(); Eroare: “cannot convert this pointer


. . . . . . . .
from const class cl* to class cl* const”
}

Explicatie: pointerul this transmis catre functia Afisare() are tipul:

const cl* const this

Definirea argumentului de functie Definirea pointerului this


const cl* cl* const

Adica un pointer a carui valoare nu se poate modifica SI prin care nu se poate


modifica obiectul indicat (pointer const la obiect const) care nu permite accesul
la functia membru Afisare()
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Problema: Nu se pot apela functiile membre pentru argumentele transmise prin
pointer/referinta constanta la un obiect

S-a ajuns la un IMPAS:


- Intentia de a utiliza argument al functiei un pointer (referinta)
la obiect const. este de a transmite date cu INTERZICEREA
modificarii obiectului, lucru care se si intampla, insa
- Ca efect secundar se obtine si BLOCAREA accesului la
functiile membre

Solutia: Limbajul C++ ofera un mecanism de acces la functiile membre,


in astfel de situatii, prin declararea acestora de tip const
Sintaxa:
void cl::Afisare() const
{ cout << a << b << endl;
}
Obs: In sintaxa de baza nu exista solutie, astfel ca mecanismul este
adaugata “fortat” la limbaj ca solutie de iesire din impas
Clase si obiecte. Functii membre inline
Functii membre inline

Exista functii membre mici/simple care se apeleaza des (ex. fct de


interfata: citire/modificare date, etc). In astfel de situatii consumul de
resurse (memorie pt. copiere date la apel si timp de apel) sunt mai mari
decat executia procedurii in sine

In astfel de situatii se prefera declararea respectivelor functii ca

inline  la compilare, apelul de functie este inlocuit fizic cu


corpul functiei (operatie de expandare a codului)

Consecinte: - se elimina intregul mecanism de apel (impreuna cu


consumul de resurse)
- CRESTE dimensiunea programului sursa, motive pentru
care se evita definirea inline a functiilor de dimensiuni
mari
Clase si obiecte. Functii membre inline
Functii membre inline

Restrictii:

- functiile inline NU pot fi declarate extern (pot fi


utilizate numai in modului de program in care au fost definite

- functiile inline NU pot contine instructiuni de ciclare


(while, for, do-while). Daca NU se respecta aceasta regula,
atunci in mod implicit, se NEGLIJEAZA atributul inline
Clase si obiecte. Functii membre inline
Functii membre inline
O functie membra care este definita in interiorul definitiei clasei este, in
mod implicit, de tip inline
ATENTIE!! ce functii definiti in interiorul clasei
Exemplu: class cl
{ int a;
float b;
public:
void SetData(int a1, float b1) //functie
{ a = a1; //definita implicit inline
b = b1;
}
int geta();
};

inline int cl::geta() //functie definita explicit inline


{ return a;
}
Clase si obiecte. Pointeri la date si functii membre
Pointeri la date si functii membre
Adresa la un membru al clasei se obtine cu operatorul de adresare &
specificand clasa din care face parte:

Sintaxa: & clasa :: membru data/functie

Tipurile de date pentru definirea/declararea unui pointer la membri


clasei au sintaxa:

Pentru date:
tip_date clasa::*nume_p_var;

Pentru functii:

tip_returnat (clasa::*nume_p_fct)(lista argumente);


Clase si obiecte. Pointeri la date si functii membre
Exemplu:
class cl
{ int a;
int cl::*pdm;
public:
int b; pdm = & cl::a;// eroare,
// a privat
void Set_a(int
a1) pdm = & cl::b; // corect
{ a = a1; cout << pob->*pdm << endl;
}
cout << op1.*pdm << endl;
int get_a()
{ return a; void (cl::*pfm)(int);
}
}; pfm = &cl::Set_a;

void main() (ob1.*pfm)(7); // ob1.a=7


{ cl ob1, ob2; (pob->*pfm)(5);// ob2.a=5
ob1.Set_a(3);
. . . . . . . . . . . .
cl *pob = &ob2;
} //sfarsit main
pob -> Set_a(5);
Clase si obiecte. Incapsularea datelor

Incapsularea datelor
Tehnica incapsularii reprezinta impachetarea la un loc, intr-un singur
tip (abstract) de date, a structurii de date cat si a procedurilor de
prelucrare a acestora.
Accesarea datelor membre se poate face direct, daca specificatorul lor
de acces este public
class cl
{ . . . . . . . . .
public:
int a;
. . . . . . . . .
};
void main()
{ cl ob1;
ob1.a = 3;
}
Clase si obiecte. Incapsularea datelor

Accesarea datelor membre declarate public vs. private

Desi o astfel de abordare este corecta, prezinta riscul modificarii


accidentale a datelor membre. Motiv pentru care, este de dorit ca,
tehnica de incapsulare a datelor sa fie insotita si de:
mecanismul de ascundere a datelor (data hidding):
- datele membre sunt definte cu grad de acces protejat ( private sau
protected )
- astfel de blocheaza accesul direct la datele membre
- accesul la aceste date membre se face numai prin intermediul
functiilor de interfata
Clase si obiecte. Incapsularea datelor

Accesarea datelor membre declarate public vs. private

Exemplu: class cl
{ int a;
float b;
public:
void SetData(int a1, float b1)
{ a = a1;
b = b1;
}
int Get_a();
{ return a;
}
};

Comentariu: Accesul poate fi diferentiat, ex.: nu am voie sa citesc b


Clase si obiecte. Date membre de tip static

Date membre de tip static

O data membra declarata static se creaza o singura data pentru clasa


in care a fost definita, indiferent de numarul de obiecte create din clasa
respectiva. Deci se aloca memorie pentru o singura variabila, care va fi
comuna tuturor obiectelor definite din clasa respectiva

Introducerea unei variabile statice in definita unei clase se face NUMAI


printr-o declaratie

In mod obligatoriu o variabila membra declarata static trebuie definita


in afara blocului de definitie a clasei (unde nu se mai foloseste cuvantul
cheie static )
Clase si obiecte. Date membre de tip static

Exemplu:
class cl
{ int a;
static int b;
. . . . . . . . .
};
. . . . . . . . . . . .

int cl::b;

Obs: Ca orice variabila statica, data membra declarata statica se


initializeaza la definire in mod implicit cu valoarea 0, sau se poate
initializa explicit cu o valoare dorita de utilizator:

int cl::b = 5;
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main()
{ public: { cl ob1, ob2; //creare
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3);
void incr_a(){a++;}
void incr_b(){b++;} ob1.incr_a();
. . . . . . . . . ob1.incr_b();
};
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main() cl::b
{ public: { cl ob1, ob2; //creare 5
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3);
void incr_a(){a++;}
void incr_b(){b++;} ob1.incr_a();
. . . . . . . . . ob1.incr_b();
};
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main() cl::b
{ public: { cl ob1, ob2; //creare 5
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3); ob1.a
void incr_a(){a++;}
void incr_b(){b++;} ob1.incr_a();
. . . . . . . . . ob1.incr_b();
};
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main() cl::b
{ public: { cl ob1, ob2; //creare 5
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3); ob1.a
void incr_a(){a++;}
void incr_b(){b++;} ob1.incr_a(); ob2.a
. . . . . . . . . ob1.incr_b();
};
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main() cl::b
{ public: { cl ob1, ob2; //creare 5
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3); ob1.a
void incr_a(){a++;}
1
void incr_b(){b++;} ob1.incr_a(); ob2.a
. . . . . . . . . ob1.incr_b();
}; 3
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main() cl::b
{ public: { cl ob1, ob2; //creare 6
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3); ob1.a
void incr_a(){a++;}
2
void incr_b(){b++;} ob1.incr_a(); ob2.a
. . . . . . . . . ob1.incr_b();
}; 3
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

Domeniul de existenta al datelor membre statice


O data membra declarata static exista (este creata) din locul definirii
sale, inaintea crearii primului obiect din clasa respectiva
Exemplu:
class cl int main() cl::b
{ public: { cl ob1, ob2; //creare 7
int a;
static int b; ob1. Set_a(1);
Set_a (int a1){a=a1;} ob2. Set_a(3); ob1.a
void incr_a(){a++;}
2
void incr_b(){b++;} ob1.incr_a(); ob2.a
. . . . . . . . . ob1.incr_b();
}; 4
. . . . . . . . . . . . ob2.incr_a();
ob2.incr_b();
int cl::b = 5; // creare b; }
//aloc memorie, etc
. . . . . . . . . . . .
Clase si obiecte. Date membre de tip static

O data membra statica poate fi apelata, daca este publica :

- prin intermediul numelui clasei:

cl :: b = 5;

- prin intermediul numelui obiectelor create din clasa respectiva:

ob1 . b = 5;
Clase si obiecte. Date membre de tip static

Functii membre de tip static

- Pot fi definita in interiorul sau in exteriorul blocului de definite al


clasei
- Au domeniul de vizibilitatea limitat la fisierul in care a fost definite
- Sunt functii comune tuturor obiectelor definite din clasa respectiva =>
- NU primesc pointer this
- NU pot folosi date membre proprii obiectelor, ci numai date
membre statice.
Clase si obiecte. Date membre de tip static

Functii membre de tip static

Exemplu:

Functie pentru contorizarea nr de obiecte create la momentul curent

class cl int main()


{ static int nr_ob; { cl ob;
public: . . . . . . . . . .
static int Get_nr_ob() cout<<cl::Get_nr_ob();
{ return nr_ob; }
}
};

int cl::nr_ob;
Clase si obiecte. Date membre de tip static

Functii membre de tip static

Pot fi apelate

- fie prin numele unui obiect

ob.Get_nr_ob();

- fie prin numele clasei

cl::Get_nr_ob();
Clase si obiecte. Structurile in C++

Structurile in C++
Structurile sunt similare claselor, pot contine date si proceduri
membre, permit si mosteniri (operatii de derivare) etc.
Singura deosebire este ca tipul de acces la membri unei structuri sunt
in mod implicit de tip public

Spre deosebire de limbajul C, in acest caz numele nou creat este fara
cuvantul cheie struct

Ex.: struct nr_complex


{ double re;
double im;
};
int main()
{ nr_complex n1={1.2,5.7};
cout<<n1.re<<‘ ‘<<n1.im<<endl;
}
Clase si obiecte. Constructori si destructori

Constructori
- Functii (speciale) care sunt apelate automat in momentul
definirii/contruirii unui obiect
- Sunt folositi in general pentru initializarea obiectelor (date membre)
- Pentru aceeasi clasa se pot definii mai multi contructori, ca functii
supraincarcate (alegerea la apel se face dupa regula celei mai bune
potriviri a listei de argumente)

Sintaxa: - numele unui constructor este identic cu cel al clasei


- NU are tip returnat

class nume_clasa
{ . . . . . .
public:
nume_clasa(lista argumente){. . . . }
. . . . . .
};
Clase si obiecte. Constructori si destructori

Constructori
Prin definitie, contructorul implicit este constructorul cu lista de
argumente vida

class nume_clasa
{ . . . . . .
public:
nume_clasa()
. . . . . .
};

Daca NU este implementat explicit NICIUN constructor, atunci


compilatorul genereaza automat un contructor implicit vid:

nume_clasa()
{
}
Clase si obiecte. Constructori si destructori

Constructori
Constructorii trebuie sa aiba specificatori de acces de tip public,
pentru a putea fi apelati de oricunde este nevoie sa definim obiecte din
clasa respectiva
Clase si obiecte. Constructori si destructori

La crearea unui obiect dintr-o clasa, pentru care s-au definit mai multi
constructori, se va apela acel contructor pentru care se potrivesc cel mai
bine argumentele reale (de apel) cu cele formale al contructorului
(conform regulilor de la functii supraincarcate)
class cl int main()
{ int a,b; { cl ob1;
public: cl ob2(3);
cl() cl ob3(4,5);
{ a = b = 0; }
}
cl(int c)
{ a = b = c;
}
cl(int a1, int b1)
{ a = a1;
b = b1;
}
};
Clase si obiecte. Constructori si destructori

La crearea unui obiect dintr-o clasa, pentru care s-au definit mai multi
constructori, se va apela acel contructor pentru care se potrivesc cel mai
bine argumentele reale (de apel) cu cele formale al contructorului
(conform regulilor de la functii supraincarcate)
class cl int main()
{ int a,b; { cl ob1;
public: cl ob2(3);
cl() cl ob3(4,5);
{ a = b = 0; }
}
cl(int c)
{ a = b = c;
}
cl(int a1, int b1)
{ a = a1;
b = b1;
}
};
Clase si obiecte. Constructori si destructori

Constructorul se apeleaza si la crearea unui obiect prin alocare dinamica

class cl int main()


{ int a,b; { cl ob1;
public: cl ob2(3);
cl() cl ob3(4,5);
{ a = b = 0;
} cl *pob;
pob = new cl(2,3);
cl(int c)
delete pob;
{ a = b = c;
}
pob = new cl(2);
cl(int a1, int b1) delete[] pob;
{ a = a1; }
b = b1;
}
};
Clase si obiecte. Constructori si destructori

Constructorul se apeleaza si la crearea unui obiect prin alocare dinamica

Obs.: Constructorul NU se apeleaza la alocarea dinamica multipla

class cl int main()


{ int a,b; { cl ob1;
public: cl ob2(3);
cl() cl ob3(4,5);
{ a = b = 0;
} cl *pob;
pob = new cl(2,3);
cl(int c)
delete pob;
{ a = b = c;
}
pob = new cl(2);
cl(int a1, int b1) delete[] pob;
{ a = a1; // vs.
b = b1; pob = new cl[2];
} delete[] pob;
}; }
Clase si obiecte. Constructori si destructori

Constructorii se folosesc in general pentru operatiile de initializare a


datelor membre. Daca clasa contine date de tip pointer, este bine sa
adminstram operatiile de alocare a memoriei prin constructori:
class vector
{ int l;
double *v;
public:
vector()
{ l = 0;
v = NULL;
}
vector(int lung_vect)
{ l = lung_vect;
v = new double[l];
if(!v)
exit(0);
}
};
Clase si obiecte. Constructori si destructori

Destructori
- Functii (speciale) care sunt apelate automat in momentul distrugerii
unui obiect, inclusiv cand acesta este alocat dinamic (utilizand delete)
- Sunt folositi in general pentru operatiile necesare administrarii datelor
membre inainte de distrugerea obiectelor
- NU se supraincarca
Sintaxa: - numele unui destructor este identic cu cel al clasei la care
se adauga prefixul ~ (tilda)
- NU are tip returnat
- NU are lista de argumente
class nume_clasa
{ . . . . . .
public:
~nume_clasa(){. . . . . . }
. . . . . .
};
Clase si obiecte. Constructori si destructori

Destructori
- Daca nu este definit explicit de utilizator, compilatorul genereaza
automat un destructor vid:

~nume_clasa()
{
}
Clase si obiecte. Constructori si destructori

Mecanismul de construire – distrugere a unui obiect

{ cl ob;

. . . . . .
}
Clase si obiecte. Constructori si destructori

Mecanismul de construire – distrugere a unui obiect

Succesiunea etapelor

{ cl ob; 1. Alocarea memoriei pentru


datele membre nestatice
. . . . . . 2. Daca este cazul, operatii
} legate de mostenire (clase
derivate)
3. Apel constructor
Clase si obiecte. Constructori si destructori

Mecanismul de construire – distrugere a unui obiect

Succesiunea etapelor

{ cl ob; 1. Alocarea memoriei pentru


datele membre nestatice
. . . . . . 2. Daca este cazul, operatii
} legate de mostenire (clase
derivate)
3. Apel constructor
. . . . . . . . . . .
1. Apel destructor
Clase si obiecte. Constructori si destructori

Mecanismul de construire – distrugere a unui obiect

Succesiunea etapelor

{ cl ob; 1. Alocarea memoriei pentru


datele membre nestatice
. . . . . . 2. Daca este cazul, operatii
} legate de mostenire (clase
derivate)
3. Apel constructor
. . . . . . . . . . .
1. Apel destructor
2. Eliberarea spatiului de
memorie
Clase si obiecte. Constructori si destructori

Destructori
Similar constructorilor, daca clasa contine date de tip pointer, este bine
sa adminstram operatiile de dealocare a memoriei prin destructori:
class vector
{ int l;
double *v;
public:
vector(){ l = 0; v = NULL; }
vector(int lung_vect)
{ l = lung_vect;
v = new double[l];
if(!v) exit(0);
}
~vector()
{ if (v)
{ delete[] v;
v = NULL;
}
}
};
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere
- Caz particular de constructor, in care argumentul este o referinta la un
obiect din aceeasi clasa
- Scopul utilizari unui astfel de constructor este crearea unui obiect
identic cu cel trimis prin argument

Sintaxa: nume_clasa(nume_clasa &r)


{ initializarea datelor membre ale obiectului curent
cu datele membre ale obiectului r
}
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere
class cl int main()
{ int a; { cl ob1;
float b; cl ob2(2, 3.5);
public:
cl(){ a = 0; b = 0; } cl ob3(ob1);
cl(int a1, float b1) cl ob4 = ob2;
{ a = a1;
b = b1; cl *pob;
} pob = new cl(ob3);

cl(cl &r) }
{ a = r.a;
b = r.b;
}
};
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere
class cl int main()
{ int a; { cl ob1;
float b; cl ob2(2, 3.5);
public:
cl(){ a = 0; b = 0; } cl ob3(ob1);
cl(int a1, float b1)
{ a = a1;
cl ob4 = ob2; ?
b = b1; cl *pob;
} pob = new cl(ob3);

cl(cl &r) }
{ a = r.a;
b = r.b;
}
};
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere
class cl int main()
{ int a; { cl ob1;
float b; cl ob2(2, 3.5);
public:
cl(){ a = 0; b = 0; } cl ob3(ob1);
cl(int a1, float b1)
{ a = a1;
cl ob4 = ob2; ?
b = b1; cl *pob;
} pob = new cl(ob3);

cl(cl &r) }
{ a = r.a;
b = r.b; La initializarea unui obiect la
} definire, se apeleaza
}; constructorul de copiere.
NU este o operatie de atribuire
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere

Daca constructorul de copiere NU este definit explicit de catre utilizator,


compilatorul genereaza automat un constructor de copiere implicit
care copiaza, intre obiectul argument si cel curent, datele membru cu
membru

In exemplul anterior, constructorul de copiere implementat este


echivalent cu constructorul de copiere implicit, DECI el NU este
necesar, aplicatia ar fi fost functionat la fel (si corect) fara
implementarea explicita a constructorului de copiere.
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere

Constructorul de copiere este folosit in apelul de functie, cand se


copiaza obiectul real (de apel) in cel formal:

void fct(cl ob) int main()


{ . . . . . . { cl ob1(2,5);
} fct(ob1);
}
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere

Constructorul de copiere este folosit in apelul de functie, cand se


copiaza obiectul real (de apel) in cel formal:

void fct(cl ob) int main()


{ . . . . . . { cl ob1(2,5);
Se executa:
} cl ob = ob1; fct(ob1);
}
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere. Cazul datelor membre cu alocare dinamica

class vector
{ int l;
double *v;
public:
vector() ~vector()
{ l = 0; { if (v)
v = NULL; { delete[] v;
} v = NULL;
vector(int lung_vect) }
{ l = lung_vect; }
v = new double[l];
if(!v) exit(0); };
}
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere. Cazul datelor membre cu alocare dinamica


int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
vector v2 = v1;
. . . . . . . .
?
}
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere. Cazul datelor membre cu alocare dinamica


int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
vector v2 = v1;
. . . . . . . .
?
} Se apeleaza constructorul de
copiere implicit = Se copiaza
datele membru cu membru
Clase si obiecte. Constructori si destructori. Constructori de copiere

Constructori de copiere. Cazul datelor membre cu alocare dinamica


int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
vector v2 = v1; v2
. . . . . . . . 5
Se apeleaza constructorul de adr1
}
copiere implicit = Se copiaza
datele membru cu membru

Rezultat: Obiectele v1 si v2 partajeaza aceeasi zona de memorie


Orice modificare facuta in datele lui v1 se concretizeaza
si in modificarea datelor lui v2, si invers.

Intrebare: Este bine? Este rau?


Comentarii: . . . . . . . .
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Modificam exemplul:
int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
{ vector v2 = v1; v2
. . . . . . . . 5
} adr1
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Modificam exemplul:
int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
{ vector v2 = v1; v2
. . . . . . . . 5

}
} ? adr1
Ce se intampla la
iesirea din bloc?
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Modificam exemplul:
int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
{ vector v2 = v1; v2
. . . . . . . . 5

}
} ? adr1
Ce se intampla la
iesirea din bloc?
1. Se apeleaza destructorul lui v2 => eliberarea spatiului de
memorie alocat datei membre v
2. Se distruge variabila statica v2 => eliberarea spatiului de
memorie alocat obiectului v2
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Modificam exemplul:
int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
{ vector v2 = v1;
. . . . . . . .

}
} ?
Ce se intampla la
iesirea din bloc?
1. Se apeleaza destructorul lui v2 => eliberarea spatiului de
memorie alocat datei membre v
2. Se distruge variabila statica v2 => eliberarea spatiului de
memorie alocat obiectului v2

Ce se obtine in final???
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Modificam exemplul:
int main() v1 adr1
{ vector v1(5); 5
. . . . . . . . adr1
{ vector v2 = v1;
. . . . . . . .

}
} ?
Ce se intampla la
iesirea din bloc?
1. Se apeleaza destructorul lui v2 => eliberarea spatiului de
memorie alocat datei membre v
2. Se distruge variabila statica v2 => eliberarea spatiului de
memorie alocat obiectului v2

Ce se obtine in final??? O variabila alocata dinamic, care indica/foloseste


o zona de memorie care a fost dealocata
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
void fct(vector v)
{
. . . . . . . . .
}

int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
void fct(vector v)
{
. . . . . . . . .
}

int main()
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
void fct(vector v)
{
. . . . . . . . .
} Apel de functie  copiere
variabile de apel in param.
formali ai functie
int main()
vector v = v1
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}

Obiect definit local (blocul de def. al functiei),


initializat cu un obiect similar deja initializat,
care are data membra alocata dinamic =>
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
v
void fct(vector v)
{
. . . . . . . . .
} Apel de functie  copiere
variabile de apel in param.
formali ai functie
int main()
vector v = v1
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}

Obiect definit local (blocul de def. al functiei),


initializat cu un obiect similar deja initializat,
care are data membra alocata dinamic =>
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
v
void fct(vector v) 5
{ adr1
. . . . . . . . .
} Apel de functie  copiere
variabile de apel in param.
formali ai functie
int main()
vector v = v1
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}

Obiect definit local (blocul de def. al functiei),


initializat cu un obiect similar deja initializat,
care are data membra alocata dinamic =>
partajeaza aceeasi zona de memorie
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
v
void fct(vector v) 5
{ adr1
. . . . . . . . .
}
?
int main()
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}

partajeaza aceeasi zona de memorie


Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
v
void fct(vector v) 5
{ adr1
. . . . . . . . .
}
?
int main()
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}
Probleme la intoarcerea din
apelul de functie 
distrugerea ob. def. local

partajeaza aceeasi zona de memorie


Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
v
void fct(vector v) 5
{ adr1
. . . . . . . . .
}
?
int main()
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}
Probleme la intoarcerea din 1. Apel destructor =
eliberare spatiu de
apelul de functie  memorie alocat dinamic
distrugerea ob. def. local

partajeaza aceeasi zona de memorie


Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
v
void fct(vector v) 5
{ adr1
. . . . . . . . .
}
?
int main()
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}
Probleme la intoarcerea din 1. Apel destructor =
eliberare spatiu de
apelul de functie  memorie alocat dinamic
distrugerea ob. def. local
2. Distrugere ob. alocat static
partajeaza aceeasi zona de memorie
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
void fct(vector v)
{
. . . . . . . . .
}
?
int main()
{ vector v1(5);
adr1
. . . . . . . . v1
fct(v1); 5
. . . . . . . . adr1
}
La intoarcerea din apelul de functie,
obiectul definit initial nu mai are
zona de memorie alocata dinamica
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect

vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}

int main()
{ vector v1 = fct();
. . . . . . . .
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect

vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}

int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
Se defineste si se intializeaza
vector fct() variabila locala v
v
{ vector v(5); 5
adr1
. . . . . . . . . adr1
return v; Apel
} functie

int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
Se defineste si se intializeaza
vector fct() variabila locala v
v
{ vector v(5); 5
adr1
. . . . . . . . . adr1
return v;
} temp -> v1
5
int main() adr1
{ vector v1 = fct(); Copie temporara a lui v ce
. . . . . . . . urmeaza sa fie atribuita la
// sau similar: iesirea din functie obiectului v1
v1 = fct();
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
Se defineste si se intializeaza
vector fct() variabila locala v
v
{ vector v(5); 5
adr1
. . . . . . . . . adr1
return v;
} temp -> v1
? 5
int main() adr1
{ vector v1 = fct();
Copie temporara a lui v ce
. . . . . . . . urmeaza sa fie atribuita la
// sau similar: iesirea din functie obiectului v1
v1 = fct();
La iesirea din functie se distruge
} obiectul local v:
- apel destructor = eliberare
spatiu alocat dinamic
- distrugere/eliberare spatiu
variabila alocata static
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect

vector fct()
{ vector v(5); adr1
. . . . . . . . .
return v;
} v1
5
int main() adr1
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
In final se obtine obiectul v1 care indica o
zona de memorie care nu-i mai este alocata
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Solutia: Definirea unui contructor de copiere propriu care sa
administreze corect alocarea dinamica a spatiului de memorie,
adica sa aloce spatiu dinamic separat in care sa se copieze
continutul primei variabile:

vector::vector(vector &vect)
{ l = vect.l;
v = new int[l];
for(int i=0;i<l;i++)
v[i] = vect.v[i];
}

int main()
{ vector v1(5);
vector v2(v1);
. . . . . . . .
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Solutia: Definirea unui contructor de copiere propriu care sa
administreze corect alocarea dinamica a spatiului de memorie,
adica sa aloce spatiu dinamic separat in care sa se copieze
adr1
continutul primei variabile:
v1
vector :: vector(vector &vect) 5
{ l = vect.l; adr1
v = new int[l];
for(int i=0;i<l;i++) v2
v[i] = vect.v[i]; 5 adr2
} adr2

int main()
{ vector v1(5);
vector v2(v1);
. . . . . . . .
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Solutia: Definirea unui contructor de copiere propriu care sa
administreze corect alocarea dinamica a spatiului de memorie,
adica sa aloce spatiu dinamic separat in care sa se copieze
adr1
continutul primei variabile:
v1
vector :: vector(vector &vect) 5
{ l = vect.l; adr1
v = new int[l];
for(int i=0;i<l;i++) v2
v[i] = vect.v[i]; 5 adr2
} adr2

Cele doua obiecte NU mai partajeaza aceeasi


int main() zona de memorie:
{ vector v1(5);
- Modificarea valorilor stocate in v2 NU
vector v2(v1);
. . . . . . . .
mai afecteaza continutul in v1, si invers
} - Distrugere lui v2 NU afecteaza spatiul
alocat lui v1, si invers
Clase si obiecte. Constructori si destructori. Constructori de copiere
Conversia datelor prin constructor
Conversia unei variabile t de tip T la tipul class cl se face prin
definirea constructorului:
cl :: cl(T t)
{ [ initilizarea datelor membre ale obiectului
curent, folosind datele membre ale lui t ]
}
Exemplu: Conversia unui numar real in numar complex
class nr_complex
{ double re, im;
public:
. . . . . . . .
nr_complex(double nr_real)
{ re = nr_real;
im = 0;
}
};
Clase si obiecte. Constructori si destructori. Constructori de copiere
Conversia datelor prin constructor
Caz 1: conversia datelor la definitie si initializare:
nr_complex ob1 = 2.3;
Se apeleaza direct constructorul corespunzator listei de argumente
Echivalent cu apelul de constructor:
nr_complex ob1(2.3);

Caz 2: conversia in urma operatiilor:


nr_complex ob2;
ob2 = 3.5 + 1.7;
- se creaza ob2 folosind constructorul implicit;
- se efectueaza operatia de adunare, rezultatul 4.2 de tip double
- se face conversia nr_complex(4.2)
- se efectueaza operatia de atribuire intre obiecte de tip nr_complex
Clase si obiecte. Constructori si destructori. Constructori de copiere
Conversia datelor prin constructor

ob2 = nr_complex(4.2);

- se efectueaza operatia de atribuire intre obiecte de tip nr_complex

ATENTIE!! Operatorul de atribuire ar trebui si el implementat, insa in


lipsa acestuia compilatorul genereaza automat un operator implicit
care transfera datel din obiectul operand drept in cel stang membru cu
membru (similar constructorului de copiere). Acest operator automat
este suficient atat timp cat clasele nu contin date alocate dinamic
Clase si obiecte. Date member de tip clasa
Date membre de tip clasa
Datele membre ale unei clase pot avea orice tip, inclusiv o alta clasa
definta/declarata anterior.
class X class Z
{ int x; { int z;
public: X mx;
X(){x = 0;} Y my;
X(int s){x = s;} public:
~X(){} Z(){z = 0;}
. . . . . . . .
Z(int);
}; Z(int,int,int);
class Y ~Z(){}
{ int y; . . . . . . . .
public: };
Y(){y = 0;}
Y(int s){y = s;} inline Z::Z(int p)
~Y(){} { z = p;
. . . . . . . . }
};
Clase si obiecte. Date member de tip clasa
Date membre de tip clasa
Daca o clasa contine date membre avand tipul o alta clasa, atunci la apelul
constructorului sau se vor apela obligatoriu si constructorii datelor
membre in ordinea in care apar datele membre in definita clasei.
- Daca nu este specificat un anumit constructor pentru datele membre,
atunci, pentru fiecare dintre acestia, se apeleaza constructorul implicit.
- Daca se doreste apelul explicit al unui constructor pentru una dintre
datele membre, sintaxa este:
nume_cls(lst_arg):ob1_memb(lst_arg1),ob2_memb(lst_arg2)…
{ bloc instructiuni apel constructor apel constructor
}

Exemplu:

inline Z::Z(int s, int p, int t):mx(s),my(p)


{ z = t;
}
Clase si obiecte. Date member de tip clasa
Etapele construirii obiectelor din clase care au date membre de tip clasa
- Mai intai se apeleaza constructorii obiectelor membre in ordinea in
care apar in definitia clasei.
- La sfarsit se apeleaza constructorul obiectului curent

Etapele distrugerii obiectelor din clase care au date membre de tip clasa
- Mai intai se apeleaza destructorul obiectului curent
- Apoi se apeleaza destructorii obiectelor membre in ordinea inversa
aparitiei in definitia clasei.
construire construire
ob.mx(1) ob.mx()
int main() int main()
ob.my(2) ob.my()
{ Z ob(1,2,3); { Z ob(1);
ob ob
. . . . . . . . . . . .
} distrugere } distrugere
~ob() ~ob()
~ob.my() ~ob.my()
~ob.mx() ~ob.mx()
Clase si obiecte. Obiecte globale. Clase locale
Obiecte globale

Se construiesc similar celor locale (discutate anterior), insa inainte de


executarea funcitie main, in ordinea aparitiei declaratiilor lor.

Distrugerea lor se face la terminarea aplicatiei in ordine inversa

Clase locale

• Clase definte in interiorul unei functii


• Este cunoscuta numai in interiorul blocului functiei respective
• Functiile membre trebuie definite numai in interiorul definitiei clasei
• NU admit variabile statice
Clase si obiecte. Clase imbricate

Clase imbricate

• Clasa definita in interiorul altei clase


• Este cunoscuta numai in interiorul clasei respective, dar…
• Tipul / Numele clasei se poate apela din exterior folosind operatorul
de rezolutiei
class cl int main()
{ { cl ob1;
public: ob1.x=1;
int x;
class cl_int cl::cl_int ob2;
{ public: ob2.x=2;
int x;
}; cout<<"ob ext "<<ob1.x<<endl;
}; cout<<"ob int "<<ob2.x<<endl;
}
Clase si obiecte. Functii si clase friend
Functii si clase friend
O functie NEMEMBRA a unei clase poate accesa datele protejate
( private / protected ) ale clasei respective daca este declarata
friend
Pentru aceasta se include in definitia clasei prototipul functiei precedat
de specificatorul friend
class cls
{ . . . .
public:
friend tip_returnat nume_fct(lista_argumente);
};
tip_returnat nume_fct(lista_argumente)
{ bloc functie
}
Obs.: E bine sa definim ca friend acele functii in care sunt multe
apelari ale functiilor de acces la datele membre private (Set(), Get()) =>
economisire timp acces si simplificarea scrierii codului functiei
Clase si obiecte. Functii si clase friend
Functii si clase friend. Exemplu:
class Y
class X { int a,b;
{ int a,b; public:
public: . . . . . . . .
. . . . . . . . Y(int s, int p)
X(int s, int p) { a = s;
{ a = s; b = p;
b = p; }
} void Set_a(int s)
void Set_a(int s) { a = s;
{ a = s; }
} int Get_a()
int Get_a() { return a;
{ return a; }
} };
int calcul(X ox,Y oy)
}; { return ox.Get_a()*oy.Get_a()+
ox.Get_b()*oy.Get_b()+
ox.Get_a()*oy.Get_b()+
ox.Get_b()*oy.Get_a();
}
Clase si obiecte. Functii si clase friend
Functii si clase friend. Exemplu:
class Y; class Y
class X { int a,b;
{ int a,b; public:
public: . . . . . . . .
. . . . . . . . Y(int s, int p)
X(int s, int p) { a = s;
{ a = s; b = p;
b = p; }
} void Set_a(int s)
void Set_a(int s) { a = s;
{ a = s; }
} int Get_a()
int Get_a() { return a;
{ return a; }
} friend int calcul(X,Y);
friend int calcul(X,Y); };
}; int calcul(X ox,Y oy)
{ return ox.a*oy.a + ox.b*oy.b +
ox.a*oy.b + ox.b*oy.a;
}
Clase si obiecte. Functii si clase friend
Functii si clase friend.

In mod similar, o functie membra a unei clase poate fi declarata


friend a altei clase

class Y;
class X
{ int x;
public:
int fct(Y ob)
{ return ob.a;
}
};
class Y
{ int a;
public:
friend int X::fct();
};
Clase si obiecte. Functii si clase friend
Functii si clase friend.

Ca o generalizare, o intreaga clasa poate fi declarata friend a altei


clase, ceea ce inseamna ca in toate functiile membre ale primeia se pot
accesa datele membre protejate ale celei de-a doua

class Y;
class X
{ int x;
public:
int fct(Y ob)
{ return ob.a;
}
};
class Y
{ int a;
public:
friend X;
};
Clase si obiecte. Alocarea dinamica a obiectelor
Alocarea dinamica a obiectelor

Alocarea spatiu de memorie pentru un singur obiect, cu posibilitatea de


initializare prin apel de constructor:

nume_clasa *pob = new nume_clasa(lista_arg_constructor);

delete pob;

Alocarea spatiu de memorie compact pentru mai multe obiecte, Nu se


poate initializa prin apel de constructor:
nume_clasa *pob = new nume_clasa[dimensiune_vector];

delete[] pob;
Clase si obiecte. Supraincarcarea operatorilor
Supraincarcarea operatorilor
Dupa cum se stie, pentru tipurile fundamentale sunt definite o serie de
operatori, care pot fi folositi direct fara alta specificare:
Exemplu: double a = 3.2, b = 5.9, c;
c = a + b;
bool d = a < b;

Pentru tipurile definite de utilizatori, acesti operatori nu-s definiti si


prin urmare nu pot fi utilizati in mod direct:
char sir1[20];
char *sir2 = “Ionescu”;
sir1 = sir2; // eroare, tb. fol. strcpy()
sir1 < sir2; // eroare tb. fol. strcmp()

Solutia: Implementarea unor functii care sa defineasca modul de


prelucrare al operatorilor pentru tipurile de date definit de utilizator
Clase si obiecte. Supraincarcarea operatorilor

Operatia de definirea a operatorilor pentru alte tipuri de date se


numeste supraincarcarea operatorilor (pe langa operatiile deja definite
pentru tipurile de baza se vor definii functii operator si pentru alte tipuri)

Functia care descrie modul de prelucrare a datelor in cazul aplicarii


operatorilor se numeste functie operator, avand numele:

operator#
simbol operatie: =. +, *

Majoritatea operatorilor pot fi supraincarcati, cu exceptia:


operatorul selectare membru .
operatorul selectare prin pointer la membru .*
operatorul de rezolutie ::
operatorul conditional ? :
operatorul sizeof
Clase si obiecte. Supraincarcarea operatorilor

In general supraincarcarea operatorilor se poate face prin 2 metode:


- Implementand o functie membra a clasei
- Implementand o functie friend (in afara clasei)

NU pot fi implementate ca functii friend (ci numai ca functii membre)


functiile operator:
- de atribuire operator=
- de indexare operator[]
- de apel de functie operator()
- selectie membru prin pointer operator->
Clase si obiecte. Supraincarcarea operatorilor

Cu exceptia functiei operator de atribuire operator=


toate celelalte functii operator pot fi mostenite

NU pot fi supraincarcati operatorii pentru tipurile predefinite ale


limbajului (int, double, etc.)

Functiile operator NU pot avea argumente implicite


Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei
Supraincarcarea operatorilor prin functii membre ale clasei
Sintaxa: Definirea in interiorul def. clasei
class nume_clasa
{ . . . . . . .
public:
tip_returnat operator#(lista_de_argumente)
{ bloc instructiuni
}
. . . . . .
};

Definirea in exteriorul def. clasei


se declara prototipul in interiorul def. clasei si se defineste functia
operator in exteriorul definitiei clasei cu sintaxa:

tip_returnat nume_clasa::operator#(lista_de_argumente)
{ bloc instructiuni
}
Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei

Pentru operatorii binari (+,-,*,etc.):

Sintaxa operator: operand1 + operand2

functia operator primeste un singur argument: operandul 2 (drept);


operandul1 (stang) este obiectul curent (prin care se apeleaza functia
operator) si se transmite functiei prin pointer this
Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei
Exemplu:
class NrComplex
{ double re, im;
public:
NrComplex()
{ re = im = 0;
}
NrComplex(double r, double i)
{ re = r;
im = i;
}
void Afisare()
{ cout << re << “ + ” << im << “i” << endl;
}
NrComplex operator+(NrComplex nr2);
NrComplex operator*(NrComplex nr2);
NrComplex& operator*(double v);
};
Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei
Exemplu (cont.):
NrComplex NrComplex::operator+(NrComplex nr2)
{ NrComplex tmp;
tmp.re = re + nr2.re;
tmp.im = im + nr2.im;
return tmp;
}
NrComplex NrComplex::operator*(NrComplex nr2)
{ NrComplex tmp;
tmp.re = re * nr2.re - im * nr2.im;
tmp.im = re * nr2.im - im * nr2.re;
return tmp;
}
NrComplex& NrComplex::operator*(double v);
{ re *= v;
im *= v;
return *this;
}
Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei
Exemplu:

Apelul functiilor operator:

int main()
{ NrComplex nr1(2.5,9.4);
NrComplex nr2(4.2,6.1);
NrComplex nr3;

nr3 = nr1 + nr2;


nr3 = nr1 * nr2;
nr3 = nr1 * 2.5; // TEMA: nr3 = 2.5 *nr1;
}
Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei

Comentarii:
1. Pentru un operator binar, functia operator primeste un singur argument,
operandul 2 (drept). Operandul 1(stang) este transmis este transmis prin
obiectul prin care se apeleaza functia, adica prin pointer this
2. Apelul de functie operator, este cel corespunzator scrierii operatiilor:
nr3 = nrl + nr2;
care este echivalent cu apelul de functie membra (sintactic corect si se
poate utiliza, insa nu este de dorit):
nr3 = nrl.operator+(nr2);

3. Pentru acelasi operator se pot defini mai multe implementari ale


functiei (supraincarcare multipla). In exemplul de mai sus, s-a
supraincarcat operatorul * pentru doua numere complexe si, respectiv,
nr. complex - scalar
Clase si obiecte. Supraincarcarea operatorilor prin functii membre ale clasei

Comentarii:
4. Este bine ca implementarea functiilor operator sa se faca in sensul
pastrarii semnificatiei operatiei (+ sa nu implementeze scaderea) si sa
respecte, pe cat este posibil, modul de operare definit pentru tipurile
fundamentale:
a) pastrare semnificatie (+ sa implementeze adunare, concatenare)
b) NU modifica niciunul dintre operanzi
c) de cele mai multe ori rezultatul este de acelasi tip cu operanzii
d) SAU poate returna o referinta la obiect de acelasi tip

Obs.: Instructiunea: nr3 = nrl + nr2;


contine si o operatie de atribuire ( = ) care nu a fost supraincarcata,
motiv pentru care se apeleaza functia operator=() implicita,
generata automat de compilator, care face atribuirea intre cele 2
obiecte (drept, stang) membru cu membru
Clase si obiecte. Supraincarcarea operatorilor unari prin functii membre ale clasei

Supraincarcare operatorilor unari, prin functii membre


In mod similar, pentru operatorii unari, functiile operator membre ale
casei nu transmit niciun argument, singurul operand se
transmite prin pointer this
Exemplu: Operatia de conjugare, asociata operatorului ~

NrComplex NrComplex::operator~()
{
NrComplex tmp;
tmp.re = re; //echivalent tmp.re = this->re;
tmp.im = - im;
return tmp;
}

Apelare: nr3 = ~nrl;


Echivalent: nr3 = nrl.operator~();
Clase si obiecte. Supraincarcarea operatorilor unari prin functii membre ale clasei

Cazuri atipice: operatorii unari pre- si postfixati


Implementarea operatorilor prefixati se face dupa modelul general, cu
pastrarea unor reguli provenite de la modul de operare al tipurilor
predefinite:
a) Functia modifica operandul
b) Se efectueaza mai intai operatia, apoi se returneaza operandul modificat

Exemplu: Operatia de incrementare prefixata


NrComple NrComplex::operator++() //operatie inventata
{
re = re + 1;
im = im + 1;
return *this;
}

Apelare: ++nrl; sau nr3 = ++nrl;


Clase si obiecte. Supraincarcarea operatorilor unari prin functii membre ale clasei

Cazuri atipice: operatorii unari pre- si postfixati

Operatorii postfixati NU se pot implementa dupa modelul general, s-ar


suprapune peste prototipul functiei prefixate.

Solutia: introducerea unui argument fals (nefolosit in implementare)


strict pentru diferentierea celor 2 functii (prototipuri).

Trebuie sa pastreze regulile modului de operare al tipurilor predef:


a) Functia modifica operandul
b) Se efectueaza mai intai operatia, apoi se returneaza operandul modificat
Clase si obiecte. Supraincarcarea operatorilor unari prin functii membre ale clasei

Cazuri atipice: operatorii unari pre- si postfixati

Exemplu: Operatia de incrementare postfixata

NrComple NrComplex::operator++(int a) //operatie inventata


{
NrComplex tmp( *this);
re = re + 1;
im = im + 1;
return tmp;
}

Apelare: nrl++; sau nr3 = nrl++;


Clase si obiecte. Supraincarcarea operatorilor prin functii friend

Supraincarcare operatorilor prin functii friend


In acest caz, functiile operator trebuie sa primeasca ca argumente toti
opernazii operatorului : 1 pentru unar, 2 pentru binar, ordinea fiind:
(operand stang, operand drept)
In definitia clasei trebuie declarate friend prototipurile functiilor op.

Exemplu:

class NrComplex
{ double re, im;
public:
. . . . . . . . . . . . . . . . . . .
friend NrComplex operator+(NrComplex,NrComplex);
friend NrComplex operator*(NrComplex,NrComplex);
friend NrComplex operator~(NrComplex);
};
Clase si obiecte. Supraincarcarea operatorilor prin functii friend

Exemplu (cont.):

NrComplex operator+(NrComp1ex nrl, NrComp1ex nr2)


{ NrComp1ex tmp;
tmp.re = nrl.re + nr2.re;
tmp.im = nrl.im + nr2.im;
return tmp;
}

NrComplex operator*(NrComp1ex nrl, NrComp1ex nr2)


{ NrComp1ex tmp;
tmp.re = nrl.re * nr2.re - nrl.im * nr2.im;
tmp.im = nrl.re * nr2.im + nrl.im * nr2.re;
return tmp;
}
Clase si obiecte. Supraincarcarea operatorilor prin functii friend

Exemplu (cont.):

NrComp1ex operator~(NrComp1ex nrl)


{ NrComp1ex tmp;
tmp.re = nrl.re;
tmp.im = - nrl.im;
return tmp ;
}

TEMA: implementarea operatiei de inmultire cu un scalar

nr3 = nrl * 2.5;

DAR nr3 = 2.5 * nrl;


Clase si obiecte. Supraincarcarea operatorilor prin functii friend

Apelare, la fel ca la implementarea cu functii membre ale clasei:

int main()
{
NrComplex nr1(2.5, 9.4);
NrComplex nr2(4.2, 6.1);
NrComplex nr3;

nr3 = nr1 + nr2;// echivalent nr3 =


operator+(nr1,nr2);
nr3 = nr1 * nr2;
nr3 = ~nr1;
}
Clase si obiecte. Supraincarcarea operatorilor prin functii friend

Cazuri atipice: operatorii unari pre- si postfixati


Similar cu implementarea cu functii membre ale clasei:

Prefixati  conform modelului general

Obs.: Trebuie modificat operandul => transmit referinta


Exemplu:
NrComplex operator++(NrComplex &nrl)
{
nrl.re = nrl.re + 1;
nrl.im = nrl.im + 1;
return nr1;
}
Apelare: ++nr; sau nr3 = ++nr;
Clase si obiecte. Supraincarcarea operatorilor prin functii friend

Cazuri atipice: operatorii unari pre- si postfixati


Similar cu implementarea cu functii membre ale clasei:

Postfixati  se introduce argument fals pentru diferentierea functiilor


la apel

Obs.: Trebuie modificat operandul => transmit referinta


Exemplu:
NrComplex operator++(NrComplex &nrl, int a)
{ NrComplex rezultat(nr1);
nrl.re = nrl.re + 1;
nrl.im = nrl.im + 1;
return rezultat;
}
Apelare: nr++; sau nr3 = nr++;
Clase si obiecte. Supraincarcarea operatorului de atribuire

Supraincarcare operatorului de atribuire

Sintaxa operator: operand_stang = operand_drept

Particularitati:
- operator binar la care se modifica operandul_stang
- se evalueaza de la dreapt ala stanga
- functia operator=()
- se implementeaza NUMAI prin functie membra nestatica
(adica nu se poate implementa ca functie friend)
- NU se mosteneste
- daca nu este implementata explicit de programator, atunci
compilatorul genereaza automat o functie implicita care transfera
datele membre din operandul drept in cel stang, membru cu membru
Clase si obiecte. Supraincarcarea operatorului de atribuire

Sintaxa generala de implementare:


class cls
{ tip1 m1;
tip2 m2;
. . . . . . .
};

cls& cls::operator=(const cls& op_drept)


{
m1 = op_drept.m1;
m2 = op_drept.m2;
. . . . . . . . . . . . . .
return *this;
}
Clase si obiecte. Supraincarcarea operatorului de atribuire

Functionalitate operatorului de atribuire este similara cu cea a


constructorului de copiere:

- daca clasa are numai date membre alocate static, atunci functia
operator generata automat de compilator este suficienta pentru o
functionare corecta, prin urmare NU mai este nevoie implementarea
explicita (care oricum ar fi similara celei implicite)

- daca clasa are si date membre alocate dinamic, utilizarea functiei


operator implicita va conduce la functionarea defectuoasa a aplicatiei,
in esenta se vor obtine doua obiecte care vor partitiona aceleasi spatii
de memorie pentru datele membre alocate dinamic. Prin urmare, in
aceasta situatie este OBLIGATORIE implementarea explicita (si
corecta) a functiei operator=( ) care sa administreze corect
spatiul de memorie alocat dinamic
Clase si obiecte. Supraincarcarea operatorului de atribuire
Exemplu: Clasa care are date membre alocate dinamic
class vector
{ int lung;
double* v;
. . . . . . . . .
public:
vector& operator=(const vector& n2);
. . . . . . . . . . . . .
};
vector& vector::operator=(const vector& n2)
{ if( lung != n2.lung) //administrare spatiu de memorie
{ if( v )
delete[] v;
lung = n2.lung;
v = new double[lung];
}
for(int i; i<lung; i++) //copier informatie
v[i]= n2.v [i];
return *this;
}
Clase si obiecte. Supraincarcarea operatorului de atribuire

Operatorii de atribuire compusi


+= , *= , /= , etc.

Pentru acestia NU exista functii operator predefinite (implicite, generate


automat de compilator), motiv pentru care, daca se doreste utilizarea lor
trebuie in mod obligatoriu implementati explicit (chiar si in situatia
claselor care contin numai date membre alocate static)
Clase si obiecte. Supraincarcarea operatorului de indexare

Supraincarcare operatorului de indexare

Sintaxa operator: operand_stang [ operand_drept ]

Particularitati:
- operator binar
- functia operator[]()

- se implementeaza NUMAI prin functie membra nestatica


(adica nu se poate implementa ca functie friend)
- operand_stang  obiectul curent (transmis prin pointer this)

- operand_drept  parametrul functiei. In general reprezinta


indicele de indexare, insa poate avea orice tip de date si poate
fi folosit in orice scop
Clase si obiecte. Supraincarcarea operatorului de indexare

Exemplu: Indexarea unui vector (modificare sau citire valoare de la un anumit


index)

class vector
{ int lung;
double* v;
. . . . . . . . . .
public:
double& operator[](int i)
{
return v[i];
}
};

int main()
{
vector vt(7);
vt[3] = 10; / // utilizare membru
stang op. atribuire
vt[2] = vt[3] + 2.5; // fol. membru drept op.
Clase si obiecte. Supraincarcarea operatorului apel de functie

Supraincarcare operatorului apel de functie

Sintaxa operator: operand_stang ( operand_drept )

Particularitati:
- operator binar
- functia operator()()
- se implementeaza NUMAI prin functie membra nestatica
(adica nu se poate implementa ca functie friend)
- operand_stang  obiectul curent (transmis prin pointer this)
- operand_drept  lista de argumente: insiruire de oricati
parametrii, separati prin virgula. Pot avea orice tip de date si
poate fi folosit in orice scop
Clase si obiecte. Supraincarcarea operatorului apel de functie

Exemplu: Implementare mecanism de modificare a datelor membre


(functie de interfata)
class NrComplex
{ double re,im;
. . . . . . . . . . . .
public:
NrComplex operator()(double valRe, double
valim)
{
re = valRe;
im = valIm;
return *this;
}
. . . . . . . . . . . . .
};
int main()
{
NrComplex nr(7,5); / / Apel constructor de initializare
. . . . . . . . . . . . . . . .
nr(9,7); / / operator apel functie; se fol pentru modificarea
Clase si obiecte. Supraincarcarea operatorului apel de functie

Observatii:

Functia operator()()
- se foloseste de obicei pentru implementarea acelei functii care se
utilizeaza cel mai des (din motive de simplificare a scrierii)
- o aplicatie interesanta este cea de indexare a tablourilor
multidimensionale

TEMA: Sa se implementeze clasa Matrice, in care accesul la elemente sa


se faca prin operator apel de functie
Clase si obiecte. Supraincarcarea operatorului pointer

Supraincarcare operatorului pointer


Sintaxa operator: operand -> ...
Exemplu: obiect->membru
Particularitati:
- operator unar = se aplica operandului de dinaintea operatorului
- functia operator->()
- se implementeaza NUMAI prin functie membra nestatica
(adica nu se poate implementa ca functie friend)
- Trebuie sa intoarca un pointer catre: (una dintre cele 2 situatii)
a) obiect din aceeasi clasa => acceseaza membrul clasei respective
b) o data de tip oarecare => se aplica operatorul -> predefinit
pentru tipul respectiv de date, prin care se selecteaza membrul
cerut din tipul respectiv de date
Clase si obiecte. Supraincarcarea operatorului pointer
class cls2
Exemplu: { int y;
class clsl public:
{ public: cls2(int v)
int x; { y = v;
}
cls1(int v)
void Afisare()
{ x = v; { cout << y << endl;
} }
void Afisare() clsl* operator->()
{ cout << x << endl; { cls1* t = new cls1(7);
} return t;
}
clsl* operator->() };
{ return this;
int main()
}
{ cls1 ob1(5);
}; cout << ob1.x << ob1->x << endl;
cls2 ob2(9);
ob2.Afisare();
ob2->Afisare();
}
Clase si obiecte. Supraincarcarea operatorului conversie de tip de date (cast)

Supraincarcare operatorului conversie de tip de date (cast)


Sintaxa definitie functie operator:

class cls
{ . . . . . . . . . .
operator TipD ();
};

TipD este tipul de date in care se doreste conversia tipului curent cls

Sintaxa apel ( = cast fortat ) :

TipD(obiect_cls) sau (TipD)obiect_cls

Operatorul se apeleaza automat (implicit) atunci cand evaluarea unei


expresii necesita conversia respectiva (evident daca functia este implementata)
Clase si obiecte. Supraincarcarea operatorului conversie de tip de date (cast)

Obs.:
Exista doua metode de converise a tipului de date:
- prin constructor
- prin operator

La un moment dat , pentru o clasa, se poate implementa NUMAI una


dintre cele 2 metode (in caz contrar se obtine eroare de ambiguitate in
alegerea metodei de conversie)

Particularitati:
- operator unar prefixat = se aplica operandului de dupa operator
- functia operator TipD()
- se implementeaza NUMAI prin functie membra nestatica
(adica nu se poate implementa ca functie friend)
Clase si obiecte. Supraincarcarea operatorului conversie de tip de date (cast)

Exemplu: int main()


class NrComplex { NrComplex nr(7,9);
{ double re, im; double x = nr;//conversie autoamata
public:
. . . . . . . . . . . . .
cout << x << endl;
operator double();
operator void*(); cout << double(nr) << endl;
};
cout << (double)nr << endl;
NrComplex::operator double() if(nr) //eroare: conversie ambigua
{ return sqrt (re*re+im*im);
{ cout << “Mesaj” << end;
}
}
NrComplex::operator void*()
}
{ return this
}
Solutia:
if( (void*)nr )
// se particuparizeaza tipul de date asociat
Clase si obiecte. Supraincarcarea operatorului conversie de tip de date (cast)

Observatie:

Daca tipul de date TipD , in care se face conversia, este tot o clasa,
pentru simplificare, este bine ca functia operator TipD() sa aiba
acces la datele membre protejate ale clasei TipD, adica sa fie
declarata functie friend in clasa TipD:

class TipD
{ . . . . . . . . . .
public:
. . . . . . . . . .
friend cls::operator TipD( );
. . . . . . . . . .
};
Clase si obiecte. Supraincarcarea operatorilor de inserare si extragere din stream

Supraincarcare operatorilor de inserare si extragere din stream


Sintaxa operatori:
inserare in stream: cout << obiect_cls;
extragere din stream: cin >> obiect_cls;
Operatorii << si >> definiti in clasele ostream si istream se pot
supraincarca pentru tipurile de date (clase) definite de
utilizator, folosind sintaxa de definire a functiei operator:

ostream& operator<<(ostream& os, tip_clasa nume_arg)


{ . . . . . . . // bloc definitie fct
return os;
}

istream& operator>>(istream& is, tip_clasa& nume_arg)


{ . . . . . . . // bloc definitie fct
return is;
}
Clase si obiecte. Supraincarcarea operatorilor de inserare si extragere din stream

Particularitati:
- operatori binari
- functiile operator: operator<<(), operator>>()
NU sunt membre ale clasa definita de utilizator pentru care se face
supraincarcarea, motiv pentru care se RECOMANDA ca ele sa fie
definite ca functii friend ale acestei clase:

class tip_clasa
{ . . . . . . .
public:
. . . . . . .
friend ostream& operator<<(ostream&, tip_clasa);
friend istream& operator>>(istream&, tip_clasa&);
. . . . . . .
};
Clase si obiecte. Supraincarcarea operatorilor de inserare si extragere din stream

Exemplu:
class Pct2D
{ double x,y;
public:
Pct2D()
{ x = y = 0;
}
friend ostream& operator<<(ostream&, Pct2D);
friend istream& operator>>(istream&, Pct2D&);
};
ostream& operator<<(ostream& os, Pct2D p)
{ os << ‘(‘ << p.x << ‘,’ << p.y << ‘)’ << endl;
return os;
}
istream& operator>>(istream& is, Pct2D& p)
{ is >> p.x;
is >> p.y;
return is;
}
Clase si obiecte. Supraincarcarea operatorilor de inserare si extragere din stream

Exemplu (cont.):

int main()
{ Pct2D p1;

cin >> p1;


cout << p1 << endl;
}

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