Sunteți pe pagina 1din 8

Lucrarea nr.

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
rect.set_value (3,4);
myarea = rect.area();
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 area: 12
#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();
}

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 rect area: 12
#include <iostream.h> rectb area: 30

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;

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.

3.1 Constructori si destructori

In general obiectele au nevoie de initializarea variabilelor lor sau de atribuirea dinamica a memoriei
pe parcursul operatiei de creare a acestora. Aceasta pentru a deveni operationale si a putea fi folosite
fara surpriza de a intoarce rezultate neasteptate (in general generatoare de probleme) pe parcursul
executiei programului. De exemplu, ce s-ar intampla daca s-ar apela functia membru area() inainte
de functia membru set_values()? S-ar obtine, probabil, un rezultat nedeterminat, din moment ce
membrii x si y nu au fost initializati.

Pentru a evita astfel de rezultate nedeterminate o clasa poate contine o functie speciala, denumita
constructor. Aceasta are acelasi nume ca si clasa. Functia constructor este apelata automat cand este
creata o noua instanta (adica un nou obiect) al clasei respective - si numai atunci. Se observa in
programul urmator includerea constructorului in programul anterior:
// exemplu clasa - 3 rect area: 12
#include <iostream.h> rectb area: 30

class CRectangle {
int width, height;
public:
CRectangle (int,int);
int area (void) {return
(width*height);}
};

CRectangle::CRectangle (int a, int b) {


width = a;
height = b;
}

int main () {
CRectangle rect (3,4);
CRectangle rectb (5,6);
cout << "rect area: " << rect.area()
<< endl;

Page 3 of 8
cout << "rectb area: " <<
rectb.area() << endl;
}

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 rect area: 12
#include <iostream.h> rectb area: 30

class CRectangle {
int *width, *height;
public:
CRectangle (int,int);
~CRectangle ();
int area (void) {return (*width *
*height);}
};

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;
}

3.2 Supraincarcarea constructorilor

Precum alte functii si constructorul poate fi supraincarcat cu oricate functii care au acelasi nume, dar
numar si tip diferit de parametrii. Compilatorul va compila apelul la acea functie care se potriveste
atat la numarul de parametrii, cat si la tipul acestora. In cazul in care aceasta potrivire nu se poate
efectua, se va genera o eroare de compilare.

In cazul in care o clasa este declara fara nici un constructor, compilatorul, in mod automat, presupune
2 constructori supraincarcati: constructorul implicit (default constructor) si constructorul de copiere
(copy constructor). De exemplu, pentru clasa:
class CExample
{
public:
int a,b,c;
void multiply (int n, int m) { a=n; b=m; c=a*b; };
};
care nu are constructori, compilatorul va asuma urmatorii constructori ca si functii membru :

• 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
CExample::CExample (const CExample& rv)
{
a=rv.a; b=rv.b; c=rv.c;
}
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 rect area: 12


clasei rectb area: 25
#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; // bine
CRectangle rectb(); // GRESIT!

Page 6 of 8
3.3 Pointeri la clase

Este perfect valid de a crea pointeri care sa "arate" (indice) catre clase. Pentru acest lucru se va
considera ca odata declarata clasa, aceasta devine un tip valid, deci se va putea folosi numele clasei
ca tip al acelui pointer. De exemplu:
CRectangle * prect;
este un pointer la un obiect al clasei CRectangle.

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 a area: 2
#include <iostream.h> *b area: 12
*c area: 2
class CRectangle { d[0] area: 30
int width, height; d[1] area: 56
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;
}

In urmatorul tabel sunt recapitulate metodele pentru a citi pointeri si operatorii (*, &, ., ->, [ ]) care
apar in exemplul anterior.

Page 7 of 8
*x se poate citi indicat de catre x
&x se poate citi adresa lui x
x.y se poate citi membrul y al obiectului x
(*x).y se poate citi membrul y al obiectului indicat de catre x
x->y se poate citi membrul y al obiectului indicat de catre x
(echivalent cu expresia precedenta)
x[0] se poate citi primul obiect indicat de catre x
x[1] se poate citi al doilea obiect indicat de catre x
x[n] se poate citi al (n+1)-lea obiect 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

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