Sunteți pe pagina 1din 7

2.3.

Clase

Identificarea unei mulţimi de obiecte care au proprietăţi şi comportamente comune poartă


numele de clasificare. Clasa este un alt concept de bază al programării orientate-obiect, şi ea
reprezintă o abstractizarea a elementelor (proprietăţilor şi operaţiilor) comune partajate de o
mulţime de obiecte şi descrie implementarea acestora.
O clasă este schema, planul după care este creat un obiect. În interiorul unei clase sunt
precizate denumirile tuturor variabilelor şi tipurile de valori pe care acestea le vor stoca (numeric,
şir de caractere, etc.), alături de toate operaţiile (metodele) pe care un obiect, construit din
respectiva clasă, le va conţine.
Operaţia prin care este creat un obiect, după schema precizată de o clasă se numeşte
instanţiere. Obiectul creat după planul oferit de o clasă este o instanţă a acelei clase.

Nu se poate crea un obiect fără a se declara clasa (schema) după care acesta a fost
instanţiat.

În lumea reală există foarte multe obiecte asemănătoare, descrise de aceeaşi mulţime de
caracteristici. Cărţile, de exemplu, au toate titlu, autor, editură, an de apariţie, format şi pot fi
deschise, închise, citite, etc. Dacă se doreşte crearea unei aplicaţii care să ia în considerare o
mulţime de cărţi, primul pas ar fi crearea unei clase “carte” în care sunt date denumirile
variabilelor, tipul valorilor suportate de ele şi metodele corespunzătoare. Pasul următor ar fi
instanţierea obiectelor de tip “carte”, fiecare în parte având valori specifice pentru variabilele sale
(pentru autor, titlu, editură, etc.).
Cu alte cuvinte, în programarea orientată obiect trebuie respectată următoarea ordine:
CREAREA CLASELOR:
 precizarea denumirii variabilelor, a tipului de date suportat de fiecare variabilă în
parte (tip standard: întreg, real, şir de caractere,etc. sau derivat: o matrice, o altă
clasă,... ) , a domeniului de vizibilitate al variabilei (în general este recomandată
respectarea proprietăţii de încapsulare, prin folosirea de variabile având modificatorul
de acces setat pe private sau protected, astfel accesul la variabile nefiind permis decât
metodelor ce fac parte din aceeaşi clasă cu variabila),etc.
 precizarea signaturii metodelor componente (a denumirii şi a parametrilor de intrare,
respectiv de ieşire), a corpurilor lor (codul care descrie comportamentul metodei), a
domeniului de vizibilitate şi a altor proprietăţi mai mult sau mai puţin specifice unei
anumite implementări a metodei orientate obiect.
 crearea obiectelor, prin specificarea clasei după a cărui model a fost creat obiectul
respectiv şi prin asignarea de valori variabilelor precizate în definiţia clasei.
 Doar în momentul instanţierii unei clase (a naşterii unui obiect) variabilele definite de
clasă sunt alocate în memorie şi sunt pot fi prelucrate de către metode.
 Fiecare instanţă (obiect) a unei clase are propria sa mulţime de valori
