Professional Documents
Culture Documents
9 CLASE SI OBIECTE
CUPRINS
9 CLASE SI OBIECTE.................................................................................................................................2
9.1 Clase, membri si obiecte.....................................................................................................................2
9.1.1 Declararea claselor......................................................................................................................2
9.1.2 Definirea obiectelor.....................................................................................................................2
9.1.3 Care este diferenta dintre clase si obiecte?..................................................................................3
9.2 Incapsulare si metode de access..........................................................................................................3
9.2.1 Tipuri de access...........................................................................................................................3
9.2.2 Metode de acces la atributele claselor.........................................................................................4
9.3 Constructorii........................................................................................................................................5
9.3.1 Constructorul de copiere..............................................................................................................7
9.4 Destructorii..........................................................................................................................................7
9.5 Metode constante.................................................................................................................................8
9.6 Atribute constante................................................................................................................................9
9.7 Atribute statice...................................................................................................................................10
9.8 Metode statice...................................................................................................................................10
9.9 Metodele inline..................................................................................................................................11
9.10 Organizarea codului.........................................................................................................................11
9.10.1 Declaratii anticipate.................................................................................................................12
9.11 Functii friend...................................................................................................................................13
9.12 Pointerul this...................................................................................................................................14
9.13 Structuri de date si clase..................................................................................................................15
9.14 Sumar..............................................................................................................................................15
9.15 Intrebari si exercitii.........................................................................................................................16
9.16 Bibliografie......................................................................................................................................17
1
InfoAcademy Adonis Butufei
9 CLASE SI OBIECTE
In acest capitol vom discuta despre clase si obiecte, diferenta dintre o clasa si un obiect.
Vom invata primul mecanism al programarii obiectuale: incapsularea.
Vom organiza codul clasei in fisiere header si fisiere sursa.
Vom invata cum sa lucram cu obiectele.
Clasele permit combinarea datelor cu functiile care lucreaza cu aceste date. Elementele claselor, datele si
functiile se numesc membri. Pentru datele membru se foloseste termenul atribute si pentru functiile
membru se foloseste termenul metode.
2
InfoAcademy Adonis Butufei
Exemplu:
class TipuriDeAccess
{
// membri privati
public:
// membri publici
protected:
// membri protected
private:
// membri privati
};
Important
3
InfoAcademy Adonis Butufei
• Directivele de acces definesc zone in declararea clasei. O zona incepe pe linia in care se afla directiva
si se termina pe linia in care apare o noua directiva sau pe linia unde se termina declararea clasei.
Membrii cu tipul de acces public pot fi apelati din afara clasei. Cei cu tipul de acces private pot fi apelati
doar din metodele clasei, iar tipul protected doar din metodele clasei sau claselor derivate1.
Exemplu:
class Complex
{
double _re;
double _im;
};
In acest exemplu este prezentata clasa Complex care are doua atribute private.
Nota
Pentru a diferentia atributele clasei de variabilele locale sau parametri am folosit prefixul (_).
O incercare de acces a acestor atribute in afara clasei genereaza eroare de compilare.
Exemplu:
Complex c1;
c1._re = 1.5; // genereaza eroare
Codul acestui exemplu a fost prezentat pe doua coloane pentru economie de spatiu.
Clasa complex are o pereche de metode pentru fiecare atribut: cate o metoda care returneaza valoarea
curenta2 si o metoda care modifica valoarea curenta a atributului3.
Dupa declararea clasei urmeaza definirea metodelor. Observam si aici operatorul rezolutie (::) pe care
l-am intalnit si in capitolul 8 la spatii de nume pe care il folosim in acelasi mod pentru a specifica
apartenenta metodelor la clasa.
9.3 Constructorii
Variabilele simple pot fi initializate folosind operatorul =. Initializarea asigura faptul ca variabila va avea
intotdeauna o valoare determinata. Pentru initializarea atributelor unei clase se folosesc metodele
constructor care au acelasi nume ca si clasa. Constructorii nu au nici un tip de returnat. In momentul
declararii unui obiect, compilatorul apeleaza constructorul clasei care initializeaza atributele.
Putem adauga la clasa Complex4 prezentata anterior un constructor fara parametri care initializeaza
ambele atribute cu 0. Constructorul fara parametri al unei clase se numeste constructor implicit.
class Complex Complex::Complex()
{ {
public: _re = 0.0;
Complex(); _im = 0.0;
}; }
In momentul declararii unei variabile de tip complex este apelat acest constructor.
Exemplu:
#include <iostream>
using namespace std;
int main()
{
Complex c; // este apelat constructorul
cout << c.Re() << " + " << c.Im() << "i\n";
return 0;
}
Deoarece am folosit prefixul (_) diferentierea parametrilor de atributele clasei este evidenta.
Folosind acest constructor putem initializa un obiect de tip complex cu valorile dorite intr-o singura linie
de cod.
Exemplu:
1: int main()
2: {
3: Complex c(2.5, 3.4);
4: return 0;
5: }
In acest exemplu in linia 3 este apelat al doilea constructor care initializeaza atributele _re si _im cu
valorile 2.5 respectiv 3.4.
Important
In standardul C++ curent un constructor nu poate apela alt constructor al aceleiasi clase. Urmatorul cod
genereaza erori de compilare.
Complex::Complex() : Complex(0.0, 0.0)
{
}
Atunci cand avem o sectiune de cod duplicata in constructorii clasei se poate muta acea sectiune intr-o
functie privata care poate fi apelata din fiecare constructor.
Exemplu:
6
InfoAcademy Adonis Butufei
In cazul clasei Complex codul pentru initializarea atributelor este similar in ambii constructori.
Declaram metoda Init in sectiunea privata cu urmatorul prototip:
void Init(double re = 0.0, double im = 0.0);
Folosim 0.0 valoare implicita pentru ambii parametri. Implementarea este foarte simpla, practic se
copiaza codul din al doilea constructor. Deoarece am specificat valorile implicite in prototipul functiei nu
mai este necesar sa le scriem si la implementare.
7
InfoAcademy Adonis Butufei
Actualizam constructorii:
Complex::Complex()
{
Init();
}
Complex::Complex(double re, double im)
{
Init(re,im);
}
Mai jos este prezentata implementarea constructorului de copiere. Initializam noua clasa cu valorile
atributelor _re si _im din clasa sursa.
Complex::Complex(const Complex &src)
{
Init(src._re, src._im);
}
Constructorul de copiere este apelat explicit atunci cand folosim un obiect sau implicit atunci cand
apelam o functie care foloseste transferul prin valoare pentru parametri, ca in exemplul de mai jos:
Complex c1(2.5, 3.7);
Complex c2(c1); // apel explicit al constructorului de copiere.
Complex c3 = c1; // apel implicit al constructorului de copiere.
Complex c4 = Add(c1, c2); // Unde Add are prototipul:
// Complex Add(Complex c1, Complex c2) (transfer prin valoare);
Pentru evitarea copierii obiectelor, functiile si metodele folosesc transferul prin referinta sau prin adresa
pentru parametrii care sunt obiecte.
9.4 Destructorii
Destructorii sunt apelati de compilator in momentul cand un obiect a ajuns la sfarsitul domeniului de
8
InfoAcademy Adonis Butufei
viata, in scopul eliberarii resurselor folosite de clasa (eliberarea memoriei, inchiderea unui fisier etc). O
clasa poate avea mai multi constructori insa un singur destructor.
Caracteristicile destructorului:
• Numele destructorului foloseste prefixul (~) urmat de numele clasei.
• Destructorul nu are parametri.
• Destructorul nu are tip de returnare.
Exemplu:
class Complex Complex::~Complex()
{ {
}
public:
~Complex();
};
9
InfoAcademy Adonis Butufei
Initializarea acestui atribut nu se poate face in declararea clasei ca in exemplul de mai jos.
class Buffer
{
const int _SIZE = 1024; // Genereaza eroare de compilare5.
//....
};
Pentru a putea initializa acest atribut trebuie sa folosim lista de initializare a constructorului. Aceasta lista
de initializare se executa inainte de executia constructorului. Aici compilatorul aloca memoria pentru
atributele clasei si acesta este momentul cand putem seta valorile atributelor constante. Sintaxa este
prezentata in exemplul urmator:
Buffer::Buffer () : _SIZE(1024)
{
}
Se folosesc doua puncte dupa paranteza ) constructorului apoi urmeaza atributele pe care dorim sa le
initializam, separate prin virgula. Lista de initializare se poate folosi si in cazul atributelor normale si
poate aduce o imbunatatire a performantei daca atributele se initializeaza in ordinea in care au fost
declarate.
In capitolul doi am intalnit tipurile de constante enumerate. Aceste constante sunt folosite frecvent in
cazul in care tipul constantei este intreg deoarece permite o initializare mai simpla. Putem modifica
exemplul anterior in modul urmator pentru a folosi constantele enumerate:
class Buffer
{
enum { _SIZE = 1000};
public:
//..
};
In C++ aceasta problema se poate rezolva foarte simplu folosind un atribut static in loc de o variabila
globala.
Exemplu:
Declaram un atribut static privat:
class Complex
{
private:
static int _nrInstante;
};
Definim atributul:
int Complex::_nrInstante = 0;
Definim metoda:
int Complex::NrInstante()
11
InfoAcademy Adonis Butufei
{
return _nrInstante;
}
Deoarece aceasta metoda apartine clasei, nu instantelor, ea poate fi apelata folosind numele clasei:
cout << Complex::NrInstante() << "numere complexe sunt in memorie\n";
12
InfoAcademy Adonis Butufei
};
#endif
Complex::Complex(double re , double im ) :
_re(re), _im(im)
{
cout << "Complex::Complex(re,im)\n";
}
double Complex::Re()const
{
return _re;
}
double Complex::Im()const
{
return _im;
}
13
InfoAcademy Adonis Butufei
Pentru a folosi un tip de data definit de utilizator (clasa, structura, uniune etc) trebuie ca acest tip sa fie
declarat anterior in cod. Deoarece tipurile de date se declara in fisierele header, pentru reducerea
dependintelor de include si izolarea detaliilor de implementare se folosesc declaratiile anticipate. Aceste
declaratii elimina necesitatea includerii fisierului header in care au fost declarate in alte headere atunci
cand se folosesc date sau parametri de tip referinta sau pointer la aceste tipuri. Headerul se va include in
fisierul sursa care acceseaza atributele sau metodele acelui tip.
De exemplu, daca in fisierul a.h avem urmatorul prototip de functie:
//a.h
void PrintPersoana(Persoana &persoana);
In fisierul a.cpp trebuie inclus headerul persoana.h pentru a putea implementa functia
PrintPersoana.
Important
Deoarece NumeFunctieFriend este o functie nu metoda (deci nu apartine clasei) ea se defineste in modul
urmator:
tipReturn NumeFunctieFriend(lista parametri)
{
//...
}
Functia se declara oriunde in interiorul clasei, deoarece este functie externa clasei si nu este influentata de
nivelurile de acces ale clasei.
Mai jos este prezentata declararea functiei friend Print pentru clasa Complex:
1: class Complex
2: {
14
InfoAcademy Adonis Butufei
Important:
Functiile friend se folosesc doar in cazuri cand alte solutii nu pot fi aplicate deoarece elimina incapsularea
oferita de programarea obiectuala6.
Din definitia metodelor observam ca dupa setarea valorii atributului se returneaza o referinta la obiectul
curent (instructiunea return *this;) Cu aceasta varianta a metodelor putem seta valorile ca in
exemplul de mai jos:
Complex c;
c.Re(2.5).Im(3.2); // apel in cascada echivalent cu:
6 Cum vom vedea in capitolul urmator functiile friend se folosesc pentru definirea operatorilor binari claselor.
15
InfoAcademy Adonis Butufei
// c.Re(2.5);
// c.Im(3.2);
16
InfoAcademy Adonis Butufei
9.14 Sumar
Clasele creaza noi tipuri de date prin gruparea datelor si functiilor care lucreaza cu aceste date.
Obiectele sunt variabile care au tipul definit de clase. Ca si analogie, clasa reprezinta planul unei case iar
obiectele sunt cladirile construite folosind acel plan.
Incapsularea permite ascunderea detaliilor de implementare, folosind directivele de acces, si ofera un set
de metode prin care putem interactiona cu obiectele.
Constructorii sunt metode speciale care sunt apelate de compilator in momentul crearii obiectelor pentru
initializarea datelor. Un constructor nu poate apela alt constructor.
Destructorii sunt metode speciale care sunt apelate de compilator in momentul in care domeniul de viata
al unui obiect s-a terminat, pentru eliberarea resurselor. O clasa poate avea un singur destructor.
Metodele constante nu modifica atributele obiectelor. Folosind directiva const pentru metode putem
identifica foarte usor erorile de modificare neautorizata a atributelor.
Atributele statice apartin claselor. Ele pot fi accesate de toate instantele acelei clase.
Metodele statice pot accesa doar atributele statice ale clasei si se pot apela fara a crea o instanta a acelei
clase.
Metodele inline se pot declara folosind cuvantul cheie sau scriind implementarea in fisierul header.
Structurile de date sunt echivalente cu clasele in C++. Singura diferenta este ca pentru clase tipul de acces
implicit este privat iar pentru structuri este public.
17
InfoAcademy Adonis Butufei
4. Dupa corectarea declaratiei clasei anterioare urmatorul cod genereaza erori de compilare. Care este
motivul?
Fractie f;
5. Declarati o clasa Persoana care are urmatoarele atribute private: _nume, _prenume, _varsta. Scrieti
metodele de acces (de setare si citire a acestor atribute).
Numar::Numar(int val)
{
_val = val;
}
int main()
{
Numar a(10);
}
18
InfoAcademy Adonis Butufei
{
int _test;
public:
static int X();
};
int A::X()
{
return _test;
}
9. Scrieti implementarea constructorului care foloseste lista de initializare pentru urmatoarea clasa:
class Punct
{
double _x;
double _y;
double _z;
public:
Punct(double x = 0.0,double y = 0.0, double z = 0.0);
};
int main()
{
A a;
}
9.16 Bibliografie
• Teach yourself C++ In an Hour A day, Sixth Edition, Sams, Jesse Liberty, Cap 10.
• Practical C++ Programming, Second Edition, O'Reilly, Steve Oualline, Cap 13 - 14.
• C++ Without Fear, Second Edition, Prentice Hall, Brian Overland, Cap 11 - 12.
19