Sunteți pe pagina 1din 7

Curs 2

Definirea claselor si tipuri abstracte de date

O clasa este un tip de date a carei variabile sunt obiecte. Un obiect este o variabila care are membri functii la fel ca si
posibilitatea de memorare a valorilor de date.
O structura este un tip definit ce permite declararea de membri variabile. Deci, pentru a obtine o clasa dintr-o structura,
trebuie sa adaugam functii membru.

Incapsularea

Combinarea unui numar de articole, cum ar fi variabilele si functiile, intr-un singur pachet, cum ar fi obiectul unei clase,
se numeste incapsulare.
Cand se defineste o functie membru, definitia trebuie sa includa numele clasei, pentru ca pot exista doua sau mai multe
clase care au functii membru cu acelasi nume.
Operatorul :: se numeste operatorul rezolutiei de domeniu, si serverste la un scop similar cu cel al operatorului punct.
Atat operatorul punct, cat si al rezolutiei de domeniu precizeaza din care clasa face parte functia membru respectiva.
ATENTIE ! Operatorul rezolutiei de domeniu :: este folosit cu numele clasei, pe cand operatorul punct este folosit cu
obiecte (adica variabile ale unei clase).
Numele clasei care precede operatorul rezolutiei de domeniu se numeste calificator de tip, deoarece acesta califica
numele functiei la unul particular.
Sintaxa generala a definitiei unei functii membru a clasei C foloseste operatorul rezolutiei de domeniu :

Tip_Returnat C :: nume_functie (lista_parametri)

Exemplu:
Functia afisare() din programul C++ de mai jos apartine clasei zi_din_an. In concluzie, retinem ca operatorul punct
este folosit pentru apelarea unei date sau functii membru ale unui obiect, iar operatorul rezolutiei de domeniu este
folosit pentru definirea unei functii membru a unei clase.
Programul urmator este un exemplu simplu de clasa.

#include <iostream.h>

class zi_din_an
{
public:
int zi;
int luna;
void afisare();
};

int main()
{
zi_din_an azi, zi_nastere;

cout << "Dati data de azi (zi luna, ex: 22 03):\n";


cin >> azi.zi >> azi.luna;
cout << "Dati ziua de nastere:\n";
cin >> zi_nastere.zi >> zi_nastere.luna;

cout << "Azi suntem in ";


azi.afisare();
cout << "Ziua dvs de nastere este ";
zi_nastere.afisare();

if (azi.luna==zi_nastere.luna
&& azi.zi==zi_nastere.zi)
cout << "La multi ani !\n";
else
cout << "O zi buna !\n";
return 0;
}

void zi_din_an::afisare()
{
cout << "luna=" << luna
<< ",ziua" << zi << endl;
}

Membrii private si public

Am vazut in exemplul precedent ca datele si functiile membru din clasa zi_din_an erau public. Deci acestea erau
accesibile din orice functie a programului respectiv. Sunt situatii cand nu ne intereseaza modul de implementare
(codificare, memorare) a datelor sau functiilor sau nu dorim sa fie accesibile. Atunci le vom declara private. Acest lucru
se face folosind cuvantul rezervat private, lista membrilor care apar dupa acesta se numesc membri privati (date sau
functii private).
Programul urmator ilustreaza aceasta tehnica pentru date private.

#include <iostream.h>

class zi_din_an
{
public:
void citire();
void afisare();
void set(int noua_zi, int noua_luna);
//Preconditie: noua_zi si noua_luna formeaza o data posibila
//Postconditie: data este resetata conform cu argumentele
int obtine_zi();
//Returneaza ziua din luna
int obtine_luna();
//Returneaza luna(1-ianuarie, 2-februarie, etc. )
private:
int zi;
int luna;
};

int main()
{
zi_din_an azi, zi_nastere;

cout << "Dati data de azi "


<<"(zi luna, ex:22 03):\n";
azi.citire();
cout << "Azi suntem in ";
azi.afisare();

zi_nastere.set(24,3);
cout << "Ziua de nastere este ";
zi_nastere.afisare();

if (azi.obtine_zi()==zi_nastere.obtine_zi()
&& azi.obtine_luna()==zi_nastere.obtine_luna())
cout << "La multi ani !\n";
else
cout << "O zi buna !\n";
return 0;
}

void zi_din_an::afisare()
{
cout << "luna=" << luna
<< ",ziua=" << zi << endl;
}

void zi_din_an::citire()
{
//membrii privati pot fi folositi in definitia functiilor
cin >> zi >> luna;
}

