Sunteți pe pagina 1din 0

1

CAPITOLUL 1
Trecere n revist a tehnicilor de programare

Acest capitol este o scurt trecere n revist a tehnicilor de programare. Pentru a
ilustra proprietile particulare i pentru a pune n eviden principalele idei i probleme
vom utiliza exemple simple.
Pentru cineva care ncearc s nvee programarea, se poate observa urmtoarea
cale de urmat:
- programare nestructurat,
- programare procedural,
- programare modular
- programare orientat pe obiect.

1.1. Programarea nestructurat

Uzual, cel care ncepe sa nvee programarea, va ncepe prin scrierea unui
program mic i simplu, constnd numai dintr-un program principal. Programul principal
va conine numai o secven de comenzi sau instruciuni care modific date care sunt
globale pentru ntreg programul. Programul principal (main) va opera direct asupra
datelor globale. Acest mod de programare poate fi ilustrat ca n figura 1.1.






Figura 1.1. Programare nestructurat

Aa cum este bine tiut, aceste tehnici de programare provoac o serie de
dezvantaje pe msur ce dimensiunea programului crete. De exemplu, dac o secven
de instruciuni este necesar n diferite zone ale programului, aceast secven trebuie
copiat. Acest fapt a condus la ideea de a extrage aceste secvene dndu-le un nume i
punnd la dispoziie o tehnic de apelare i de ntoarcere din aceste proceduri.

1.2. Programarea procedural

Cu ajutorul programrii procedurale, programatorul are posibilitatea de a plasa
secvene de instruciuni (proceduri) ntr-un singur loc din program. Pentru a invoca
procedura se va utiliza un apel de procedur. Dup ce secvena de instruciuni este
procesat, execuia programului continu cu instruciunea urmtoare locului n care a fost
fcut apelul de procedur. Modul n care are loc apelul procedurii, preluarea controlului
de ctre aceasta, precum i revenirea n programul principal, pot fi ilustrate ca n figura
1.2.

program
program principal
date
2






















Figura 1.2. Execuia unei proceduri

Prin introducerea unor parametri, care pot fi chiar proceduri (numite uneori
subproceduri), programele pot fi scrise mult mai structurat i fr erori. De exemplu, dac
o procedur este scris corect, de cte ori va fi utilizat ea va oferi rspunsuri corecte.
Prin urmare, n cazul n care apar erori la execuie, atenia va fi concentrat asupra
zonelor de program care nu s-a demonstrat c sunt corecte.
n aceast etap, un program poate fi vzut ca o secven de apeluri de proceduri.
Programul principal este responsabil de a oferi datele apelurilor individuale, datele sunt
procesate de ctre proceduri i odat programul finalizat el trebuie s prezinte datele
rezultate. Astfel, fluxul de date poate fi ilustrat ca fiind un graf ierarhizat, un arbore,
pentru un program care nu are i subproceduri (Figura 1.3.).











Figura 1.3. Programare procedural
Apel procedur
Apel procedur


Pocedur
Program
principal
program
program principal
date
procedura 1 procedura 2 procedura 3
3
Programul principal coordoneaz apelurile de proceduri i ofer datele ca
paramatri.
Recapitulnd, acum avem un singur program care este divizat n fragmente mici
numite proceduri. Pentru a permite utilizarea general a procedurilor sau grupurilor de
proceduri chiar i n alte programe, ele trebuie s permit separarea. Acest lucru va fi
realizat n cadrul programrii modulare, care permite gruparea procedurilor n module.

1.3. Programarea modular

Cu programarea modular, procedurile cu o funcionalitate comun sunt grupate
mpreun n cadrul unor module separate. n aceast situaie, un program nu va mai
conine numai o singur parte. Acum el va fi divizat n cteva pri mai mici care vor
interaciona prin intermediul apelurilor de proceduri i care vor forma ntregul program
(figura 1.4.).




















Figura 1.4. Programarea modular


Programul prioncipal coordoneaz apelurile de proceduri n module separate i
administreaz datele sub form de parametri.
Fiecare modul poate avea propriile date. Acest fapt permite fiecrui modul s i
administreze o stare intern care poate fi modificat prin apeluri de proceduri din
interiorul su. Totui, exist numai o singur stare pentru fiecare modul i fiecare modul
este prezent o singur dat n ntregul program.



program
program principal
date
modul 1
procedura 2 procedura 3
date + date1
procedura 1
modul 2
date + date2
4
1.4. Un exemplu cu structuri de date

Programele utilizeaz structuri de date pentru a memora datele. Exist cteva
structuri de date foarte cunoscute, cum ar fi listele, arborii, vectorii, seturile, stivele,
cozile, pentru a numi numai unele dintre ele. Fiecare dintre aceste structuri de date poate
fi caracterizat prin structura ei i prin metodele de acces.

1.4.1. Manevrarea listelor simplu nlnuite

Listele simplu nlnuite sunt bine cunoscute ca utiliznd structuri foarte simple,
constnd din elemente care sunt legate mpreun ca n figura 1.5.




Figura 1.5. Sructura unei liste simplu nlnuite

Ca operaii foarte simple, s presupunem c listele simplu nlnuite ofer ca
metode de acces adugarea unui element la sfritul listei sau tergerea elementului din
capul listei. Structurile de date mai comlexe vor face uz de cele deja existente. De
exemplu, o coad poate fi structurat ca fiind o list simplu nlnuit. Ea va oferi ca
metode de acces punerea (put) unui element la sfrit i scoaterea (get) primului
element (comportare first-in first-out (FIFO)).
n continuare este prezentat un exemplu simplu care ne va ajuta s nelegem
cteva concepte de proiectare. ntruct acest exemplu este utilizat numai pentru a elustra
aceste concepte i probleme, el nu este nici complet, nici optimizat.
S presupunem c dorim realizarea unei liste n limbajul de programare C.
ntruct considerm c listele sunt structuri de date comune, vom decide implementarea
lor ntr-un modul separat. Tipic, acest lucru va necesita scrierea a dou fiiere: definirea
interfeei i implementarea propriu-zis. Folosind un pseudocod simplu i convenind c
ntre simbolurile /* */ vom nscrie comentariile, definirea interfeei poate avea
urmtoarea form:

/*Definirea interfeei pentru un modul care implementeaz o list simplu
nlnuit pentru a memora date de orice tip*/

MODUL lista_simlu_nlnuit_1

BOOL iniializare_list ();
BOOL apelare_list(ANY data);
BOOL tergere_list();
sfrit_list();
ANY primul_din_list();
ANY urmtorul_din_list();
BOOL list_vid();
END
5

Definirea interfeei ne va descrie numai ceea ce este disponibil, nu i cum ne este
acceseibil. Vom ascunde aceste informaii n fiierul de implementare. Acesta este un
principiu fundamental n ingineria software: ascunderea informaiei privind
implementarea (information hiding). Acest lucru ne permite s modificm
implementarea, de exemplu pentru a utiliza un algoritm care s stocheze elementele mult
mai rapid, dar mai mare consumator de memorie, fr a fi nevoie s modificm alte
module din program: apelurile ctre procedurile furnizate fiind aceleai.
Ideea acestei interfee este urmtoarea: nainte de utilizarea listei se va apela
funcia iniializare_list() pentru a iniializa variabilele locale ale modulului. Urmtoarele
dou proceduri implementeaz metodele de acces apelare i tergere. Procedura apelare
necesit o discuie mai detaliat. Funcia apelare_list are ca argument data de un tip
oarecare. Acest lucru este necesar dac se dorete utilizarea funciei n mai multe medii
diferite, astfel nct tipul de date al elementelor care vor fi memorate n list nu este
cunoscut apriori. n consecin, trebuie utilizat un tip special ANY care permite asocierea
cu el a datelor de orice tip. A treia procedur sfrit_list() este necesar s fie apelat
atunci cnd programul se termin pentru a permite modulului s tearg variabilele
interne utilizate. De exemplu se dorete eliberarea memoriei utilizate.
Cu urmtoarele dou proceduri extrage_Primul() i extrage_Urmtorul() se
creeaz un mecanism simplu de traversare a listei. Traversarea se poate realiza utiliznd
urmtoarea bucl:

ANY data;
data extrage_Primul();
WHILE data ESTE VALID DO
Prelucreaz(data)
data extrage_Urmtorul();
END

Acum avem un modul list care permite utilizarea unei liste avnd elemente de
orice tip. Dar ce se ntml dac avem nevoie de mai mult de o singur list n program?

1.4.2. Manevrarea listelor multiple

Decizi s modifici modulul pentru a fi capabil s manipuleze mai multe liste. De
aceea trebuie s creezi o nou descriere de interfa care s includ i o definiie pentru
manevrarea listei. Aceast manevrare este utilizat n orice procedur furnizat pentru a
identifica n mod unic lista n chestiune. Fiierul de definire a interfeei pentru noul
modul lista va arta stfel:

/* Un modul lista pentru mai mult de o list */

MODUL lista_simlu_nlnuit_2
DECLAR TIP manevrare_lista;
manevrare_lista creare_lista();
distrugere_lista(manevrare_lista aceasta);
6

BOOL apelare_list(manevrare_lista aceasta, ANY data);
ANY primul_din_list(manevrare_lista aceasta);
ANY urmtorul_din_list(manevrare_lista aceasta);
BOOL list_vid(manevrare_lista aceasta);
END

Se utilizeaz DECLAR TIP pentru a introduce un nou tip manevrare_lista care
reprezint metoda de manevrare a listei. Nu se specific cum este reprezentat aceast
manevrare sau cum este implementat. Se vor ascunde detaliile de implementare ale
acestui tip n fiierul de implementare. n modulul anterior au fost ascunse funcii i
proceduri. Acum se ascund i informaii pentru un tip de date definit de ctre utilizator,
manevrare_lista.
Se utilizeaz creare_lista() pentru a obine o manevrare a unei liste vide. Orice
alt procedur va conine acum ca parametru aceasta care va identifica lista n discuie.
Toate procedurile vor opera cu aceast manevrare care este vzut ca o metod global.
Acum se poate spune c pot fi create obiecte list. Fiecare astfel de obiect poate fi
identificat prin manevrarea sa i numai acele metode vor fi aplicate care sunmt definite
s opereze n acea manevrare.