corespunzătoare variabilelor sale. Fiecare carte are autorul şi titlul propriu.
Toate instanţele unei clase suportă doar metodele precizate în definiţia clasei, singura
diferenţă între obiectele provenite din aceeaşi clasă constând în valorile diferite (dar de
acelaşi tip) ce sunt stocate în variabile
A apărut astfel conceptul de clasa. Clasa realizează, in speţa, ceea ce am văzut mai
înainte: grupează datele si unităţile de prelucrare a acestora intr-un modul, unindu-le astfel intr-o
entitate mult mai naturala. Deşi tehnica se numeşte "Programare Orientata Obiect", conceptul de
baza al ei este Clasa. Clasa, pe lângă faptul ca abstractizează foarte mult analiza/sinteza
problemei are proprietatea de generalitate, ea desemnând o mulţime de obiecte care împart o serie
de proprietăţi.
De exemplu: Clasa "floare" desemnează toate plantele care au flori, precum clasa "Fruct"
desemnează toate obiectele pe care noi le identificam ca fiind fructe. Bineînţeles, in
implementarea efectiva a programului nu se lucrează cu entităţi abstracte, precum clasele ci se
lucrează cu obiecte, care sunt "instanţieri" ale claselor. Altfel spus, plecând de la exemplul de mai
sus, daca se construieşte un program care sa lucreze cu fructe, el nu va prelucra entitatea "fruct"
ci va lucra cu entităţi concrete ale clasei "fruct", adică "mar", "par", "portocala", etc.
Apare insa următoarea problema: "cum se trece de la o structura generala la una
particulara, mai precis ce înseamnă efectiv procesul de instanţiere?". Instanţierea (trecerea de la
clasa la obiect) înseamnă atribuirea unor proprietăţi specifice clasei, astfel încât aceasta sa indice
un obiect anume, care se diferenţiază de toate celelalte obiecte din clasa printr-o serie de atribute.
Daca vom considera ca "fruct_exotic" care desemnează clasa tuturor fructelor exotice conţine
proprietatea "culoare" atunci atribuind acesteia valoarea "galben" noi vom crea o noua
mulţime( clasa fructelor exotice care au culoarea galbena ) care este o subclasa a clasei
"fruct_exotic", deci realizam astfel o particularizare. Mai mult decât atât, daca vom adaugă noi si
noi atribute vom individualiza clasa astfel încât sa ajungem la un caz concret, care este Obiectul.
Odată identificate entităţile( in speţa clasele ) ele nu rămân izolate; ele vor fi grupate in
module, pachete, programe, etc., care vor stabili legături intre ele. Aceste legături reflecta relaţiile
care se stabilesc intre clasele/obiectele problemei pe care am preluat-o din natura. Extinzând
exemplul de mai sus, vom adaugă o noua clasa: "Raft" , care va avea următoarele proprietăţi:
"număr" si "conţinut". Vom instanţia(particulariza) clasa "Raft" atribuind atributelor "număr"
valoarea "1" si "conţinut" valoarea "fructe". Aceasta înseamnă ca am creat un obiect al clasei
"Raft" care: "este primul din magazin si conţine fructe". Bineînţeles ca acest raft va fi in relaţie
cu, clasa "Fruct" pe care am exemplificat-o mai devreme. Astfel el conţine obiecte de tip "Fruct".
Relaţia pe care am enunţat-o mai sus se mai numeşte si relaţie de compunere, o relaţie
fundamentala in POO, iar clasa "Raft" se numeşte clasa compusa(eng. Agregate), fiindcă in
componenta ei intra alte clase, in cazul nostru "Fruct", cum se vede in diagrama de mai jos:

************************ ************************
* * * *
* *1 n* *
* RAFT <>==================> FRUCT *
* * * *
* * * *
************************ ************************
Un raft conţine mai multe fructe(n)
Fig.2.6.

Sa consideram in continuare ca in magazin avem si fructe care trebuie păstrate la


temperaturi joase. Pentru ele vom avea nevoie de un raft special. Acest nou raft(sa-l numim raft
frigorific) este in esenţa tot un raft doar ca are in plus proprietatea de răcire. Acest lucru ne duce
cu gândirea la faptul ca putem reutiliza codul scris pentru "Raft" pentru a implementa o clasa
numita "RaftFrigorific". Altfel spus, dorim ca noua noastră clasa sa fie o subclasa a clasei "Raft"
deoarece ea "are toate proprietăţile clasei "Raft" pus altele particulare, care o diferenţiază". Acest
lucru, in mod intuitiv, este numit moştenire.
Moştenirea este o relaţie statica(definita in momentul programării) care pune in legătura o
clasa cu alta(sau mai multe) astfel încât clasa rezultata sa "preia" toate atributele clasei/claselor pe
care o/le moşteneşte.
Clasa care moşteneşte atributele altei clase se numeşte "clasa derivata" iar clasa care are
moştenitori se numeşte "clasa de baza". Terminologia este, si in acest caz, intuitiva. Unul din
avantajele moştenirii, care se observa direct, este acela al reutilizării codului: clasa derivata nu va
mai implementa metodele clasei de baza, ci va implementa numai metodele ei specifice; mai mult
clasa derivata va conţine (prin intermediul moştenirii) toate atributele(date si subrutine sau
"metode") ale clasei de baza. Astfel spus si clasa "RaftFrigorific" va avea atributele "număr" si
"conţinut".
Următoarea diagrama ilustrează moştenirea:

**************************
* *
* RAFT <|-+
* * |
************************** |
|
|
************************** |
* * |
* RAFTFRIGORIFIC ---+
* *
**************************

Fig.2.7. Clasa RaftFrigorific moşteneşte clasa Raft

Moştenirea este de asemeni o relaţie fundamentala in POO, care este recunoscuta ca fiind
un principiu de baza, alături de Încapsulare, si Polimorfism;
Am văzut mai sus ca o clasa poate moşteni o alta clasa, ceea ce înseamnă ca o entitate
preia toate atributele altei entităţi. Putem avea, de asemeni, mai multe clase care moştenesc o
clasa. Fie clasa "A" si clasele "B", "C" si "D"; sa presupunem ca "B", "C", "D" moştenesc pe "A".
In acest caz putem face afirmaţia: "B, C si D sunt de tip A". Aceasta însemna ca B, C si D
moştenesc toate caracteristicile clasei A deci pot fi identificate cu o clasa de tip A.
Făcând o analogie cu exemplul anterior, daca A -> "Fruct", B -> "mar", C -> "nuca", D ->
"pruna", afirmaţia de mai sus ar suna in felul următor: "mărul, para si nuca sunt fructe", lucru
care este in mod evident adevărat. Dar sa consideram următoarea situaţie: "Fruct" poate
implementa o subrutina pe care o vom numi "mănâncă-mă!". Deoarece, prin moştenire, clasele
"Mar", "Par" si "Nuca" preiau toate atributele clasei "Fruct", deci si subrutina "mănâncă-mă!"
înseamnă ca un mar se mănâncă la fel ca o pruna! Bineînţeles, daca încercam sa muşcam cu pofta
dintr-o nuca... Asta înseamnă ca "mănâncă-mă!" trebuie sa se particularizeze pentru fiecare clasa
in parte, reflectând un comportament adecvat cu proprietăţile acesteia. Acest lucru mai este numit
si polimorfism.
El este al treilea si cel mai important principiu al POO. El asigura faptul ca fiecare clasa
se comporta diferit (polimorfic) la un anumit mesaj trimis către obiect(in cazul nostru, apelul
subrutinei "mănâncă-mă!"). Se observa ca polimorfismul exista in strânsă legătura cu moştenirea,
fără de care nu ar exista. El aduce insa o nuanţa moştenirii: " Preiau din clasa de baza doar acele
proprietăţi care sunt comune si reflecta un comportament adecvat structurii mele". Altfel spus,
prin polimorfism pot face o moştenire selectiva.

Clase şi funcţii amicale


Diminuarea căilor de acces la atribute şi metode este posibilă prin utilizarea noţiunii de
prietenie. Mai precis clasele sau metodele prietene pot accesa date private ale clasei care le este
declarată prietenă. Este vorba de un mecanism care permite spargerea încapsulării. De exemplu, o
clasă prietenă Agenţi îi poate declara prietenie clasei Clienţi, caz în care toate metodele clasei
Agenţi pot accesa toate atributele şi metodele clasei Clienţi.

Clasa Clienţi:public Personal (


Agenţi* Banca;
….
friend class agenţi;

);
Definirea clasei Clienţi prezentată mai sus poate fi mai protejată utilizând metoda mailing
a clasei Agenţi şi funcţii externă transfer ca putând avea acces la variabilele şi metodele private
ale clasei Clienţi.