void zi_din_an::set(int noua_zi, int noua_luna)


{
zi=noua_zi;
luna=noua_luna;
}

int zi_din_an::obtine_zi()
{
return zi;
}

int zi_din_an::obtine_luna()
{
return luna;
}

Cand se defineste o clasa, de obicei toti membrii variabila sunt privati. Asta inseamna ca membrii variabila pot doar sa
fie accesati sau modificati prin functii membru.
Sintaxa generala este:

class nume_clasa
{
public:
declarare membru_1;
declarare membru_2;
...
declarare membru_n;
private:
declarare membru_n+1;
...
};

ATENTIE ! Nu uitati la sfarsitul declararii unei clase semnul ; Functiile membru care permit accesarea variabilelor
membru private se numesc functii accessor (de acces). In exemplul precedent functiile obtine_zi si obtine_luna sunt
functii accessor.
Este legala folosirea intructiunii de atribuire pentru obiecte. De exemplu in programul precedent daca scriem:
zi_nastere = azi;
aceasta este echivalenta cu
zi_nastere.zi = azi.zi;
zi_nastere.luna = azi.luna;
Mai mult, atribuirea este legala chiar daca varibilele membru sunt membri privati.
Comparatie intre class, struct si union

Structurile sunt folosite de obicei cu toate variabilele membru publice si fara functii mebru. Cu toate acestea, o structura
C++ poate avea variabile membru private si functii membru private si publice. Totusi se recomanda, folosirea structurilor
in varianta clasica.
Un union este similar cu un struct, cu exceptia faptului ca permite definirea de varibile care impar spatiul de memorie.

Exemplu:
union int_sau_long
{
int i;
long l;
} un_numar;
Compilatorul va aloca memorie suficienta pentru memorarea variabilei un_numar pentru a incape in cel mai mare
element din union.
Elementele unui union sunt accesata in aceeasi maniera ca la struct.

Constructori

Deseori, dorim sa initializam toate variabilele membru pentru un obiect cand il declaram. Constructorul este o functie
membru care este automat apelata cand un obiect al acestei clase este declarat. Un constructor este folosit pentru
initializarea valorilor unor sau tuturor variabilelor membru precum si pentru a face alte tipuri de initializari pe care le
dorim. Exista doua exceptii fata de functiile membru obisnuite:
1. Un constructor trebuie sa aiba acelasi nume ca al clasei.
2. Definitia constructorului nu poate intoarce o valoare. Mai mult, nu se precizeaza tipul intors, nici macar void.

Exemplu: continuam exemplul precedent


class zi_din_an
{
public:
void citire();
void afisare();
void set(int noua_zi, int noua_luna);
int obtine_zi();
int obtine_luna();

zi_din_an(int noua_zi, int noua_luna);

private:
int zi;
int luna;
};

Putem intelege obiectele azi, respectiv zi_de_nastere astfel:


zi_din_an azi(22, 3), zi_nastere(16, 4);
Este eronat sa facem astfel (ca la functii membru obisnuite):
zi_din_an azi, zi_nastere;
azi.zi_din_an(22, 3);
zi_nastere.zi_din_an(16, 4);

Un constructor nu poate fi apelat la fel ca functiile membru obisnuite. Definitia unui constructor se da in acelasi mod ca
orice alta functie membru.

Exemplu:
zi_din_an::zi_din_an(int noua_zi, int noua_luna)
{
zi=noua_zi;
luna=noua_luna;
}

Observam ca definitia constructorului este similara cu cea a functiei membru set (din programul precedent). Diferenta
este ca nu intoarce nimic (nici macar void).
In general, constructorii sunt supraincarcati, deci obiectele se pot initializa in mai multe moduri.
Un constructor se poate apela de mai multe ori pentru un obiect. Sintaxa apelului explicit a unui constructor este diferita
de sintaxa folosita pentru apelul altor functii membru. Un constructor se apeleaza cu operatorul de asignare = in loc de
operatorul punct.

Exemplu: Am vazut ca putem apela constructorul in momentul declararii, astfel:


zi_din_an azi(22,3);
Putem acum reapela contructorul, astfel:
azi = zi_din_an(22,3);
De fapt un constructor este o functie ce returneaza un obiect de tipul clasei respective.
ATENTIE ! Constructorul este privit ca o functie membru care initializeaza un obiect si poate fi apelat folosind o sintaxa
neobisnuita.

Constructori fara argumente