1.5. Probleme ale programrii modulare

1.5.1. Crearea i distrugerea explicit

n exemplu, de fiecare dat cnd se dorete utilizarea unei liste, va trebui
declarat explicit o manevrare i realizat un apel al unei proceduri creare_lista() pentru a
obine o list valid. Dup utilizarea listei, trebuie explicit apelat procedura
distrugere_lista() cu parametru lista care se dorete distrus. Dac se dorete urilizarea
unei liste ntr-o procedur, se va utiliza un cod de genul:
PROCEDURE foo ()
BEGIN
manevrare_lista lista_mea;
lista_mea creare_lista();

/* Prelucrri asupra listei */

distrugere_lista(lista_mea);

END

S comparm lista cu alte tipuri de date, de exemplu tipul ntreg. ntregii sunt
declarai cu un scop particular (de exemplu n interiorul unei proceduri). Odat definii, ei
pot fi utilizai. Cnd s-a ndeplinit scopul n care au fost creai (de exemplu se iese din
procedura n care au fost declarai) ntregii sunt pierdui. Ei sunt creai i distrui automat.
Unele compilatoare chiar iniializeaz ntregii creai cu o valoare specifica, de regul 0.
7
Unde este diferena la obiectele liste? Timpul de via al unei liste este de
asemenea definit prin scopul su, deci ea trebuie creat odat aprut scopul respectiv i
distrus odat ce acesta dispare. La momentul crerii lista trebuie sa fie iniializat ca
fiind vid. De aceea este de dorit s putem face o definire a listei similar cu definirea
unui ntreg. O secven de cod avnd acest scop poate arta de felul:

PROCEDURE foo ()
BEGIN
manevrare_lista lista_mea; /* Lista este creat i iniializat */

/* Prelucrri asupra listei */

END /* lista_mea este distrus */

Avantajul este acela c compilatorul va avea grij s apeleze procedurile de
iniializare i de terminare. Aceasta va asigura o tergere corect a listei, returnnd
programului resursele libere.

1.5.2. Decuplarea datelor i operaiilor

Decuparea datelor i operaiilor duce n mod uzual la o structur bazat mai mult
pe operaii dect pe date: se creeaz un modul comun care grupeaz toate operaiile (de
tipul ..._lista()). Se pot utiliza aceste operaii furniznd n mod explicit datele asupra
crora s opereze. Rezult o structur a modulului orientat mai mult pe operaii dect pe
date actuale. Se poate spune c operaiile definite specific datele care pot fi utilizate.
n orientarea pe obiecte structura este organizat pe date. Se alege reprezentarea
datelor care acoper cel mai bine cerinele utilizatorului. n consecin, programele vor fi
structurate mai mult pe date dect pe operaii. Astfel, avem de-a face exact cu opusul cii
anterioare: datele vor specifica oparaiile posibile. Modulele vor grupa reprezentrile
datelor.

1.5.3. Lipsa siguranei tipului

n exemplele prezentate a fost utilizat un tip special ANY care permite listei s
cuprind orice dat dorete. Aceasta implic faptul c compilatorul nu va putea garanta
sigurana tipului. Considernd urmtorul exemplu n care compilatorul nu poate s
verifice corectitudinea:
PROCEDURE foo()
BEGIN
SomeDataType data1;
SomeOtherType data2;
manevrare_lista lista_mea;
lista_mea creare_lista();
apelare_list(lista_mea, data1);
apelare_list(lista_mea, data2); /* Oops */

8
...

distrugere_lista(lista_mea);
END
Va cdea n responsabilitatea programatorului faptul c lista este utilzat corect. O
variant posibil este aceea a introducerii unor informaii suplimentare privind tipul
fiecrui element al listei. Aceasta implic ns o ncrcare suplimentar i nu ferete
programatorul de cerina de a stii ceea ce se manevreaz.
Ceea ce ne dorim este un mecanism care s ne permit s specificm pe ce tip de
dat s fie lista definit. Funciile listei trebuie s rmna aceleai indiferent dac n lista
sunt nregistrate numere, caractere, sau chiar alte liste. De aceea este de dorit ca o
declarare de lista s fie de genul:

manevrare_lista <numr> lista1; /* o lista de numere */
manevrare_lista <caracter> lista2; /* o lista de caractere */

Rutina lista corespunztoare va putea astfel s returneze tipul corect de date.
Compilatorul va fi capabil s verifice consistena tipului de date.

1.5.4. Strategii i reprezentri

Exemplul lista implic operaii de traversare a acesteia. Tipic, este utilizat
n acest scop un cursor care va puncta elementul curent. Aceasta implic o strategie de
treversare care s definesac ordinea n care sunt vizitate elementele structurii de date.
Pentru o structur de date simpl cum este o list simplu nlnuit, poate
fi luat n calcul numai o singur strategie de traversare. Pornind cu elementul cel mai din
stnga se viziteaz succesiv vecinii din dreapta pn cnd se atinge elementul din
extrema dreapt. Pentru structuri mai complexe, cum ar fi cazul arborilor, acestea pot fi
traversate utiliznd mai multe strategii. Mai ru, uneori strategiile de traversare depind de
un context particular n care sunt utilizate structurile de date. n consecin, capt sens
separarea reprezentrii actuale a structurii de date de strategia de traversare.

1.6. Programarea orientat pe obiect

Programarea orientat pe obiect rezolv unele dintre problemele enumerate
anterior. Spre deosebire de alte tehnici, n aces caz vom avea obiecte care interacioneaz,
fiecare urmndu-i propria stare (figura 1.6.).
9


Figura 1.6. Programarea orientat pe obiect. Obiectele din program
interacioneaz transmindu-i mesaje unul altuia.

Vom considera din nou exemplul cu liste. Problema n cazul programrii
modulare aceea c trebuie create i distruse explicit acele proceduri de manevrare a
listelor. Apoi trebuie utilizate aceste proceduri ale modulului pentru a face orice
modificare.
n programarea orientat pe obiect vom avea attea obiecte liste cte va fi nevoie.
n loc de apelarea unei proceduri care trebuie s realizeze manevrarea listei dorite, se va
transmite un mesaj obiectului list dorit. Fiecare obiect este responsabil de propriile
iniializri i distrugeri corecte. Nu mai este nevoie de crearea unor proceduri de creare i
terminare explicite.
Se poate pune ntrebarea: i ce? Nu este acest lucru numai o dezvoltare a tehnicii
de programare modular? Se poate spune ca aa este dac acest fapt ar fi totul despre
orientarea spre obiecte. Mai departe vom vedea i alte faciliti ale orientrii pe obiect,
ceea ce face ca programarea orientat pe obiect s devin o nou tehnic de programare.


CAPITOLUL 2
Tipuri abstracte de date

Unii autori definesc programarea orientat pe obiect ca fiind programarea unor
tipuri abstracte de date i a relaiilor dintre ele. n acest capitol vom introduce tipurile
abstracte de date ca fiind un concept de baz pentru orientarea pe obiect i vom examina
mai detaliat conceptele utilizate n exemplul cu liste.

2.1. Probleme de manevrabilitate

Primul lucru cu care ne confruntm cnd scriem un program este
problema. Tipic suntem confruntati cu probleme din viata real i dorim s ne facem
viaa mai uoar prin realizarea unui program care s rezolve acele probleme. Dar
problemele din viaa real sunt nebuloase, i atunci. Primul lucru pe care trebuie s l
10
facem este acela de a ncerca s nelegem problema pentru a putea separa detaliile care
nu sunt necesare. Vom ncerca s obinem propria imagine abstract, modelul problemei.
Acest proces de modelare se numete abstractizare i este ilustrat n figura 2.1.

Figura 2.1: Crearea modelului pentru o problem prin
abstractizare

Modelul definete o viziune abstract a problemei. Acest lucru presupune c
modelul se concentreaz numai asupra coninutului problemei i ncearc s definesc
proprietile acesteia. Aceste proprieti includ:
- datele care vor fi implicate
- operaiile care au fost identificate.
Ca un exemplu s considerm administrarea angajailor unei ntreprinderi. eful
administraiei vine la tine i i cere s creezi un program care s i permit s
administreze angajaii. Aceast cerin nu este prea exact. De exemplu, ce informaii
privind angajaii sunt necesare pentru a realiza administrarea lor? Angajaii sunt
persoane reale care pot fi caracterizate cu mai multe proprieti; numai cteva dintre
acestea sunt:
- nume;
- dimensiuni;
- data naterii;
- cod numeric personal;
- numrul camerei;
- culoarea prului;
- pasiuni.
Cu certitudine c pentru a rezolva problema de administrare nu vor fi necesare
toate aceste caracteristici. Numai unele dintre ele sunt specifice problemei. n consecin,
va trebui creat un model al angajatului pentru problem. Modelul va cuprinde numai
acele caracteristici care sunt necesare pentru a ndeplini cerinele administrrii, de
exemplu numele, data naterii i CNP. Aceste caracteristici vor fi numite datele
modelului angajat. n acest moment avem o descriere a persoanelor reale cu ajutorul unui
angajat abstract.
Bine neles c aceast pur descriere nu este suficient. Trebuie definite unele
operaii cu care administraia s poat manevra angajaii abstraci. De exemplu, trebuie s
existe o operaie care s permit crearea unui nou angajat atunci cnd n instituie apare o
nou persoan. n consecin, vor trebui identificate operaiile care trebuie fcute asupra
11
angajailor abstraci. De asemenea trebuie permis accesul la datele angajatului numai prin
operaii asociate. Acest lucru ne va asigura de faptul c ntotdeauna elementele datelor
vor fi n situaii corecte.
Pentru a concluziona, abstractizarea reprezint structurarea unei probleme
nebuloase ntr-o entitate bine definit prin definirea datelor i a operaiilor. Entitile vor
reuni datele i operaiile. Acestea nu vor fi decuplate unele de altele.