Clasa Clienţi:public Person (


Agenţi*banca
….
Friend void agenţi::mailing();
Friend int transferer (clienţi*, agenţi*, agenţi*);
);
Principiile de ascundere a informaţiei şi încapsulare, sunt implementate prin intermediul
cuvintelor cheie public şi private.
Cuvântul cheie Private permite reprezentarea privată a anumitor atribute ale unei clase
încapsulate. Spre deosebire de Smalltalk, programatorul poate decide sau nu schimbarea
atributelor (fără violarea principiului încapsulării).
Astfel membrii clasei care sunt declaraţi în secţiunea privată sunt vizibili numai
instanţelor şi membrilor clasei, fiind în acelaşi timp inaccesibili celorlalte clase şi instanţe ale
acestora. Membrii claselor care sunt declaraţi în secţiunea publică sunt accesibili tuturor
obiectelor şi funcţiilor, secţiunea publică constituind implementarea serviciilor pe care o clasă le
oferă clienţilor săi.
Secţiunea privată este utilizată în primul rând pentru informaţiile stării unui obiect, şi
poate conţine, de asemenea, declaraţiile funcţiilor membre care nu sunt oferite spre utilizare
clienţilor clasei.
Un caz special al paradigmei client/server ne este oferit de C++, în cazul relaţiei dintre o
clasă dată şi derivatele sale. Aici este posibil să se definească zone protejate, iar membrii acestor
zone se comportă ca membrii publici în clasele derivate. Astfel, aceste elemente violează
principiul de ascundere a informaţiei. Fiecare clasă conţine un constructor şi un destructor de
obiecte. Destructorul este apelat implicit pentru obiectele alocate în grămadă (pentru dezalocarea
spaţiului obiectului).
Pentru a putea controla încapsularea, C++ permite declararea interiorului unei clase ale
cărei funcţiuni sunt amicale altor clase (friend), şi le permit accesul la partiţia unei clase. Amiciţia
poate fi declarată pentru o clasă (caz în care toate metodele pot accesa toate atributele particulare)
sau pentru metode.
Clasele nu sunt percepute ca obiecte şi nu există metaclase însă legătura dinamică şi
polimorfismul inclus sunt acceptate.
Există mai multe niveluri de protecţie: variabilele şi metodele pot fi declarate publice,
protejate (vizibile numai în subclase) sau particulare. Încapsularea poate fi spartă prin noţiunea de
prietenie.

Clase abstracte şi clase concrete


O clasă abstractă nu are instanţe directe. Acest tip de clase este creat în mod uzual pentru
a se utiliza ca bază în cadrul unei ierarhii de clase. Deoarece această clasă nu poate avea instanţe
directe, nu are sens să-i implementăm metodele (metode abstracte) acestea acţionând ca şabloane
pentru metodele care le redefinesc în clasele derivate.
Descoperirea claselor abstracte de bază de-a lungul unui proces de analiză şi proiectare a
ciclului de viaţă software este o acţiune foarte importantă. Aceste clase sunt tipuri generice în
relaţiile UN TIP DE, iar descoperirea lor înseamnă descoperirea unui început pentru alte clase,
care pot deriva din acestea. Mai mult, instanţele claselor derivate pot fi utilizate în listele de
argumente acolo unde se aşteaptă o instanţă a unei clase abstracte de bază. Acest aspect are
adânci consecinţe în dezvoltarea software.
O clasă concretă are instanţe directe. O clasă concretă de bază este o clasă din care se pot
deriva noi clase, pornind de la aceasta, care vor reprezenta forme geometrice plane: triunghi,
pătrat, dreptunghi.
Unul din obiectivele proiectării orientate spre obiecte este de a crea ierarhii de moştenire,
extensibile. Cel mai bun mod de a ne asigura de acest lucru este de a afla dacă există o clasă
abstractă, bază a tuturor claselor, prezente şi viitoare, abstracte şi concrete din cadrul unei
aceleaşi familii. Atât clasele abstracte cât şi cele concrete pot deriva din aceeaşi clasă abstractă,
dar sunt rare cazurile în care se derivează o clasă abstractă dintr-una concretă.