Daca in definitia unei clase, exista macar o definitie de constructor, atunci C++ va alege spre folosinta definitia
potrivita.
Exemplu:
class C1
{
public:
C1(int a, double b);
void ceva();
private:
int a;
double b;
};
Putem apela constructorul astfel:
C1 obiect(7,2.5);
O declaratie de genul
C1 obiect1;
este gresita deoarece exista in definitia clasei doar un singur constructor cu doua argumente. Declaratia de mai sus ar fi
corecta daca ori declaram obiect1 de doua argumente, ori mai declaram in clasa C1 un constructor fara argumente.
Un constructor fara argumente se numeste constructor implicit, deoarece se aplica in cazul implicit cand declaram un
obiect fara specificarea vreunui argument.

Exemplu: Redefinim clasa C1 astfel:


class C1
{
public:
C1(int a, double b);
C1();
void ceva();
private:
int a;
double b;
};
Acum declaratia C1 obiect1; este corecta.
ATENTIE ! Declaratia C1 obiect1; poate cauza probleme. Compilatorul ar putea crede ca este vorba de un prototip
pentru o functie numita obiect1 fara argument si care intoarce o valoare de tip C1.
Daca am declarat un obiect al unei clase folosind constructorul implicit, atunci il putem initializa apoi folsind alt
constructor.
Exemplu: pentru clasa de mai sus putem avea:
C1 obiect;
obiect = C1(4,6.7);
In schimb nu putem avea declaratiile (motivul este explicat mai sus):
C1 obiect();
obiect = C1(4,6.7);

Tipuri de date abstracte

Un tip de data este o multime de valori impreuna cu o multime de operatii de baza definite pentru aceste valori.

Exemplu:
int este un tip de data ce foloseste valorile
{-32768,...,-1,0,1,...,32767} si operatiile +,-,*,/,% (si altele)
Un tip de data se numeste tip de data abstract (ADT-Abstract Data Type) daca programatorii ce folosesc acel tip nu au
acces la detaliile implementarii valorilor si operatiilor.

Exemplu: tipurile predefinite (cum ar fi int) sunt tipuri de date abstracte.


Tipurile definite de programator, cum ar fi struct si class nu sunt implicit tipuri abstracte de date.
Daca nu sunt definite si folosite cu atentie, tipurile definite de programator pot fi folosite in mod neintuitiv pentru a face
un program greu de inteles si de modificat. Modul cel mai bun de a evita aceste probleme este sa fim siguri ca toate
tipurile de date declarate de programator sunt tipuri
abstracte de date.
Pentru a defini o clasa care sa fie un tip abstract de date, trebuie sa separam specificarile modului de folosire a tipului de
catre programator de detaliile modului de implementare a tipului.
Separarea trebuie sa fie completa astfel incat la o schimbare in implementarea clasei, orice program care foloseste clasa
abstracta de date sa nu necesite schimbari suplimentare. Un mod de a asigura aceasta separare este:
1.Facem toate variabilele membru ale clasei membri private.
2.Facem toate operatiile de baza de care programatorul are nevoie functii membru public ale clasei (specificand modul
de folosire a fiecarei functii membru specifice).
3.Facem orice functie help a clasei membru private.

Interfata unui ADT (definit ca o clasa in C++) consta in functiile membru publice impreuna cu comentariile care
specifica modul de folosire a acestor functii membru publice. Implementarea unui ADT consta in membrii privati ai
clasei si definitiile functiilor membre publice si private.
Deci clasa poate fi impartita in interfata si implementare.

Exercitii propuse spre implementare

1.Scrieti un program C++ in care definiti o clasa contbancar ce contine marea majoritate a operatiilor bancare.
De exemplu, o schita pentru definitia acestei clase poate fi:
class contbancar
{
public:
void seteaza(long lei, double dobanda);
//Postconditie: Soldul din contul bancar este lei
void actualizeaza();
//Postconditie: actualizeaza soldul dupa un an
double obtine_soldul()
//Returneaza soldul curent
double obtine_dobanda();
//Returneaza dobanda din contul bancar
void afisare(ostream& iesire);
//Preconditie: iesire este un flux fisier de iesire sau cout
//Postconditie: Soldul si dobanda sunt afisate catre fluxul de iesire
private:
double sold;
double dobanda;
};
2.Scrieti un program C++ in care se definiti o clasa Arbore ce contine operatiile fundamentale asupra arborilor binari
(creare, parcurgere, stergere, numarare).
ATENTIE ! Radacina si numarul de noduri se recomanda a fi declarate private.

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