2.2. Proprietile tipurilor de date abstracte

Am vzut n exemplul anterior c prin abstractizare se creaz o entitate bine
definit care poate fi manevrat. Aceast entitate definete o structur de date coninnd
un set de articole. De exemplu, fiecare angajat administrat are un nume, o dat de natere
i un CNP.
Structura de date poate fi accesat numai cu operaiile definite. Acest set de
operaii se numete interfa i este exportat de ctre entitate. O entitate cu proprietile
tocmai descrise se numete tip de date abstract.
Figura 2.2. arat un tip de date abstract care const n structura de date abstract i
operaii. Numai operaiile sunt vizibile din afar i definesc interfaa.

Figura 2.2: An abstract data type
(ADT).

Odat un nou angajat creat, structura de date este completat cu valorile actuale.
n acest moment vom dispune de o instan a unui angajat abstract. Se vor putea crea
astfel att de multe instane ale unui angajat abstract cte sunt necesare pentru a descrie
situaia real a persoanelor angajate.
S ncercm acum s punem caracteristicile unui tip de date abstract ntr-un mod
mai formal:
Definiie: Un tip de date abstract este caracterizat de urmtoarele proprieti:
1. Export un tip.
2. Export un set de operaii. Acest set se numete interfa.
3. Operaiile interfeei sunt unicul mecanism de acces la structura de date a
tipului.
4. Axiomele i precondiiile definesc domeniul de aplicaie al tipului.

Cu prima proprietate este posibil crearea mai multor instane ale unui ADT, aa
cum s-a exemplificat cu situaia angajailor. Putem s ne reamintim exemplul listelor. n
prima versiune am implementat o list ca un modul i am putut utiliza o singur list la
un moment dat. A doua versiune a introdus manevrarea ca fiind o referin la un obiect
12
list. Din ceea ce am invat acum, manevrarea n conjuncie cu operaiile definite n
modulul lista definesc un tip de date abstract Lista:
1. Atunci cnd realizm manevrarea definim o variabil corespunztoare ca fiind
de tip Lista.
2. Interfaa la instana tipului Lista este definit prin fiierul de definire a interfeei.
3. Deoarece fiierul de definire a interfeei nu include o reprezentare actual a
manevrrii, nu poate fi modificat direct.
4. Domeniul de aplicaie este definit de nelesul semantic al operaiilor furnizate.
Axiomele i precondiiile includ propoziii cum ar fi:
- O list vid este o list.
- Fie l=(d1, d2, d3, ..., dN) o list. Atunci Ladaug (dM) va avea ca rezultat
l=(d1, d2, d3, ..., dN, dM).
- Primul element al listei poate fi ters numai dac lista nu este vid.

Toate aceste proprieti vor fi valabile numai datorit nelegerii i disciplinei
noastre n utilizarea modulului lista. Este responsabilitatea noastr s utilizm instanele
Lista conform acestor reguli.

Importana ncapsulrii structurilor de date

Principiul ascunderii structurii de date utilizate i de a furniza numai o interfa
bine definit este cunoscut ca ncapsulare. De ce este att de important s ncapsulm
structura de date?
Pentru a rspunde la aceast ntrebare vom considera urmtorul exemplu
matematic n care vom dori s definim un ADT pentru numere complexe. Pentru cele ce
urmeaz este suficient s tim c numerele complexe constau n dou pri: o parte real
i o parte imaginar. Ambele pri sunt reprezentate prin numere reale. Numerele
comlexe definesc cteva operaii: adunarea, scderea, nmulirea i mprirea sunt numai
cteva dintre ele. Axiomele i precondiiile sunt valabile aa cum sunt definite de ctre
definirea matematic a numerelor complexe. De exemplu, exist un element neutru
pentru adunare.
Pentru a reprezenta un numr complex este necesar s definim structura de date
care va fi utilizat de ADT. Pot exista cel puin dou posibiliti de a realiza acest lucru:
- Ambele pri pot fi memorate ntr-un tablou cu dou valori, unde prima
valoare indic partea real i a doua valoare indic partea imaginar a numrului
complex. Dac x semnific partea real i y semnific partea imaginar, ne putem gndi
c le putem accesa cu ajutorul tablourilor: x = c[0], y = c[1].
- Ambele pri pot fi memorate ntr-o nregistrare cu dou valori. Dac r
semnific partea real i i semnific partea imaginar, ne putem gndi c le putem accesa
cu ajutorul nregistrrilor: x = c.r, i y = c.i.

Punctul 3 din definiia ADT spune c pentru fiecare acces la structura de date
trebuie s fie definit o operaie. Exemplele anterioare de acces par s contrazic aceast
cerin.
S ne utm din nou la cele dou modaliti de reprezentare a numerelor complexe.
S privim numai partea real. n primul caz x a fost egal cu c[0], n al doilea x a fost
13
egal cu c.r. n ambele cazuri x a fost egal cu ceva. Acest ceva a fost diferit funcie de
structura de date actual utilizat. n ambele cazuri operaia realizat egal cu a avut
acelai neles n a declara x ca fiind egal cu partea real a numrului complex c.
Dac ne gndim la operaii mai complexe, impactul separrii structurilor de date
de operaii devine chiar mai clar. De exemplu, adunarea a dou numere complexe
presupune realizarea adunrii pentru fiecare parte. n consecin, trebuie accesat
valoarea fiecrei pri care este diferit pentru fiecare versiune. Prin furnizarea unei
operaii adunare pot fi ncapsulate aceste detalii din utilizarea actual. ntr-un context de
aplicaie poi spune adun dou numere complexe fr a te preocupa cum se ajunge la
acest rezultat.
Odat creat un ADT pentru numere complexe, s spunem Complex, acesta
va putea fi utilizat n acelai mod ca i un tip de date bine cunoscut, cum ar fi ntreg.

2.3. Tipuri de date abstracte generice

ADT sunt utilizate pentru a defini un nou tip din care pot fi create instane. Aa
cum s-a vzut din exemplul cu liste, uneori aceste instane opereaz la fel de bine pe alte
tipuri de date. De exemplu, se pot crea instane pentru liste de mere, automobile sau chiar
liste. Definirea semantic a unei liste va fi ntotdeauna aceeai. Numai tipul elementelor
de date se va schimba, funcie de tipul listei pe care se opereaz.
Aceast informaie adiional poate fi specificat printr-un parametru generic care
este specificat la momentul creerii instanei. Astfel, o instan a unui ADT generic este o
instan actual a unei variante particulare a ADT. O lista de mere poate fi declarat:
List <Mere> list_de_mere;
Parantezele unghiulare conin tipul de date pentru care poate fi creat o variant
generic a ADT List.

2.4. Notaii

Deoarece ADT furnizeaz o vedere abstract pentru a descrie proprietile unui
set de entiti, utilizarea lui este independent de un limbaj de programare particular. De
aceea vom introduce o notaie prin care descrierea fiecrui ADT va conine dou pri:
- Data: Aceast parte descrie structura de date utilizat n ADT ntr-o form
informal.
- Operaii: Aceast parte decrie operaiile valide cu acest ADT, adic i
descrie interfaa. Vom utiliza o operaie special numit constructor pentru a descrie
aciunile care trebuie realizate pentru a crea o entitate a acestui ADT i un destructor
pentru a descrie aciunile care trebuie realizate atunci cnd entitatea este distrus. Pentru
fiecare operaie vor fi date argumente, ca i precondiii i postcondiii.

Ca exemplu prezentm descrierea unui ADT Integer. Fie k un ntreg:
ADT Integer este
Data
O secven de cifre opional prefixat de semn plus sau minus. Vom referi acest
numr ca fiind N.
Operations
14
constructor
Creaz un ntreg nou.
add(k)
Creaz un ntreg nou sum care este suma lui N i k.
n consecin, postcondiia acestei operaii va fi sum = N +k. Nu
trebuie confundat aceast expresie cu instruciunea de atribuire utilizat n limbajele de
programare!
sub(k)
Similar cu add, aceast operaie creaz un nou ntreg dif ca fiind
diferena celor dou valori ntregi. Postcondiia n acest caz va fi dif = N-k.
set(k)
Seteaz N la valoarea k. Postcondiia pentru aceast operaie este
N = k.
destructor
Distruge ntregul creat cu operaia constructor.
...
End

Aceast descriere este o specificaie pentru un ADT Integer. Trtebuie reinut c se
utilizeaz cuvinte pentru a numi operaii, cum ar fi add pentru adunare. ntr-adevr se
poate utiliza i semnul +, mai intuitiv, dar acesta poate duce la anumite confuzii: trebuie
fcut distincia ntre operaia + din uzul matematic i + din postcondiie. Numele
operaiei este numai o sintax, semantica fiind descris de pre- i postcondiiile asociate.
Limbajele de programare reale sunt libere s aleag o implementare
arbitrar pentru un ADT. De exemplu, implementarea operaiei add cu operatorul infix +
conduce la un aspect mai intuitiv pentru adunarea ntregilor.

2.5. Tipuri de date abstracte i orientarea pe obiect

ADT permit crearea de instane cu proprieti i comportri bine definite. n
orientarea pe obiect ADT sunt referite ca fiind clase. Astfel, o clas definete proprietile
obiectelor care sunt instane ntr-un mediu orientat pe obiect.
ADT definesc funcionalitatea punctnd datele implicate, structura lor, operaiile
cu axiomele i precondiiile necesare. Astfel, programarea orientat pe obiect este
programarea cu ADT-uri, combinnd funcionalitatea unor ADT diferite pentru a rezolva
problema. De aceea, instanele (obiectele) ADT (claselor) sunt dinamic create, utilizate i
distruse.

2.6. Exerciii

