Professional Documents
Culture Documents
3 Clase C++
O clasa reprezinta o metoda logica de organizare a datelor si functiilor unei aceleasi familii. O clasa este declarata folosind cuvantul cheie class, care are o functionalitate similara cu cuvantului cheie struct din C. Diferenta fundamentala este aceea ca o clasa poate include intre membrii sai si functii, nu numai date ca in structura struct din C. Forma generala a unei clase este:
class class_name { permission_label_1: member1; permission_label_2: member2; ... } object_name;
unde class_name reprezinta numele clasei (tip definit de utilizator), iar campul optional object_name reprezinta unul sau mai multi identificatori valizi de obiecte. Corpul declaratiei poate contine membrii (members), care pot fi atat declaratii de date cat si declaratii de functii si, optional, etichete de permisiune (permission labels), care pot fi una din urmatoarele cuvinte cheie: private:, public: sau protected:. Acestea fac referinta la permisiunea pe care membrii o dobandesc:
private - membrii clasei sunt accesibili numai din cadrul altor membrii ai aceleiasi clase sau din clase prietene (friend) protected - membrii clasei sunt accesibili din cadrul membrilor acelorasi clase sau clase prietene (friend) si, totodata, din membrii claselor derivate (derived) public - membrii sunt accesibili de oriunde clasa este vizibila
Daca se declara membrii unei clase inainte de a include o eticheta de permisiunea, acestia vor fi considerati (implicit) private. Exemplu:
class CRectangle { int x, y; public: void set_values (int,int); int area (void); } rect;
S-a declarat clasa CRectangle si un obiect rect al acestei clase. Aceasta clasa contine 4 membrii: 2 variabile de tipul int (x si y) in sectiunea private (fiind sectiunea cu permisiune implicita) si 2 functii in sectiunea public: set_values() si area(), in care caz s-a declarat numai prototipul acestora. A se observa diferenta intre numele clasei si numele obiectului. In exemplul anterior CRectangle reprezinta numele clasei (adica un tip utilizator), pe cand rect este un obiect de tip CRectangle. Este vorba de exact aceeasi diferenta dintre int si a din declaratia urmatoare:
int a;
unde int este tipul (numele clasei), iar a este variabila (numele obiectului). In intructiuni succesive in corpul programului se poate referi orice membru public al obiectului rect, ca si cand ar fi functii sau variabile normale, prin simpla adaugare a numelui obiectului urmat de un punct si apoi membrul clasei (la fel ca in cazul structurii). De exemplu: Page 1 of 8
In schimb nu se va putea accesa direct membrii privati x si y ai clasei decat de catre un alt membru al clasei (adica, de exemplu, de catre orice functie definita in cadrul clasei). Iata un exemplu:
// exemplu clasa #include <iostream.h> class CRectangle { int x, y; public: void set_values (int,int); int area (void) {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; } int main () { CRectangle rect; rect.set_values (3,4); cout << "area: " << rect.area(); } area: 12
Ce apare nou in programul de mai sus este operatorul :: din definitia functiei set_values(). Acest operator este utilizat pentru a declara membrii clasei in afara acesteia. A se observa, de asemenea, ca functia area() a fost definita in interiorul clasei. Nota: Se prefera definirea in cadrul clasei a functiilor care au un corp mic (sau foarte mic). Acestea vor fi IMPLICIT considerate inline de catre compilator. Nota: Se prefera folosirea membrilor private pentru ca, accidental, sa nu se modifice valoarea acestora, modificarea (cat si citirea) fiind posibila numai prin intermediul functiilor publice.
Unul din avantajele mari ale clasei este acela ca se pot declara diferite obiecte ale clasei respective. Urmatorul exemplu adauga un al doilea obiect rectb:
// exemplu clasa 2 #include <iostream.h> class CRectangle { int x, y; public: void set_values (int,int); int area (void) {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; rect area: 12 rectb area: 30
Page 2 of 8
} int main () { CRectangle rect, rectb; rect.set_values (3,4); rectb.set_values (5,6); cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; }
A se observa ca rect.area() nu furnizeaza acelasi rezultat ca rectb.area() pentru simplul motiv ca fiecare obiect de tipul CRectangle are propriile lor variabile x si y. Pe acesta este si bazat conceptul de obiect si programare orientat-obiect (OOP - Object-Oriented Programming). In acest exemplu clasa (tipul obiectului) este CRectangle, iar acesta are doua instante (sau obiecte): rect si rectb, fiecare cu propriile variabile membru si propriile functii membru.
Page 3 of 8
Se observa ca rezultatele acestui exemplu sunt identice cu exemplul precedent. In acest ultim exemplu functia set_values a fost inclocuita cu constructorul clasei. A se observa modul in care parametrii sunt transmisi constructorului in momentul in care clasa este creata:
CRectangle rect (3,4); CRectangle rectb (5,6);
De asemeni se poate observa ca nu exista valoare intoarsa de catre constructor nici in prototipul acestuia, nici in corpul acestuia (nici macar de tipul void). Un constructor nu intoarce niciodata vreo valoare, deci nu trebuie specificat nici un tip pentru valoarea intoarsa de constructor, pentru ca acesta nu intoarce nici un fel de valoare de nici un fel de tip.
Exercitiu 3.1
Sa se modifice programul anterioar, astfel: - se se adauge clasei CRectangle functiile publice set_width() si set_height() care vor modifica valoarea membrilor width si, respectiv, length - sa se afiseze noua valoare intoarsa de functia membru area() Nota: in primul caz se va modifica clasa CRectangle prin adaugarea: - prototipurilor noilor functii in clasa si corpurile noilor functii dedesubt, SAU - direct corpul functiilor in clasa (pentru a fi tratate drept inline la compilare) Destructorul (destructor) are o functionalitate opusa constructorului. Acesta este chemat in mod automat atunci cand un obiect este eliberat din memorie, fie pentru ca scopul existentei obiectului s-a terminat (de exemplu cand este declarata o instanta a unei clase in interiorul unei functiei, iar aceasta se termina de executat) fie pentru ca obiectul a fost alocat dinamic (cu new) si este eliberat utilizand operatorul delete. Destructorul are intotdeauna acelasi nume ca si clasa si este precedat de tilda (~) ca un prefix. Totodata, la fel ca in cazul constructorului, destructorul nu returneaza nici o valoare. Utilitatea destructorului apare atunci cand un obiect atribuie memorie dinamica pe parcursul existentei acestuia si, in momentul cand este distrus, trebuie sa elibereze memoria alocata lui. Exemplu:.
// examplu constructor si deconstructor #include <iostream.h> class CRectangle { int *width, *height; public: CRectangle (int,int); ~CRectangle (); int area (void) {return (*width * *height);} }; rect area: 12 rectb area: 30
Page 4 of 8
CRectangle::CRectangle (int a, int b) { width = new int; height = new int; *width = a; *height = b; } CRectangle::~CRectangle () { delete width; delete height; } int main () { CRectangle rect (3,4), rectb (5,6); cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; return 0; }
constructorul vid (empty constructor) - un constructor care nu are parametrii si este definit ca un nop (No OPeration - un bloc vid de instructiuni) si, in consecinta, nu face nimic
CExample::CExample () { };
constructorul de copeiere (copy constructor) - un constructor cu un singur parametru de acelasi tip care atribuie fiecarei variabile membru de tip non-static al obiectului o copie a obiectului transmis ca parametru:
Page 5 of 8
Este important de observat ca ambii constructori impliciti exista numai daca nu sunt declarati explicit alti constructori. In cazul in care exista declarat un constructor cu oricati parametrii si de orice tip, atunci nici unul din constructorii impliciti nu vor exista. In cazul in care se doreste existenta acestora, se vor defini de catre utilizator. Bineinteles ca se poate supraincarca constructorul clasei prin furnizarea de diversi constructori pentru care se transfera parametrii intre paranteze, sau nu (empty):
// supraincarcarea constructorilor clasei #include <iostream.h> class CRectangle { int width, height; public: CRectangle (); CRectangle (int,int); int area (void) {return (width*height);} }; CRectangle::CRectangle () { width = 5; height = 5; } CRectangle::CRectangle (int a, int b) { width = a; height = b; } int main () { CRectangle rect (3,4); CRectangle rectb; cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; }
In acest exemplu rectb a fost declarat fara parametrii, ceea ce a condus la initializarea cu ajutorul constructorului fara parametrii, care atribuie ambelor variabile membru valoarea 5. Nota: a se observa declaratia unui nou obiect pentru care nu se doreste transmisia de parametrii, deci nu se includ paranteze:
CRectangle rectb; CRectangle rectb(); // GRESIT! // bine
Page 6 of 8
La fel ca in cazul structurilor, pentru a referi (accesa) direct un membru al obiectului de tip pointer la tipul clasa, se va folosi operatorul ->. Iata un exemplu de combinatii posibile:
// exemplu de pointeri la clase #include <iostream.h> class CRectangle { int width, height; public: void set_values (int, int); int area (void) {return (width * height);} }; void CRectangle::set_values (int a, int b) { width = a; height = b; } int main () { CRectangle a, *b, *c; CRectangle * d = new CRectangle[2]; b= new CRectangle; c= &a; a.set_values (1,2); b->set_values (3,4); d->set_values (5,6); d[1].set_values (7,8); cout << "a area: " << a.area() << endl; cout << "*b area: " << b->area() << endl; cout << "*c area: " << c->area() << endl; cout << "d[0] area: " << d[0].area() << endl; cout << "d[1] area: " << d[1].area() << endl; return 0; } a area: 2 *b area: 12 *c area: 2 d[0] area: 30 d[1] area: 56
In urmatorul tabel sunt recapitulate metodele pentru a citi pointeri si operatorii (*, &, ., ->, [ ]) care apar in exemplul anterior.
Page 7 of 8
se poate citi se poate citi se poate citi se poate citi se poate citi se poate citi se poate citi se poate citi
indicat de catre x adresa lui x membrul y al obiectului x membrul y al obiectului indicat de catre x membrul y al obiectului (echivalent cu expresia precedenta) primul obiect indicat de catre x al doilea obiect indicat de catre x al (n+1)-lea obiect indicat de catre x indicat de catre x
Pentru a intelege mai bine tabelul anterior trebuie mrevizuite notiunile de pointeri si structuri!
Exercitiul 3.2
Sa se rescrie programul creat la Exercitiul 3.1 astfel incat toate instantele clasei CRectangle sa fie de tip pointer (CRectangle *instance SAU CRectangle *instance[n]). Nota: la terminarea programului se va apela operatorul de stergere (eliberare a memoriei) delete pentru toate instantele create!
Page 8 of 8