Clase si obiecte - ai.pub.roai.pub.ro/resources/files/PC/PC7_POO3.pdf · resurse (memorie pt....
Transcript of Clase si obiecte - ai.pub.roai.pub.ro/resources/files/PC/PC7_POO3.pdf · resurse (memorie pt....
Clase si obiecteClasa = 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;
double im;
public:
nr_complex adunare(nr_complex n1)
{ nr_complex rez;
rez.re=n1.re+re;
rez.im=n1.im+im;
return rez;
};
nr_complex inmultire(nr_complex);
};
Zona membri private
Zona membri public
Clase si obiecte
Specificatori de acces
Ex.: class nr_complex
{ [ private: ]
double re;
double im;
public:
nr_complex adunare(nr_complex n1)
{ nr_complex rez;
rez.re=n1.re+re;
rez.im=n1.im+im;
return rez;
}
nr_complex inmultire(nr_complex);
};
Zona membri private
Zona membri publicDefintitie functie
Declaratie functie
Clase si obiecte
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)
Domeniul de definitie al clasei
incepe cu definirea clasei
se termina la sfarsitul fisierului
#include . . . . . .
. . . . . . . . . . .
class nume
{. . . D e f i n i t i e c l a s a . . .
};
. . . . . . . . . . .
int main()
{
. . . . . . . . . . .
}
. . . . . . . . . . .
Clase si obiecte. Date si functii membre.
Functiile membre pot fi definite:
in interiorul definitiei clasei, cu sintaxa clasica:
class nume_clasa
{ . . . . . . . D e f i n i t i e C l a s a . . . . . . .
tip_returnat nume_functie(lista argumente)
{
. . . . . . . C o r p u l F u n c t i e i . . . . .
}
};
in exteriorul definitiei clasei, cu sintaxa:
tip_returnat nume_clasa :: nume_functie(lista argumente)
{
. . . . . . . . C o r p u l F u n c t i e i . . . . . . .
}
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;
}
void cl::set(int a1, float b1)
{ a = a1;
b = b1;
}
Diferenta intre lista
argumente de la
declaratie si definitie
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. Date si 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
Exemplu:
class cl
{ int a;
float b;
public:
void SetData(int a1, float b1)
{ . . . . . . . . }
void Afisare()
{ . . . . . . . . }
};
int main()
{ . . . . . . . . . .
cl ob1,ob2;
ob1.SetData(2,3.5);
ob2.SetData(5,1.7);
. . . . . . . . . .
}
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 claseiZona memorie
ob1
2
3.5
a
b
ob2
5
1.7
a
b
cl
Implementare
functie
SetData
Implementare
functie
Afisare
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Exemplu:
class cl
{ int a;
float b;
public:
void SetData(int a1, float b1)
{ . . . . . . . . }
void Afisare()
{ . . . . . . . . }
};
int main()
{ . . . . . . . . . .
cl ob1,ob2;
ob1.SetData(2,3.5);
ob2.SetData(5,1.7);
. . . . . . . . . .
}
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 claseiZona memorie
ob1
2
3.5
a
b
ob2
5
1.7
a
b
cl
Implementare
functie
SetData
Implementare
functie
Afisare
Cum se face apelul de functie daca exista o
singura implementare, obiecte/date diferite ?
Clase si obiecte. Pointer this. Mecanism administrare apel functii membre
Exemplu:
class cl
{ int a;
float b;
public:
void SetData(int a1, float b1)
{ . . . . . . . . }
void Afisare()
{ . . . . . . . . }
};
int main()
{ . . . . . . . . . .
cl ob1,ob2;
ob1.SetData(2,3.5);
ob2.SetData(5,1.7);
. . . . . . . . . .
}
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
cl
void SetData(int a1, float b1)
{ a = a1;
b = b1;
}
SetData
void Afisare()
{ cout << “a=” << a << endl;
cout << “b=” << b << endl;
}
Afisare
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
sintaxa, este scrisa numai in scop
didactic, de a explica modul de
transmitere a pointerului la
obiectul curent, pentru a identifica
datele membre
Modul de apelare EXPLICITA a
datelor membre, este corecta
Totusi scrierea IMPLICITA este
cea dorita/utilizata
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();
. . . . . . . .
}
Explicatie: pointerul this transmis catre functia Afisare() are tipul:
const cl* const this
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()
Eroare: “cannot convert this pointer
from const class cl* to class cl* const”
Definirea argumentului de functieconst cl*
Definirea pointerului this
cl* const
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. Pointer this. Mecanism administrare apel functii membre
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
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. Functii membre inline
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);
Exemplu:
class cl
{ int a;
public:
int b;
void Set_a(int
a1)
{ a = a1;
}
int get_a()
{ return a;
}
};
void main()
{ cl ob1, ob2;
ob1.Set_a(3);
cl *pob = &ob2;
pob -> Set_a(5);
. . . . . . . . . . . . . .
int cl::*pdm;
pdm = & cl::a;// eroare,// a privat
pdm = & cl::b; // corect
cout << pob->*pdm << endl;
cout << op1.*pdm << endl;
void (cl::*pfm)(int);
pfm = &cl::Set_a;
(ob1.*pfm)(7); // ob1.a=7
(pob->*pfm)(5);// ob2.a=5
. . . . . . . . . . . .
} //sfarsit main
Clase si obiecte. Pointeri la date si functii membre
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;
}
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. Incapsularea datelor
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 )
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
cl::b
5
ob1.a
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
cl::b
5
ob1.a
ob2.a
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
cl::b
5
ob1.a
1ob2.a
3
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
cl::b
6
ob1.a
2ob2.a
3
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
{ public:
int a;
static int b;
Set_a (int a1){a=a1;}
void incr_a(){a++;}
void incr_b(){b++;}
. . . . . . . . .
};
. . . . . . . . . . . .
int cl::b = 5; // creare b;
//aloc memorie, etc
. . . . . . . . . . . .
int main()
{ cl ob1, ob2; //creare
ob1. Set_a(1);
ob2. Set_a(3);
ob1.incr_a();
ob1.incr_b();
ob2.incr_a();
ob2.incr_b();
}
cl::b
7
ob1.a
2ob2.a
4
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
{ static int nr_ob;
public:
static int Get_nr_ob()
{ return nr_ob;
}
};
int cl::nr_ob;
int main()
{ cl ob;
. . . . . . . . . .
cout<<cl::Get_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. Date membre de tip static
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){. . . . }
. . . . . .
};
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 a,b;
public:
cl()
{ a = b = 0;
}
cl(int c)
{ a = b = c;
}
cl(int a1, int b1)
{ a = a1;
b = b1;
}
};
int main()
{ cl ob1;
cl ob2(3);
cl ob3(4,5);
}
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 a,b;
public:
cl()
{ a = b = 0;
}
cl(int c)
{ a = b = c;
}
cl(int a1, int b1)
{ a = a1;
b = b1;
}
};
int main()
{ cl ob1;
cl ob2(3);
cl ob3(4,5);
}
Clase si obiecte. Constructori si destructori
Constructorul se apeleaza si la crearea unui obiect prin alocare dinamica
class cl
{ int a,b;
public:
cl()
{ a = b = 0;
}
cl(int c)
{ a = b = c;
}
cl(int a1, int b1)
{ a = a1;
b = b1;
}
};
int main()
{ cl ob1;
cl ob2(3);
cl ob3(4,5);
cl *pob;
pob = new cl(2,3);
delete pob;
pob = new cl(2);
delete[] pob;
}
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 a,b;
public:
cl()
{ a = b = 0;
}
cl(int c)
{ a = b = c;
}
cl(int a1, int b1)
{ a = a1;
b = b1;
}
};
int main()
{ cl ob1;
cl ob2(3);
cl ob3(4,5);
cl *pob;
pob = new cl(2,3);
delete pob;
pob = new cl(2);
delete[] pob;
// vs.
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
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}
Constructori de copiere
class cl
{ int a;
float b;
public:
cl(){ a = 0; b = 0; }
cl(int a1, float b1)
{ a = a1;
b = b1;
}
cl(cl &r)
{ a = r.a;
b = r.b;
}
};
int main()
{ cl ob1;
cl ob2(2, 3.5);
cl ob3(ob1);
cl ob4 = ob2;
cl *pob;
pob = new cl(ob3);
}
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere
class cl
{ int a;
float b;
public:
cl(){ a = 0; b = 0; }
cl(int a1, float b1)
{ a = a1;
b = b1;
}
cl(cl &r)
{ a = r.a;
b = r.b;
}
};
int main()
{ cl ob1;
cl ob2(2, 3.5);
cl ob3(ob1);
cl ob4 = ob2;
cl *pob;
pob = new cl(ob3);
}
?
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere
class cl
{ int a;
float b;
public:
cl(){ a = 0; b = 0; }
cl(int a1, float b1)
{ a = a1;
b = b1;
}
cl(cl &r)
{ a = r.a;
b = r.b;
}
};
int main()
{ cl ob1;
cl ob2(2, 3.5);
cl ob3(ob1);
cl ob4 = ob2;
cl *pob;
pob = new cl(ob3);
}
?
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);
fct(ob1);
}
Se executa:cl ob = 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()
{ 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. Cazul datelor membre cu alocare dinamica
int main()
{ vector v1(5);
. . . . . . . .
vector v2 = v1;
. . . . . . . .
}
5
adr1
?
v1 adr1
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
int main()
{ vector v1(5);
. . . . . . . .
vector v2 = v1;
. . . . . . . .
}
5
adr1
?
Se apeleaza constructorul de
copiere implicit = Se copiaza
datele membru cu membru
v1 adr1
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
int main()
{ vector v1(5);
. . . . . . . .
vector v2 = v1;
. . . . . . . .
}
5
adr1
Se apeleaza constructorul de
copiere implicit = Se copiaza
datele membru cu membru
5
adr1
v1
v2
adr1
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()
{ vector v1(5);
. . . . . . . .
{ vector v2 = v1;
. . . . . . . .
}
}
5
adr1
5
adr1
v1
v2
adr1
Clase si obiecte. Constructori si destructori. Constructori de copiere
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Modificam exemplul:int main()
{ vector v1(5);
. . . . . . . .
{ vector v2 = v1;
. . . . . . . .
}
}
5
adr1
5
adr1
v1
v2
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()
{ vector v1(5);
. . . . . . . .
{ vector v2 = v1;
. . . . . . . .
}
}
5
adr1
5
adr1
v1
v2
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()
{ vector v1(5);
. . . . . . . .
{ vector v2 = v1;
. . . . . . . .
}
}
5
adr1
v1 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
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()
{ vector v1(5);
. . . . . . . .
{ vector v2 = v1;
. . . . . . . .
}
}
5
adr1
v1 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
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
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
Clase si obiecte. Constructori si destructori. Constructori de copiere
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
Obiect definit local (blocul de def. al functiei),
initializat cu un obiect similar deja initializat,
care are data membra alocata dinamic =>
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
vector v = v1
Apel de functie copiere
variabile de apel in param.
formali ai functie
Clase si obiecte. Constructori si destructori. Constructori de copiere
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
vector v = v1
Apel de functie copiere
variabile de apel in param.
formali ai functie
v
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
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
vector v = v1
Apel de functie copiere
variabile de apel in param.
formali ai functie
5
adr1
v
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
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
5
adr1
v
partajeaza aceeasi zona de memorie
?
Clase si obiecte. Constructori si destructori. Constructori de copiere
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
5
adr1
v
partajeaza aceeasi zona de memorie
?
Probleme la intoarcerea din
apelul de functie
distrugerea ob. def. local
Clase si obiecte. Constructori si destructori. Constructori de copiere
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
5
adr1
v
partajeaza aceeasi zona de memorie
?
Probleme la intoarcerea din
apelul de functie
distrugerea ob. def. local
1. Apel destructor = eliberare spatiu de
memorie alocat dinamic
Clase si obiecte. Constructori si destructori. Constructori de copiere
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
5
adr1
v
partajeaza aceeasi zona de memorie
?
Probleme la intoarcerea din
apelul de functie
distrugerea ob. def. local
1. Apel destructor = eliberare spatiu de
memorie alocat dinamic
2. Distrugere ob. alocat static
Clase si obiecte. Constructori si destructori. Constructori de copiere
void fct(vector v)
{
. . . . . . . . .
}
int main()
{ vector v1(5);
. . . . . . . .
fct(v1);
. . . . . . . .
}
5
adr1
v1adr1
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 1: Apel la functie cu parametru obiect dintr-o clasa
?
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
vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}
int main()
{ vector v1 = fct();
. . . . . . . .
}
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
Clase si obiecte. Constructori si destructori. Constructori de copiere
vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}
int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
Clase si obiecte. Constructori si destructori. Constructori de copiere
vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}
int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
Apel
functie
5
adr1
vadr1
Se defineste si se intializeaza
variabila locala v
Clase si obiecte. Constructori si destructori. Constructori de copiere
vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}
int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
5
adr1
vadr1
Se defineste si se intializeaza
variabila locala v
5
adr1
temp -> v1
Copie temporara a lui v ce
urmeaza sa fie atribuita la
iesirea din functie obiectului v1
Clase si obiecte. Constructori si destructori. Constructori de copiere
vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}
int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
5
adr1
vadr1
Se defineste si se intializeaza
variabila locala v
5
adr1
temp -> v1
Copie temporara a lui v ce
urmeaza sa fie atribuita la
iesirea din functie obiectului v1
?
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
vector fct()
{ vector v(5);
. . . . . . . . .
return v;
}
int main()
{ vector v1 = fct();
. . . . . . . .
// sau similar:
v1 = fct();
}
Constructori de copiere. Cazul datelor membre cu alocare dinamica
Studiu de caz 2: Returnarea din functie a unui obiect
adr1
5
adr1
v1
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
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);
. . . . . . . .
}
5
adr1
v1
adr1
5
adr2
v2
adr2
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:
Clase si obiecte. Constructori si destructori. Constructori de copiere
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);
. . . . . . . .
}
5
adr1
v1
adr1
5
adr2
v2
adr2
Cele doua obiecte NU mai partajeaza aceeasi
zona de memorie:
- Modificarea valorilor stocate in v2 NU
mai afecteaza continutul in v1, si invers
- Distrugere lui v2 NU afecteaza spatiul
alocat lui v1, si invers
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:
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 ]
}
class nr_complex
{ double re, im;
public:
. . . . . . . .
nr_complex(double nr_real)
{ re = nr_real;
im = 0;
}
};
Exemplu: Conversia unui numar real in numar complex
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. Constructori si destructori. Constructori de copiere
Date membre de tip clasa
Datele membre ale unei clase pot avea orice tip, inclusiv o alta clasa
definta/declarata anterior.
class X
{ int x;
public:
X(){x = 0;}
X(int s){x = s;}
~X(){}. . . . . . . .
};
class Y
{ int y;
public:
Y(){y = 0;}
Y(int s){y = s;}
~Y(){}. . . . . . . .
};
class Z
{ int z;
X mx;
Y my;
public:
Z(){z = 0;}
Z(int);
Z(int,int,int);
~Z(){}. . . . . . . .
};
inline Z::Z(int p)
{ 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
}
Exemplu:
inline Z::Z(int s, int p, int t):mx(s),my(p)
{ z = t;
}
apel constructor apel constructor
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.
int main()
{ Z ob(1,2,3);
. . . . . .
}
construireob.mx(1)
ob.my(2)
ob
distrugere~ob()
~ob.my()
~ob.mx()
int main()
{ Z ob(1);
. . . . . .
}
construireob.mx()
ob.my()
ob
distrugere~ob()
~ob.my()
~ob.mx()
Clase si obiecte. Date member de tip clasa
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
{
public:
int x;
class cl_int
{ public:
int x;
};
};
int main()
{ cl ob1;
ob1.x=1;
cl::cl_int ob2;
ob2.x=2;
cout<<"ob ext "<<ob1.x<<endl;
cout<<"ob int "<<ob2.x<<endl;
}
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 X
{ int a,b;
public:
. . . . . . . .
X(int s, int p)
{ a = s;
b = p;
}
void Set_a(int s)
{ a = s;
}
int Get_a()
{ return a;
}
};
class Y
{ int a,b;
public:
. . . . . . . .
Y(int s, int p)
{ a = s;
b = p;
}
void Set_a(int s)
{ a = s;
}
int Get_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 X
{ int a,b;
public:
. . . . . . . .
X(int s, int p)
{ a = s;
b = p;
}
void Set_a(int s)
{ a = s;
}
int Get_a()
{ return a;
}
friend int calcul(X,Y);
};
class Y
{ int a,b;
public:
. . . . . . . .
Y(int s, int p)
{ a = s;
b = p;
}
void Set_a(int s)
{ a = s;
}
int Get_a()
{ return a;
}
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
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();
};
Functii si clase friend.
Clase si obiecte. 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;
};
Functii si clase friend.
Clase si obiecte. Functii si clase friend
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
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#
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
simbol operatie: =. +, *
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
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 prinobiectul 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 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 setransmite 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 unari prin functii membre ale clasei
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 operatorilor prin functii friend
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 atribuire
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. atribuire
Clase si obiecte. Supraincarcarea operatorului de indexare
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
} / / valorilor datelor membre
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 apel de functie
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
Exemplu:
Clase si obiecte. Supraincarcarea operatorului pointer
class clsl
{ public:
int x;
cls1(int v)
{ x = v;
}
void Afisare()
{ cout << x << endl;
}
clsl* operator->()
{ return this;
}
};
class cls2{ int y;
public:cls2(int v){ y = v;}
void Afisare(){ cout << y << endl;}
clsl* operator->(){ cls1* t = new cls1(7);
return t;}
};
int main()
{ cls1 ob1(5);
cout << ob1.x << ob1->x << endl;
cls2 ob2(9);
ob2.Afisare();
ob2->Afisare();
}
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:
class NrComplex
{ double re, im;
public:
. . . . . . . . . . . . .
operator double();
operator void*();
};
NrComplex::operator double()
{ return sqrt (re*re+im*im);
}
NrComplex::operator void*()
{ return this
}
int main()
{ NrComplex nr(7,9);
double x = nr;//conversie autoamata
cout << x << endl;
cout << double(nr) << endl;
cout << (double)nr << endl;
if(nr) //eroare: conversie ambigua
{ cout << “Mesaj” << end;
}
}
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 operatorului conversie de tip de date (cast)
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;
}
Clase si obiecte. Supraincarcarea operatorilor de inserare si extragere din stream