1. ADT Integer.
a) De ce nu sunt precondiii pentru operaiile add i sub?
Ambele operaii add i sub pot fi aplicate pentru orice valoare a lui N. De aceea,
aceste operaii pot fi realizate n orice moment. Nu exist nici o restricie n utilizarea lor.
15
b) Evident, descrierea ADT Integer este incomplet. Adugai metodele mul, div
i oricare alta. Descriei impactul lor specificnd pre i postcondiiile.
Vom defini trei operaii noi, aa cum s-a cerut: mul, div i abs.Ultima va
returna valoarea absolut a ntregului. Operaiile sunt definite dup cum urmeaz:
mul(k)
div(k)
abs()
Operaia mul nu necesit precondiii. Ea este similar operaiilor add i sub.
Postcondiia este res = N * k. Urmtoarea operaie div cere ca parametrul k s nu fie zero.
n consecin, vom defini urmtoarea precondiie: k diferit de 0. Ultima operaie abs
returneaz valoarea lui N dac N este pozitiv, sau 0 sau N dac N este un numr negativ.
Din nou nu are importan ce valoare are N atunci cnd se realizeaz operaia.
Postcondiia va fi:
dac N >= 0 atunci abs = N
altfel abs = -N

1. Realizai un ADT Fracie care s descrie proprietile fraciilor.
a) Ce structur de date poate fi utilizat?
O fracie este format din numrtor i numitor. Ambele sunt numere ntregi. Este
un exemplu similar cu cel al numerelor complexe prezentate anterior. Vom putea alege
din cel puin dou structuri pentru a memore valorile: tablou sau nregistrare.
b) Cum va arta interfaa?
Interfaa reprezint un set de operaii vizibile din afar. Putem descrie aceast
interfa n modul urmtor:
- citete valoarea numrtorului/numitorului;
- seteaz valoarea numrtorului/numitorului;
- adun o fracie i returneaz suma;
- scade o fracie si returneaz diferena;
- .....

c) Numii cteva axiome i precondiii.
Cteva axiome i precondiii valabile pentru orice fracie sunt valabile i pentru
ADT:
- Numitorul trebuie s fie diferit de zero, altfel fracia are o valoare
nedefinit.
- Dac numrtorul fraciei este zero, valoarea fraciei este zero pentru orice
valoare a numitorului.
- Orice numr ntreg poate fi reprezentat ca o fracie pentru care
numrtorul este numrul respectiv, iar numitorul este unu.

2. De ce este necesar introducerea de axiome i precondiii n definirea unui
ADT?
Este necesar precizarea unor axiome i definirea unor precondiii pentru a fi
siguri c instanele ADT vor fi utilizate corect. De exemplu, dac nu declarm faptul c 0
este element neutru pentru adunare poate fi un ADT Integer care poate s ofere un
16
rezultat eronat atunci cnd efectueaz adunarea lui 0 la N. Axiomele i precondiiile ne
ofer sigurana funcionarii corecte.

3. Descriei relaiile dintre:
- instan i ADT
O instan este o reprezentare actual a unui ADT. Se poate spune c este un
exemplu al acestuia. Atunci cnd un ADT declar c utilizeaz un numr mtreg cu
semn ca structur de date, o instan actual poate avea ca valoare, de exemplu, -5.
- tipuri de date abstracte generice i tipuri de date abstracte corespondente
ADT generice definesc aceleai proprieti ca i ADT corespondente. Totui ele
sunt dedicate unui alt tip particular. De exemplu, ADT Lista definete proprietile unei
liste. Astfel, putem avea o operaie append(elem) care ataeaz un nou element elem
listei. Nu se precizeaz care este tipul elementului actual elem, ci doar se tie c acesta va
fi ultimul elemet al listei. Dac vom utiliza ADT generic Lista, tipul acestui elemnt va fi
cunoscut: el va fi furnizat de ctre parametrul generic.


CAPITOLUL 3
Concepte ale orientrii pe obiect

n capitolul anterior am introdus deja cteva concepte ale orientrii pe obiect.
Totui ele au fost aplicate ntr-un mediu procedural sau ntr-o manier verbal. n acest
capitol vom analiza aceste concepte mai detaliat i le vom da denumiri aa cum sunt
utilizate n limbajele de programare orientate pe obiect existente.

3.1. Implementarea tipurilor de date abstracte

Anterior am introdus tipurile de date abstracte ca fiind o vedere abstract pentru a
defini proprietile unui set de entiti. Limbajele de programare orientate pe obiect
trebuie s permit implementarea acestor tipuri. n conscin, odat ce am implementat un
ADT, vom avea disponibil o reprezentare particular a acestuia.
Considerm din nou ADT Integer. Limbajele de programare ca Pascal, C i altele
ofer ele nsele o implementare a acestuia. Implementarea se numete int sau integer.
Atunci cnd a fost creat o variabil de acest tip se pot utiliza operaiile furnizate pentru
acesta. De exemplu, se pot aduna doua numere ntregi:

int i, j, k; /* Se definesc trei ntegi */

i = 1; /* se atribuie 1 intregului i */
j = 2; /* se atribuie 2 intregului j */
k = i + j; /* se atribuie suma lui I i j lui k*/

S analizm acest fragment de cod i s punem n eviden relaiile
conform unui ADT Integer. Prima linie definete trei instane i, j i k de tip ntreg. n
consecin, pentru fiecare dintre aceste instane trebuie apelat operaia special
constructor. n exemplul nostru, acest lucru se realizeaz intern de ctre compilator.
Compilatorul rezerv memorie pentru a reine valoarea unui ntreg i i asociaz numele
17
corespondent. Dac ne vom referi la i, ne vom referi la zona de memorie care a fost
construit de definirea lui i. Opional, compilatorul poate s aleag s iniializeze
memoria, de exemplu o poate seta n 0.
Urmtoarea linie
i = 1;
seteaz valoarea lui i n 1. Aceast linie poate fi descris cu ajutorul notaiilor
ADT cum urmeaz:
Realizeaz operaia de setare (set) cu argument 1 pe instana ntreag i.
Propoziia se va scrie: i.set(1)

Acum avem o reprezentare a dou niveluri. Primul nivel este nivelul ADT n care
exprimm orice se va face cu o instan a acestui ADT prin invocarea operaiilor definite.
La acest nivel pre i postcondiiile sunt utilizate pentru a descrie ceea ce are loc. n
exemplul urmtor aceste condiii sunt nscrise ntre acolade.

{ Precondiie: i = n unde n este orice Integer }
i.set(1)
{ Postcondiie: i = 1 }

Nu trebuie uitat c vorbim despre nivelul ADT. n consecin, condiiile sunt
condiii matematice.
Al doilea nivel este nivelul implementare unde este aleas pentru operaii
o reprezentare actual. n C = semnul implemeteaz operaia set(). Pentru aceeai
operaie, n Pascal a fost aleas urmtoarea reprezentare:
i:=1;
Ambele cazuri reprezint implementarea operaiei set.
Trecem mai departe i privim linia
k = i + j ;
Bineneles c + a fost ales s reprezinte operaia de adunare (add). Putem citi
partea i+j ca adun valoarea lui i la valoarea lui j, astfel, la nivelul ADT rezultnd:
{ Precondiie: Fie i = n1 i j = n2 cu n1, n2 ntregi particulari }
i.add(j)
{ Postcondiien: i = n1 i j = n2 }
Postcondiia ne asigur c ntregii i i j nu i modific valoarea. Dac ne
reamintim spacificaia pentru add, aceasta spune c este creat un nou ntreg, valoarea
acestuia fiind suma. n consecin, trebuie s furnizm un mecanism de acces la aceast
instan nou. Vom realiza acest lucru prin aplicarea operaiei set pe instana k:
{ Precondiie: Fie k = n unde n este orice ntreg }
k.set(i.add(j))
{ Postcondiie: k = i + j }

Dup cum se poate vedea, unele limbaje de programare au ales o reprezentarea
care este aproape similar cu formularea matematic utilizat n pre i postcondiii. Acest
fapt face ca uneori s fie dificil s nu amestecm cele dou niveluri.

18
3.2 Clas

O clas este o reprezentare actual a unui ADT. Din acest motiv ea va
furniza detaliile de implementare pentru structura de date utilizat i pentru operaii.
Utiliznd ADT Integer vom realiza propria clas pentru acesta:

class Integer
{
attributes:
int i

methods:
setValue(int n)
Integer addValue(Integer j)
}
n acest exemplu ca i n exemplele care vor urma, vom utiliza o notaie
care nu este proprie unui limbaj de programare specific. n aceast notaie,
class{}nseamn definirea unei clase. ntre acolade sunt dou seciuni attributes: i
methods: care definesc implementarea structurii de date i a operaiilor corespunztoare
ADT. Din nou facem distincie ntre cele dou niveluri cu termeni diferii: La nivelul
implementare vorbim despre atribute care sunt elemente ale structurii de datela nivelul
ADT. Aceeai interpretare o avem i n privina metodelor, care sunt implementarea
operaiilor ADT.
n exemplul prezentat, structura de date const ntr-un singur element: o
secven de cifre cu semn. Atributul corespondent este un ntreg ordinar dintr-un limbaj
de programare. Sunt definite numai dou metode setValue( ) i addValue( )
reprezentnd cele dou operaii de adunare i setare.

Definiie: O clas este o imlementare a unui tip de date abstract (ADT). Ea definete
atribute i metode care implementeaz structura de date i respectiv operaiile ADT.
Instanele claselor se numesc obiecte. n consecin, clasele definesc proprietile i
comportarea unui set de obiecte.

3.3. Obiect