Clasa generică şi excepţiile


Începând cu versiunea 3, C++ posedă clase generice sau template. Conceptul template nu
este nou, rădăcinile sale se regăsesc în teoria tipurilor abstracte de date şi în numeroase limbaje
care suportă acest concept. De exemplu Eiffel utilizează parametrii generici formali în definirea
claselor, iar Modula-2 utilizează construcţia modulară.
Elementele template sunt similare tipurilor abstracte de date. De fapt ele pot fi privite ca
implementări ale acestor tipuri. Astfel, o clasă template are o interfaţă şi un corp, la fel ca o clasă
oarecare C++, doar că această clasă utilizează parametrii formali.
O template este o clasă parametrizată, ce poate fi definită printr-o declaraţie de tipul:
template<T1 A1,…, Tn An> clasa C (definirea clasei parametrizate;)
Unde Ti este fie un tip de bază, fie un cuvânt cheie Class.
A1…An sunt identificatorii tipului sau clasei care pot fi utilizaţi ca parametrii în definirea
unei clase. De exemplu, se poate defini o listă cu N obiecte ale unei clase
Template<clasa tip, int N> clasa listă (//cod utilizant tip şi listă…;)
Folosirea unei clase generice se realizează simplu prin instanţierea parametrilor la nivelul
declarat. Este posibil de exemplu declararea unei liste de 10 conturi cum ar fi:
List<conturi, 10>.
Avantajele utilizării elementelor template sunt: trebuie scrise o singură dată, pot fi
specializate pentru obţinerea de noi clase, combinând moştenirea cu specializările template creşte
productivitatea software.
Într-o lume ideală, programele pe calculator ar trebui să funcţioneze fără erori sau
întreruperi. Excepţiile apar sub diferite forme:
- intrare eronată
- erori numerice
- erori de stocare a datelor
- erori de procesare;
- erori de memorare.
O excepţie este rezolvarea situaţiei în momentul apariţiei unei anomalii. Ea poate fi
declanşată prin comanda throw(server), este capturată prin comanda catch care declanşează un
generator de excepţii. O funcţie poate specifica liste de excepţii.

Loc de muncă (0,n) (1,1)


Ipoteză Mesaje

(1,n) (1,1)
(0,n)
Repartiţie Conducere
(1,1) (0,1)

Angajat (1,n) (1,1)


Câştigă Profit
Fig.2.8. Schema entitate-asociaţie
Colecţii
Când un atribut este multivaloare, valoarea sa este o colecţie. De exemplu, atributul
elemente din clasa loc de muncă este un ansamblu de obiecte angajaţi. Sunt doi factori de suport
ai colecţiei într-un limbaj obiect, primul că noi avem în operaţii specifice de manipulare, şi al
doilea este de a furniza o clasă parametrică pentru construirea şi manipularea colecţiilor de
obiecte.
Colecţia este construcţia realizată prin regruparea unui ansamblu sau a unor
multiansamble de elemente într-o structură manipulată prin metode caracteristice, adesea obţinute
prin utilizarea unei clase de parametrii.

Obiect

Clasa Colecţia Angajaţi


Liste
Ansamblu Tabel

Fig.2.9. Clasa Colecţii Liste


angajaţi
Este posibilă o specializare a unei clase generic numită Colecţii în subclase alcătuite din
ansamble, tabele sau liste, fiecare având metode proprii de acces la elemente. Astfel operaţiile
clasice ca: unirea ansamblelor, accesul la elemente din tabele sau pe parcursul listei putând fi
utilizate cu aceleaşi instrumente de transmitere a mesajelor. Această orientare este extensibilă în
măsura în care programul poate adăuga propriile subclase pentru manipularea colecţiei.

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