Ne reamintim exemplul angajailor prezentat n capitolul 2. Am discutat depre
instane ale angajailor abstraci. Aceste instane sunt acum exemple ale angajatului
abstract, deci ele conin valoarea actual pentru a reprezenta un angajat particular. Vom
numi aceste instane obiecte.
Obiectele sunt unic identificabile printr-un nume. De aceea putem avea dou
obiecte distincte cu acelai set de valori. Acest lucru este similar cu limbajele de
programare tradiionale n care puteam avea, s spunem, dou variabile i i j avnd
ambele aceeai valoare, -2. De notat c am utilizat i i j pentru a numi cei dou ntregi.
Ne vom referi la setul de valoari de la un moment dat ca fiind starea obiectului.

Definiie: Un obiect este o instan a unei clase. El poate fi unic identificat printr-un
nume i definete o stare care este reprezentat prin valorile atributelor sale la un moment
particular de timp.
19
Starea unui obiect se schimb n conformitate cu metodele care i sunt
aplicate. Ne vom referi la aceast posibil secven de schimbare de stri ca fiind
comportarea obiectului.

Definiie: Comportarea unui obiect este definit de setul de metode care i poate fi
aplicat.

Avem acum dou concepte principale ale orientrii pe obiect, clasa i obiectul.
Programarea orientat pe obiect este deci implementarea unui tip de date abstract, sau, cu
alte cuvinte, transcrierea claselor. n momentul execuiei instanele acestor clase,
obiectele, realizeaz scopul programului prin schimbarea strii lor. De aceea se poate
interpreta c un program executabil este o colecie de obiecte. Problema care se pune este
cum interacioneaz aceste obiecte? Vom introduce un nou concept, acela de mesaj.

3.4. Mesaj

Un program executabil este o colecie de obiecte care sunt create, interacioneaz
i sunt distruse. Interaciunea se bazeaz pe mesaje care sunt transmise de la un obiect la
altul cernd destinatarului s aplice asupra sie nsui o metod. Pentru a face neleas
aceast comunicare, vom reveni la clasa Integer prezentat la 3.2. n pseudocodul utilizat
putem crea obiecte noi i putem invoca asupra lor metode. De exemplu, putem utiliza:

Integer i; /* definirea unui obiect nou integer */
i.setValue(1); /* Setarea valorii lui la */

pentru a exprima faptul c obiectul ntreg i este setat la valoarea 1. Mesajul care
este transmis obiectului i este: aplic-i metoda setValue cu argumentul 1. Am notat
transmiterea mesajului cu .. Aceasta este notaia care este utilizat i n limbajul C++.
Alte limbaje orientate pe obiect pot utiliza alte notaii, de exemplu -.
Transmiterea unui mesaj care cere unui obiect s-i aplice o metod este similar
cu apelarea unei proceduri ntr-un limbaj de programare tradiional. Putem spune
aadar c orientarea pe obiect este imagine a unor obiecte autonome care comunic unele
cu altele prin schimbul de mesaje. Obiectele reacioneaz atunci cnd recepioneaz
mesaje aplicndu-i metode pe ele nsele. Ele pot de asemenea s invalideze execuia unei
metode, de exemplu n cazul n care obiectul apelat nu are permisiunea s execute metoda
cerut.
n exemplul nostru, mesajul i metoda care trebuie aplicat odat recepionat
mesajul au acelai nume: Transmitem mesajul aplic-i metoda setValue cu argumentul
1 obiectului i care aplic setValue (1).

Definiie: Un mesaj este o cerere adresat unui obiect de a-i invoca una dintre metodele
sale. Un mesaj va conine:
- numele metodei i
- argumentele metodei.

n consecin, invocarea unei metode este reacia cauzat de recepionarea unui
mmesaj. Acest lucru este posibil numai n cazul n care metoda este cunoscut obiectului.
20

Definiie: O metod este asociat cu o clas. Un obiect invoc o metod ca reacie la
recepionarea unui mesaj.

3.5. Rezumat

Principiul fundamental al programrii orientate pe obiect este acela de a vedea un
program ca fiind o colecie de obiecte care interacioneaz. Obiectele din aceast colecie
reacioneaz dup ce au recepionat un mesaj schimbndu-i starea n conformitate cu
invocarea metodelor care pot cauza transmiterea altor mesaje ctre alte obiecte. Acest
lucru este ilustrat n figura 3.1.
n aceast figur programul const din numai patru obiecte. Aceste obiecte
transmit mesaje unul altuia aa cum se indic prin sgei. Se observ c obiectul trei i
transmite sie nsui un mesaj.

Figura 3.1: Un program constnd din patru
obiecte.

Cum ne ajut o astfel de privire n dezvoltarea unui software? Pentru a rspunde
la aceast ntrebare s ne reamintim cum am dezvoltat software pentru limbaje de
programare procedurale. Primul pas a fost acela de a diviza problema n piese mai mici i
mai uor de administrat. Tipic, aceste piese sunt orientate ctre proceduri care vor rezolva
problema, mai puin ctre datele invocate.
Ca exemplu, s considerm un calculator. Mai precis, cum apare un caracter pe
ecran atunci cnd este apsat o tast. ntr-un mediu procedural sunt civa pai necesar
de a fi urmai pentru a aduce un caracter pe ecran:
1. ateapt, pn cnd este apsat o tast;
2. ia valoarea (codul) tastei;
3. scrie valoarea tastei la poziia curent a cursorului
4. avanseaz poziia cursorului.

21
Nu se pot distinge entiti cu proprieti bine definite i cu comportare bine
definit. ntr-un mediu orientat pe obiect se va distinge interaciunea care are loc ntre
taste i ecran. Odat ce o tast recepioneaz un mesaj care i va schimba starea n a fi
apsat, obiectul corespunztor ei va transmite un mesaj ctre obiectul ecran. Acest
mesaj cere obiectului ecran s afieze valoarea asociat tastei.

3.6. Exerciii

1. Clasa
a) Ce deosebete o clas de un ADT?
O clas este reprezentarea actual a unui ADT. De exemplu, un ADT pentru
ntregi poate include o operaie set pentru a seta valoarea instanelor sale. Aceast
operaie este implementat diferit n limbaje de programare diferite. n C semnul egal
definete operaia de setare pentru ntregi. n timp ce n limbajul Pascal este utilizat irul
de caractere :=. n consecin, clasele implementeaz operaiile pentru a furniza
metode. Similar, structura de date a unui ADT este implementat de ctre atributele
clasei.
b) Realizai o clas pentru ADT Complex. Ce reprezentri alegei pentru
operaiile ADT? De ce?
Class Complex
class Complex
{
attributes:
Real real,
imaginary

methods:
:=(Complex c) /* Seteaz valoarea unui numr complex */
Real realPart()
Real imaginaryPart()
Complex +(Complex c)
Complex -(Complex c)
Complex /(Complex c)
Complex *(Complex c)
}

Am ales simbolurile cunoscute pentru operatori: +pentru adunare, - pentru
scdere, / pentru mprire i * pentru nmulire pentru a implementa operaiile
corespunztoare ale unui ADT Complex. Astfel, obiecte ale clasei Complex pot fi utilizate
cum urmeaz:

Complex c1, c2, c3
c3 := c1 + c2

Instruciunea de adunare poate avea i forma:

c3 := c1.+(c2)

22
Se poate nlocui semnul + cu add pentru a reveni la o reprezentare pe care am
utilizat-o mai demult. Oricum, trebuie neles faptul c + nu este altceva (nimic mai
mult) dect un alt nume pentru add.

2. Mesaje
a) De ce vorbim despre mesaje i nu de apel de procedur?
Obiectele sunt entiti autonome care ofer numai o interfa bine definit. Am
vorbit despre obiecte ca fiind entiti active. De exemplu, obiectele sunt responsabile de
ele nsele, ele pot invalida invocarea unei metode. Acest fapt deosebete un obiect de un
modul, care este pasiv. Acesta este motivul pentru care nu vorbim despre apel de
procedur. Vorbim despre mesaje care cer unui obiect s-i invoce una dintre metodele
proprii.
b) Enumerai cteva mesaje care au sens n mediul Internet (vor trebui identificate
obiecte).
Internetul ofer cteva obiecte. Dou dintre cele mai cunoscute sunt client i
server. De exemplu putem utiliza un client FTP (obiect) pentru a accesa datele memorate
pe un server FTP (obiect). Astfel, Clientul transmite un mesaj ctre server cerndu-i s
furnizeze datele memorate acolo.
c) De ce termenul mesaj are mai mult sens n ultimul exerciiu dect
termenul apel de procedur?
n mediul client-server avem dou entiti distante care acioneaz: clientul i
serverul. Tipic, aceste dou entiti schimb date sub forma unor mesaje Internet.

CAPITOLUL 4
Alte concepte ale orientrii pe obiect ( I )

n capitolul anterior au fost introduse concepte fundamentale ale programrii
orientate pe obiect. Acum vom detalia ideea orientrii pe obiect.

4.1. Relaii.

n exerciiul 2.6.4. am analizat relaia dintre tipurile de date abstacte i instane.
Vom intra n detalii.

Relaia de tip un fel de (A-Kind-Of).

Considem ca trebuie s realizm un program care realizeaz desene. Acest
program va permite desenarea unor obiecte variate, cum ar fi puncte, cercuri, ptrate,
triunghiuri i multe altele. De exemplu, clasa punct va defini un punct prin coordonatele
sale:
class Point
{
attributes:
int x, y

methods:
setX(int newX)
getX()
23
setY(int newY)
getY()
}
Vom continua definirea claselor programului de desen cu o clas care descrie
cercurile. Un cerc este definit de centru i de rez.
class Circle
{
attributes:
int x, y,
radius

methods:
setX(int newX)
getX()
setY(int newY)
getY()
setRadius(newRadius)
getRadius()
}

Comparnd cele dou definiii de clase putem observa urmtoarele:
Ambele clase au dou elemente drept date, x i y. n clasa Point aceste
elemente descriu poziia punctului, n clasa Circle ele descriu centrul cercului. Astfel, x i
y acelai neles n ambele clase: ele descriu poziia obiectului asociat prin definirea unui
punct.
Ambele clase ofer acelai set de metode pentru a obine sau a seta
valoarea celor dou elemente x i y.
Clasa Circle adaug un element nou de date radius (raza) i metodele de
acces corespunztoare.

Cunoscnd proprietile clasei Point, putem descrie un cerc ca fiind un punct plus
o raz i metode de a-l accesa. Astfel, un cerc este un fel de ( a kind of) punct.
Totui, un cerc este puin mai specializat. Putem ilustra aceast proprietate ntr-o manier
grafic:

Figure 4.1: Ilustrarea unei relaii de tip a-
kind-of''.

n acest figur i n figurile urmtoare clasele sunt reprezentate utiliznd
dreptunghiuri. Numele lor va ncepe ntotdeauna cu o majuscul. Sgeata indic direcia
relaiei, astfel nct se poate citi Cercul este un fel de Punct.



24

Relaia de tipul este o (is a)

Relaia anterioar este utilizat la nuvelul clasei pentru a descrie relaia dintre
dou clase similare. Dac vom crea obiecte ale unor astfel de dou clase vom considera
relaia dintre ele ca fiind de tip este o.
Deoarece clasa Circle este un fel de clas Point, o instan a Circle, numit
acircle, este un point. n consecin, fiecare cerc are un comportament ca i un punct. De
exemplu, se poate deplasa un punct pe direcia x prin modificarea valorii lui x. Similar, se
poate deplasa i un cerc n aceast direcie prin modificarea valorii sale x. Figura 4.2.
ilustreaz aceast relaie. n aceast figur i n urmtoarele obiectele vor fi desenate
utiliznd dreptunghiuri cu coluri rotunjite. Numele lor vor fi scrise numai cu litere mici.

Figure 4.2: Ilustrarea unei relaii de tip is-a''

Relaia de tipul parte a (part of)

Uneori este nevoie s putem construi obiecte combinndu-le cu altele. Se
cunoate acest lucru din programarea procedural unde se construiete o structur sau
nregistrare pentru a pune mpreun date de diferite tipuri.
S ne ntoarcem la programul de desen. Avem deja create cteva clase
pentru figurile accesibile. Vom decide c dorim s avem o figur special care s
reprezinte propriul logo care s constea din un cerc i un triunghi (s presupunem c
avem deja definit o clas Triangle). Astfel, logo-ul va consta din dou pri, sau, cu alte
cuvinte, cercul i triunghiul sunt pri (part of) ale logo-ului:

class Logo
{
attributes:
Circle circle
Triangle triangle

methods:
set(Point where)
}
Vom ilustra relaia n figura 4.3.

Figure 4.3: Ilustrarea unei relaii de tip part-of''


25

Relaia de tipul are o (has a)

Aceast relaie este versiunea invers a relaiei part of. De aceea vom putea cu
uurin aduga aceast relaie la ilustrarea relaiei part-of prin adugarea sgeilor cu
sens contrar (figura 4.4.).

Figure 4.4: Ilustrarea unei relaii de tip has-a ''

4.2. Motenirea

Cu motenirea vom avea posibilitatea s utilizm relaiile de tip a-kind-of i is-a.
Aa cum le-am descris, clasele care sunt un fel de (a-kind-of) alte clase mprtesc
proprietile acestora. n exemplul nostru cu punc i cerc putem defini un cerc care
motenete de la punct:
class Circle inherits from Point
{
attributes:
int radius

methods:
setRadius(int newRadius)
getRadius()
}

Clasa Circle motenete de la point toate elementele de date i toate metodele. Nu
mai este nevoie s le definim pentru a doua oar; vom utiliza definiiile existente ale
datelor i metodelor.
La nivelul obiect vom fi acum capabili s utilizm un cerc la fel cum am
utiliza un punct, deoarece cercul este (is-a) punct. De exemplu, putem defini un obiect
circle i putem seta coordonatele punctului centru:

Circle acircle
acircle.setX(1) /* motenite de la Point */
acircle.setY(2)
acircle.setRadius(3) /* adugat de Circle */

Relaia is-a este deasemenea implicat deoarece putem utiliza un cerc oriunde este
ateptat un punct. De exemplu, putem scrie o funcie sau o metod, s zicem move(), care
poate muta un punct n direcia x:

move(Point apoint, int deltax)
{
apoint.setX(apoint.getX() + deltax)
}
26

Deoarece un cerc motenete de la un punct, putem utiliza aceast funcie cu un
argument cerc pentru a muta punctul centru i, astfel, ntreg cercul:

Circle acircle
...
move(acircle, 10) /* mut cercul prin modificarea centrului*/

Vom ncerca s formalizm termenul de motenire:

Definiie: Motenirea este mecanismul care permite unei clase A s moteneasc
proprietile unei clase B. Vom spune c A motenete de la B. Obiectele clasei A vor
avea astfel acces la atributele i metodele clasei B fr a fi nevoie s le redefinim.

Urmtoarea definiie definete doi termeni cu care avem posibilitatea s ne
referim la clasele participante la procesul de motenire.

Definiie: Dac clasa A motenete de la clasa B, atunci B se numete superclas a lui A.
A este numit subclas a lui B. Obiectele unei subclase pot fi utilizate acolo unde sunt
ateptate obiecte ale superclasei. Aceasta este posibil datorit faptului c obiectele
subclasei au acelai comportament ca i obiectele superclasei.

n literatur se mai pot ntlni i ali termeni pentru superclas, respectiv subclas.
Superclasa se mai numete i clas printe, iar subclasa se mai poate numi clas fiu, sau
clas derivat.
Bineneles, se poate moteni n continuare i de la o subclas, fcnd din aceasta
o superclas a noii subclase. Aceasta duce la o ierarhie de relaii superclase/subclase.
Dac se deseneaz aceast ierarhie se obine un graf al motenirii.

Un desen comun, o schem, se poate realiza utiliznd sgei pentru a indica relaia
de motenire ntre dou clase sau obiecte. n exemplul nostru am utilizat motenit de la
. n consecin, sgeata pornete de la subclas pn la superclas, aa cum este ilustrat
n figura 4.5.

Figura 4.5: Un graf simplu pentru
motenire

27
n literatur se mai pot ntlni ilustraii n care sgeile sunt orientate invers.
Sensul n care este orientat sgeata depinde de modul n care decide autorul s
interpreteze relaia.

4.3. Motenirea multipl

Un mecanism important al orientrii pe obiect este motenirea multipl.
Motenirea multipl nu nseamn c mai multe subclase mprtesc aceeai superclasa.
De asemenea nu nseamn c o subclas poate moteni de la o clas care la rndul ei este
o subclas a unei alte clase.
Motenirea multipl nseamn c o subclas poate avea mai mult dect o
superclas. Aceasta permite subclasei s moteneasc proprietile mai multor superclase
i s le mbine.

Ca un exemplu vom considera din nou programul de desen. Presupunem c avem
deja o clas String care permite manevrarea convenient a unui text. De exemplu, trebuie
s avem o metod pentru a apela un alt text. n programul nostru vom dori s utilizm
aceast clas pentru a aduga text la obiectele posibil de desenat. Va fi de asemenea
posibil s utilizm rutinele existente cum ar fi move() pentru a modifica poziia textului.
n consecin, are sens s presupunem c un text desenat are un punct care s defineasc
locaia n spaiul de desenat. De aceea vom deriva o clas nou DrawableString care
motenete proprieti de la Point i String aa cum este ilustrat n figura 4.6.

Figura 4.6: DrawableString motenete proprietile de la Point
and String.

n limbajul pseudocod vom scrie acest lucru:

class DrawableString inherits from Point, String
{
attributes:
/* All inherited from superclasses */

methods:
/* All inherited from superclasses */
}
28
Vom putea utiliza obiecte ale clasei DrawableString ca i cnd ar fi puncte
(points) sau iruri (strings). Deoarece un obiect drawablestring este (is-a) point el poate fi
deplasat:
DrawableString dstring
...
move(dstring, 10)
...
Deoarece este (is-a) un string, putem scrie cu ajutorul lui un alt text:
dstring.append("The red brown fox ...")

Definiie: Dac o clas A motenete de la mai mult de o clas, adic A
motenete de la B1, B2,.., Bn, vorbim despre o motenire multipl. Aceasta poate
introduce conflicte de nume n A dac cel puin dou din superclasele sale definesc
proprieti diferite cu acelai nume.
Definiia de mai sus a introdus termenul de conflicte de nume care apare atunci
cnd mai mult de o superclas utilizeaz acelai nume pentru atribute sau metode. De
exemplu, s presupunem c n clasa String este definit o metod setX() care seteaz irul
la o secven de caractere X. ntrebarea care se pune este ce va moteni
DrawableString? Versiunea Point, versiunea String, sau niciuna?
Aceste conflicte pot fi rezolvate n cel puin dou moduri:
Ordinea n care apar superclasele va decide care dintre proprieti este
accesibil. Celelalte vor fi ascunse.
Subclasa trebuie s resolve conflictul prin furnizarea unei proprieti
numind-o i definirea modului n care va fi utilizat una dintre superclasele sale.

Prima soluie nu este foarte convenabil deoarece introduce consecine implicite
depinznd de ordinea n care clasele se motenesc unele pe altele. Pentru al doilea caz,
subclasele trebuie sa redefineasc explicit proprietile care sunt implicate ntr-un conflict
de nume.
Un tip special de conflict este introdus dac o clas D motenete multiplu de la
superclasele B i C care la rndul lor sunt derivate dintr-o superclas A. Aceasta conduce
la un graf al motenirii ca n figura 4.7.

Figura 4.7: Un conflict de nume introdus de o
superclas mprtit de de alte superclase utilizate n
motenirea multipl.
29

ntrebarea care rezult este care dintre proprietile lui D sunt motenite de la
superclasele B i C? Unele dintre limbajele existente rezolv aceast motenire special
prin divizarea lui D cu
Proprietile lui A plus
Proprietile lui B i C excluznd proprietile pe care le-au motenit
acestea de la A.

n consecin, D nu poate introduce conflicte de nume cu nume ale clasei A.
Totui, dac B i C aduc proprieti cu acelai nume, D va ajunge la un conflict de nume.
Alt posibil soluie este ca D s moteneasc din ambele pri. n aceast
soluie D D va avea dou copii ale proprietilor lui A: una este motenit de la B, alta de
la C.
Dei motenirea multipl este un mecanism foarte puternic al orientrii pe obiecte,
din cauza conflictului de nume muli autori o evit. Deoarece rezultatul motenirii
multiple poate fi atins i cu ajutorul motenirii simple, unele limbaje orientate pe obiect
nu permit utilizarea motenirii multiple. Totui, utilizat cu grij, sub anumite condiii,
motenirea multipl ofer o cale eficient i elegant pentru formularea problemelor.

4.4. Clase abstracte

Cu ajutorul motenirii putem fora o subclas s ofere aceleai proprieti ca i
superclasele sale. n consecin, obiectele unei subclase se comport la fel ca obiectele
superclasei.
Uneori are sens ca proprietile unui set de obiecte s fie numai descrise, fr a
cunoate comportarea actual. n exemplul de program de desen, fiecare obiect poate
oferi o metod de a fi desenat n aria de desen. Totui, paii necesari pentru a desena un
obiect depind de modul de reprezentare. De exemplu, rutina de desenare a unui cerc este
diferit de rutina de desenare a unui dreptunghi.
S numim metoda de desenare print(). Pentru a fora fiecare obiect desenabil s
includ o astfel de metod, vom defini o clas DrawableObject din care fiecare alt clas
din exemplul nostru va moteni proprietile generale ale obiectelor desenabile:

abstract class DrawableObject
{
attributes:

methods:
print()
}

Aici vom introduce un cuvnt cheie nou, abstract. El va fi utilizat pentru a
exprima faptul c clasele derivate trebuie s redefineasc proprietile pentru a asigura
o funcionalitate deplin. Astfel, din punctul de vedere al clasei abstracte, proprietile
sunt numai specificate, dar nu pe deplin definite. Definirea complet incluznd semantica
proprietilor trebuie furnizat de clasele derivate.
Acum, fiecare clas din exemplul de program de desen motenete proprieti de
la clasa general de obiecte desenabile. Astfel clasa Point se transform n:
30

class Point inherits from DrawableObject
{
attributes:
int x, y

methods:
setX(int newX)
getX()
setY(int newY)
getY()
print() /* Redefinit pentru Point */
}

Acum avem posibilitatea de a fora fiecare obiect desenabil s dein o metod
print care s poat furniza funcionalitatea de a desena obiectul n aria de desenare.
Superclasa tuturor obiectelor desenabile, clasa DrawableObject, nu va oferi nici o
funcionalitate care s permit desenarea ei. Aceasta deoarece nu este n intenia noastr
de a crea obiecte din ea. Aceast clasa va avea numai rolul de a specifica proprietile pe
care trebuie s le defineasc fiecare dintre clasele derivate. Ne vom referi la aceast clas
special ca fiind o clas abstract.

Definiie: O clas A este numit clas abstract dac este utilizat numai ca superclas
pentru alte clase. Clasa A numai va specifica proprieti. Nu va fi utilizat pentru a crea
obiecte. Clasele derivate trebuie s defineasc proprietile specificate de ctre A.

Clasele abstracte ne permit s structurm graful motenirilor.

4.5. Exerciii

1. Motenire. Considerm din nou exemplul cu programul de desen.
a) Definii o clas Rectangle prin motenirea de la clasa Point. Punctul poate indica
poziia colului din stnga sus a dreptunghiului. Care vor fi atributele clasei? Ce metode
noi vei introduce?




Definiia clasei Rectangle:
class Rectangle inherits from Point
{
attributes:
int _width, // lungimea dreptunghiului
_height // limea dreptunghiului

methods:
setWidth(int newWidth)
getWidth()
setHeight(int newHeight)
getHeight()
}
31
n acest exemplu este definit un dreptunghi prin colul stnga superior (coordonate
motenite de la Point) i prin dimensiunile sale. O alt variant ar fi definirea lui prin
colul stnga superior i colul dreapta inferior. Ca metode noi de acces sunt lungimea i
limea.
b) Toate exemplele curente sunt date pe baza unei priviri bidimensionale. Se dorete
introducerea obiectelor tridimensionale, cum ar fi sfera, cubul, paralelipipedul. Creai o
clas Sphere prin utilizarea unei clase 3D-Point. Specificai rolul punctului n sfer. Ce
relaii vei utiliza ntre clasa Point i clasa 3D-Point?

O sfer este definit prin centru n spaiul tridimensional i o raz. Centrul este un punct
n spaiul tridimensional, aa c definim clasa Sphere astfel:
class Sphere inherits from 3D-Point
{
attributes:
int _radius;

methods:
setRadius(int newRadius)
getRadius()
}
Aceast definire este similar cu o clas cerc n spaiu bidimensional.
Pentru clasa 3D-Point , aceasta este o clas Point cu o dimensiune adiional:

class 3D-Point inherits from Point
{
attributes:
int _z;

methods:
setZ(int newZ);
getZ();
}
n consecin, 3D-Point i Point sunt ntr-o relaie de tip is-a.
c) Ce funcionalitate ofer move() pentru obiectele tridimensionale?
move() ,aa cum a fost definit, permite obiectelor 3D s se deplaseze pe axa x, adic
ntr-o singur dimensiune.
d) Desenai graful motenirilor incluznd clasele DrawableObject, Point, Circle,
Rectangle, 3D-Point i Sphere.
Figura 4.8: Graful motenirilor pentru cteva obiecte desenabile.
32

e) Privii graful motenirilor din figura 4.9.
Figura 4.9: Variant de graf pentru clasa Sphere.
O definire conform cu acest graf ar putea fi:
class Sphere inherits from Circle
{
attributes:
int z /* Add third dimension */

methods:
setZ(int newZ)
getZ()
}
Dai cteva avantaje/dezavantaje pentru aceast alternativ.
n acest exemplu clasa Sphere motenete de la Circle i doar adaug a treia coordonat.
Aceasta are ca avantaj faptul c sfera poate fi manevrat ca un cerc (de exemplu raza sa
poate fi modificat foarte simplu prin metode/funcii cu care sunt manevrate cercurile).
33
Are ca dezavantaj faptul c distribuie manevrarea obiectului (punctul centru n spaiul
3D) peste ierarhia motenirilor: de la Point peste Circle la Sphere. Astfel, manevrarea nu
este accesibil ca un ntreg.
2. Motenirea multipl. Comparai grafurile motenirilor din figurile 4.7 i 4.10. n
aceast figur am reprezentat faptul c B i C au fiecare propria copie a lui A.
Figura 4.10: Ilustrarea unei a doua variante pentru motenirea multipl

Graful din figura 4.10 introduce conflict de nume prin proprietile clasei A.
Totui, aceste proprieti sunt unic identificate prin utilizarea cii de la D la A. Astfel, D
poate modifica proprietile lui A motenite de B prin utilizarea cii de motenire prin B.
Similar, D poate modifica proprieti ale lui A motenite prin C prin utilizarea cii de
motenire prin C. n consecin, acest conflict de nume nu conduce n mod obligatoriu la
o eroare atta timp ct sunt definite cile.







34
CAPITOLUL 5
Alte concepte ale orientrii pe obiect ( II )
Continum prezentarea conceptelor programrii orientate pe obiect printr-o sumar
introducere n legturi statice i dinamice. Cu ajutorul acestora vom putea introduce apoi
noiunea de polimorfism ca un mecanism care permite aplicarea unei singure interfee
pentru mai multe situaii similare, implementndu-se filozofia o singur interfa, mai
multe metode. Polimorfismul permite scoaterea n eviden a relaiei logice ntre aciuni
similare.
5.1. Tipuri generice
Cunoatem deja tipurile generice dintr-un capitol anterior atunci cnd am discutat
despre tipuri de date abstracte generice. Cnd definim o clas, noi definim un tip definit
de utilizator (user define type). Unele din aceste tipuri pot opera asupra altor tipuri. De
exemplu, pot exista liste de mere, liste de maini, liste de numere complexe i chiar liste
de liste.
n momentul n care definim o clas trebuie s fim capabili s spunem c acea
clas va defini un tip generic. Totui, nu vom sti cu ce tipuri va fi utilizat clasa. n
consecin, trebuie s definim clasa cu ajutorul unui placeholder la care ne vom referi ca
fiind tipul asupra cruia opereaz clasa. Astfel, definirea clasei ne va furniza un template
al unei clase actuale. Definiia unei clase actuale este creat odat ce vom declara un
obiect particular. S ilustrm acest lucru cu urmtorul exemplu. S presupunem c dorim
s definim o clas li9st care va fi un tip generic. Astfel, va fi posibil s declarm obiecte
list pentzru mere, maini, sau alte tipuri.

template class List for T
{
attributes:
... /* Structura de date necesar pentru implementarea */
/* listei */

methods:
append(T element)
T getFirst()
T getNext()
bool more()
}

Clasa template List arat ca orice alt definiie de clas. Totui, prima linie
decclar List ca fiind un template pentru diferite tipuri. Identificatorul T este utilizat ca
placeholder pentru un tip actual. De exemplu, append() ia un element ca argument. Tipul
acestui element va fi tipul de date cu care va fi creat un obiect list actual. De exemplu,
putem declara un obiect lista pentru meredac exist o definiie a tipului mere.



35
List for Apple appleList
Apple anApple,
anotherApple
appleList.append(anotherApple)
appleList.append(anApple)

Prima linie declar appleList ca fiind o list de mere. n acest moment,
compilatorul utilizeaz definiia template, substituie oriunde apare T cu Apple i creaz o
definiie de clas actual pentru aceasta. Aceasta conduce la o definiie de clas similar
cu cea care urmeaz:

class List
{
attributes:
... /* Structura de date necesar pentru implementarea */
/* listei */

methods:
append(Apple element)
Apple getFirst()
Apple getNext()
bool more()
}

Ceea ce este mai sus nu este exact ceea ce genereaz compilatorul. Compilatorul
trebuie s se asigure c noi putem crea liste multiple pentru tipuri diferite n orice
moment. De exemplu, dac avem nevoie de o alt list, de exemplu de pere, putem scrie:

List for Apple appleList
List for Pear pearList

n ambele cazuri compilatorul genereaz o definiie de clas actual. Motivul
pentru care cele dou nu intr n conflict prin numele lor este acela c compilatorul
genereaz nume unice. ntruct acest lucru nu ne este vizibil, nu intrm n detalii. n
orice caz, dac declarm o alt list de mere, compilatorul va indica faptul c exist deja
o astfel de definiie de clas actual i o va utiliza pe aceasta, sau dac nu exist va crea
una nou. Astfel,

List for Apple aList
List for Apple anotherList

Va crea o definiie de clas actual pentru aList i o va reutiliza pentru anotherList. n
consecin, ambele vor fi de acelai tip. Vom rezuma toate acestea n urmtoarea
definiie:
Definiie: Dac o clas A este parametrizat cu un tip de date B, A este numit clas
template. Odat creat un obiect A, B este nlocuit cu un tip de date actual. Aceasta
permite definirea unei clase actuale bazat pe specificaia template a lui A i pe tipul de
date actual.
Suntem capabili s definim clase template cu mai mult de un parametru. De
exemplu, directoarele sunt colecii de obiecte n care fiecare obiect poate fi referit printr-o
36
cheie. Desigur, un director poate fi capabil s memoreze orice tip de obiect. Dar sunt
posibile, deasemenea, o varietate de chei. De exemplu, cheile pot fi iruri de caractere sau
numere. n consecin, vom putea defini o clas template Directory care se bazeaz pe
dou tipuri de parametri, unul pentru cheie i unul pentru obiectele memorate.

5.2. Legturi statice i dinamice

n limbajele de programare puternice tipic se declar variabilele nainte de a fi
utilizate. Aceasta implic definirea variabilelor prin care compilatorul rezerv spaiu
pentru variabile. De exemplu, n Pascal o expresie de felul:

var i : integer;

declar variabila i ca fiind de tip ntreg. n plus, ea definete un spaiu de memorie
suficient pentru a memora o valoare ntreag. Cu declaraia vom lega numele i de tipul
integer. Aceast legtur este adevrat n scopul n care i este declarat. Aceasta permite
compilatorului s verifice n timpul compilrii consistena tipului. De exemplu, n
urmtoarea asociere va rezulta o eroare de nepotrivire de tip cnd vom ncerca
compilarea:

var i : integer;
...
i := 'string';

Acest tip particular de legtur l vom numi static deoarece este fixat n timpul
compilrii.

Definiie: Dac tipul T al unei variabile este explicit asociat cu numele su N prin
declarare, vom spune c numele N este legat static de T. Procesul de asociere este numit
legare static.

Exist limbaje de programare care nu utilizeaz tipizarea explicit a variabilelor.
De exemplu, unele limbaje permit introducerea de variabile n momentul n care sunt
necesare:

... /* Nu apare i */
i := 123 /* Crearea lui i ca un ntreg */

Tipul lui i este cunoscut de ndat ce i este setat valoarea. n acest caz, i este
ntreg din momentul n care i atribuim ntregul numr. Astfel, deoarece coninutul lui i
este un numr, tipul lui i este integer.

Definiie: Dac tipul T al unei variabile cu numele N este implicit asociat de coninutul
su, vom spune c N este legat dinamic de T. Procesul de asociere este numit legare
dinamic.

Cele dou legri difer prin momentul n care are loc legarea tipului la variabile.
Considerm exemplul de mai jos, care este posibil numai n cazul legrii dinamice:
37
if somecondition() == TRUE then
n := 123
else
n := 'abc'
endif

Tipul lui n dup instruciunea if depinde de evaluarea condiiei somecondition().
Dac aceasta este TRUE, n este de tip integer, altfel este de tip string.

5.3. Polimorfism

Polimorfismul permite unei entiti (de exemplu variabil, funcie sau obiect) s ia
o varietate de reprezentri. Va trebui s facem diferena ntre diferite tipuri de
polimorfism.
Primul tip este similar conceptului de legare dinamic. Aici, tipul variabilei
depinde de coninutul su. Astfel, tipul su depinde de coninut la un moment dat:

v := 123 /* v este integer */
... /* utilizarea lui v ca integer */
v := 'abc' /* v "comut" la string */
... /* utilizarea lui v ca string */

Definiie: Conceptul de legare dinamic permite unei variabile s ia diferite tipuri n
funcie de coninutul de la un moment dat. Aceast abilitate a unei variabile este numit
polimorfism.

Un alt tip de polimorfism poate fi definit pentru funcii. De exemplu, presupunem
c dorim s definim o funcie isNull() care returneaz TRUE dac argumentul su este 0
i FALSE altfel. Pentru numere ntregi este simplu:

boolean isNull(int i)
{
if (i == 0) then
return TRUE
else
return FALSE
endif
}

Totui, dac dorim s verificm acest lucru pentru numere reale, va trebui s utilizm o
alt comparaie datorit problemei de precizie:

boolean isNull(real r)
{
if (r < 0.01 and r > -0.99) then
return TRUE
else
return FALSE
endif
}

38
n ambele cazuri dorim ca funcia s aib acelai nume isNull. n limbajele de programare
fr polimorfism pentru funcii nu vom putea declara aceste dou funcii, dublarea
numelui crend ambiguitate. Totui, dac limbajul poate lua n considerare parametrii
pentru funcii, declararea poate fi posibil. Astfel funciile (metodele) sunt unic
identificate prin:
numele funciei (metodei) i
tipurile din lista parametrilor.

Deoarece lista parametrilor celor dou funcii isNull difer, compilatorul este capabil s
ofere apelarea corect a funciei prin utilizarea tipului actual al argumentelor:

var i : integer
var r : real

i = 0
r = 0.0

...

if (isNull(i)) then ... /* utilizare isNull(int) */
...
if (isNull(r)) then ... /* utilizare isNull(real) */


Definiie: Dac o funcie (sau o metod) este definit prin combinaia
numele su i
lista de tipuri pentru paramerii si
vorbim despre polimorfism. Acest tip de polimorfism permite reutilizarea aceluiai nume
pentru funcii (metode) att timp ct listele parametrilor difer. Uneori acest tip de
polimorfism este numit suprancrcare, supradefinirea (overloading).

Ultimul tip de polimorfism permite unui obiect s i aleag metodele corecte.
Considerm din nou funcia move(), care ia un obiect din clasa Point ca argument. Am
utilizat aceast funcie cu orice obiect al claselor derivate, datorit relaiei de tipul is-a.
Vom considera acum funcia display() care va fi utilizat pentru afiarea obiectelor
desenabile. Declaraia aceste funcii poate arta astfel:

display(DrawableObject o)
{
...
o.print()
...
}
Vom dori s utilizm aceast funcie cu obiecte ale claselor derivate din DrawableObject:




39
Circle acircle
Point apoint
Rectangle arectangle
display(apoint) /* Should invoke apoint.print() */
display(acircle) /* Should invoke acircle.print() */
display(arectangle) /* Should invoke arectangle.print() */
Metoda actual va fi definit de coninutul obiectului o al funciei display(). ntruct este
destul de complicat, vom lua un exemplu mai abstract:
class Base
{
attributes:

methods:
virtual foo()
bar()
}

class Derived inherits from Base
{
attributes:

methods:
virtual foo()
bar()
}

demo(Base o)
{
o.foo()
o.bar()
}

Base abase
Derived aderived

demo(abase)
demo(aderived)

n acest exemplu am definit dou clase Base i Derived. Fiecare clas definete dou
metode foo() i bar(). Prima metod este definit ca virtual. Aceasta nseamn c dac
aceast metod este invocat, definirea ei va fi evaluat prin coninutul obiectului.
Definim apoi o funcie demo() care ia ca argument un obiect Base. n consecin, putem
utiliza aceast funcie cu obiecte ale clasei Derived deoarece este valabil relaia is-a.
Vom apela aceast funcie cu un obiect Base i respectiv cu un obiect Derived.
Presupunem c foo() i bar() sunt definite pentru a tipri numele lor i clasa din care sunt
definite. n acest caz la ieire vom avea:

foo() of Base called.
bar() of Base called.
foo() of Derived called.
bar() of Base called.
40
De ce acest rezultat? Primul apel al lui demo() utilizeaz un obiect Base. Astfel,
argumentul funciei este ocupat cu un obiect al clasei Base. n momentul invocrii
funciei foo(), funcionalitatea ei actual este aleas pe baza coninutului curent al
obiectului corespondent o. De aceast dat este un obiect al clasei Base. n consecin,
este apelat foo() cum a fost definit n clasa Base.
Apelul bar() nu este legat de coninutul su. Funcia nu este marcat ca virtual. n
consecin, bar() este apelat n maniera clasei Base.
Al doilea apel al demo() ia ca argument un obiect al clasei Derived. Astfel, argumentul o
este ocupat cu un obiect Derived. Totui, o nsui reprezint partea Base a obiectului
furnizat aderived.
Acum, apelul foo() este evaluat prin examinarea coninutului lui o, astfel nct este apelat
n maniera Derived. Pe de alt parte, bar() este n continuare evaluat n sensul Base.

Definiie: Obiectele unei superclase pot fi ocupate cu obiecte ale subclaselor sale.
Operatorii i metodele subclaselor pot fi definite pentru a fi evaluate n dou contexte:
1. Pe baza tipul obiectului, conducnd la o evaluare n sensul superclasei.
2. Pe baza coninutul obiectului, conducnd la o evaluare n sensul subclaselor coninute.
Al doilea tip este numit polimorfism.

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