Program Are Obiect Orientata 2 Anul II

214
 Universitatea “Transilvania” din Braşov Facultatea de Matematică şi Informatică Catedra de Informatică aplicată Programare obiect orientată 2 Dorin Bocu

Transcript of Program Are Obiect Orientata 2 Anul II

Page 1: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 1/214

Universitatea “Transilvania” din BraşovFacultatea de Matematică şi InformaticăCatedra de Informatică aplicată

Programare obiect orientată 2

Dorin Bocu

Page 2: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 2/214

...O parte din eforturile ştiinţei calculatoarelor sunt dedicate îmbunătăţirii permanentea paradigmelor de modelare. Prin istoric şi prin realizările de ultimă oră, ingineria softului nu face decât să confirme această aserţiune.  Modelarea orientată pe obiecteeste un exemplu remarcabil de instrument, gândit pentru a fi utilizat în realizarea desisteme soft, competitive din punct de vedere al preţului şi al calităţii . Programareaorientată pe obiecte îngăduie fanilor ei să verifice, în practică, forţa unui stil de a

modela, a cărui capacitate de a mapa domeniul problemei peste domeniul soluţiei estecu mult superioară altor paradigme.

Cuvânt înainte al autorului

Au trecut ani buni de când lumea a început să întrebuinţeze, în vorbire şi în alte contexte, sintagma “programareobiect orientată” sau, ceva mai aproape de spiritul limbii române, “programare orientată pe obiecte”. Pregătită şianunţată de numeroasele controverse pe marginea preamultelor slăbiciuni ale vechilor paradigme de programare,

Page 3: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 3/214

orientarea pe obiecte s-a instalat confortabil de-a lungul întregului proces de dezvoltare a unui sistem soft, devenind înzilele noastre “religia care guvernează atât etapa de modelare a unui sistem soft cât şi etapa de implementare”.Au apărut limbaje, precum şi medii de programare şi dezvoltare a sistemelor soft, a căror arhitectură este esenţialtributară ideii de orientare pe obiecte (Java, C++, C#, Object Pascal – câteva exemple mai cunoscute de limbaje, Delphi,C-Builder, Visual C++ - câteva exemple mai cunoscute de medii de programare, Rational Rose, ObjectiF – două dintremediile de dezvoltare cu bună răspândire în lumea ingineriei softului).

Este clar, orientarea pe obiecte nu este doar o modă în programare, ci o modalitate, fără rival, pentrumoment, de a dezvolta sisteme soft.

Pentru informaticienii a căror practică se reduce la “apropierea cât mai rapidă de tastatură” pentru a rezolva o problemă, orientarea pe obiecte este o încercare care tulbură minţile şi întârzie rezolvarea problemei. Seriile de

studenţi care “mi-au trecut prin mână” mi-au întărit convingerea că   însuşirea spiritului orientării pe obiecte este o problemă destul de dificilă, deoarece, aproape tot ceea ce este reclamat de obşnuinţele omului în materie de învăţare,este dificil de operaţionalizat când este vorba de însuşirea acestui spirit. Mult mai apăsat decât în alte paradigme, înorientarea pe obiecte, specialistul trebuie să acorde atenţia cuvenită elaborării soluţiei înainte de a o implementa .Metodele cele mai răspândite de învăţare a limbajelor de programare se bazează pe formula:

Prin aplicaţii, spre descoperirea subtilităţilor sintactice, semantice şi pragmatice ale unui limbaj deprogramare.

Cititorul atent a înţeles faptul că învăţarea unui limbaj de programare este un exerciţiu de voinţă care presupune parcurgerea a trei etaje:

• Învăţarea stereotipurilor sintactice fundamentale ale limbajului (sintaxa limbajului)• Descoperirea unui număr cât mai mare de semantici primitive, care pot fi învelite cu sintaxa limbajului

(semantica limbajului)• Formarea unor deprinderi de utilizare eficientă a limbajului, în funcţie de natura şi complexitatea problemei,

 pentru rezolvarea respectivei probleme (pragmatica limbajului).

Ideea călăuzitoare a acestei cărţi este de a invita cititorul să înveţe singur sintaxa orientării pe obiecte, încercând să îl ajute, îndeosebi în efortul de deconspirare a semanticii şi pragmaticii orientării pe obiecte.

Trimiterile de natură sintactică vor fi raportate la limbajele Java şi C++, suficient de înrudite din punct de vederesintactic pentru a nu pune la grea încercare disponibilitatea la effort de rutină a cititorului. Ceva mai rar, se vor facetrimiteri şi la Object Pascal, un limbaj cu o istorie asemănătoare limbajului C++, din punct de vedere al modului încare permite îmbinarea trecutului şi a prezentului, în materie de suport pentru paradigmele de modelare.

Trebuie să mărturisesc, totodată, faptul că,  în viziunea acestui cărţi, fiecare cititor este o instanţă cognitivăactivă, capabilă de effort permanent de abstractizare, singura modalitate de a ajunge la o înţelegere superioară aesenţei unei paradigme de modelare şi, în particular, de programare.

Atitudinea de spectator, cu instinct de conservare puternic, la derularea ideilor din această carte, este absolutcontraproductivă pentru atingerea obiectivului fundamental:   învăţarea cât mai multor elemente - suport, esenţialepentru modelarea / programarea orientată pe obiecte a soluţiei unei probleme.

Page 4: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 4/214

Ce se va întâmpla cu cei care nu se vor putea împăca cu ideea de a se dezmorţi voluntar, iată o problemă în legăturăcu care prefer să spun doar atât: nu peste mult timp vor descoperi că au îmbătrânit înainte de vreme, fără a fi  înţeles mare lucru despre plăcerea de a uita de scurgerea timpului, realizând lucruri care să uimească,deopotrivă, pe alţii şi pe propriul lor creator.

Referindu-mă la studenţii pentru care, în principal, am scris această carte, trebuie să spun că, în viziunea mea, ideeade student se confundă cu imaginea unui individ care are apetenţă pentru studiu . Dacă, în facultate, se maistudiază şi discipline care, unora li se par, nefolositioare, datoria studentului este să facă efortul de a se identifica cuideile fundamentale ale unui număr cât mai mare de discipline, socotite de el folositoare. Dacă, în facultate, studenţii semai întâlnesac şi cu profesori ale căror căutări nu sunt încă suficient de bine sistematizate, acesta nu este un motiv de arenunţa la dorinţa de a cunoaşte.

De la natură, studentul poate fi asimilat cu un obiect care are toate capabilităţile necesare pentru a parcurgedrumul dificil, dar pasionant, al cunoaşterii elementelor fundamentale, în diferite ramuri ale matematicii şiştiinţei calculatoarelor.

Aş aminti, tuturor celor care nu au realizat încă, faptul că omul are nevoie de ştiinţă pentru a înţelege o parte dinrealitatea necunoscută ( rezultă că ştiinţa are funcţie explicativă), pentru a modela comportamentul unor fenomeneşi procese din realitatea obiectivă, în vederea optimizării dinamicii lor (rezultă că ştiinţa are funcţie modelatoare),pentru a îmbogăţi realitatea obiectivă cu obiecte artificiale (rezultă că ştiinţa are funcţie demiurgică).

Sper ca cititorul să înţeleagă bine rolul activ pe care trebuie să şi-l asume în deconspirarea, prin studiu individual şiexerciţii perseverente, a etajelor sintactice esenţiale programării în C++ şi Java.

Page 5: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 5/214

Capitolul 1Cum se explică permanenta nevoie de paradigme noi în ingineria softului

Ce înţelegem prin orientarea pe obiecte

Page 6: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 6/214

1.1 Cum se explică permanenta nevoie de paradigme noi  în ingineria softului?Binefacere sau blestem, omenirea este, asemenea întregului univers, într-o continuă deplasare spre alte repere

ontologice şi gnoseologice. Avea dreptate Heraclit din Efes când, folosind cuvinte meşteşugit alese, constata că singuracertitudine a universului pare a fi devenirea. Dacă, acum peste 2500 de ani în urmă, devenirea ocupa o poziţiecentrală în modul de gândire al lui Heraclit, în zilele noastre devenirea s-a transformat în izvor nesecat şi cauză a tuturor transformărilor importante pe care le suportă universul cunoscut omului. S-ar părea că nimic din ceea ce face omul nudurează. Acest fapt este, după ascuţimea simţurilor noastre, în opoziţie cu ceea ce Natura sau Marele Creator fac.Omul aspiră la eternitate luptând cu efemerul inerent al creaţiilor lui. Marele Creator este eternitatea însăşi. Las peseama filozofilor continuarea efortului de preamărire sau punere la index a rolului pe care îl joacă devenirea în viaţaomului şi, de ce nu, în univers.

Caracterul obiectiv al devenirii poate explica, în genere şi nevoia de paradigme1 noi în ingineria softului şi, în particular în programare.

*

Permiţându-mi o scurtă digresiune, ingineria softului este o ramură a ştiinţei calculatoarelor care se ocupă, la urmaurmei, de studierea unei probleme extrem de delicate: “Dată o problemă oarecare, ce trebuie făcut pentru a o

rezolva cu ajutorul calculatorului?”Confruntaţi de-a lungul timpului, cu diferite tipuri de probleme, specialiştii în ingineria softului au făcut odescoperire banală:

Efortul depus pentru a rezolva o problemă cu ajutorul calculatoruluieste direct proporţional cu complexitatea problemei.

Odată făcută această descoperire iese la iveală altă întrebare: “Cum definim complexitatea unei probleme?”Atenţie, cititorule, este vorba de complexitatea unei probleme nu de complexitatea soluţiei algoritmice a uneiprobleme.

Complexitatea unei probleme este o caracteristică intrinsecă a enunţului asumat al acesteia.Complexitatea soluţiei algoritmice a unei probleme este o caracteristică intrinsecă a modului în care o anumită

instanţă cognitivă (de pildă un student din anul II) obţine respectiva soluiţie algoritmică.

Este, sper, cât se poate de clar faptul că cele două tipuri de complexitate cuantifică caracteristicile structurale aleunor colecţii de obiecte, diferite din punct de vedere al sferei de cuprindere şi al conţinutului.

1 Este cazul să spunem că, prin paradigmă se înţelege, fără a exagera cu explicaţiile, un mod de abordare a problemelor dintr-un anumit domeniu,evident, cu scopul de a rezolva aceste probleme. Poate că limba română nu avea neapărată nevoie de acest cuvânt, dar insistenţa cu care este utilizat înalte părţi poate fi considerată o scuză pentru utilizarea lui în această carte.

Page 7: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 7/214

Cei care au parcurs unul sau mai multe cursuri de iniţiere în Algoritmică şi Programare îşi amintesc, probabil,înţelesul pe care îl are complexitatea unui algoritm. Formalizarea matematică a complexităţii algoritmilor este un prilejminunat de a ilustra forţa de analiză a matematicii de puterea continuului, aplicată universului algoritmilor, al căror comportament este eminamente discret.

Este corect să evidenţiem, în acest punct, utilitatea teoretică şi practică (îndeosebi în cazul aplicaţiilor critice relativla complexitatea algoritmilor folosiţi) a eforturilor de clasificare a algoritmilor secvenţiali şi paraleli, în funcţie decomplexitatea lor Acest gen de afirmaţii sunt prezentate în toată cuprinderea şi adâncimea lor în cărţi fundamentalepentru învăţărea programării calculatoarelor2.

Ingineria softului (IS) ia act de această realitate şi, în replică, îşi concentrează atenţia asupra complexităţiiproblemelor. O încercare de a evidenţia elementele cu ajutorul cărora putem descrie complexitatea unei probleme în

ingineria softului ne conduce la seria de observaţii de mai jos.

• Rezolvarea unei probleme cu ajutorul calculatorului înseamnă, de cele mai multe ori, simularea / asistarea decătre calculator a unor activităţi, desfăşurate de către sisteme de altă natură. Aşadar, aproape invariabil, neaflăm în faţa unor dificultăţi care rezultă din caracterul instabil al relaţiei dintre model şi sistemul modelat. Neglijarea acestui aspect simplifică efortul de realizare, în cele din urmă, a unui sistem soft, dar preţul plătiteste exprimat, sintetic, astfel: uzură morală rapidă şi posibilităţi de adaptare reduse. Se poate lupta cumijloace raţionale împotriva caracterului instabil al relaţiei dintre model şi sistemul modelat? Răspunsul este:da, se poate lupta, dacă specialistul în IS este dispus să anticipeze impactul posibilelor schimbări alesistemului modelat asupra soluţiei (modelului). Anticipând schimbările sistemului modelat, simplificămefortul de adaptare a soluţiei la aceste schimbări.

• Modelul care stă la baza soluţiei unei probleme abstractizează viziunea specialistului sau grupului despecialişti în IS, asupra sistemului modelat. Semn al posibilităţilor noastre limitate de a cunoaşte, orice viziunenu poate decât să aproximeze comportamentul sistemului modelat. Chiar şi în aceste condiţii, de la aaproxima defectuos până la a aproxima inspirat este nu doar un drum lung ci şi plin de diverse tipuri de încercări. Exemple de astfel de încercări:

• specificarea completă a cerinţelor funcţionale;• acordarea atenţiei cuvenite cerinţelor non-funcţionale;• alegerea inspirată a modalităţilor de armonizare a cerinţelor contradictorii;• alegerea inspirată a paradigmei de modelare, etc.

• Trecerea, cu succes, peste dificultăţile schiţate mai sus este realizată “în condiţii ergonomice” dacămanagementul acestor dificultăţi (plus nenumărate altele) este tratat cu maximum de seriozitate şi competenţă.

Încercând să forţăm o concluzie, complexitatea unei probleme în IS este influenţată de:

1. Stabilitatea relaţiei model-sistem modelat; lipsa de stabilitate în această relaţie, asumată conştient, inducecreşterea complexităţii problemei de rezolvat.

2 Knuth, Cormen

Page 8: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 8/214

2. Complexitatea structurii sistemului modelat (creşterea acesteia induce, de asemenea, creşterea complexităţii problemei de rezolvat).

3. Desfăşurarea în condiţii de eficienţă a procesului de rezolvare a unei probleme, adaugă un plus de complexitateoricărei probleme. Neasumându-se acest plus de complexitate, putem uşor compromite procesul de realizare aunui sistem soft (=soluţia executabilă pe un calculator real a unei probleme date). Un management bun are derezolvat probleme de procurare şi alocare optimă a resurselor, comunicare între partenerii de proiect(=specialiştii în IS, beneficiarii, utilizatorii), lansare cu succes pe piaţă (dacă este cazul), etc. Nu aş sfătui penici un specialist în IS să considere normală o afirmaţie de genul: “Dacă cele spuse la punctul 2 sunt tratate cumaximum de seriozitate şi competenţă, 1 şi 3 nu mai înseamnă mare lucru”. Îndeosebi în cazul proiectelor 

mari, s-a dovedit, de nenumărate ori, neadevărul unei astfel de afirmaţii.

În IS, complexitatea problemelor nu este un accident; mai mult, putem spune că este legitim să ne aşteptăm laelemente de complexitate chiar şi acolo unde s-ar părea că acestea sunt lipsă. Dacă mai amintim cititoruluiobservaţia tendenţioasă, potrivit căreia complexitatea de calitate se întemeiază pe simplitate , acesta înţelege mai bineinsistenţa cu care prezint implicaţiile complexităţii unei probleme asupra calităţii soluţiei acestei probleme. Calitate?Complexitate3? Complexitate de calitate? Multe se mai pot spune. Specialistul în IS doreşte să ştie câteva lucrurisimple:

• Care sunt primejdiile?• Care sunt exigenţele?• Cum se poate evita un eşec?, etc.

Astfel de întrebări, ne vom pune, într-o formă sau alta şi în această carte de iniţiere în programarea orientată peobiecte şi le puteţi găsi reluate în cărţile Iniţiere în ingineria sistemelor soft şi Iniţiere în modelarea obiect orientatăa sistemelor soft utilizând UML, scrise de D. Bocu şi apărute la Editura Albastră.

 Nevoia presantă de a căuta, permanent, răspunsuri noi la astfel de întrebări, justifică avalanşa de noutăţi carecaracterizează şi lumea limbajelor de modelare, specifice ingineriei softului.

1.2 Ce se înţelege prin orientarea pe obiecte?S-au scris destule cărţi pe tema orientării spre obiecte. Şi mai multe sunt, probabil, articolele din revistele de

specialitate. Unele, foarte convingătoare. Altele mai puţin. Nu cred că voi umple, brusc, golul care mai există, încă, înlimba română, scriind această carte. Dar voi încerca să fac înţeles modul de gândire al unui specialist în IS, care vederealitatea informaţională în termeni specifici orientării spre obiecte.

Orice sistem informaţional4 este mai uşor de înţeles dacă avem elemente suficiente referitoare la datele

vehiculate în sistem, procedeele de prelucrare (vehiculare) a datelor din sistem, interfeţele sistemului cu mediul încare acesta operează. Fiecare dintre elementele specificate mai sus are reguli proprii de organizare şi fiinţare. În plus,

3 Orice exerciţiu de modelare urmăreşte, indiferent de acuitatea mijloacelor de investigaţie, un anumit mod de organizare a complexităţii sistemuluimodelat.4 Ca şi realitatea informaţională, sistemul informaţional desemnează un ansamblu de resurse care optimizează fluxurile informaţionale dintr-un sistemgazdă. Pentru o documentare mai atentă invit cititorul să răsfoiască atent o carte bună de ingineria softului.

Page 9: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 9/214

<Soluţia unei probleme> = <Organizarea datelor>+ <Organizarea prelucrărilor>+ <Optimizarea interfeţelor>

mai există şi relaţiile strânse dintre aceste elemente. De fapt, întreaga istorie a IS se învârte în jurul ecuaţiei prezentatăîn Figura 1.

Figura 1. Ecuaţia generală a soluţiei unei probleme în IS.

Ecuaţia de mai sus a primit de-a lungul timpului numeroase rezolvări.*

Înainte de a descrie tipurile fundamentale de rezolvări, voi efectua o scurtă trecere în revistă a vocabularului IS,esenţial în comunicarea dintre partenerii unui proiect de dezvoltare a unui sistem soft.

Prin urmare, o firmă producătoare de soft produce şi livrează produse şi servicii care se adresează nevoilor şicerinţelor clienţilor. Cerinţele clienţilor constitue un exemplu de problemă cu care trebuie să se confrunte echipa dedezvoltare. Produsele şi serviciile care satisfac aceste cerinţe pot fi considerate ca fiind soluţii. Pentru a livra soluţiivalide (= de calitate, la preţ de cost redus şi în timp util) firmele trebuie să facă permanent achiziţie, comunicare(partajare) şi utilizare de cunoştinţe specifice referitoare la domeniul problemei de rezolvat. Pentru a discrimina şicomunica eficient informaţiile necesare pentru rezolvarea unei probleme, firmele folosesc tehnologii adecvate. Otehnologie este, în general vorbind, un instrument pe care membrii echipei de dezvoltare trebuie să înveţe s-o foloseascăla întregul ei potenţial.

Aşadar, problema de rezolvat, la care se adaugă necesitatea de a învăţa modul de utilizare a tehnologiilornecesare în rezolvarea problemei, ne permit o imagine, încă optimistă, asupra complexităţii efortului de realizarea unui sistem soft. Amplificarea acestei complexităţi este motivul pentru care întregul efort de realizare a unui sistemsoft este structurat sub forma unui proiect. În cadrul unui proiect se desfăşoară, după reguli precise, toate activităţilenecesare pentru a asigura succesul efortului de realizare a unui sistem soft. Două dintre dimensiunile esenţiale pentrusuccesul unui proiect sunt limbajul de modelare folosit şi tipul de proces utilizat pentru a materializa forţa limbajuluide modelare. Despre toate acestea, mai multe aspecte în [Iniţiere în ingineria sistemelor soft].

*

Revenind la întrebarea de bază a acestui paragraf, să observăm că, încă de la apariţia primelor calculatoare, a apăruto nouă dilemă în faţa omenirii:

Cum putem învăţa calculatoarele să ne rezolve în mod optimproblemele?

La început, când calculatoarele erau folosite exclusiv pentru rezolvarea unor probleme cu carater ştiinţific, soluţiaera programarea în cod maşină. Dificultăţile de bază în rezolvare acestor tipuri de probleme erau două :elaborarea

Page 10: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 10/214

modelelor matematice şi transpunerea lor în cod maşină. Mai ales programarea în cod maşină, era un gen deexerciţiu la care nu se îngrămădeau decât indivizi care manifestau un interes ieşit din comun pentru sistemeleelectronice de calcul din acea generaţie. Apariţia limbajelor de asamblare a generat o relaxare a “cortinei de fier”instalată de codul maşină între calculatoare şi marea masă a curioşilor. O relaxare asemănătoare s-a produs şi în ceea ce priveşte tipurile de probleme abordabile cu ajutorul calculatoarelor. Era momentul în care intrau pe scenă aplicaţiilede gestiune, datorită apariţiei memoriilor externe. Locul datelor simple începe să fie luat de date structurate şi din ce înce mai voluminoase. Presiunea exercitată de cererea crescândă de aplicaţii de gestiune a impus trecerea la limbajele denivel înalt şi mediu. În paralel, cu deosebire în faţa proiectelor uriaşe (controlul traficului aerian, gestiuneatranzacţiilor unor bănci, informatizarea tot mai multor activităţi ale intreprinderilor industriale) apare nevoiadisciplinării procesului de derulare a acestor proiecte din faza de specificare a cerinţelor, trecând prin faza de

analiză, continuând cu proiectarea soluţiei şi terminând (grosier vorbind) cu programarea.De unde această nevoie de disciplinare? Foarte simplu, complexitatea problemelor (parcă am mai auzit

undeva despre acest lucru) nu mai putea fi stăpânită lucrând fără metodă. Astfel au apărut, de-a lungul timpului,tot felul de mode în ceea ce priveşte abstractizarea soluţiei şi nu numai.

Managementul unui proiect trebuie să aibă, permanent, în vizor, cel puţin, asigurarea limbajului de modelareadecvat şi  a modelului de dezvoltare optim5. De la moda programelor-mamut (singura posibilă în vremea  programării în cod maşină) s-a ajuns treptat la nevoia modularizării (= descompunerea problemei iniţiale însubprobleme, eventual aplicarea repetată a acestui procedeu, obţinându-se nişte piese ale soluţiei numite module, care,asamblate, compuneau, în sfârşit soluţia). Întrebarea care a „furnicat”, ani la rând, creierele teoreticienilor şi practicienilor, deopotrivă, era:

Care sunt criteriile după care se face modularizarea unei soluţii?

Există o serie de factori externi ai calităţii unui sistem soft care ţin sub presiune tendinţa de a modulariza de amorulartei, precum: corectitudinea, robusteţea, reutilizabilitatea, portabilitatea, etc. Există şi o serie de factori interni aicalităţii unui sistem soft, care presează, în egală măsură, precum: structurarea soluţiei, claritatea algoritmilor,calitatea arhitecturii, etc.

Menţinerea în echilibru a acestor factori de presiune este o sarcină extrem de dificilă . În cele din urmă,cercetătorii au ajuns la concluzia că, din punct de vedere al celui care lucrează, materializarea acestor factori la parametri satisfăcători sau marginalizarea lor, depind de decizia luată în ceea ce priveşte relaţia dintre date şiprelucrări în procesul de modularizare a soluţiei unei probleme. Istoria ne arată că au existat teoreticieni şi practicieni încredinţati că singura metodă de modularizare validă este modularizarea dirijată de date (altfel spus,înainte de a te ocupa de organizarea prelucrărilor, rezolvă, în mod optim, problema organizării datelor; din schema deorganizare a acestora se va deriva şi schema de structurare a prelucrărilor). Tot istoria ne arată că au existat şiteoreticieni şi practicieni încredinţati că singura metodă de modularizare validă este modularizarea dirijată deprelucrări (altfel spus, ocupă-te, mai întâi, de organizarea prelucrărilor şi, mai apoi, fă rost de datele necesare şiorganizează-le conform cerinţelor prelucrărilor). Curând s-a observat că dihotomia date-prelucrări nu este beneficăsub nici o formă. A existat o soluţie de compromis (modularizarea dirijată de fluxurile de date), care s-a dovedit întimp nesatisfăcătoare în numeroase situaţii din realitate. Din punct de vedere al criticilor fundamentale care se potformula la adresa acestor abordări esenţa este următoarea: Dacă  soluţia unei probleme înseamnă ansamblul date-

5 Mai multe detalii în această privinţă în cartea Iniţiere în ingineria sistemelor soft, D. Bocu, Editura Albastră, Cluj-Napoca, 2002

Page 11: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 11/214

prelucrări, fiecare componentă având o existenţă relativ autonomă şi reguli proprii de organizare, atunci avem situaţiadin Figura 2.

Figura 2. Perspectiva clasică asupra relaţiei dintre date şi prelucrări în structura unei soluţii

Esenţial în mesajul transmis de Figura 2 este faptul că datele sunt sficient de izolate de prelucrări pentru ca omodificare în structura unei componente să dea uşor peste cap structura celeilalte componente.

Conform paradigmelor caracterizate în Figura 2, era posibilă o caracterizare de tipul celei prezentate pentru problema de mai jos.

 Problema 1: Să se realizeze un sistem soft care simulează deplasarea unui om pe o suprafaţă plană.

Dacă aş fi un partizan al modularizării dirijate de date, mai întâi mi-aş pune următoarele întrebări: care suntatributele informaţionale care caracterizează un om (stilizat convenabil, să spunem)?. Cum se caracterizează un plan?Cum se memorează intern şi extern datele despre aceste obiecte? După ce am “distilat” satisfăcător lumea datelor, începsă mă ocup şi de lumea prelucrărilor necesare în jurul acestor date. Obţin, inclusiv în viziunea limbajelor de programaresuport, două lumi, care interferă, dar au reguli de organizare şi reprezentare în memorie distincte. Mai trist, legăturadintre date şi prelucrări este o problemă care se gestionează prin programare , ca şi când nu ar fi suficiente problemele celelalte. Ce ne facem, însă, dacă apare necesitatea simulării deplasării unei vieţuitoare în genere, pe osuprafaţă plană? Pentru fiecare vieţuitoare în parte iau travaliul de la capăt? Posibil, dar total contraindicat din multe puncte de vedere( preţ de cost, extensibilitate, încadrare în termenele de execuţie, etc.). Este limpede, reformulat ca maisus, enunţul problemei ne pune în faţa sarcinii de a modela comportamentul unor obiecte, heterogene ca tip, dar întrecare există afinităţi, atât de natură informaţională cât şi comportamentală. Astfel apare, ceea ce în modelarea obiectorientată se numeşte problema gestiunii similarităţilor unor colecţii de obiecte . Gestiunea corectă a similarităţilor unei colecţii de obiecte, heterogene din punct de vedere al tipului definitor, se realizează desfăşurând în paralel efort declasificare şi, acolo unde este cazul, ierarhizare cu ajutorul operaţiilor de generalizare / specializare. Cum aratălumea privită din această perspectivă? Simplificând intenţionat, cam ca în Figura 3.

 Nu voi da, încă, nici o definiţie, dar voi face o serie de observaţii pe care le voi aprofunda în capitolele următoare.

Problemă(activitate-sistemreal al cărui

comportamenttrebuie modelat)

DATE

PRELUCRĂRI

Page 12: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 12/214

1. Se insinuează faptul că soluţia orientată pe obiecte a unei probleme se obţine în urma unui demers deorganizare a unor obiecte, care au atât proprietăţi informaţionale cât şi comportament (se manifestă, astfel, într-un cadru absolut natural, un mai vechi principiu utilizat în modelare şi anume principiul încapsulării datelor şi prelucrărilor. Încapsulare facem şi în Pascal, când scriem unit-uri care furnizează anumite servicii unor categorii bine definite de utilizatori. Aceste unit-uri au interfaţă şi implementare.

Figura 3. Perspectiva orientată pe obiecte a soluţiei unei problemeManifestarea principiului încapsulării, în acest cadru, însemna ascunderea detaliilor de implementare faţă de

utilizatori, prin publicarea unei interfeţe stabile. O interfaţă este stabilă dacă utilizatorul ei nu sesizează eventualelemodificări aduse implementării interfeţei.

2. În sfârşit, aplicând riguros principiul încapsulării, putem defini clase de obiecte care au o importanţă esenţială pentru maparea domeniului problemei peste domeniul soluţiei. Există, însă, numeroase alte raţiuni pentrucare principiul încapsulării se aplică conjugat cu alt principiu important în modelarea orientată pe obiecte:principiul moştenirii. Aplicarea acestui principiu ne ajută să raţionalizăm redundanţele care apar, în modinerent, în procesul de elaborare a unei soluţii în genere . Mai mult, principiul moştenirii pregăteşte terenul pentru rezolvarea unor probleme interesante care ţin de polimorfism şi genericitate. Exemplul de referinţă înaceastă privinţă este Java.

Fără a mai insista prea mult, să desprindem concluzia care se impune evident la acest nivel de prezentare:Modelând orientat pe obiecte, asigurăm maximum de corespondenţă posibilă între obiectele care populeazăsistemul modelat şi obiectele care dau, practic, viaţă soluţiei . Lucru absolut remarcabil, deoarece principiulîncapsulării (temelie a modularizării de calitate în orientarea pe obiecte) introduce elemente de stabilitate deosebită asoluţiei chiar şi în situaţia în care apara modificări în sfera domeniului problemei.

Problemă(activitate-sistem real alcăruicomportamenttrebuie modelat)

C1

C11 C12

C111

C121 C122

Soluţia orientată pe obiecte a problemei

Page 13: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 13/214

Prăpastia dintre date şi prelucrări este înlocuită de reguli precise de asociere a datelor şi prelucrărilor,pentru a descrie tipuri de obiecte întâlnite în domeniul problemei şi care sunt importante pentru economia deresurse a soluţiei.

Din această perspectivă privind lucrurile, este evident faptul că modelarea orientată pe obiecte este altceva decâtmodelarea clasică (indiferent de nuanţă). Desluşirea acestui altceva, la nivel de sintaxă, semantică şi pragmatică(prin raportare la un limbaj de programare) ne va preocupa în continuare. Cei care se grăbesc să abordeze şispecificul modelării orientate pe obiecte, abstracţie făcând de limbajele de programare- suport pentru implementare, potconsulta lucrarea [ Iniţiere în modelarea obiect orientată utilizând UML6 ].

6 Dorin Bocu, Editura Albastră, Cluj-Napoca, 2002

Page 14: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 14/214

Capitolul 2Concepte în programarea orientată pe obiecte

Principii în programarea orientată pe obiecte

2.1 Concepte în programarea orientată pe obiecteÎncepând cu acest capitol, orientarea pe obiecte va fi privită, nu de la înălţimea preceptelor ingineriei softului, ci din

 perspectiva programării Java şi C++, îndeosebi. Subliniez, încă odată, marea provocare pentru un programatorcare încearcă forţa unui limbaj în materie de obiect orientare nu este în sintaxă, semantica asociată diferitelortipuri de enunţuri sintactice sau stilul de codificare, ci însuşirea spiritului orientării pe obiecte aşa cum este elpromovat de elementele suport ale limbajului.

Page 15: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 15/214

De aceea, reamintesc cititorului conştient faptul că va trebui să se întrebuinţeze serios pentru a descifra, dacă maieste cazul, oferta limbajului C++ în ceea ce priveşte: tipurile fundamentale de date (similarităţi remarcabile cu Java,dar şi deosebiri, datorate în principal faptului că în C++ pointerii se manifestă cu foarte multă vigoare în cele maineaşteptate contexte), reprezentarea structurilor de prelucrare (din nou, similarităţi remarcabile între C++ şi Java),operaţiile I/O relative la consola sistem, din perspectivă C, precum şi suportul C pentru lucrul cu fluxuri, dacă se doreşteacest lucru. Nu voi spune decât următoarele: C++ este un superset al limbajului C; compilatoarele de C++ suntrealizate astfel încât toate enunţurile din C sunt acceptate, dar ele recunosc şi o varietate mare de enunţurispecifice modului de lucru în orientarea pe obiecte.

După cum rezultă din titlul acestui paragraf, în atenţia mea se vor afla enunţurile tipice programării orientate peobiecte în C++ sau Java.

Înainte de a ajunge la aceste enunţuri, trebuie să facem primii paşi  în învăţarea spiritului orientării pe obiecte.Voi prezenta, în continuare conceptele fundamentale de care “ne lovim” frecvent când programăm orientat pe obiecte.

Spuneam în Capitolul 1 că, din perspectivă orientată pe obiecte, sistemul pe care îl modelăm va fi întotdeaunaabstractizat de o colecţie de tipuri de obiecte, între care există anumite relaţii. Să ne imaginăm, de exemplu, că vremsă modelăm lumea poligoanelor astfel încât să putem oferi suport pentru învăţarea asistată de calculator aproprietăţilor poligoanelor. Există o mare diversitate de poligoane. Chiar şi cele care sunt de maxim interes din punctde vedere al predării/învăţării în şcoală, sunt suficient de multe pentru a pune probleme de abordare a prezentării proprietăţilor lor. Şi în acest caz, ca în oricare altul, la început avem în faţa ochilor realitatea de modelat, care poate fisau nu structurată după legile ei naturale.

Pentru un individ cu pregătire matematică adecvată este evident că obiectele din Figura 4 sunt clasificate aprioric.Eventual, putem spune că lipsesc unele tipuri de poligoane, pentru că inventarul făcut de noi în Figura 4 este incomplet.

Figura 4. Diferite tipuri de poligoane, aşa cum se pot întâlni, în realitatea modelată, prin reprezentanţi

Probleme noastră nu este de a stabili nişte frontiere înăuntrul cărora să avem obiecte de acelaşi tip, ci de a spunecare sunt obiectele care nu ne interesează. Nu se întâmplă, întotdeauna, aşa. Există probleme în care efectiv trebuie sădepunem eforturi pentru a clasifica obiectele.

Page 16: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 16/214

Operaţia de clasificare presupune identificarea unor categorii de obiecte, apelând, simultan la omiterea unordetalii, socotite nesemnificative, pentru a obţine efectul de similaritate în procesul de caracterizare a obiectelor.

Dacă în atenţia noastră se află problema clasificării poligoanelor, atunci, dacă în caracterizarea unui poligonreţinem atribute precum: lista coordonatelor vârfurilor, definiţia(), aria(), perimetrul(), atunci rezultatul clasificăriieste o clasă de obiecte pe care o putem numi clasa Poligon. Astfel că putem da definiţia de mai jos.

 Definiţia 1 Se numeşte clasă o colecţie de obiecte care partajeazăaceeaşi listă de atribute informaţionale şi comportamentale.

Prin urmare, primul concept important cu care ne întâlnim în programarea orientată pe obiecte este conceptul declasă. Rezolvarea orientată pe obiecte a unei probleme se bazează esenţial pe abilitatea specialistului (în cazul nostru programatorul) de a descoperi care sunt clasele pe baza cărora se poate construi soluţia. Presupunând că avem şi noiaceastă abilitate şi, în acord cu criteriile proprii de clasificare (reflectate şi în inventarul din Figura 4), obţinemurmătoarea colecţie de clase candidate la obţinerea soluţiei problemei noastre.

Figura 5. Clasele candidate la obţinerea soluţiei pentru problema modelării poligoanelor

Departe de mine ideea că am dat o soluţie definitivă problemei clasificării poligoanelor. Am prezentat, însă, osoluţie tributară unei anumite viziuni. În conformitate cu această viziune, singurele poligoane care prezintă interes pentru noi sunt triunghiurile, patrulaterele şi romburile. Figura 5 ne atrage atenţia, explicit, asupra diversităţii tipologice

Clasa patrulaterelor 

Clasa triunghiurilor  Clasa hexagoanelor 

Page 17: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 17/214

a patrulaterelor, fapt care evidenţiază necesitatea recurgerii şi la alt operator decât clasificarea pentru a gestiona aceastădiversitate. Situaţia este, oarecum asemănătoare şi în cazul triunghiurilor, dar nu am subliniat explicit acest lucru.

Făcând abstracţie de aceste elemente, deocamdată, să revenim asupra problemei care ne interesează cel mai mult înacest moment: cum stabilim proprietăţile unei clase?

Regulile de bază în stabilirea proprietăţilor unei clase sunt următoarele:• Lista atributelor informaţionale ale unei clase este, întotdeauna, rezultatul unui compromis între

necesitatea unui maximum de informaţii despre obiectele clasei respective (informaţii, care, în fond,caracterizează starea obiectelor din clasa respectivă) şi necesitatea unui minimum de redundanţeacceptate. Obiceiul unor programatori de a supradimensiona lista atributelor unei clase pe motiv că “mai

 bine să fie decât să le ducem lipsa”, nu este un model de urmat, nici atunci când există memorie “cucarul”.

• Odată specificate, atributele trebuie declarate ca fiind resurse private ale clasei, folosind sintaxaspecifică limbajului pentru ascunderea unei resurse. Dogma orientării pe obiecte în legătură cu listaatributelor este că acestea sunt accesibile, diferitelor categorii de clienţi, în setare ca şi în consultare,prin intermediul unor metode speciale de setare(numite şi modificatori) sau consultare(numite şiselectori), cărora li se mai adaugă metode speciale implicate în crearea obiectelor unei clase(constructorii), respectiv, eliminarea acestor obiecte (destructorii). Evident, mai există şi alte tipuri uzualede metode, precum iteratorii sau indexatorii, cărora li se acordă o atenţie specială în C#.

• Odată specificată lista atributelor informaţionale se poate trece la specificarea listei operaţiilor clasei,listă care abstractizează comportamentul clasei. În procesul de specificare a comportamentului unei clasetrebuie avute permanent în vedere cele două dimensiuni ale comportamentului unei clase:

comportamentul reclamat de gestiunea stării obiectelor (crearea lor, setarea valorilor atributelor,modificarea valorilor atributelor, consultarea valorilor atributelor, distrugerea obiectelor) precum şicomportamentul reclamat de relaţia clasei în cauză cu alte clase. Lista operaţiilor unei clase, la nevoie, poate fi organizată, din punct de vedere al modului de acces la aceste operaţii. Un singur lucru este generalvalabil în această privinţă: faptul că orice clasă trebuie să afişeze o listă cu operaţiile publice, careasigură accesul clienţilor la serviciile oferite de clasă . Lista acestor operaţii se numeşte, în mod normal,interfaţa clasei.

• Atenţie, cititorule! Când specifici resursele unei clase, eşti preocupat să spui ce fac obiectele claseirespective, omiţând intenţionat cum face clasa ceea ce trebuie să facă . Aşadar, nu strică să facem odistincţie necesară între definirea unei clase (= specificarea atributelor şi a operaţiilor) şi implementareaclasei (= scrierea codului asociat operaţiilor clasei). Definirea răspunde unor comandamente externe (ceţin de modul de utilizare a obiectelor clasei); implementarea răspunde unor comandamente care ţin deintimitatea comportamentului obiectelor (mod de reprezentare în memorie a obiectelor, mod de

implementare a operaţiilor în acest context). Să mai adăugăm că o operaţie implementată se mai numeşteşi metodă.

Folosind notaţia UML pentru reprezentarea vizuală a proprietăţilor unei clase, avem situaţia din Figura 6.

Page 18: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 18/214

Un concept, inevitabil în programarea orientată pe obiecte este şi conceptul de obiect. L-am folosit, deja, la modulintuitiv, ca fiind o parte a unei realităţi având o anumită valoare de întrebuinţare în contextul în care apare. Acum estemomentul să dăm următoarea definiţie.

 Definiţia 2. Se numeşte obiect o instanţă a unei clase.

De la teoria generală a tipurilor de date, se ştie că instanţa unui tip de dată este o variabilă având o anumităreprezentare în memorie, deci o identitate, şi o anumită stare din punct de vedere al conţinutului memorieiasociate. În toate limbajele de programare, care oferă suport orientării pe obiecte, clasa este asimilată unui tip de dată(este drept un tip special), care devine folositor în momentul în care se manifestă prin intermediul instanţelor. Instanţele

unei clase se vor numi, aşadar, obiecte sau, uneori, variabile obiect.Dogmatic vorbind, dacă soluţia unei probleme este modelată ca o singură clasă, atunci ne aşteptăm ca dinamica

aplicaţiei corespunzătoare să fie opera comportamentului unei instanţe a clasei. Ce se întâmplă, însă, dacă soluţiaunei probleme este abstractizată de o ierarhie sau de o reţea de clase? În acest caz, dinamica aplicaţiei este operacolaborării între instaţele unora dintre clasele ierarhiei sau reţelei în cauză. Semantic vorbind, modul în carecolaborează mai multe obiecte pentru a rezolva o anumită problemă, este greu de fixat într-o formulă definitivă. Din punct de vedere tehnic, însă, rezolvarea este relativ simplă, după cum se poate deduce şi din Figura 7.

Figura 6. Notaţia UML pentru o clasă

<Nume clasă>

 Lista atributelor informaţionale, specificate prin nume, tip şi eventual valoare implicită 

 Lista operaţiilor, specificate prin signatură 

Page 19: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 19/214

Figura 7. Exemplu de comunicare(colaborare) între două obiecte

 Notaţia UML7 pentru o clasă şi înţelesul complet al noţiunii de signatură8 pot fi urmărite, luând-o înaintea timpului,consultând lucrarea [ Iniţiere în modelarea obiect orientată utilizând UML, Dorin Bocu, Editura Albastră, Cluj-

 Napoca, 2002]În Figura 7 se prezintă schema fundamentală pentru colaborarea dintre obiecte. Unul dintre obiecte (obiectul de tip

Produs, în cazul nostru) iniţiază comunicarea cu celălalt obiect (de tip Furnizor, în cazul nostru). Se mai obişnuieşte săse spună că obiectul de tip Produs i-a trimis un mesaj obiectului de tip Furnizor. Este de aşteptat ca, într-o formă saualta, mesajul să fie urmat de un răspuns. Aşadar, dacă OFurnizor este o variabilă de tip Furnizor şi dacă aceastăvariabilă este accesibilă unui obiect de tip Produs, atunci comunicarea este posibilă, cu condiţia ca obiectil de tip

Produs să cunoască interfaţa clasei definitoare a obiectului OFurnizor şi să aibă acces la această interfaţă. În variantacea mai simplă, un mesaj are structura:

7 UML-prescurtare de la Unified Modeling Language-Limbaj de modelare unificat, specificat de Rational Software Corporation şi omologat castandard de facto de către grupul OMG8 Signatura cuprinde, în genere: numele opreraţiei, lista de parametri şi, opţional, tipul returnat

Obiect 

ListareFurn(CodProd)

Clasa definitoare

a obiectului

(Produs)CodProd:112233

(Furnizor)AdresaListaFurn: XXXXXXXX

Furnizor

ListaFurn *AdresaListaFurn;:

ListareFurn(char codp[11]):

Produschar codprod[11];:

void afisare();:

Operaţia afisare() apelează operaţia ListareFurn()

Page 20: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 20/214

<Obiect>.<Nume_metodă>([<Lista_de parametri_actuali>]);

ceea ce ne îndreptăţeşte să dăm definiţia de mai jos.

 Definiţia 3. Se numeşte mesaj apelul unei metode a unui obiect, apelefectuat de către un client potenţial al obiectului în cauză.

Cunoaşterea acestui fapt este deosebit de importantă în situaţia în care vrem să explicăm semantica polimorfismuluiîn programarea orientată pe obiect, ceea ce vom face în partea următoare a acestui capitol.

În sfârşit, să mai menţionez faptul că răspunsul pe care îl dă un obiect când primeşte un mesaj de la alt obiectdepinde de starea în care se află obiectul care primeşte mesajul. Este un aspect asupra căruia programatorul trebuiesă fie atent, deoarece o stare improprie a obiectului destinatar, poate provoca eşuarea iniţiativei obiectuluiexpeditor de a comunica. Multe excepţii apar, în faza de testare a programelor, tocmai pentru că nu s-a manifestatsuficientă preocupare pentru evitarea utilizării obiectelor atunci când acestea sunt într-o stare critică (referinţenerezolvate, resurse necesare insuficiente, etc.).

Fie, în continuare, definiţia conceptului de stare.

 Definiţia 4. Se numeşte stare a unui obiect o abstractizare a valoriloratributelor acelui obiect precum şi a relaţiilor pe care obiectul le arecu alte obiecte.

Aşadar, recapitulând, conceptele esenţiale cu care operăm în lumea orientării pe obiecte sunt: clasă, obiect, stareobiect, mesaj.

2.2 Principii în programarea orientată pe obiecteAm văzut în paragraful 2.1 care sunt conceptele cele mai importante cu care ne întâlnim în programarea orientată

 pe obiecte. Se ştie de la alte discipline exacte că, fără principii de utilizare a lor, conceptele sunt bune doar de pus înraft, ca nişte bibelouri cu care putem aminti posterităţii de o lume dispărută. Conceptele prind viaţă, cu adevărat, doar înmomentul în care sunt acompaniate de un set de principii care fixează regulile esenţiale de utilizare a conceptelor.Evident, vom vedea care sunt aceste principii. Ce ne mai aşteaptă dincolo de ele? Ne aşteaptă invitaţia de a probasinguri valabilitatea acestor principii, la început, improvizând cu inerentă stângăcie, mai apoi descoperindadevărate şabloane de rezolvare a unor probleme tip. Ne stă la dispoziţie, în cantităţi industriale, în internet,experienţa tuturor celor care şi-au făcut o religie din orientarea pe obiecte şi au realizat aplicaţii de referinţă în acestspirit. Voi prezenta, în continuare, principiile pe care le consider absolut necesare pentru a programa în spiritul

orientării pe obiecte.AbstractizareaObişnuiesc să insist pe importanţa acestui principiu deoarece mânuirea lui fără inspiraţia necesară (iar inspiraţia,

într-un domeniu, are cunoaşterea acelui domeniu ca înaintemergător) poate pune lesne sub semnul întrebării calitateaunei soluţii.

Page 21: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 21/214

Abstractizarea este procesul de ignorare intenţionată a detaliilornesemnificative şi de reţinere a proprietăţilor definitorii ale uneientităţi.

Prin urmare, din perspectivă procesuală, abstractizarea este o modalitate de a reflecta asupra proprietăţilor uneientităţi, cu scopul de a obţine reprezentări care descriu comportamentul entităţii, reprezentări care pot îndeplini simultanfuncţii explicative, funcţii modelatoare şi, de ce nu, funţii demiurgice, la diferite paliere de profunzime. Utilitatea uneiabstracţii se manifestă atunci când apar beneficiari în sfera ei de manifestare. Ca un exemplu, referindu-ne la limbajelede programare, putem observa că, toate limbajele oferă suport specific pentru abstractizare. Cu cât suportul pentruabstractizare este mai consistent, cu atât putem spune că avem de-a face cu un limbaj de programare de nivel mai înalt.

In cazul limbajelor de programare, abstractizarea înseamnă un anumit gen de apropiere de limbajul uman şi, prinaceasta, de gândirea umană.

De asemenea, la nivelul limbajelor de programare vorbim despre trei tipuri fundamentale de abstracţii, ca rezultateale procesului de abstractizare: abstracţiile procedurale, abstracţiile la nivelul datelor şi clasele.

Abstracţiile procedurale sunt cel mai mult folosite în programare. Utilizarea lor metodică permite ignorareadetaliilor legate de desfăşurarea proceselor. Toate funcţiile puse la dispoziţia programatorilor în C prin intermediuluisistemului de fişiere antet sunt exemple de abstracţii procedurale, a căror utilizare este uşor de învăţat dacă lecunoaştem: numele, eventual lista de parametri şi/sau tipul returnat, plus semantica operaţiilor realizate de respectiveleabstracţii. Nu trebuie să avem, neapărat, informaţii despre implementarea acestor funcţii. Care este câştigul? Se crează,la un anumit nivel de abstractizare a unui program, posibilitatea ca acesta să fie exprimat ca o succesiune de operaţiilogice şi nu în termeni de instrucţiuni primare ale limbajului. Pentru lizibilitatea programului şi, în consecinţă, pentrudepanare, aşa ceva este de maxim interes.

Abstracţiile la nivelul datelor permit, de asemenea, ignorarea detaliilor legate de reprezentarea unui tip de date, în beneficiul utilizatorilor tipului de date. Un exemplu remarcabil de astfel de abstracţie la nivelul datelor este tipulvariant, specificat de cei de la firma Borland în cadrul limbajului Object Pascal. Cei care au realizat aplicaţii Delphi şi“au dat cu nasul” peste tipul variant au probabil amintiri plăcute despre versatilitatea şi uşurinţa în utilizare a acestui tipde dată.

Clasele ca abstracţii combină într-o nouă abstracţie, extrem de puternică şi polivalentă semantic, cele douăabstracţii mai sus pomenite, care ţin de acea epocă din istoria programării în care deviza era: “Algoritmi+structuri dedate=programe”. Arsenalul pus la dispoziţia programatorului de clase, în calitate de instrumente de abstractizare va fiîn atenţia acestui curs, în continuare.

ÎncapsulareaPrincipiul încapsulării insistă pe separarea informaţiilor de manipulare a unei entităţi de aspectele

implementaţionale. Se deduce, cu uşurinţă, faptul că   încapsularea este o varietate de abstractizare. Practicatămetodic şi cu suport sintactic adecvat, în programarea orientată pe obiecte, încapsularea este susţinută şi la alte nivele,de către limbaje de programare diferite. De exemplu, conceptul de unit din Object Pascal, permite încapsularearesurselor unei aplicaţii Delphi, ceea ce, în fond, înseamnă modularizare, la un nivel de abstractizare mai înalt decât celspecific încapsulării la nivel de clase. Cuvintele cheie pe care se sprijină operaţionalizarea principiului încapsulării suntinterfaţa şi implementarea. Motivul pentru care se insistă atât pe acest principiu este simplu: separând interfaţa de

Page 22: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 22/214

implementare şi admiţând că interfaţa este foarte bine structurată (rezultă că este stabilă în timp şi acceptată deutilizatori din punct de vedere al utilităţii şi comodităţii în utilizare) înseamnă că eventuale modificări aleimplementării (absolut fireşti în condiţiile îmbunătăţirii permanente a mediilor de execuţie şi programare) nuvor putea afecta utilizatorii.

Este bine ca cititorul să facă distincţie între încapsulare şi localizarea datelor şi a funcţiilor, în cadrul aceleeaşientităţi. Încapsularea are nevoie de localizare pentru a sublinia caracterul de black-box al entităţilor, dar ea înseamnămult mai mult decât atât. De asemenea, nu trebuie să fetişizăm încapsularea, aşteptând de la ea să garanteze siguranţa în procesul de manipulare a obiectelor. Cât de sigur în utilizare este un sistem soft, hotărăşte programatorul, care combinăeficient forţa principiului încapsulării cu procedeele tehnice de asigurare a protecţiei faţă de ingerinţele cu efectenegative.

Aşadar, din perspectiva încapsulării, o clasă, indiferent de limbajul în care va fi implementată, trebuie să aibă,obligatoriu, două compartimente, ca în Figura 8.

Figura 8. Componentele obligatorii ale unei clase, din perspectiva încapsulării

MoştenireaMultă vreme, moştenirea a fost un vis pentru a cărui îndeplinire, într-o formă destul de primitivă, programatorii

trebuiau să depună eforturi intense. Apariţia limbajelor care oferă suport sintactic pentru operaţionalizarea principiilor orientării pe obiecte (OO), a confirmat, printre altele şi marea importanţă a principiului moştenirii pentru specificul uneisoluţii OO. Din perspectivă mecanică privind lucrurile, acest principiu afirmă posibilitatea ca o clasă B sămoştenească o parte dintre proprietăţile unei clase A. În acest fel avem la dispoziţie un mecanism practic pentrugestiunea similarităţilor, naturale, de altfel într-o societate de obiecte foarte diversificată. În paragraful 2.1 (Figura 4)am prezentat, deja, un exemplu de societate posibilă de obiecte, în care diversitatea punea probleme de clasificare,lăsând deschisă problema gestiunii similarităţilor, în cazul mulţimii patrulaterelor. Mergând pe linia utilizării notaţieiUML pentru reprezentarea unei soluţii OO, atunci trebuie să spunem că dacă avem o clasă B care moşteneşte o partedintre proprietăţile clasei A, acest lucru va fi redat grafic în felul în care este arătat în Figura 9.

Student

 Date şi operaţii private

Operaţii publice

( Implementarea)

( Interfaţa)

Page 23: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 23/214

Figura 9. O parte din semantica relaţiei de moştenire care operează între clase

După cum se vede, relaţia de moştenire nu este doar o relaţie al cărei înţeles se reduce la posibilitatea ca B să

moştenească o parte din proprietăţile lui A; semantica relaţiei de moştenire este mult mai subtilă.Mai întâi, este vorba despre necesitatea de a reflecta cu îndemânarea necesară la cele două posibilităţi de aidentifica o astfel de relaţie: procedând top-down sau bottom-up, deci specializând, după ce am identificat o clasărădăcină, sau generalizând, după ce am terminat operaţia de clasificare a claselor şi am început să organizăm clasele înfamilii, după similarităţile care le leagă. Indiferent de abordare, rezultatul trebuie să fie acelaşi: o ierarhie de clase, încare similarităţile sunt distribuite pe nivele de abstractizare, reducând astfel la minimum redundanţele şi pregătindterenul pentru o reutilizare elegantă a codului şi pentru o serie de alte avantaje care însoţesc un lanţ de derivare.Exemplificăm cu ierarhia din Figura 10, a cărei semantică ne este deja cunoscută.

În Figura 10 regăsim aproape toate elementele specifice unei soluţii obiect orientate, care foloseşte judicios principiul moştenirii. Astfel, aproape toate soluţiile orientate pe obiect au o clasă rădăcină (care, în anumite situaţii poate fi o clasă abstractă, adică o clasă care nu poate avea instanţe directe, dar referinţe având tipul ei pot fi asociate cuinstanţe ale descendenţilor), dacă soluţia se reduce la o singiră ierarhie de clase. În ierarhie putem întâlni şi claseintermediare, precum şi clase terminale sau frunză.

A

B

Clasa părinte, superclasa,clasa de bază 

Clasa copil, subclasa,clasa derivată 

Simbolul care indică relaţia de generalizaredintre clasele A şi B

     G      E     N      E     R     A     L     I     Z

A     R     E

 S     P     E     

 C     I     A     L     I     Z     A     R     E     

Page 24: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 24/214

Figura 10. Principiul moştenirii în acţiune

Din punctul de vedere al programatorului, pe lângă utilitatea moştenirii în procesul de gestiune a similarităţilor, mai

există un avantaj care poate fi exploatat în faza de implementare a soluţiei, avantaj derivat din principiul moştenirii subforma unui alt principiu care afirmă că:

Orice părinte poate fi substituit de oricare dintre descendenţi

Acest principiu este de mare utilitate pentru programatori, el fiind operaţionalizat prin intermediul operaţie decasting, aplicată obiectelor ale căror clase definitoare sunt în relaţie de moştenire. Evident, este vorba de un castingimplicit în lumea obiectelor (descendentul moştenind tot ceea ce se poate de la strămoşi, va putea opera în loculstrămoşului). Castingul de acest tip se numeşte up-casting. Se practică, explicit şi down-castingul, dar programatorultrebuie să fie pregătit să răspundă de consecinţe. Într-un down-casting, este posibil ca obiectul de tip strămoş, convertitla un obiect de tip descendent, să nu asigure coerenţa informaţională de care are nevoie descendentul, deci pot apare, principial, excepţii. În Java se întâlnesc amândouă tipurile de casting.

În sfârşit, în Figura 10 avem un exemplu de utilizare a moştenirii simple, potrivit căreia un descendent poate avea

un singur strămoş. Unele limbaje de programare(C++, de exemplu) acceptă şi moştenirea multiplă, ceea ce înseamnă căo clasă poate avea doi sau mai mulţi strămoşi. O astfel de soluţie pentru principiul moştenirii este plină de riscuri, cutoate avantajele pe care le presupune. Moştenirea multiplă poate genera ambiguităţi care pot pune la încercare răbdarea programatorului.

Patrulater

 Poligon

Triunghi

Paralelogram

Romb Dreptunghi

Trapez Patrulaterinscriptibil

Clasă rădăcină, poate fi şiabstractă 

Clasă intermediară 

Clase frunză 

Page 25: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 25/214

Figura 11. Exemplu de moştenire multiplă

În exemplul din Figura 11, clasa D are ca strămoşi clasele B şi C. Obiectele clasei D vor avea moştenite resurselelui A, atât pe traseul lui B cât şi pe traseul lui C. Ambiguitatea referirii la o resursă a lui A în cadrul unei instanţe a lui Deste evidentă. Când este considerată strict necesară, moştenirea multiplă se utilizează cu discernământ. Java şi C# numai promovează moştenirea multiplă, propunând alte soluţii la această problemă.

Moştenirea nu este doar o problemă de sintaxă, ci este esenţa însăşi a programării orientate pe obiecte. Pe temeiul

moştenirii are rost să vorbim în continuare de principiul polimorfismului, aplicat la lumea obiectelor.

PolimorfismulDupă cum se vede şi în exemplul prezentat în Figura 10, ierarhia de clase care modelează, la urma urmei,

comportamentul unei aplicaţii poate avea mai multe clase frunză, deci clase care pote genera instanţe. Crearea uneiinstanţe este, indicutabil o problemă în care programatorul trebuie să se implice, el trebuind să stabilească, în funcţie dedinamica aplicaţiei, ce constructor va coopera la crearea unei instanţe. În ideea că avem o aplicaţie care se ocupă desimularea învăţării poligoanelor, vi se pare interesant să declarăm câte o variabilă pentru fiecare tip de poligon dinierarhia prezentată în Figura 10 (mai puţin clasa rădăcină)? Nu este interesant din două motive:

1. Explozia de variabile obiect nu este un indiciu de performanţă în programare.2. Odată create obiectele, programatorul trebuie să ştie în orice moment ce fel de obiect lucrează la un

moment dat. Chiar că aşă ceva poate deveni supărător într-o aplicaţie de mare complexitate.

 Nu ar fi mai civilizat să declarăm o variabilă de tip Poligon în care să păstrăm instanţe create cu ajutorulconstructorilor oricăror descendenţi care pot avea urmaşi direcţi? Admiţând că, în clasa Poligon, am declarat o operaţiecalculArie() care este suprascrisă în fiecare descendent, atunci situaţia creată este următoarea: obiectul creat cu ajutorulconstructorului unui descendent al clasei Poligon şi păstrat într-o variabilă de tip Poligon (principiul substituţieiîngăduie acest lucru), să-i spunem p, va putea să apeleze diferite implementări ale operaţiei calculArie(), în funcţie de

A

B C

D

Page 26: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 26/214

contextul în care se crează p. Aşadar, un mesaj de tipul p.calculArie() ce răspuns va genera? Răspunsul va fi dependentde context, controlul contextului (adică alegerea metodei specifice clasei definitoare a obiectului păstrat în p)realizându-se de către sistem prin mecanisme specifice, în timpul execuţiei programului. Acest mod de legare a unuinume de operaţie de codul metodei specifice tipului definitor al variabile obiect gazdă se numeşte late binding. Este unmod de legare mai puţin performant decât legarea statică (la compilare), dar avantajele scuză dezavantajeleinsignifiante, în condiţiile în care viteza procesoarelor şi disponibilul de RAM sunt în expansiune permanentă.

S-a înţeles, probabil, faptul că polimorfismul este de neconceput fără moştenire în care specializarea claselor să se bazeze şi pe suprascrierea unor metode în clase aflate în relaţie de moştenire. Tot ceea ce trebuie să ştie programatorulde aici încolo este avertismentul că:

Moştenirea şi polimorfismul sunt ideale ca uz şi contraindicate ca abuz.

Terminând excursia în lumea conceptelor şi a principiilor programării orientate pe obiecte, nu ne rămâne decât săanunţăm că în capitolele următoare vom încerca să vedem aceste abstracţii la lucru în context Java sau C++.

Capitolul 3Specificarea şi implementarea unei clase 

Perspectiva Java

Page 27: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 27/214

3.1 În loc de introducereFără să am pretenţia că am epuizat semantica modelării orientate pe obiect, în capitolele precedente, în acest capitol

voi începe incursiunea în lumea elementelor suport oferite de Java şi C++ pentru implementarea orientată pe obiect amodelelor obiect orientate.

Laboratoarele de cercetare şi lumea practicienilor văd, încă, în aceste două limbaje nişte momente de referinţă înzbuciumata evoluţie a limbajelor de programare. Apariţia limbajului C# la orizont, „prin bunăvoinţa” celor de laMicrosoft, se anunţă un concurent redutabil, care, îşi propune să câştige, deopotrivă, atenţia fanilor Java şi C++. Până ceapele se vor limpezi, mă voi ocupa de ceea ce, tocmai, am anunţat în lista subiectelor care fac obiectul acestui capitol.

3.2 Atenţie la importanţa efortului de abstractizare!Voi încerca să arăt cum se specifică şi implementează clasele în Java. În tot acest timp, încercaţi, împreună cu

mine, să nu minimalizaţi nici o clipă importanţa hotărâtoare a abstractizării în elaborarea unor soluţii stabile şiflexibile9.

În acest scop voi considera un exemplu pretext de problemă prin intermediul căreia voi încerca să pun în valoare puterea de reprezentare a limbajelor Java şi C++.

Să se scrie codul Java / C++ care pune la dispoziţia unor utilizatori potenţiali capabilităţi de lucru cu listesimplu înlănţuite de numere întregi, pentru care resursele necesare reprezentării sunt alocate dinamic. Încontinuare mă voi referi la această problemă cu acronimul LSI.

9 Nu este o contradicţie între termeni. Cele mai bune modele, într-o lume care nu stă pe loc, sunt modelele care pot fi socotite, în acelaşi timp, închiseşi deschise, deci stabile şi flexibile.

Page 28: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 28/214

De ce numai acest tip de listă? De ce doar numere întregi? Pentru că aşa cere utilizatorul în acest moment. Nici maimult, nici mai puţin. Aşa se întâmplă şi în viaţa de toate zilele. Specialiştii în IS trebuie să livreze beneficiarilor ceeace aceştia se aşteaptă să primească. Amorul artei sau dispreţul faţă de beneficiar, sunt taxate necruţător de cătreansamblul regulilor jocului din industria de soft.

 Nu voi exagera cu descrierea travaliului conceptual în urma căruia am ajuns la nişte concluzii în legătură curezolvarea problemei LSI. Dar, câteva elemente de descriere a atmosferei trebuie, totuşi precizate.

Se ştie că structurile dinamice de date sunt preferate structurilor statice de date, atunci când utilizareachibzuită a memoriei şi flexibilitatea relaţiilor dintre obiectele care populează structura sunt critice pentrucalitatea unui sistem soft.

Se mai ştie, totodată, că o structură dinamică de date este complet specificată dacă am clarificat:

• Tipul datelor care populează structura.• Mecanismul de înlănţuire a datelor din structură.• Punctele de intrare în structură.• Operaţiile cu ajutorul cărora întreţinem şi consultăm structura.

Fiecare din cerintele de mai sus, poate face obiectul unor consideraţii cu implicaţii interesante asupra soluţiei. Mălimitez doar la a observa faptul că o structură de date dinamică este un exemplu reprezentativ de tip de dată carepoate fi modelat orientat pe obiecte, în aşă fel încât serviciile oferite să fie complete şi uşor de apelat .

Intrând puţin în domeniul problemei, dacă ne gândim la o listă simplu înlănţuită, semantica ei poate fi vizualizată, parţial, ca în Figura 12.

Figura 12. Incercare de vizualizare a unei liste simplu înlănţuitePrin urmare, obiectele care fac parte din inventarul problemei sunt: Nod (având ca proprietăţi informaţionale Data

şi Adresa de legătură cu următorul element iar ca proprietăţi comportamentale, cel puţin operaţii legate de crearea unui

Adresa de start a primului nod

Data_ 1 Data_2 Data_n

 Informaţenod 

 Legătura spre următorul nod  Ultimul nod nu are un succesor 

Page 29: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 29/214

nod şi consultarea proprietăţilor lui informaţionale) şi Lista (un obiect care, în principiu este o agregare 10 de obiecte detip Nod).

Un obiect care poartă marca tipului Lista va avea, aşadar, proprietăţi informaţionale şi comportament specific.Abstractizând cu înverşunare, lista proprietăţilor informaţionale ale unui obiect de tip Lista ar putea să conţină doar adresa primului nod din listă. Însă, dacă trecem în revistă exigenţele clienţilor faţă de un obiect de tip Lista, vomdescoperi că este indicat să avem un atribut pentru a indica dacă lista conţine sau nu elemente (un exemplu deredundanţă în procesul de utilizare a memoriei interne care asigură o viteză sporită în procesul de utilizare a unei liste).Dacă acest atribut este un întreg care indică chiar numărul elementelor din listă, cu atât mai bine. Aşadar, în notaţieUML, în acest moment am putea avea situaţia din Figura 13.

Figura 13. Clasele candidate la rezolvarea problemei LSDI

Ce observaţii putem face? Clasa Nod este o clasă concretă, adică, având constructor, poate avea instanţe. Să maiobservăm faptul că atributele clasei Nod sunt prefixate cu câte un semn -, ceea ce, în UML, înseamnă că sunt private.Conform dogmei OO, absolut normal. De asemenea, să mai observăm că operaţiile clasei Nod sunt prefixate cu semnul+ şi sunt scrise cu font drept, ceea ce, în UML, înseamnă că sunt publice şi au deja implementare valabilă. Semanticaacestei clase şi a contextului în care operează s-ar părea că nu ne pretinde specificarea unor operaţii private sau protejate. Oare? Este adevărat că în Java, de exemplu, crearea unui obiect de tip Nod se va face rezonabil, chiar şi dacă

nu am prevedea un constructor, dat fiind faptul că obiectele se crează şi în acest caz, atributele fiind iniţializate cu valori predefinite (0 pentru numere, null pentru obiecte, false pentru valori booleene, ’\u0000’ pentru caractere). Dacă unastfel de comportament implicit nu este de acceptat, atunci este loc pentru a specifica operaţii care fac validarea stării

10 In modelarea obiect orientată se foloseşte relaţia de agregare pentru a indica o asociere între obiecte care, din punct de vedere semantic, sunt într-o relaţie parte-întreg. Reprezentarea unei relaţii de agregare este la latitudinea programatorului.

Nod

-Int Data;-Nod Urmatorul;

+Nod(int Numar);+void setareData(int Numar);+int consultareData();+void setareUrmator(Nod AUrm)+Nod consultUrmator()

Lista

-Nod Astart;-Nod AUltim;-Int NrElem;

+void setareAStart(Nod Element);+Nod consultaAStart();+void setareNrElem(int ne);+int consultaNrElem();+setareAUltim(Nod Element)+Nod consultaAUltim();+void insereazaDNod(Nod Element);+void insereazaINod(Nod Element);+void stergeNodAdr(Nod Element);+void stergeNodNum(int Nr);+salveazaInFisier(char numef[]);

+incarcaDinFisier(char numef[]);)

Page 30: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 30/214

obiectelor. Aceste operaţii ar putea fi folosite, ca uz intern, de orice altă operaţie care este sensibilă la starea obiectuluicare o foloseşte la un moment dat.

Pe de altă parte, observăm faptul că unele dintre operaţiile clasei Lista sunt scrise cu caractere italice. În UMLaceasta înseamnă că aceste operaţii sunt abstracte. Prin urmare, clasa Lista este o clasă abstractă, deci nu areconstructor şi tipul introdus de această clasă nu va putea avea instanţe directe. Pentru a fi utilă, clasa Lista trebuie săaibă descendenţi. Care vor fi aceşti descendenţi? Vom considera că aceşti descendenţi sunt doi: o clasă care modeleazăo listă simplu înlănţuită de întregi, în care cuvântul de ordine la creare este ordinea fizică de introducere şi oclasă care modelează o listă simplu înlănţuită de întregi, în care elementele listei sunt introduse astfel încât, dupăfiecare introducere acestea să fie în ordine crescătoare. Pe scurt: liste indiferente la ordinea numerelor întregi şi listesensibile la ordinea numerelor întregi. Vom obţine ierarhia din Figura 14.

Figura 14. Ierarhia claselor care modelează două varietăţi de listă simplu înlănţuită.

Se poate observa că cele două varietăţi posedă operaţiile necesare pentru a simula, în caz de nevoie şicomportamentul unei stive (AStart este Top-ul iar  inserareINod() şi  stergeNodAdr(AStart) sunt operaţiile specificeunei stive, adică Push() şi Pop()). Cititorul bănuieşte că inserareINod() este abreviere de la „inserare înainte de nod” iar inserareDNod() este abtreviere de la „inserare după nod”.

Consideraţii de acest gen şi chiar mai profunde, trebuie să prilejuiască orice încercare de rezolvare orientată peobiect a unei probleme.

3.3 Specificarea şi implementarea unei clase în JavaEste cunoscut faptul că, în Java, orice aplicaţie este puternic obiect orientată, cel puţin datorită cadrului sintactic

obligatoriu pentru realizarea unui applet sau a unei aplicaţii Java obişnuite. Dacă spiritul orientării pe obiecte este bineînţeles, atunci Java este o soluţie interesantă pentru multe probleme a căror rezolvare presupune realizarea unor aplicaţii pentru care lumea Internet-ului este puternic deschisă. Indiferent de tipul aplicaţiei, piesele de bază în realizarea acesteiasunt clasele. Vom avea, în cazul unei aplicaţii Java obişnuite, o singură clasă publică, care conţine funcţia main() şi unasau mai multe clase care modelează, la diferite nivele de rafinare, comportamentul aplicaţiei. De asemenea, în cazulunui applet Java, vom avea o singură clasă publică care extinde clasa Applet şi una sau mai multe clase care modelează,la diferite nivele de rafinare, comportamentul applet-ului.

Privită de la cel mai înalt nivel de abstractizare, definiţia unei clase în Java este:

[<Listă modificatori>] class <Nume clasă> [ extends <Clasa de bază>] [ implements <Lista interfeţe>]

Lista

ListaOarecare ListaSortata

Page 31: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 31/214

{  //Listă de resurse sau corp clasă 

 }

Resursele unei clase sunt de două tipuri: atribute şi/sau operaţii. Problema noastră, după cum am văzut, este de aorganiza aceste resurse, astfel încât să putem beneficia de o serie de avantaje din punct de vedere al efortului dedezvoltare cât şi din punct de vedere al calităţii softului 11.

În paragraful 2.2 am văzut că o încapsulare corectă (în acord şi cu dogma OO) înseamnă să declarăm ca privateatributele şi să definim o interfaţă corespunzătoare clasei. Vom vedea, mai jos, ce înseamnă acest lucru în cazul problemei noastre.

Atributele unei clase se specifică sintactic astfel:

[<Listă modificatori atribut>] Tip <Lista identificatori variabile>;

Operaţiile unei clase se specifică prin signatură şi implementare ca mai jos:

[<Listă_modificatori_operaţie>]Tip_returnat Identificator_metodă>([<Listă parametri>) [ throws <Lista excepţii>]{ 

<Corp operaţie> }

Formalizmul folosit pentru prezentarea sintaxei de definire a unei clase se bazează, după cum se poate deduce, peurmătoarele convenţii:

Orice construcţie a utilizatorului este prezentată între simbolurile < ...>.Orice construcţie opţională este încadrată de simbolurile [...].Cuvintele rezervate sunt evidenţiate prin îngroşare.

Întrebarea firească care se pune este următoarea: la ce ne folosesc aceste elemente de variaţie în procesul dedefinire a unei clase.

Voi încerca să răspund pe rând la toate ramurile acestei intrebări.

Modificatorii aplicabili claselorDupă cum se poate observa, cuvântul cheie class poate fi prefixat, opţional, de un modificator. Lista completă a

acestor modificatori este: abstract, final, public.

Modificatorul de clasă „abstract”Java permite extinderea unei clase existente cu o subclasă. Cu timpul, este posibil să vă constituiţi propriile

 biblioteci de clase care consideraţi că vor fi extinse de alţi programatori. Pentru unele clase, poate să fie inutil să

11 Despre calitatea softului cititorul poate găsi elementele esenţiale în D. Bocu, Iniţiere în ingineria sistemelor soft, Editura Albastră, 2002

Page 32: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 32/214

implementaţi o operaţie cât timp nu se cunoaşte cum va fi extinsă clasa. În astfel de cazuri, puteţi utiliza cuvântul cheieabstract pentru a indica faptul că în descendenţi toate operaţiile clase trebuie să fie supradefinite obligatoriu.

Clasa Lista din Figura 14 ar putea fi definită, prin urmare astfel, în Java:

abstract class Lista{ 

 private Nod AStart; private Nod AUltim; private int NrElem; public void setareAStart(Nod Element);

 public Nod consultaAStart(); public void setaretNrElem(); public int consultaNrElem(); public Nod consultaAUltim(); public abstract void insereazaDNod(Nod Element); public abstract void insereazaINod(Nod Element); public abstract void stergeNodAdr(Nod Element); public abstract void stergeNodNum( int Nr); public final void salveazaInFisier(char numef[]); public final Nod incarcaDinFisier( char numef[]);) }

Este evident faptul că descendenţii ListaOarecare şi ListaSortata sunt obligaţi să implementeze toate operaţiileclasei Lista,  care sunt abstracte. De asemenea, să observăm că implementarea definitivă a operaţiilor desalvare/restaurare a listei este realizată în clasa Lista şi va fi folosită fără modificări în descendenţi.

Modificatorul de clasă „final” (tocmai l-am utilizat mai sus)În general vorbind, Java permite unei clase să extindă o altă clasă. Atunci când definim o clasă, în contextul în care

anticipăm utilizarea ei, s-ar putea să nu dorim extinderea ei de către alte clase. În acest caz, prin includerea cuvântuluicheie final în cadrul definiţiei clasei vom împiedica crearea de subclase ale clasei în cauză. Aşadar, clasa:

 public final class NumeClasa {...}

nu va putea să aibă urmaşi.

Modificatorul de clasă „public”Atunci când utilizăm cuvântul cheie public în cadrul declaraţiei clasei, ne asigurăm că acea clasă este vizibilă /

accesibilă de oriunde. Dacă dorim să controlăm accesul la o clasă, cuvântul cheie public nu are ce căuta în declaraţiaclasei. Să reamintim, totodată, faptul că Java permite o singură clasă publică într-un fişier cu cod sursă. Evident,caracterul public al unei clase poate avea alte conotaţii în contextul organizării codului sursă al unei aplicaţii cu ajutorul pachetelor. Mai precis spus, o clasă publică poate fi utilizată din exteriorul pachetului în care a fost declarată, pentru acrea instanţe sau pentru a o extinde. În schimb, o clasă care nu a fost declarată publică este considerată o clasa friend , putând fi accesată doar din interiorul pachetului în care este rezidentă.

Page 33: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 33/214

Modificatorii aplicabili atributelorDomeniul de valabilitate al unui atribut defineşte locaţiile din program în care atributul este cunoscut. În procesul

de definire a unei clase putem controla domeniul unui atribut al clasei precedând declaraţia lui cu unul din cuvintelecheie: public, private, protected, static, final, tranzient, volatile. Să menţionăm faptul că un atribut care nu esteînsoţit de nici un modificator este vizibil friendly, adică doar din interiorul clasei şi din clasele din acelaşi pachet.

Modificatorul de atribut „public”Un atribut public este vizibil / accesibil oriunde este vizibilă / accesibilă clasa care îl conţine. Aşadar, pentru a

declara ca public un atribut vom proceda ca mai jos:

: public int vizibilOriundeEsteVizibilaClasa;:

Dogma spune că o clasă care ajunge la client trebuie să-şi ascundă atributele faţă de acesta, accesul la ele fiindmijlocit de interfaţă, dacă este cazul. Nu este, însă, exclus ca o serie de clase neterminale (care nu sunt, deci clasefrunză) să declare ca publice o parte a atributelor, protecţia lor fiind controlată, la nivelul descendenţilor prinintermediul interfeţelor sau al organizării în pachete.

Modificatorul de atribut „private”Un atribut privat este vizibil numai în interiorul clasei sale. Subclasele şi clienţii externi nu pot accesa aceste

atribute.

Modificatorul de atribut „protected”Un atribut al clasei, declarat ca protejat, este accesibil în descendenţii clasei sau în cadrul pachetului din care face

 parte clasa deţinătoare. Atenţie, un atribut declarat ca protected într-o clasă va putea fi accesat în scriere şi citire în toţidescendenţii clasei în cauză, rezidenţi chiar şi în afara pachetului gazdă al clase care deţine atributul protejat. Nu va fi permis accesul direct la atributul protejat pentru clase care nu sunt descendeţi ai clasei care declară atributul protejat.

Modificatorul de atribut „static”Orice atribut care nu este declarat ca static este numit atribut de instanţă, ceea ce înseamnă că fiecare instanţă are

 propria copie a atributului. Atunci când este în interesul comportamentului clasei ca un atribut să fie partajat de toateobiectele clasei în cauză, acel atribut va fi declarat ca static.

Modificatorul de atribut „final”Atunci când în definiţia unei clase menţionăm un atribut final, indicăm compilatorului faptul că acel atribut are

valoare constantă, care nu poate fi modificată de program. Iniţializarea atributului cu o valoare se poate face la creareaobiectlui gazdă, prin contribuţia constructorului sau în cadrul unei declaraţii de tipul:

: protected static final int nr=10;:

Atenţie! Cele două metode de iniţializare sunt mutual exclusive.

Page 34: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 34/214

Modificatorul de atribut „transient”Atunci când declarăm un atribut ca fiind de tip transient, indicăm compilatorului Java faptul că atributul nu este o

 parte permanentă a obiectului, deci de uz intern şi în cazul serializării, de exemplu, nu va fi salvat pe memoria externă.Un atribut tranzient se declară astfel:

: private transient String password;

:

Modificatorul de atribut „volatile”Atunci când se compilează programul, compilatorul analizează codul şi, adeseori va efectua anumite manevre cu

scopul de a optimiza performanţele codului. Atunci când dorim să scoatem un atribut de sub incidenţa unei astfel deeventualităţi, o declarăm ca volatilă. Practic, aceasta înseamnă că există situaţii particulare în care comunicaţia cu alte  programe sau rutine necesită neintervenţia compilatorului asupra unui atribut, esenţial pentru buna desfăşurare acomunicaţiei în cauză.

Modificatorii aplicabili operaţiilorÎn această secţiune vom prezenat o serie de modificatori care, de cele mai multe ori, sunt aplicabili metodelor care

implementează operaţiile claselor. Aceşti modificatori sunt: public, private, protected, static, final, abstract, native,synchronized.

Modificatorul de metodă „public”Semnificaţia acestui modificator, în cazul în care se aplică unei metode, este asemănătoare cu cea pe care o are

când se aplică unui atribut.

Modificatorul de metodă „private”Semnificaţia acestui modificator, în cazul în care se aplică unei metode, este asemănătoare cu cea pe care o are

când se aplică unui atribut.

Modificatorul de metodă „protected”Semnificaţia acestui modificator, în cazul în care se aplică unei metode, este asemănătoare cu cea pe care o are

când se aplică unui atribut.

Modificatorul de metodă „static”Semnificaţia acestui modificator, în cazul în care se aplică unei metode, este, într-o oarecare măsură, asemănătoare

cu cea pe care o are când se aplică unui atribut. Mai precis, trebuie să spunem că o metodă statică, pentru a fi utilizatănu reclamă neapărat o instanţă, putând fi utilizată şi printr-un apel de tipul:

 NumeleClasei. NumeleMetodeiStatice(parametri);

Page 35: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 35/214

O metodă statică poate fi utilizată pentru a accesa alţi membri statici ai clasei, dar, în nici un caz, pentru a accesavariabile nestatice.

Modificatorul de metodă „final”Am văzut, deja, în cursul 2, că anumite metode ale claselor pot fi supradefinite în clasele descendente. Dacă, din

variate motive, dorim să blocăm posibilitatea supradefinirii unei metode, atunci vom informa compilatorul de aceastăintenţie declarând metoda ca finală astfel:

 public final void MetodaNuPoateFiSupradefinita();

Modificatorul de metodă „abstract”Dacă o metodă a unei clase este precedată de cuvântul cheie abstract, atunci compilatorul nu va autoriza crearea de

instanţe ale clasei în cauză. Totodată, o clasă care extinde clasa în cauză va trebui să implementeze metoda abstractăobligatoriu. Declararea se face astfe:

 public abstract void implementareUlterioară();

Atenţie! O metodă abstractă nu poate fi privată sau finală .Semantica cuvântului cheie abstract (= metoda va fi implementată în descendenţi) vine în contradicţie cu

semantica cuvintelor cheie private şi final care spun, în moduri diferite, că metoda nu poate fi modificată.

Modificatorul de metodă „native”Acest modificator se utilizează pentru a spune compilatorului că o anumită metodă utilizează cod scris într-un alt

limbaj de programare, cum ar fi C/C++, de exemplu. Această posibilitate trebuie folosită cu discernământ deoareceloveşte puternic în portabilitatea aplicaţiei, aşa cum este ea înţeleasă în Java.

Modificatorul de metodă „synchronized”Se ştie că Java oferă suport pentru multitasking sub forma „un program mai multe fire de execuţie”. În funcţie de

activitatea programului respectiv, uneori este necesar să garantăm faptul că, două sau mai multe fire nu pot accesasimultan aceeaşi metodă. Prin urmare, pentru a controla numărul de fire de execuţie care pot accesa o metodă la unmoment dat, utilizăm cuvântul cheie synchronized. Atunci când compilatorul Java întâlneşte o metodă prefixată decuvântul cheie synchronized, introduce un cod special care blochează metoda când un fir începe execuţiainstrucţiunilor metodei şi o deblochează când firul îşi încheie execuţia. În mod uzual, sincronizarea metodelor estereclamată de necesitatea partajării datelor.

Am prezentat, mai sus, semantica cuvintelor cheie ascunse sub sintagma „modificatori”, aplicaţi atributelor sauoperaţiilor.

Sintaxa care stă la baza definirii unei clase mai conţine, opţional şi cuvântul cheie extends pentru a indica o clasăde bază clasei în curs de definire.

De asemenea, în sintaxa prezentată se mai evocă şi eventualitatea apariţiei cuvântului cheie implements urmat denumele interfeţelor pe care le implementează clasa, atunci când este cazul. Evident, cuvântul cheie extends este legat de problematica moştenirii în programarea orientată pe obiecte în Java iar cuvântul cheie implements este legat de

Page 36: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 36/214

 problematica utilizării interfeţelor, pentru a introduce numeroase elemente de flexibilitate în programarea Java, inclusivrezolvarea moştenirii multiple, neadmisă direct în Java.

Despre aceste două probleme vom discuta pe îndelete in Capitolul 5.Înainte de a trece la prezentarea cadrului C++ pentru definirea unei clase putem urmări, mai jos, codul Java asociat

definirii claselor Nod şi Lista, aşa cum apar ele în lumina observaţiilor făcute până acum.

 //--------------------------------------------- //Cod Java care demareaza procesul de rezolvare //a problemei LSI  //---------------------------------------------

 //Specificare minimala a clasei Nod  //Implementare clasa Nod class Nod { 

 private int Data; private Nod Urmatorul;

 //constructor  public Nod(int Numar){ 

 Data=Numar; };

 //modificator atribut Data public void setareData(int nr){ 

 Data=Numar; };

 //selector atribut Data public int consultareData(){ 

return Data; };

 //Modificator atribut Urmatorul  public void setUrmator(Nod Element){ 

Urmatorul=Element; };

 //Selector atribut Urmatorul 

Page 37: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 37/214

 public Nod consultaUrmator(){ 

return Urmatorul; };

 };

 //Specificare aproape completa a clasei abstracte Listaabstract class Lista{ 

 private Nod AStart;

 private Nod AUltim; private int NrElem;

 //Modificator atribut AStart  public void setareAStart(Nod Element){ 

 AStart=Element; };

 //Selector atribut AStart  public Nod consultaAStart(){ 

return AStart;

 };

 //Modificator atribut NrElem public void setareNrElem(int ne){ 

 NrElem=ne; };

 //Selector atribut NrElem public int consultaNrElem(){ 

return NrElem; };

 //Modificator atribut AUltim public void setareAUltim(Nod Element){ 

 AUltim=Element; };

Page 38: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 38/214

 //Selector atribut AUltim public Nod consultaAUltim(){ 

return AUltim; };

 //Metoda abstracta //Va fi implementata in descendenti //Insereaza un element dupa ultimul nod introdus

 public abstract void insereazaDNod(Nod Element);

 //Metoda abstracta //Va fi implementata in descendenti //Insereaza un element inaintea ultimului nod introdus public abstract void insereazaINod(Nod Element);

 //Metoda abstracta //Va fi implementata in descendenti //Sterge un element de adresa specificata public abstract void stergeNodAdr(Nod Element);

 //Metoda abstracta

 //Va fi implementata in descendenti //Insereaza un element de pozitie specificata public abstract void stergeNodNum(int Nr);

 //Metoda publica finala //Deocamdata neimplementata //Salveaza lista reperata de AStart  //intr-un fisier de nume specificat  public final void salveazaInFisier(char numef[]){ 

System.out.println("Neimplementata..."); };

 //Metoda publica finala //Deocamdata neimplementata //Restaureaza lista folosind informatiile din fisierul  //de nume specificat  public final Nod incarcaDinFisier(char numef[]){ 

Page 39: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 39/214

System.out.println("Neimplementata...");return null;

 }; }

Codul prezentat mai sus trebuie să fie extins şi rafinat pentru a acoperi toate cerinţele iniţiale ale problemei şi pentru a face faţă exigenţelor de calitate fireşti (modularizare corectă, fiabilitate, extensibilitate, etc.).

Page 40: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 40/214

Capitolul 4Specificarea şi implementarea unei clase

Perspectiva C++

Comparaţie Java / C++

4.1 Specificarea şi implementarea unei clase în C++4.1.1 Scurtă introducereIstoria limbajului C a fost scrisă de mult. Istoria limbajului C++, încă se scrie. La apariţia lor, aceste două limbaje

au făcut rapid prozeliţi mulţi, îndeosebi printre profesionişti. Noutăţile aduse la rampă de C şi C++ au fost preluate, fărădrept de apel şi de către noile limbaje de programare (Java, C#), care au fost specificate în contextul apariţieiuniversului INTERNET. Atenţionând cititorul asupra faptului că în C++ orientarea pe obiecte are o mare diversitate deelemente suport, a căror prezentare în detaliu în această carte nu este posibilă din motive obiective, voi încerca, încontinuare, prezentarea direcţiilor cheie pe care se poate merge în C++ pentru a face programare orientată pe obiecte.

4.1.2 Orientarea pe obiecte cu structurile şi uniunile dinC++ Nevoia de sintaxă care să susţină implementarea orientată pe obiect a modelelor orientate pe obiecte a fost resimţită

încă din epoca programării în C, epocă în care definirea structurilor îngăduia „punerea laolaltă a datelor şi a

Page 41: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 41/214

 prelucrărilor”, ceea ce înseamnă suport de un anumit tip pentru încapsulare. Prezenţa prelucrărilor alături de date erarealizată prin posibilitatea de a declara membri ai unei structuri care erau pointeri la funcţii .

Contextul sintactic şi câte ceva despre semantica ideii de mai sus, în exemplele de mai jos.

Cod C care prezintă un exemplu de structură orientată pe obiecte //Exemplul 4.1#include<conio.h>#include<iostream.h>

 //Definirea tipului abstract de date

 //utilizand cuvantul cheie struct  //cu semantica din C struct tad { int data;//Exemplu de membru pointer la functieint (*funct)();

 };

 //Prototipul functiei, compatibila cu pointerul  //specificat ca membru in struct int f();

 //Instanta tad tad vtad;void main(){ //Setare valoare membru datavtad.data=10;clrscr();//Setare valoare membru pointer la functievtad.funct=&f;//Utilizare membru pointer la functiecout<<vtad.funct();getch();

 };

 //A se observa modul in care se realizeaza implementarea. //Accesarea membrilor de tip data se face in context  //variabila struct int f(){ 

Page 42: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 42/214

return vtad.data* vtad.data; };

Cod C++ care prezintă un exemplu de structură orientată pe obiecte

 //Exemplul 4.2#include<conio.h>#include<iostream.h>

 //Definirea tipului abstract de date

 //utilizand cuvantul cheie struct  //cu semantica din C++struct tad { int data;//Exemplu de membru functieint funct();

 };

int tad::funct(){ return data*data;

 };

 //Instanta tad tad vtad;void main(){ //Setare valoare membru datavtad.data=10;clrscr();

//Utilizare membru functie//Se observa progresul fata de implementarea aceleasi idei//in C cout<<vtad.funct();getch();

 };

La vremea apariţiei lor aceste mecanisme au fost o surpriză foarte plăcută pentru programatorii educaţii în spiritulorientării pe obiecte. Evident, aceste mecanisme erau încă departe de semantica completă a orientării pe obiecte. Şitotuşi, cu ajutorul enunţului struct, programatorul poate defini structuri de date, reprezentabile în memoria internă,

Page 43: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 43/214

echivalente ale tipului înregistrare (record) teoretizat în algoritmică şi în numeroase limbaje de programare.Caracteristica fundamentală a acestor structuri o reprezintă posibilitatea de a grupa date membre care contribuie lacaracterizarea informaţională a unui obiect, posibilitate care are ca rezultat şi introducerea unui mecanism de adresarenou (calificarea cu punct), cunoscut şi în Object Pascal, de exemplu. Evident, dacă vom considera necesar, pentrureprezentarea în memorie a unei structuri putem aloca memorie şi dinamic. Astfel apar pointerii la structuri de date, prilej cu care se combină forţa pointerilor cu posibilităţile pe care le oferă structurile.

Cod C++ care prezintă un exemplu de structură orientată pe obiecte alocată dinamic

 //Exemplul 4.3

#include<conio.h>#include<iostream.h>#include<alloc.h>

 //Definirea tipului abstract de date //utilizand cuvantuli cheie struct  //cu semantica din C++struct tad { int data;//Exemplu de membru functieint funct();

 };

int tad::funct(){ return data*data;

 };

 //Declararea unui pointer la un tad tad * ptad ;

void main(){ //Alocare de memorie pentru ptad 

  ptad=(tad*)malloc(sizeof(tad)); 

 //Utilizare pointer...observati mecanismul nou de selectare //a membrului in cazul pointerilor  ptad->data=10;

clrscr();

Page 44: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 44/214

//Utilizare membru functie in context de pointer  //la structura

cout<< ptad->funct();getch();

//Eliberarea memoriei gestionată de ptad  free(ptad);

 };

Tipul union, prezent în C şi C++ este introdus, în esenţă, cu scopul de a permite partajarea de către datele

membre a aceleeaşi zone de memorie, fapt care ne îngăduie să imaginăm foarte multe soluţii simple la situaţii frecventîntâlnite în realitate, a căror rezolvare, în lipsa tipului union, ne poate obliga la eforturi deosebite. Mai jos este prezentatun exemplu trivial de operare asupra conţinutului unui întreg, în condiţiile în care îl obligăm pe acesta să partajezeaceeaşi zonă de memorie cu un tablou de două caractere. Versatilitatea tabloului ne va permite să operăm asupraconţinutului întregului, dat fiind faptul că, atunci când fac parte dintr-o uniune, datele membre îşi partajează şi accesulla conţinutul comun.

Cod C++ care prezintă un exemplu de uniune orientată pe obiecte

 //Exemplul 4.4 #include<conio.h>#include<iostream.h> //Definirea tipului abstract de date

 //utilizand cuvantul cheie unionunion tad { void schimb();void set_octet(unsigned nr);void arata_cuvant(void);

  unsigned u;unsigned char c[2] ;

 };void tad::schimb(){ unsigned char tamp;tamp=c[0];c[0]=c[1];c[1]=tamp;

 };void tad::arata_cuvant(){ cout<<u<<endl;

Page 45: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 45/214

 };void tad::set_octet(unsigned nr){ u=nr;

 };

void main(){ clrscr();tad vtad;

vtad.set_octet(10000);cout<<"Inainte de...";vtad.arata_cuvant();vtad.schimb();cout<<"Dupa....";vtad.arata_cuvant();getch();

 };

Se mai pot spune multe lucruri despre puterea acestor două cuvinte cheie. De pildă, cuvântul cheie struct poate fiutilizat pentru a defini câmpuri de biţi, instrumente de lucru la nivel de structuri de biţi, extrem de puternice în C/C++.De asemenea, în cazul acestor structuri operează şi semantica specificatorilor de vizibilitate public şi private (asupracărora vom reveni pe larg la prezentarea tipului class. După cum se vede, vizibilitatea implicită, atât în cazul struct câtşi în cazul union este publică. În sfărşit, ambele tipuri ne oferă posibilitatea de a face benefica distincţie întrespecificarea şi implementarea unei structuri de date.

Mai mult decât aceste cuvinte cheie, obţinem dacă apelăm la tipul class, recunoscut de orice compilator de C++. Defapt, temelia specificării supersetului C++ o reprezintă tipul class şi extensiile cerute de acest tip pentru a spori suportulacordat programatorilor care lucrează orientat pe obiecte, în toate sensurile posibile.

4.1.3 Orientarea pe obiecte cu tipul classAdevărata fortă a orientării pe obiecte în C++ este întruchipată de tipul class, care aduce, pe lângă sintaxa de bază,

o serie de alte elemente remarcabile pentru confortul şi forţa programării în C++ (clasele şi funcţiile prietene,suprascrierea operatorilor, moştenirea multiplă, clasele template, supradefinirea funcţiilor într-un lanţ de derivare, etc.).Voi încerca în continuare să prezint cât mai multe dintre aceste elemente, reunite în sintagma sintaxa de bază.

Sintaxa C++ pentru specificarea unei clase

class <Nume_clasă> [:<Nume_clasă_de_bază>]{ 

<Date membre><Operaţii>

Page 46: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 46/214

[  public:<Date membre><Operaţii>]

[  protected :<Date membre><Operaţii>]

[  private:<Date membre><Operaţii>]

 };

După cum se poate observa, sintaxa C++ care stă la baza specificării unei clase conservă mare parte din semanticaspecificării unei clase în Java. În ceea ce priveşte sintaxa de bază pentru specificarea datelor membre şi a operaţiilor membre, cadrul C++ este prezentat mai jos.

<Tip data> <Identificator>;

<Tip returnat> <Nume operaţie>([<Lista de parametri>]);

În ceea ce priveşte specificarea datelor membre, trebuie să atrag atenţia asupra faptului că nu se admite asociereaunor valori implicite la definirea datelor membre, problema setării valorice a datelor membre fiind exclusiv decompetenţa programatorului (constructorii sau operaţiile dedicate setării valorilor datelor membre).

În ceea ce priveşte specificarea operaţiilor membre, deocamdată să semnalăm faptul că, în principiu, există operaţiicare respectă sintaxa precizată mai sus, dar există şi o excepţie importantă, constructorii, care nu acceptă să întoarcă untip, nici măcar void. De asemenea, mai există o serie de variaţiuni la sintaxa de specificare a unei operaţii membre, precum:

• Orice versiune de constructor are acelaşi nume cu clasa; deosebirile între versiuni apar la lista deparametri.

• Destructorul are ca nume numele clasei prefixat cu caracterul ~.• Funcţiile virtuale beneficiază de un supliment de sintaxă.• Operaţiile statice, ca şi membrii statici, beneficiază, de asemenea, de un supliment de sintaxă.

Utilizarea membrilor statici în C++ poate fi înţeleasă din Exemplul 4.5.

 //Exemplul 4.5#include <iostream.h>#include <conio.h>class Numar { int nr;

Page 47: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 47/214

  //Data membra statica //Aici doar este definita //Cererea de memorie, catre compilator, este facuta //in zona globala a programuluistatic float nf;

public:int getnr();

//Operatie membra statica

static float getnf();Numar(){ 

nr=0; nf=0.5;cout<<"Constructorul explicit...fara parametri"<<endl;};Numar(int nr);

 };

 //Cererea de memorie pentru data membra statica float Numar::nf;

 //Implementare externa constructor cu parametru

void Numar::Numar(int nr){ Numar::nr=nr;nf=0.5;cout<<"A lucrat constructorul explicit...1 parametru"<<endl;

 }; //Implementare operatie membra statica //Nu se poate referi decat la date membre statice float Numar::getnf(){ return nf;

 };

int Numar::getnr(){ return nr;

 };void main(){ 

Page 48: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 48/214

clrscr();Numar N1=Numar(10);Numar N2;cout<<N1.getnr()<<endl;cout<<N2.getnr()<<endl;cout<<N2.getnf()<<endl;cout<<N1.getnf()<<endl;getch();

 };

Din sintaxa cadru deducem că una dintre principalele probleme cu care ne confruntăm la specificarea unei clase înC++, la fel ca în Java, de altfel, este stabilirea condiţiilor de acces la membrii unei clase. Tabloul complet alsemanticii condiţiilor de acces la membrii unei clase în C++ este prezentat în Figura 15.

Figura 15. Controlul accesului în clasele C++

Aşadar, cuvintele cheie public, protected şi private ne ajută să definim secţiuni în care avem un anumit tip devizibilitate. Fiecare astfel de secţiune începe cu unul din cuvintele cheie de mai sus, urmat de caracterul :. Valabilitateaunei astfel de secţiuni încetează la întâlnirea caracterului } sau la întâlnirea unui alt cuvânt cheie pentru controlulaccesului.

class B:public A

Membrii privaţi

Membrii protejaţi

 friend class F ;

 Funcţia f, prietenă a clasei A

Clasă  prietenă a clasei A

class A

class F 

Page 49: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 49/214

Un exemplu de secţiune publică avem în Exemplul 4.5.Pentru mai multă precizie să precizăm următoarele:

• Cuvântul cheie public introduce o secţiune ale cărei componente sunt vizibile în tot programul, într-un contextadecvat.

• Cuvântul cheie protected introduce o secţiune ale cărei componente pot fi accesate doar de descendenţii claseiîn care apare secţiunea.

• Cuvântul cheie private introduce o secţiune ale cărei componente sunt vizibile doar în interiorul clasei.Clienţii clasei pot accesa componentele private doar prin intermediul interfeţei.

• Dacă definiţia clasei începe cu o secţiune în care nu apare nici unul din cuvintele cheie de mai sus, tipul deacces implicit este private.

Sintaxa C++ pentru implementarea unei claseCodul aferent operaţiilor unei clase poate fi scris în afara clasei sau în interiorul acesteia.Implementarea externă a unei operaţii urmează sintaxa:

<Tip><Nume clasă deţinătoare>::<Nume operaţie>([<Lista parametri>]){ 

 //Cod  };

De observat utilitatea operatorului de rezoluţie „::” la implementarea unei operaţii, pentru a indica

compilatorului clasa deţinătoare a operaţiei. Utilizatorul de rezoluţie globală mai are şi alte valori de întrebuinţare în C++. Una dintre ele apare în Exemplul 4.5, unde operatorul :: este folosit pentru a transmitecompilatorului o cerere de alocare de memorie pentru o variabilă statică.

Dacă se optează pentru implementarea externă, atunci apelul unei funcţii, membră a clasei, se face în maniereacunoscută de la funcţii în genere (utilizarea stivei pentru a memora punctul de revenire şi datele locale ale funcţiei, predarea controlului către codul funcţiei iar la return golirea stivei, etc.). Toate aceste operaţii pot afecta performanţele programului în anumite condiţii.

Evitarea unei astfel de situaţii se face implementând inline anumite funcţii membre. Implementând inline o funcţieîi spunem compilatorului ca fiecare apel al funcţiei inline să fie înlocuit cu o copie a codului funcţiei respective. Creşteviteza, dar poate să crească alarmant şi memoria internă folosită. De aceea, implementarea inline trebuie utilizată cudiscernământ.

O funcţie al cărei cod asociat este scris la definirea clasei este automat considerată ca inline de către compilator. O

funcţie implementată în afara definiţiei clasei, a cărei signatură este prefixată de cuvântul cheie inline, este, deasemenea, tratată de compilator ca inline.

inline <Tip> <Nume clasă deţinătoare>::<Nume operaţie> ([<Lista parametri>]){ 

 //Cod 

Page 50: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 50/214

 };

Cu toate că este un truism pentru majoritatea cititorilor, să menţionăm faptul că o funcţie care întoarce un rezultatface acest lucru cu ajutorul instrucţiunii return, utilizată cu o sintaxă de tipul:

return <Expresie>;

 Nu cred că este necesar să iniţiez o dezbatere specială pe tema controlului vizibilităţii asupra resurselor unei claseC++. Semantica tipurilor de vizibilitate este similară celei discutată pe larg în Cursul 3 (Specificarea unei clase în Java).

Alocarea memoriei pentru obiecte în C++Exemplele prezentate au arătat, deja, pentru cunoscători, cum se alocă memoria pentru obiecte în C++. În C++

 putem aloca memorie pentru obiecte static sau dinamic.

Varianta statică de alocareRevenind la Exemplul 4.5, observăm că avem două maniere de alocare statică a memoriei:

: Numar N1=Numar(10);

Numar N2;:

Mai întâi, N 1 este o instanţă a clasei Numar, creată şi iniţializată cu concursul constructorului parametrizat al clasei

Numar.În al doilea rând,  N 2 este o instanţă a clasei Numar, creată şi iniţializată cu concursul constructorului fără

 parametri al clase Numar. Apelul constructorului fără parametri este implicit.

Varianta dinamică de alocareAlocarea dinamică a memoriei pentru obiecte este înţeleasă corespunzător odată cu înţelegerea completă a rolului

 pointerilor în programarea C++. Dată fiind importanţa acestui subiect pentru formarea unui programator, voi insera oserie de consideraţii de strictă necesitate pentru înţelegerea şi utilizrarea pointerilor în C++. Modelul de memorie folosit pentru implementarea acestei idei este prezentat în Figura 16.

Page 51: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 51/214

Figura 16. Modelul de alocare dinamică a memorie în C++

Aşadar, tipul pointer este un tip de dată ale cărui instanţe pot păstra adrese către alte tipuri de date. Declararea unui pointer în C++ corespunde sintaxei de mai jos:

<Tipul de bază al pointerului> *<Pointer>;

Elementul magic în această declaraţie este caracterul „*” Cu ajutorul lui, în declaraţia de mai sus am specificatcompilatorului că <Pointer> este o variabilă care poate păstra o adresă către o porţiune de memorie în care am una saumai multe valori, al căror tip definitor este <Tipul de bază al pointerului>.

În variabila <Pointer> putem obţine o adresă în mai multe moduri:• Prin atribuire, de la altă variabilă pointer;• Prin atribuirea adresei unei variabile statice (folosind operatorul &, de obţinere a adresei unei variabile statice;

de menţionat faptul că operatorul & se mai foloseşte şi pentru definirea de alias-uri sau în sintaxa detransmitere prin referinţă a parametrilor unei funcţii);

• Prin formularea unei cereri de alocare de memorie (în unul dintre modurile posibile în C şi C++), caz în care,dacă cererea poate fi rezolvată se va primi adresa unei porţiuni din Heap, memorie destinată special alocăriidinamice. Această ultimă consideraţie este dependentă de platforma DOS, ca platformă ţintă pentruexecutabilul rezultat în urma compilării. În Windows, datele problemei în ceea ce priveşte alocarea dinamică amemorie se modifică, dat fiind faptul că avem alt model de memorie. Nu mai lucrăm cu memorie segmentatăci cu memorie flat, manevrabilă după alte tehnici, mult mai bine puse la punct decât cele corespunzătoare platformei DOS.

În momentul în care în variabila pointer avem o adresă, începe să se manifeste potenţialul pointerilor sub forma:aritmetica pointerilor, paralela tablou-pointer, conversii, creare de structuri dinamice, lucrul la nivel de octeţi şibiţi, etc.

Revenind la Exemplul 4.5, ne putem imagina că am declarat un pointer la clasa Numar (fie acesta pnumar ) pe carel-am asociat cu o adresă prin apelul operatorului new, urmat de apelul constructorului, pentru a realiza iniţializarea. A seurmări codul prezentat mai jos.

Variabilă pointer  Adresă de memorie

Memoria referită de adresă(porţiune contiguă)

Page 52: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 52/214

: //Declarare şi alocare de memorie Numar *pnumar=new Numar(11); //Utilizare pointer  //Referirea unui membru in contextul unui pointer  //se face cu ajutorul secventei de simboluri „->”.cout<<pnumar->getnr()<<endl;cout<<pnumar->getnf()<<endl;:

Problematica metodelor virtuale sau a metodelor virtuale pure o vom relua în contextul discuţiei referitaore la polimorfism.

Implicaţiile moştenirii şi polimorfismului asupra unora dintre conceptele prezentate mai sus, vor fi discutate încapitolele următoare.

Se poate urmări, în continuare, varianta C++ a codului Java pentru schiţarea, la nivel înalt de abstractizare, asoluţiei pentru problema LSI.

Cod C++ care exemplifica utilizarea tipului class pentru rezolvarea problemei LSI

#include <iostream.h>#include <conio.h>

 //Specificare minimala a clasei Nod class Nod { 

int Data;Nod *Urmatorul;

public:

//constructorul explicit al clasei Nod Nod(int Numar);

//modificator atribut Datavoid setareData(int Numar);

//selector atribut Dataint consultareData();

//Modificator atribut Urmatorul void setUrmator(Nod *Element);

Page 53: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 53/214

//Selector atribut Urmatorul Nod *consultaUrmator();

 };

 //Specificare clasa abstrcata Listaclass Lista{ 

Nod *AStart;

Nod *AUltim;int NrElem;

public:

//Metoda virtuala puravirtual void insereazaDNod(Nod Element)=0;

//Metoda virtuala puravirtual void insereazaINod(Nod Element)=0;

//Metoda virtuala puravirtual void stergeNodAdr(Nod Element)=0;

//Metoda virtuala puravirtual void stergeNodNum(int Nr)=0;

//Modificator atribut AStart implementat inlineinline void setareAStart(Nod *Element){ 

 AStart=Element;};

//Selector atribut AStart implementat inlineinline Nod *consultaAStart(){ 

return AStart;};

//Modificator atribut NrElem implementat inlineinline void setareNrElem(int ne){ 

Page 54: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 54/214

 NrElem=ne;};

//Selector atribut NrElem implementat inlineinline int consultaNrElem(){ 

return NrElem;};

//Modificator atribut AUltim implementat inline

inline void setareAUltim(Nod *Element){ 

 AUltim=Element;};

//Selector atribut AUltim implementat inlineinline Nod *consultaAUltim(){ 

return AUltim;};

//Metoda publica//Salvare lista in fisier de nume specificat 

void salveazaInFisier(char numef[]);

//Metoda publica//Restaureaza lista folosind informatiile din fisierul //de nume specificat Nod *incarcaDinFisier(char numef[]);

 };

class ListaOarecare: public Lista{ 

 public: //Constructor explicit inlineinline ListaOarecare(){ 

 setareAStart(NULL); setareAUltim(NULL); setareNrElem(0);cout<<"Constructor ListaOarecare..."<<endl;

 };

Page 55: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 55/214

 // inline void insereazaDNod(Nod Element){ 

cout<<"Neimplementata...Lista oarecare"<<endl; setareNrElem(consultaNrElem()+1);

 }

inline void insereazaINod(Nod Element){ 

cout<<"Neimplementata...Lista oarecare"<<endl; setareNrElem(consultaNrElem()+1);

 };

inline void stergeNodAdr(Nod Element){ 

cout<<"Neimplementata...Lista oarecare"<<endl; };

inline void stergeNodNum(int Nr){ 

cout<<"Neimplementata...Lista oarecare"<<endl; };

 };

 //Implementare Nod::Nod(int Numar){ Data=Numar;

 };

 //modificator atribut Datavoid Nod::setareData(int Numar){ Data=Numar;

 };

 //selector atribut Dataint Nod::consultareData(){ return Data;

 };

Page 56: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 56/214

 //Modificator atribut Urmatorul void Nod::setUrmator(Nod *Element){ Urmatorul=Element;

 };

 //Selector atribut Urmatorul  Nod *Nod::consultaUrmator(){ 

return Urmatorul; };

 //Specificare aproape completa a clasei abstracte Lista

void Lista::salveazaInFisier(char numef[]){ cout<<"Neimplementata...Lista"<<endl;

 };

 //Metoda publica //Deocamdata neimplementata //Restaureaza lista folosind informatiile din fisierul 

 //de nume specificat  Nod *Lista::incarcaDinFisier(char numef[]){ cout<<"Neimplementata...Lista"<<endl;return NULL;

 };

 //Functia principala //Introdusa doar ca parghie pentru verificarea //evolutiei implementarii codului //In stadiul final codul va fi utilizat ca un ansablu //de doua fisiere antet: unul care contine //specificarea claselor si unul care realizeaza implementarea // acestor clase

void main(){ clrscr();

 

Page 57: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 57/214

 //Alocarea dinamica a memoriei pentru obiecte//in C++ListaOarecare *LO=new ListaOarecare();LO->salveazaInFisier("Test");LO->stergeNodNum(1);getch();

 };

Invit cititorul să depună eforturi personale pentru a aprofunda următoarele subiecte:

• Rolul pointerilor în programarea C++. Legătura cu tablourile.• Pointerii la funcţii.• Clase şi funcţii prietene.• Constructorii şi destructorii în programarea C++.

4.2 Comparaţie Java/C++Similitudinile sintactice şi semantice care apar în utilizarea limbajelor Java şi C++ sunt de necontestat.

Similitudinile sunt benefice pentru fanii C++ care migrează către Java sau invers.

În categoria similitudinilor putem include:•

Acelaşi nucleu de cuvinte cheie utilizat în cele două limbaje (class, public, protected, private, static);• Aceleaşi principii promovate(încapsularea, moştenirea, polimorfismul);• Sintaxă asemănătoare pentru reprezentarea prelucrărilor aferente operaţiilor;

La capitolul deosebiri semnalez:

• Modul diferit de utilizare a cuvintelor cheie pentru controlul accesului la resursele unei clase;• Modul diferit de rezolvare, în cele două limbaje, a problemei alocării dinamice a memoriei pentru obiecte;• Diferenţa de abordare în ceea ce priveşte moştenirea (simplă, în Java, multiplă, în C++). Fiecare soluţie are

fani şi critici.• Diferenţe în rezolvarea problemei supradefinirii în cele două limbaje (metode virtuale, în C++, pur şi simplu

supradefinire pentru metode cu acelaşi nume, în clase înrudite, în Java). Soluţia Java pare mai elegantă.• Diferenţe datorate prezenţei pointerilor în C++ şi absenţei lor din Java.• Diferenţe datorate prezenţei claselor şi funcţiior prietene în C++ şi absenţei lor din Java.• Diferenţe datorate lipsei claselor template din Java.• Diferenţe datorate posibilităţii de a supraîncărca operatorii în C++ şi lipsei de suport în acest sens în Java.• Diferenţe în ceea ce priveşte controlul complexităţii şi modularizării proiectelor în cele două limbaje (pachete

în Java, fişiere header în C++).

Page 58: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 58/214

• Diferenţe în rezolvarea problemei implementării operaţiilor unei clase.• Flexibilitatea şi uşurinţa în manevrarea datelor membre statice (Java stă mai bine).• Posibilitatea de a bloca supradefinirea unei operaţii într-un lanţ de derivare (Java oferă suport, C++ nu).• Facilităţi pentru crearea de clase singleton (Java are suport, C++ nu)• etc.

Pentru curioşi, apariţia limbajului C#, însoţit de o logistică impresionantă, ar putea să însemne rezolvarea multoradintre aceste diferenţe.

Page 59: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 59/214

Capitolul 5Moştenirea în programarea orientată pe obiecte

 Perspectiva Java şi Perspectiva C++

Page 60: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 60/214

5.1 Scurtă introducereAm văzut, deja, faptul că unul dintre principiile importante în programarea orientată pe obiecte este

principiul moştenirii. Aşa cum se întâmplă, în general, cu principiile, nici principiul moştenirii nu trebuie fetişizatsau bagatelizat. Bagatelizarea lui înseamnă, ceva de genul: „Hai să facem moştenire ca să ne aflăm în treabă sau ca săvedem dacă funcţionează”. Fetişizarea, din contră, ar însemna „Sfinte Sisoe, nimic mai frumos şi mai eficient decât

aplicarea principiului moştenirii la tot pasul”.Ambele variante sunt false. Cum am mai spus şi altă dată, principiulmoştenirii este disponibil pentru uz, nu pentru abuz. Ceva mai concret spus:

Moştenirea este o modalitate performantă de reutilizare a codului, dar nu este întotdeauna cel mai buninstrument pentru îndeplinirea acestui obiectiv. 

Dacă este folosită necorespunzător, programele obţinute vor fi destul de fragile.

Moştenirea poate fi utilizată cu succes în cadrul unui pachet, unde implementările subclaselor şisuperclaselor sunt controlate de aceeaşi programatori. De asemenea, poate fi folosită la extinderea claselor careau fost concepute şi documentate exact în acest scop.

Însă, moştenirea unor clase concrete obişnuite, în afara graniţelor unui pachet, poate fi periculoasă. Trebuie săsubliniez faptul că toate consideraţiile pe care le fac în acest paragraf se referă la moştenirea înţeleasă ca moştenire aimplementării (o clasă extinde o altă clasă, exprimându-ne în spirit Java). Se ştie, desigur că relaţia de moştenireoperează şi în relaţia dintre interfeţe, chestiune care nu cade sub incidenţa observaţiilor critice, de mai sus, la adresamoştenirii.

Defecţiunea esenţială care poate apare când apelăm la moştenire se referă la faptul că, prin moştenire, încapsularea are de suferit în mod natural.

Şi aceasta deoarece funcţionarea corectă a unei subclase depinde de detaliile de implementare ale superclasei .Implementarea superclasei se poate modifica de la o versiune a programului la alta, situaţie în care , subclasa esteexpusă deteriorării chiar şi în cazul în care codul ei a rămas neatins. Prin urmare, subclasa este obligată să evoluezeodată cu superclasa, exceptând, bineînţeles, situaţia în care autorii superclasei au conceput-o şi documentat-o special pentru a fi extinsă.

O regulă de bun simţ în utilizarea principiului moştenirii ne spune că  este bine să folosim moştenirea numaidacă subclasa este, într-adevăr, un subtip al superclasei.

Altfel spus, o clasă B trebuie să extindă o clasă A numai dacă între cele două clase există o relaţie de tipul „Beste un A”.

Page 61: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 61/214

Cu referire la mulţimea poligoanelor, părerea unor aşa zişi specialişti, conform căreia putem deriva clasadreptunghi din clasa triunghi este complet în afara logicii relaţiei de moştenire. Nici în visul cel mai frumos undreptungi nu este un triunghi. În schimb, putem spune că triunghiul este un descendent al poligonului, pe motiv că oricetriunghi este un poligon, etc.

Concluzionând, moştenirea este un aspect important în programare, dar problematic, pentru că poate fiaplicat denaturându-i esenţa şi pentru că încalcă, în mod natural, regulile încapsulării .

Moştenirea se poate folosi eficient numai când între superclasă şi subclasă există o relaţie reală de genul „tip-subtip”. Chiar şi în acest caz, codul obţinut poate fi fragil, având probleme când apar modificări şi fiind predispus laanumite breşe în securitatea resurselor unei clase.

Evitarea unor astfel de probleme este posibilă, în anumite situaţii, prin utilizarea compunerii în locul moştenirii.Relaţia de compunere presupune ca în definiţia unei clase A să apară şi instanţe ale altor clase, ale căror servicii

urmează să fie utilizate de către clasa A. Pe de altă parte, este tot atât de adevărat faptul că multe probleme rezolvate înC++ cu ajutorul pointerilor, nu ar avea rezolvare echivalentă semantic în Java, fără suportul moştenirii.

5.2 Moştenirea în Java Nu este cazul să revin asupra sintaxei operaţiei de moştenire în Java.Java a optat pentru un cuvânt cheie pentru a informa compilatorul de intenţia unei clase de a moşteni proprietăţile

altei clase. Acest cuvânt cheie este extends. Ceea ce trebuie să semnalăm ca important, pentru spiritul moştenirii înlimbajul Java, este faptul că acesta nu oferă suport pentru moştenirea multiplă, în sensul în care este aceastaînţeleasă în alte limbaje. În Java, o clasă poate avea o singură superclasă. De aici rezultă posibilitatea teoretică de aconstrui doar ierarhii de clase, cu suportul oferit de moştenirea cu extends. Dat fiind faptul că în practică există şinenumărate situaţii în care semantica moştenirii multiple se impune ca alternativa cea mai valabilă, Java oferă o portiţă pentru a simula moştenirea multiplă cu ajutorul interfeţelor. Jongleriile care se pot face cu ajutorul interfeţelor audepăşit de mult intenţiile iniţiale ale specificatorilor limbajului Java. Mă voi ocupa de acest subiect în paragraful 5.3.

Exemplul 5.1 ilustrează moştenirea, având ca idee călăuzitoare specializarea clasei de bază prin adăugare demembri noi. De asemenea, Exemplul 5.1 ilustrează şi cele două tipuri de casting posibile în programarea orientată peobiecte din Java. În esenţă, este vorba despre faptul că, având contextul din Figura 17, sunt posibile două tipuri decasting, principial deosebite.

Figura 17. Derivare pretext pentru două tipuri de casting

A

B

Page 62: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 62/214

Primul tip de casting este implicit. Este vorba despre conversia unei variabile obiect de tip B la o variabilă detip A. Motivul pentru care acest tip de conversie este implicit este simplu: resursele lui A se regăsesc printreresursele lui B. Astfel că, atunci când B este coerent din punct de vedere al stării, nu există nici un motiv ca A să fiealtfel, în urma conversiei.

Al doilea tip de casting necesită acordul explicit al programatorului pentru a fi efectuat şi într-un anumit sens,asumarea răspunderii pentru această conversie. Este vorba de conversia unei variabile obiect de tip A la o variabilăde tip B. De ce este necesar acordul? Foarte simplu: resursele lui A sunt incluse printre resursele lui B. Conversia demai sus este posibil să aducă variabila de tip B într-o stare improprie pentru utilizarea unor metode, deoarece unele datemembre pot rămâne neiniţializate adecvat. Cu toate acestea, down casting-ul este esenţial în programarea generică,asupra căreia vom reveni într-un curs special.

 Exemplul 5.1 //Clasa de bază  //Modelează informaţional obiectul Fruct  //Potrivit abordării din acest cod  //metoda consultaTipFruct() nu poate fi //redefinită în descendenţiclass Fruct { 

 private int tipfruct; Fruct(int t){ 

tipfruct=t;

System.out.println("Constructor Fruct..."); } final int consultaTipFruct(){ 

return tipfruct; }

 }

 //Subclasă a clasei Fruct  //Para este un fruct->este respectat spiritul natural  //al moştenirii //Se adaugă noi atribute informaţionale //Se adaugă metode specifice //Este un exemplu clasic de specializare prin adaugareclass Para extends Fruct { 

 private double greutate; private int forma; Para(int t,double g,int f)

Page 63: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 63/214

{  super(t);System.out.println("Constructor Para..."); greutate=g; forma=f;

 }double consultaGreutate(){ 

return greutate; }

int consultaForma(){ 

return forma; }

 }

 //Subclasă a clasei Fruct  //Portocala este un fruct->este respectat spiritul natural  //al moştenirii //Se adaugă noi atribute informaţionale //Se adaugă metode specifice //Este un exemplu clasic de specializare prin adăugareclass Portocala extends Fruct 

{  private int tipcoaja; Portocala(int tf,int tc){ 

 super(tf);System.out.println("Constructor Para...");tipcoaja=tc;

 }

int consultaTipCoaja(){ 

return tipcoaja; }

 }

 //Clasa care utilizează ierarhia de clase de mai sus //Tipurile Para şi Portocala au acelaşi supertip //dar sunt incompatibile la atribuire //deoarece sunt părţi ale unor lanţuri de derivare

Page 64: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 64/214

 //diferite public class Mosten1{ 

 public static void main(String[] s){ 

 //Declarare variabilă referinţă  //având tipul clasei rădăcină  Fruct of;

 //Declarare şi alocare variabilă referinţă 

 //de tip Para Para obpara=new Para(1,1.5,2);

 //Declarare şi alocare variabilă referinţă  //de tip Portocala Portocala obport=new Portocala(10,1);

 //Utilizare normală a variabilei de tip ParaSystem.out.println("Para ..creata ca referinta Para");System.out.println("Tip fruct:"+ obpara.consultaTipFruct());System.out.println("Greutate fruct:"+obpara.consultaGreutate());System.out.println("Forma fruct:"+obpara.consultaForma());

 //Utilizare normala a variabilei de tip PortocalaSystem.out.println("Portocala creata ca referinta Portocala");System.out.println("Tip fruct:"+obport.consultaTipFruct());System.out.println("Tip coaja:"+obport.consultaTipCoaja());

 //Exemplu de Up casting (implicit)of=new Para(1,2.5,3);

 //Exemplu de Down casting (explicit); //Foarte util in programarea genericaobpara=(Para)of;

 //Utilizare variabile referinţă  //setate prin casting explicit System.out.println("Para ...creata ca referinta Fruct");System.out.println("Tip fruct:"+obpara.consultaTipFruct());System.out.println("Greutate fruct:" +obpara.consultaGreutate());System.out.println("Forma fruct:"+obpara.consultaForma());

 }

Page 65: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 65/214

 };

Exemplul 5.2 ilustrează specializarea prin redefinirea metodelor, ca bază pentru comportamentul polimorfical obiectelor în Java. Mecanismul polimorfismului îl voi pune în discuţie în Capitolul 6.

 Exemplul 5.2 //Clasa de baza //Modelează informţional obiectul Fruct  //Metoda consultaTipFruct() se va redefini //in descendentul Para

class Fruct { 

 private int tipfruct; Fruct(int t){ 

tipfruct=t;System.out.println("Constructor Fruct...");

 }int consultaTipFruct(){ 

return tipfruct; }

 }

 //Subclasă a clasei Fruct  //Para este un fruct->este respectat spiritul natural  //al moştenirii //Se adaugă noi atribute informaţionale //Se redefineşte metoda consultaTipFruct() //Este un exemplu clasic de specializare prin redefinireclass Para extends Fruct { 

 private double greutate; private int forma; Para(int t,double g,int f){ 

 super(t);System.out.println("Constructor Para..."); greutate=g; forma=f;

 }

Page 66: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 66/214

int consultaTipFruct(){ 

System.out.println("Consultare tip fruct..redefinire Para");return super.consultaTipFruct();

 }

double consultaGreutate(){ 

return greutate; }

int consultaForma(){ 

return forma; }

 }

 //Subclasă a clasei Fruct  //Portocala este un fruct->este respectat spiritul natural  //al moştenirii //Se adaugă noi atribute informaţionale //Se redefineşte metoda consultaTipFruct() //Este un exemplu clasic de specializare prin redefinireclass Portocala extends Fruct 

{  private double greutate; private int forma; Portocala(int t,double g,int f){ 

 super(t);System.out.println("Constructor Portocala..."); greutate=g; forma=f;

 }

int consultaTipFruct(){ 

System.out.println("Consultare tip fruct..redefinire Porto");return super.consultaTipFruct();

 }

double consultaGreutate(){ 

Page 67: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 67/214

return greutate; }int consultaForma(){ 

return forma; }

 }

 public class Mosten2{ 

 public static void main(String[] s){ 

 //Declarare variabilă referinţă de tipul clasei rădăcină  Fruct of;

 //Alocare referinţă utilizând constructorul unei subclase //a clasei rădăcină (Para)of=new Para(1,2.75,3);System.out.println("Para ...creata ca referinta Fruct"); //Utilizare, de fapt, în spirit polimorfic //a variabilei definite şi alocate mai susSystem.out.println("Tip fruct:"+of.consultaTipFruct());

 //Alocare referinţă utilizând constructorul unei subclase //a clasei rădăcină (Portocala)of=new Portocala(2,0.75,4);System.out.println("Portocala ...creata ca referinta Fruct"); //Utilizare, de fapt, în spirit polimorfic //a variabilei definite si alocate mai susSystem.out.println("Tip fruct:"+of.consultaTipFruct());

 } };

5.3 Moştenirea multiplă în JavaDeşi o modalitate comodă de a ieşi din impas în anumite situaţii, moştenirea multiplă este criticată pentru

confuziile pe care le poate genera, dacă este utilizată fără un „efort de inventariere”, adecvat focalizat asupra proprietăţilor claselor candidate la calitatea de superclase pentru o clasă derivată din ele. Duplicarea câmpurilor şi ametodelor, precum şi violarea crasă a încapsulării sunt principalele motive de îngrijorare când este vorba de utilizareamoştenirii multiple. Aşadar, ne aflăm în situaţia din Figura 18.

Page 68: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 68/214

Figura 18. Moştenirea multiplă

Dacă semantica din domeniul problemei impune o asemenea abordare, din punct de vedere conceptual, atunci înJava soluţia pentru posibilitatea de a spune despre C că este A sau B sau A şi B o reprezintă utilizarea interfeţelor.Interfaţa este o varietate de clasă, caracterizată prin faptul că poate declara metode abstracte şi publice şi, dacă estenecesar, variabile care sunt considerate, implicit, de tip public, static şi final, deci constante. În foarte mare măsură,comportamentul unei interfeţe este asemănător comportamentului unei clase.

Atât de profundă este asemănarea încât, în anumite situaţii interfeţele şi clasele se pot substitui reciproc. Pentru aînţelege modul de lucru cu interfeţele consider esenţiale următoarele precizări:

1. Mai întâi trebuie să învăţăm cum se declară o interfaţă . Aceasta este o problemă de sintaxă, mult mai simplădecât problema conceptuală, care trebuie clarificată înainte de a ajunge la sintaxă. Din punct de vedere conceptual, tipul

de raţionament pe care îl facem seamănă cu cel pe care îl facem când specificăm o clasă abstractă care are toatemetodele virtuale pure, în C++ sau abstracte în Java. Din punct de vedere sintactic, avem cadrul:

interface <Nume_interfaţă> [ extends <Listă _de_interfeţe>]{ 

<Signaturi de metode> }

Se observă, deja, amănuntul care deosebeşte „mecanica utilizării claselor” de „mecanica utilizării interfeţelor”,anume, suportul pentru moştenire multiplă în cazul interfeţelor. Pe acest amănunt se bazează alternativa Java lamoştenirea multiplă relativ la clase.

2. În al doilea rând, utilizarea unei interfeţe este posibilă, în mai multe moduri, după ce am specificat şiimplementat o clasă care o utilizează. Ne amintim de sintaxa:

class <Nume_clasă> [ extends Nume_superclasă] implements <Listă de interfeţe>{ 

<Date membre><Funcţii membre>

A B

C

Page 69: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 69/214

 };

După cum se poate observa, o clasă poate implementa mai multe interfeţe, depăşindu-se, astfel, restricţia Java înlegătură cu moştenirea multiplă în relaţia dintre clase. Să mai subliniez şi faptul că o clasă care implementează una saumai multe interfeţe poate avea cel mult un strămoş, eventual nici unul. Disciplina astfel introdusă este, sper, clară:metodele unei clase (care are, eventual un strămoş) pot fi acoperitoare ca specificare şi implementare pentrulistele de metode ale unor de interfeţe. În acest mod, avem la dispoziţie un mecanism de a vedea, din unghiuri diferite,ansamblul resurselor unei clase. Este clar că soluţia Java determină programatorii să mediteze mai atent înainte de aface joncţiunea cu mai multe interfeţe.

3. Utilizarea efectivă a interfeţelor este diversă: ca tipuri definitoare pentru referinţe la obiecte, ca tipuri implicateîn casting, ca tipuri utile în programarea generică, etc. Căteva modalităţi de utilizare a interfeţelor se pot vedea înExemplul 5.3 şi în Exemplul 5.4.

 Exemplul 5.3 //Interfata I1 //Expune functia f1()interface I1{ 

 public void f1(); }

 //Interfata I2

 //Expune functia f2()interface I2{ 

 public void f2(); };

 //Interfata I12 //Extinde interfetele I1 si I2 //Exemplu de mostenire multipla //a interfetelor interface I12 extends I1,I2{ 

 public void f3(); }

 //Clasa A implementeaza interfata I1class A implements I1{ 

 public A()

Page 70: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 70/214

{ System.out.println("AAAA...");

 }; public void f1(){ 

System.out.println("f1...."); };

 };

 //Clasa B implementeaza interfata I2

class B implements I2{ 

 public B(){ 

System.out.println("BBBB..."); }; public void f2(){ 

System.out.println("f2...."); };

 };

 //Clasa C implementeaza interftata I12

 //Evident,functiile expuse de interfetele //I1 si I2 sunt implementate si de catre //clasa C  //Deoarece I12 este derivata din I1 si I2 //ni se ingaduie sa privim instantele de tip //I12 ca fiind de tip I1 sau I2, dupa cum //este in interesul nostruclass C implements I12{ 

 public C(){ 

System.out.println("CCCC..."); }; public void f3(){ 

System.out.println("f3..."); }; public void f1(){ 

Page 71: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 71/214

System.out.println("f1...."); }; public void f2(){ 

System.out.println("f2...."); };

 };

 public class TestInterf 

{  public static void main(String args[]){ 

 // Crearea unui obiect de tip I1 // utilizand clasa A I1 ob1=new A();System.out.println("Ura...");

 // Utilizarea obiectului de tip I1ob1.f1();

 // Crearea unui obiect de tip I12 // utilizand clasa C  I12 ob12=new C();

 // Utilizarea obiectului de tip I12ob12.f1();ob12.f2();ob12.f3();

 // Crearea unui obiect de tip I1 // utilizand clasa C  I1 ob2=new C();

 // Utilizare obiect de tip I1 // creat cu suport C ob2.f1();

 //  Down casting dirijat de // interfeteob2=(I1)ob12;ob2.f1();

Page 72: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 72/214

 } }

 Exemplul 5.4  //Interfata IConst care declara //doua constante si o metodainterface IConst { 

int Numar=100;

String s="Bine ati venit!";void ftest();

 } //  A foloseste interfata IConst  //  Este obligata sa implementeze ftest()class A implements IConst { 

 A(){ 

System.out.println("Constructor.."); }; public void ftest(){ 

System.out.println("ftest() la lucru..."); };

 }

 public class TInterf1{ 

 public static void main(String s[]){ 

 // Creare variabila obiect  // de tip A // se mostenesc constantele // interfetei IConst  A va=new A();System.out.println(va.Numar);System.out.println(va.s);va.ftest(); // Creare variabila obiect  // de tip IConst  IConst iva=new A();

Page 73: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 73/214

System.out.println(iva.Numar);System.out.println(iva.s);iva.ftest();

 }; }

Înainte de a pune punct subiectului să mai precizez următoarele:

• Un program nu poate crea instanţe dintr-o interfată.• Toate metodele unei interfeţe sunt implicit publice şi abstracte. Nici un alt tip nu este permis.• Toate metodele trebuie să fie implementate de clasa care utilizează interfaţa.

5.4 Moştenirea în C++C++ propune caracterul „:” ca separator între clasa de bază şi superclasă pentru a indica compilatorului necesitatea

asigurării logisticii specifice unei operaţii de moştenire. Sintaxa efectivă a moştenirii ne oferă chiar mai mult decât atât,după cum se poate vedea mai jos.

class <Nume_clasa>[[ :] [<Modificator de protecţie>]<Lista de superclase>]

{ <Date membre><Funcţii membre>

 };Din sintaxa de mai sus, se poate deduce faptul că o clasă A poate moşteni o clasă B într-un mod mai flexibil decât

în Java. Modificatorul de protecţie, care poate apare, opţional, între operatorul de derivare „:” şi superclasă introduce oserie de combinaţii între vizibilitatea resurselor în clasa moştenită şi modificatorul de acces asociat operaţiei demoştenire, combinaţii care pot fi acoperitoare pentru cele mai neaşteptate semantici întâlnite în diverse probleme, dupăcum rezultă şi din Tabelul 5.1.

Tipul de acces alelementului înclasa de bază

Modificatorul deprotecţie asociat clasei debază la definirea clasei

Accesul în clasaderivată la element

Private Private interzisProtected Private private

Public Private privatePrivate Public interzisProtected Public protectedPublic Public public

Tabelul 5.1 Problematica accesului la membrii unei clase derivateUn exemplu interesant este răspunsul C++ la următoarea problemă:

Page 74: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 74/214

Dată clasa A, ce sintaxă de derivare folosim pentru ca o clasă B sămoştenească doar implementarea interfeţei clasei A?

Mai exact spus, B să moştenească implementarea interfeţei clasei A dar să nu o poată exporta direct cătrenici un tip de client. Evident, în practică, există numeroase astfel de situaţii în care dorim să folosim interfeţele unor clase fără a le expune direct clienţilor.

Soluţia tehnică a acestei probleme este moştenirea privată a clasei A de către clasa B (varianta a 3-a din Tabelul5.1), după cum se poate observa şi în Exemplul 5.5.

 Exemplul 5.5#include <iostream.h>#include <conio.h>

 //Superclasa căreia vrem să-i moştenim //doar implementarea interfeţei //adică: // constructorul Baza() // metoda setarenr() // metoda citestenr()class Baza{ int nr;

public:Baza(){ nr=0;

};

void setarenr(int n){ nr=n;

};int citestenr(){ return nr;

}; };

 //Clasa derivată Urmas care //moşteneşte privat superclasa Bazaclass Urmas: private Baza

Page 75: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 75/214

{ public:Urmas(){ };void setaren(int n){ setarenr(n);

};int afisarenr()

{ return transform();

};int transform(){ return citestenr()*citestenr();

}; };void main(){ Urmas ourm;clrscr();ourm.setaren(100);

cout<<ourm.transform();ourm.afisarenr();//  Ar fi ilegal enunţul ourm.citestenr()în // acest program deoarece ar însemna să expun clienţilor // însăşi interfaţa clasei Baza// ceea ce contrazice intenţia noastrăgetch();

 };

Conform uzanţelor din C++, moştenirea implicită a unei clase de către altă clasă este moştenirea privată. Prinurmare, cuvântul cheie private în derivarea din Exemplul 5.5 este redundant, fiind pus în scop didactic.

După cum anunţă şi sintaxa prezentată la începutul paragrafului 5.4, în C++ se poate face moştenire multiplă.Extrem de avantajos, cu o condiţie: cel ce face moştenire multiplă să o planifice temeinic înainte de a o folosiefectiv. Discuţiile sunt oricum prea vaste pe această temă. Pentru un programator la început de drum în programareaorientată pe obiecte, moştenirea multiplă trebuie să fie o soluţie extremă, la care se apelează după foarte multeexperimente şi cercetări asupra unor şabloane în materie de moştenire multiplă. Deranjul provocat de moştenireamultiplă nu este numai la utilizare ci, mai ales, în procesul de programare.

Practic, fiecare clasă poate fi considerată ca având un API propriu. Combinarea a două sau a mai multor clase într-o clasă nouă, prin moştenire, înseamnă combinarea API-urilor. În cazul proiectelor mari, este uşor de prevăzut ce se

Page 76: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 76/214

 poate întâmpla dacă nu asigurăm API-uri dizjuncte din punct de vedere al serviciilor expuse sau, în cel mai fericit caz,care să conducă la suprascriere în clasa colectoare.

Alta este situaţia în C++ şi în ceea ce priveşte transmiterea de parametri către constructorii superclasei. Ceeace în Java era rezolvat prin apelarea prioritară a constructorului superclasei, referit ca super, în C++ trebuie să respectesintaxa:

<Clasa derivata> ([<Lista parametri>]):<Superclasa 1>(<Lista de argumente 1>),<Superclasa 2>(<Lista de argumente 2>),<Superclasa 3>(<Lista de argumente 3>),

:<Superclasa N>(<Lista de argumente N>)

{  //Corpul constructorului

 }

Acestea sunt deosebirile de abordare între C++ şi Java în problema moştenirii. Cum beneficiem de moştenire?Aceasta este o întrebare cu un răspuns vast, niciodată lămurit până la capăt. Evident, vom avea compatibilitate laatribuire între strămoşi şi descendenţii lor (vezi principiul substituţiei!), deci vom putea beneficia de casting implicit.Cu riscurile de rigoare se îngăduie şi casting-ul explicit.

În încheiere, să ne imaginăm că am implementat toate metodele claselor care constituie soluţia problemei LSI.Presupunând că am declarat un pointer la clasa Lista, atunci, compatibilitatea acestui pointer cu oricare pointer ladescendenţii ListaOarecare şi ListaOrdonata va permite schimbarea fără probleme a modului de operare asupra uneiliste, în anumite circumstanţe, desigur.

O instanţă de tip ListaOrdonata trebuie să aibă un switch care abstractizează instaurarea sau nu a relaţiei de ordineîntre elementele unei liste. În caz că nu s-a instaurat această ordine, se activează automat refacerea stării de ordine, oride câte ori este cazul. Evident, problema apare numai atunci când facem conversii de la oarecare la ordonat. Invers nueste nici o dramă.

Page 77: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 77/214

Page 78: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 78/214

Capitolul 6Polimorfismul în programarea orientată pe obiecte

 

Perspectiva Java şi perspectiva C++

6.1 Să reamintim, pe scurt, ce este polimorfismul.După cum stau lucrurile în limbajele de programare orientate pe obiecte, polimorfismul este singurul principiu a

cărui forţă se manifestă în timpul execuţiei programelor. Valoarea principiului moştenirii este esenţial concentrată în posibilitatea de a reutiliza efortul de dezvoltare a unui sistem soft. Încapsularea este, de asemenea, un principiu a căruimanifestare nu este evidentă decât de pe poziţia de programator, în esenţă. Ar fi, însă, nedrept să nu subliniem că atât încapsularea cât şi moştenirea trebuie să fie mânuite cu multă abilitate pentru a obţine efecte polimorfice demare subtilitate şi utilitate.

Încercând o definiţie a polimorfismului, independentă de limbajul de programare şi din punctul de vedere al programatorului care beneficiază de el, numim polimorfism posibilitatea ca un apel de funcţie (metodă , operaţie)

să genereze răspunsuri diferite în funcţie de contextul în care a fost formulat.

6.2 Tipuri de polimorfism la nivelul limbajelor deprogramare. Exemplificare în C/C++

Page 79: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 79/214

 Nevoia de polimorfism, resimţită acut mai ales în programare, este în mare măsură sinonimă cu nevoia de confort.În stadiul în care se află, actualmente, realizările specialiştilor în materie de polimorfism la nivelul limbajelor de programare, putem semnala următoarele tipuri importante de polimorfism:

• Polimorfismul orientat pe suprascrierea funcţiilor în programarea clasică.• Polimorfismul orientat pe suprascrierea funcţiilor în cadrul definiţiei unei clase.• Polimorfsimul orientat pe supraîncărcarea operatorilor în programarea orientată pe obiecte.• Polimorfismul orientat pe redefinirea funcţiilor în programarea orientată pe obiecte, într-un lanţ de

derivare.

Indiferent de tipul lui, polimorfismul de calitate cere investiţie de timp şi creativitate, pe moment, în beneficiul unor viitoare reutilizări, cu minimum de efort din partea clienţilor.

Polimorfismul orientat pe suprascrierea funcţiilor în programarea clasicăAceastă formă de polimorfism este, practic, cea mai veche. Ea presupune posibilitatea de a scrie funcţii care au

acelaşi nume, retunează acelaşi tip de dată, dar se pot deosebi prin tipul şi numărul parametrilor. Această posibilitateeste ilustrată în Exemplul 6.1, perfect legal în programarea în limbajele C/C++.

 Exemplul 6.1 //Suprascrierea funcţiilor în programarea clasică în C  //Sunt specificate şi implementate două versiuni, //diferite prin lista de parametri ale funcţiei suma()

#include <iostream.h>#include <conio.h>

 //Prima versiune a funcţiei suma() //Parametrul s este transmis prin referinţăvoid suma(float &s ,int o1,int o2){ s=o1+o2;

 };

 //A doua versiune a funcţiei suma() //Parametrul s este transmis prin referinţă

void suma(float &s ,int o1, int o2, int o3){ s=o1+o2+o3;

 };

void main()

Page 80: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 80/214

{  float st;

clrscr(); 

 //Utilizarea versiunii 2 suma(st,12,13,14);

cout<<st<<endl; 

 //Utilizarea versiunii 1 suma(st,12,13);

cout<<st;getch();

 };

Care sunt observaţiile care se impun? Mai întâi, este de remarcat faptul că trebuie să existe un programator careeste suficient de informat cu privire la variaţiile de comportament ale unei funcţii având acelaşi nume şi care returneazăacelaşi tip de dată. Deşi nu excludem posibilitatea de a întâlni o astfel de situaţie şi în alte contexte, programatoriiversaţi ştiu foarte bine cât de mult valorează versionarea unei funcţii în programarea generică, atunci când soluţiatemplate-urilor prezintă unele inconveniente. În al doilea rând, dacă versionarea este realizată cu simţ de răspundere,utilizarea diferitelor versiuni în diferite situaţii este extrem de comodă şi benefică, găsind o soluţie de partajare acodului versiunilor între mai multe programe. În al treilea rând, nu putem trece cu vederea faptul că la compilare esterealizată legarea unui apel de versiune de codul aferent (acest gen de legare se numeşte early binding).

Polimorfismul orientat pe suprascrierea funcţiilor în cadrul definiţiei unei claseAceastă formă de polimorfism satisface unele cerinţe de versionare a comportamentului operaţiilor unei clase, în

spiritul celor spuse relativ la suprascrierea în stil clasic a funcţiilor. După cum se anticipează în Exemplul 6.2 (de codC++), acest tip de polimorfism poate fi combinat cu polimorfismul orientat pe supradefinirea metodelor într-un lanţ dederivare.

 Exemplul 6.2#include <iostream.h>#include <conio.h>

 //Clasa de bazaclass Super { int numar;public:Super(int n){ numar=n;

};

Page 81: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 81/214

  //Versiunea 1 a functiei f1()void f1()

{ cout<<"Super::Functie de test"<<endl;getch();

};

 //Versiunea 2 a functiei f1() // Suprascrie prima versiune a lui f1() inauntrul 

 //clasei Super  //In raport cu clasa Baza f1()este virtuala //Deci urmeaza sa fie supradefinita

virtual void f1(int n){ cout<<"Super::Numar: "<<n<<endl;getch();

}; };

 //Clasa derivataclass Baza:public Super { 

public:Baza(int n):Super(n){ };void f1(int n){ cout<<"Baza::Numar: "<<n<<endl;getch();

}; };

void main(){ 

 //Pointer la Super Super *PSuper;

 //Alocare dinamică a memoriei pentru pointer-ul Psuper  //în context Super  PSuper=new Super(10);

Page 82: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 82/214

clrscr();

 //Utilizare Psuper; apelare succesiva a doua versiuni ale //functiei f1() PSuper->f1(); PSuper->f1(10);delete PSuper;

 //Alocare dinamică a memoriei pentru pointer-ul PSuper  //în context Baza

 PSuper=new Baza(12); PSuper->f1(12);delete Psuper;

 };

Polimorfsimul orientat pe supraîncărcarea operatorilor în programarea orientată pe obiecteSubiect ocolit de specificatorii limbajului Java, însă generator de satisfacţii deosebite pentru programatorii în C++.

Ideea de bază constă în faptul că este la latitudinea celor care programează orientat pe obiecte în C++ săredefinească comportamentul unui foarte mare număr de operatori (+, -, *, >>, <<, new, delete, etc.).

Atenţie! Nu poate fi schimbată nici aritatea nici prioritatea operatorilor predefiniţi, prin supraîncărcare.Protocolul de supraîncărcare a unui operator, astfel încât acesta să opereze asupra obiectelor unei clase este

următorul:

1. Definiţia clasei trebuie să conţină o funcţie operator membru sau o funcţie operator prietenă, avândsintaxa specială:

Varianta funcţie membră

<Tip returnat> operator # (<Lista de argumente>);

sau

Varianta funcţie friend

 friend <Tip returnat> operator # (<Lista de argumente>);

În această sintaxă, atrag atenţia cuvântul cheie operator (care informează compilatorul că funcţia supraîncarcăun operator) şi caracterul # care semnifică un substitut pentru operatorul pe care doriţi să-l supraîncărcaţi, altuldecât: “.” , “*” , “::” , “?” .De remarcat faptul că, alegând varianta funcţie membră, un operator binar va fi specificat ca o funcţie cu un parametru, care va indica operandul din stânga, operandul din dreapta fiind vizibil prin intermediul pointeruluithis. De asemenea, dacă alegem varianta funcţie membră, un operator unar va fi implementat ca o funcţie

Page 83: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 83/214

fără parametri, pointerul this permiţând referirea operandului. Defecţiunea în cazul utilizării unei funcţiimembru pentru supraîncărcarea unui operator este clară: parametrul din stânga trebuie să fie un obiect, nupoate fi o constantă. Este evident că, în aceste condiţii funcţiile prietene sunt de preferat.

2. Funcţiile operator se vor implementa folosind una din sintaxele:

<Tip returnat> <Nume clasă>::operator # (<Lista de argumente>){  // Corp funcţie operator specificată ca membră  };

sau

<Tip returnat> operator # (<Lista de argumente>){  // Corp funcţie operator specificată ca prietenă  };

Lucrurile pot fi înţelese şi mai bine, urmărind Exemplul 6.3 (cod C++).

 Exemplul 6.3#include<conio.h>#include<iostream.h>

 //Clasa complex contine functia operator + ca membru //operatorul + este extins la multimea numerelor complexe //cu ajutorul unei metode membru a clasei complex 

 //Clasa complex contine functia operator - ca functie friend  //operatorul - este extins la multime numerelor complexe //cu ajutorul unei metode friend class complex{ float x,y;

 public:complex(){};complex(float a,float b){ static int i;i++;clrscr();cout<<"Lucreaza constructorul...Obiectul->:"<<i;

Page 84: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 84/214

getch();x=a;y=b;

};void disp_nc();

//prototipul operatorului +complex operator+(complex &op2);

 //prototipul operatorului -

friend complex operator-(complex &op1,complex &op2); };

void complex::disp_nc(){ cout<<x<<"+i*"<<y;

 };

 //Implementare operator + //Aceasta sintaxa transforma apelul <ob1+ob2> //in +(ob2), ob1 fiind accesibil prin pointerul  //special <this>complex complex::operator+(complex &op2)

{ complex temp;temp.x=op2.x+x;temp.y=op2.y+y;return temp;

 };

complex operator -(complex &op1,complex &op2){ complex temp;temp.x=op1.x-op2.x;temp.y=op1.y-op2.y;return temp;

 };

void main(){ complex tamp1,tamp2;complex *pod1,*pod2;

Page 85: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 85/214

complex ob1(10,10),ob2(11,11);clrscr();gotoxy(20,10);cout<<"Primul numar complex ->:";ob1.disp_nc();getch();gotoxy(20,11);cout<<"Al doilea numar complex->:";ob2.disp_nc();getch();ob1=ob1+ob2;gotoxy(20,13);cout<<"Suma numerelor complexe->:";

ob1.disp_nc();getch();

pod1=new complex(200,200);pod2=new complex(300,300);tamp1=*pod1;

clrscr();gotoxy(20,10);cout<<"Al treilea numar complex ->:";tamp1.disp_nc();

tamp2=*pod2;gotoxy(20,11);cout<<"Al patrulea numar complex ->:";

tamp2.disp_nc();

gotoxy(20,14);cout<<"Suma numerelor complexe->:";tamp1=tamp1+tamp2;tamp1.disp_nc();

tamp1=*pod1;tamp2=*pod2;tamp1=tamp1-tamp2;gotoxy(20,15);cout<<"Diferenta numerelor complexe->:";tamp1.disp_nc();getch();

 }

Polimorfismul orientat pe redefinirea funcţiilor în programarea orientată pe obiecte, într-un lanţ dederivareEste element suport esenţial pentru specializarea claselor într-un lanţ de derivare, specializare care se realizează

 prin redefinirea comportamentului unor metode ale strămoşilor. Pentru a se îmbina extinderea comportamentului cu

Page 86: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 86/214

reutilizarea codului, este de dorit ca redefinirea comportamentului să planifice utilizarea comportamentului versiunii dinstrămoş.

Exemplul 6.4 ne arată cum se pune problema redefinirii în C++.

 Exemplul 6.4 #include <iostream.h>#include <conio.h>

 //Structura suport pentru pastrarea //coordonatelor varfurilor poligoanelor 

 struct Varf { int x,y;Varf *Legs;

 };

 //Clasa Poligon //Clasă abstracta->nu are constructor şi destructor  //Furnizează prototipurile metodelor definitie() şi arie() //ca metode virtuale pure. //Furnizează implementarea pentru metodele: // perimetru() // ElibMem() // setare_pvarfuri() // consultare_pvarfuri() // setare_nrvarfuri() // consulatre_nrvarfuri()class Poligon{ Varf *pvarfuri;int nrvarfuri;public:

 //Metode virtuale pure //Vor fi redefinite în descendenţi 

virtual void definitie()=0;virtual float arie()=0;float perimetru();void ElibMem();void setare_pvarfuri(Varf *p);Varf * consultare_pvarfuri();void setare_nrvarfuri(int nv)

Page 87: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 87/214

{ nrvarfuri=nv;

};int consultare_nrvarfuri(){ return nrvarfuri;

};

 };

 float Poligon::perimetru(){ 

cout<<"perimetru(): ";cout<<"Calculul perim. este neimplem... Poligon" <<endl;getch();return 0;

 };

void Poligon::ElibMem(){ Varf*pwork;while (pvarfuri!=NULL){ 

pwork=pvarfuri->Legs;delete pvarfuri;pvarfuri=pwork;

}; };

void Poligon::setare_pvarfuri(Varf *p){ pvarfuri=p;

 };

Varf * Poligon::consultare_pvarfuri(){ return consultare_pvarfuri();

 };

 //Clasa Triunghi  //Clasă concretă având ca superclasă clasa Poligon //Redefineşte comportamentul metodelor:

Page 88: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 88/214

 // definitie(); arie() //Furnizează constructor şi destructor 

class Triunghi :public Poligon{ public:Triunghi(Varf *pt,int tnrv){ setare_pvarfuri(pt);setare_nrvarfuri(tnrv);

cout<<"Constructor Tringhi..."<<endl;};virtual ~Triunghi(){ cout<<"Destructor Triunghi..."<<endl;;ElibMem();

}; 

 //Redefinire metodevoid definitie();float arie();

 };

void Triunghi::definitie(){ cout<<"definitie(): ";cout<<"Triunghiul este poligonul cu trei laturi"<<endl;getch();

 };

 float Triunghi::arie(){ cout<<"arie(): ";cout<<"Neimplementata deocamdata...Triunghi"<<endl;getch();return 0;

 };

class Patrulater :public Poligon{ public:Patrulater(Varf *pt,int tnrv)

Page 89: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 89/214

{ setare_pvarfuri(pt);setare_nrvarfuri(tnrv);cout<<"Constructor Patrulater..."<<endl;

}; 

 //Destructor virtual virtual ~Patrulater();void definitie();float arie();

 };

 Patrulater::~Patrulater(){ ElibMem();cout<<"Destructor Patrulater..."<<endl;

 };

void Patrulater::definitie(){ cout<<"definitie(): ";cout<<"Patrulaterul este poligonul cu patru laturi"<<endl;getch();

 };

 float Patrulater::arie(){ cout<<"arie(): ";cout<<"Neimplementata deocamdata...Patrulater"<<endl;getch();return 0;

 };

class Paralelogram:public Patrulater { public:Paralelogram(Varf *pt,int tnrv):Patrulater(pt,tnrv){ 

cout<<"Constructor Paralelogram..."<<endl;};

  //Destructor virtual 

Page 90: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 90/214

virtual ~Paralelogram(){ ElibMem();cout<<"Destructor Paralelogram..."<<endl;

};

 //Redefinire metodevoid definitie();float arie();

 };

void Paralelogram::definitie(){ 

cout<<"definitie(): ";cout<<"Paralelogramul este patrulat. cu laturile paral. doua cate doua"<<endl;getch();

 };

 float Paralelogram::arie(){ cout<<"arie(): ";cout<<"Neimplementata deocamdata...Paralelogram"<<endl;getch();

return 0; };

class Dreptunghi :public Paralelogram{ public:Dreptunghi(Varf *pt,int tnrv):Paralelogram(pt,tnrv){ cout<<"Constructor dreptunghi..."<<endl;

};virtual ~Dreptunghi(){ ElibMem();cout<<"Destructor Dreptunghi..."<<endl;

};void definitie();float arie();

 };

Page 91: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 91/214

void Dreptunghi::definitie(){ cout<<"definitie(): ";

cout<<"Dreptunghiul este paralelogramul cu un unghi drept"; cout<<endl;getch();

 };

 float Dreptunghi::arie(){ cout<<"arie(): ";

cout<<"Neimplementata deocamdata...Dreptunghi"<<endl;return 0;

 };

void main(){ 

 Poligon *RefPol;Patrulater *RefPatr;clrscr();

  RefPol=new Triunghi(NULL,3);RefPol->arie();RefPol->definitie();

RefPol->perimetru();cout<<endl;delete RefPol;

RefPatr=new Patrulater(NULL,4);RefPatr->arie();RefPatr->definitie();RefPatr->perimetru();cout<<endl;delete RefPatr;RefPatr=new Paralelogram (NULL,4);RefPatr->arie();RefPatr->definitie();RefPatr->perimetru();delete RefPatr;

 };

Pentru o mai bună înţelegere a Exemplului 6.4, sunt necesare o serie de precizări în ceea ce priveşte genul de polimorfism ilustrat.

Page 92: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 92/214

Mai întâi, din punct de vedere sintactic, trebuie să observăm faptul că informăm compilatorul de intenţia deredefinire a unei metode în aval (într-un lanţ de derivare) prin specificarea acesteia în clasa gazdă ca metodăvirtuală sau ca metodă virtuală pură. 

Prototipul unei metode virtuale are sintaxa:

virtual <Tip returnat> <Nume metoda>([<Lista de parametri>]);

Prototipul unei metode virtuale pure are sintaxa:

virtual <Tip returnat> <Nume metoda>([<Lista de parametri>])=0;

Clasele care conţin cel puţin o metodă virtuală pură sunt clase abstracte, deci nu pot avea instanţe directe,neavând nici constructori. În schimb, clasele abstracte pot fi folosite pentru a declara referinţe către descendenţi,ceea ce exte extrem de folositor dacă dorim polimorfism.

De remarcat că redefinirea se bazează pe o restricţie importantă: în procesul de redefinire se conservă signatura(numărul de parametri, tipul lor şi tipul returnat).

Odată ce o metodă a fost declarată virtuală sau virtuală pură, compilatorul ştie că această metodă este posibil să fieredefinită în descendenţi şi, de asemenea, compilatorul ştie că pentru clasa care conţine metode virtuale şi pentru toateclasele descendente ei, la crearea primului obiect, constructorul va crea şi tabela VMT (Virtual Methode Table), ostructură partajată de toate obiectele unei clase, folosită de sistem pentru a realiza genul de legare a unui apel de codulcontextual, numit late binding. Prin urmare, atunci când se crează un obiect, al cărui tip definitor este undeva într-unlanţ de derivare, dacă în amonte a existat intenţie de redefinire a unor metode, sistemul va crea, numai în cazul primuluiobiect de tipul respectiv, o tabelă care conţine adresele metodelor virtuale ale clasei. Aceste adrese vor fi utilizate în procesul de late binding.

Să mai observăm faptul că, f ără a fi prefixaţi de cuvântul cheie virtual, destructorii sunt apelaţi pe principiul“Întotdeauna lucrează constructorul tipului definitor al unei variabile obiect sau al unui pointer la un obiect” ,ceea ce înseamnă un gen de legare statică a destructorului. Dacă dorim legare dinamică, atunci destructorul estedeclarat ca virtual.

Efectul poate fi urmărit în Exemplul 6.4.

6.2 Polimorfismul în context JavaJava implementează principiul polimorfismului la scara posibilităţilor proprii. În Java nu avem decât programare

orientată pe obiecte, oricare ar fi calitatea acesteia. Astfel că se oferă suport pentru polimorfism orientat pe

suprascrierea funcţiilor şi polimorfism orientat de supradefinire. Java nu oferă sintaxă pentru supraîncărcareaoperatorilor, deci nu este posibil polimorfismul aferent. Merită să remarcăm faptul că supradefinirea în Java este maisimplă decât în C++, din punct de vedere sintactic vorbind. Pur şi sumplu, dacă compilatorul sesizeză că în amonteleunui lanţ de derivare există o metodă care este supradefinită în aval, atunci compilatorul generează informaţii necesare pentru realizarea legării la execuţie. Cerinţa conservării signaturii în procesul de supradefinire este prezentă şi înJava.

Un model de utilizare a polimorfismului se poate observa în Exemplul 6.5.

Page 93: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 93/214

 Exemplul 6.5 //Clasa radacinaclass Poligon{ 

 private String definitie; public Poligon(String d){ 

definitie=new String(d); };

 public String citesteDefinitie(){ 

return definitie; };

 //Metoda va fi supradefinita in descendenti  public void arie(){ 

System.out.println("Poligon...neimplementata!"); };

 };

class Triunghi extends Poligon{ 

 public Triunghi(String d){ 

 super(d); };

 //Supradefinire public void arie(){ 

System.out.println("Triunghi...neimplementata!"); };

 };

class Patrulater extends Poligon{ 

 public Patrulater(String d){ 

 super(d);

Page 94: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 94/214

 };

 //Supradefinire public void arie(){ 

System.out.println("Patrulater...neimplementata!"); };

 };

 public class Polimorf 

{  public static void main(String[] s){ 

 //Referinta la radacina Poligon PRef;

 //Alocare in context Poligon PRef=new Poligon("Linie franta inchisa");System.out.println(PRef.citesteDefinitie());

 //Sintaxe la utilizare este aceeasi in cele trei contexte PRef.arie();System.out.println("");

 //Alocare in context Triunghi  PRef=new Triunghi("Poligonul cu trei laturi");System.out.println(PRef.citesteDefinitie()); PRef.arie();System.out.println("");

 //Alocare in context Patrulater  PRef=new Patrulater("Poligonul cu patru laturi");System.out.println(PRef.citesteDefinitie()); PRef.arie();System.out.println("");

 }; };

 Nu am motive să reiau discuţia pe marginea mecanismului de legare dinamică a metodelor supradefinite în Java.Chiar dacă compilatorul foloseşte alt gen de informaţii, la intrare, rezultatul final, pentru programator este acelaşi.

 Nu consider o problemă deosebită comentarea şi exemplificarea suprascrierii în clasele Java.

Page 95: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 95/214

Page 96: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 96/214

Capitolul 7Tratarea structurată a excepţiilor în programarea orientată pe obiecte

7.1 O problemă, în plus, în programare: tratareaexcepţiilorProgramatorii adevăraţi trebuie să ia, obligatoriu, în calcul şi posibilitatea de a crea programe robuste, care fac faţă

atât cerinţelor specificate dar nerafinate suficient, cât şi cerinţelor nespecificate dar formulate de utilizator, din diversemotive. Programele care au aceste calităţi se numesc robuste.

În programarea clasică, soluţia acestei probleme se putea numi, destul de exact spus, programare defensivă.Seamănă puţin cu conducerea preventivă din şoferie dacă ne gândim că programând defensiv, în fond punem răul înainte, deci nu ne bazăm pe cumsecădenia şi buna pregătire a utilizatorului .

Încercarea de a trata situaţiile de excepţie care pot apare la execuţia unui program, folosind metode clasice(programarea defensivă) duce la creşterea semnificativă a complexităţii codului ceea ce afectează, în mod direct,lizibilitatea şi, în mod indirect, corectitudinea codului

Pentru a face faţă cerinţelor legate de problema tratării excepţiilor (aşa se numesc în jargon profesional erorile careapar în timpul execuţiei programelor) anumite limbaje de programare oferă suport adecvat. Includem aici limbaje precum: Object Pascal, C++, Java, Visual C++.

  Nu toate compilatoarele de C++ oferă suport, dar standardul ANSI C++ cere acest lucru în mod explicit.Compilatoarele din familia Borland, începând cu versiunea 4.0 oferă acest suport.

Page 97: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 97/214

Esenţialul din punctul de vedere al programatorului C++ este ca el să-şi formeze abilitatea de a scrie, în jurulaplicaţiilor, cod C++ care îndeplineşte funcţia de handler de excepţii.

7.2 Mecanisme de bază în tratarea excepţiilor în C++Suportul sintactic C++ pentru tratarea excepţiilor se rezumă la trei cuvinte cheie, a căror semantică preliminară o

 prezentăm în Tabelul 7.1.

Cuvântul cheie Semnificaţietry Delimitează o porţiune de cod în care se

instituie controlul sistemului asupraexcepţiilor în timpul rulării.

throw Lansează o excepţie de un anumit tipcatch Captează o excepţie lansată

Tabelul 7.1 Cuvintele cheie ale limbajului C++ referitoare la tratarea excepţiilor

Forma de bază a tratării excepţiilorAşadar, atunci când programele dumneavoastră efectuează prelucrarea excepţiilor, trebuie să includeţi în cadrul

unui bloc try instrucţiunile pe care doriţi să le monitorizaţi în eventualitatea apariţiei unei excepţii. Dacă execuţia uneiinstrucţiuni se termină cu o eroare, trebuie să lansaţi o eroare, corespunzătoare acţiunii funcţiei în care se aflăinstrucţiunea. Programul plasează instrucţiunea throw în cadrul blocului try-catch. Forma generalizată a blocului care

captează şi tratează erorile este:try{ 

//blocul try //if(eroare) throw valoare_excepţie;

 }catch (Tip_excepţie Nume_variabilă ){ 

//Prelucrarea excepţiei }

În cadrul acestei forme generalizate, valoarea valoare_excepţie, aruncată, trebuie să corespundă tipuluiTip_excepţie.

Scrierea unui handler de excepţii simpluPentru a înţelege mai bine semantica unui handler de excepţii, studiaţi programul prezentat în Exemplul 7.1.

 Exemplul 7.1#include <iostream.h>

Page 98: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 98/214

void main(){ cout<<"Start"<<endl;

  try{ 

cout<<"In interiorul blocului try…"<<endl;  throw 100;

cout<<"Nu se va executa…niciodata";}

  catch (int i)

{ cout<<"Am captat o excepţie --valoarea este:";cout<<i <<endl;

}cout<<"Sfarsit…";

 };

Programul de mai sus implementează un bloc try-catch simplu. În loc să se aştepte ca programul să eşueze datorităunei erori, se utilizează instrucţiunea throw pentru lansarea erorii prezumtive. După ce blocul try lansează eroarea, blocul catch o captează şi prelucrează valoarea transmisă de instrucţiunea throw. Este evident şi din acest exemplu cămecanismul try-throw-catch oferă suport pentru rezolvarea problemei tratării excepţiilor, dar nu rezolvă de la sineaceastă problemă. Altfel spus, tratarea corectă a excepţiilor unui program este o problemă de atitudine caproiectant şi ca programator.

Lansarea excepţiilor cu o funcţie din cadrul blocului tryAtunci când programele apelează funcţii din cadrul blocurilor  try , C++ va transmite excepţia apărută într-o astfel

de funcţie în afara funcţiei dacă nu există un bloc try în interiorul funcţiei.Exemplul 7.2 ne arată cum se petrec lucrurile într-o astfel de situaţie.

 Exemplul 7.2#include <iostream>void XHandler(int test){ cout<<"Inauntrul functiei XHandler, test are valoarea: "<<test<<endl;if(test) throw test;

 }; void main(){ cout<<"Start:"<<endl;

  try{ 

Page 99: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 99/214

cout<<"Inauntrul blocului try…"<<endl;XHandler(1);XHandler(2);XHandler(0);

}  catch(int i){ cout<<"Am captat o exceptie. Valoarea este:";cout<<i<<endl;

};

cout<<"Sfarsit"; };

Plasarea unui bloc try într-o funcţieAm văzut cum apare un bloc try în funcţia principală a unui program. C++ permite blocuri try şi în alte funcţii ale

unui program, diferite de funcţia principală.Atunci când se plasează un bloc try într-o funcţie, C++ reiniţializează blocul de fiecare dată când se intră în acea

funcţie. Exemplul 7.3 ilustrează cele spuse.

 Exemplul 7.3#include <iostream.h>void XHandler(int test){ try

{ if(test) throw test;

}catch(int i){ cout<<"Am captat exceptia nr.: "<<i<<endl;

} };void main(){ cout<<"Start: "<<endl;XHandler(1);XHandler(2);XHandler(0);XHandler(3);cout<< "Sfarsit";

 };

Page 100: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 100/214

Un comentariu pe marginea celor prezentate până acum ar fi următorul: o instrucţiune catch se execută numai dacă programul lansează o excepţie în cadrul blocului try situat imediat înainte. În caz că o astfel de excepţie nu se lansează blocul catch va fi ignorat.

Utilizarea mai multor instrucţiuni catch cu un singur bloc tryPe măsură ce tratările excepţiilor devin tot mai complexe, uneori este necesar şi posibil ca un singur bloc try să

lanseze excepţii de mai multe tipuri. În cadrul programelor dumneavoastră puteţi construi un handler de excepţii, astfelîncât să accepte captarea mai multor excepţii. Într-o astfel de situaţie sintaxa generală este:

try

{ //instrucţiuni

 }catch (<tip_1> <var_1>){ 

//tratare excepţie 1 }catch(<tip_2> <var_2>){ 

//tratare excepţie 2 }:catch(<tip_n> <var_n>)

{ //tratare excepţie n

 }

Cu acest amendament sintactic, deducem că instrucţiunile catch pot capta orice tip returnat, nu numai tipurile de bază acceptate de C++. Acest "fenomen" este ilustrat în codul de mai jos (Exemplul 7.4).

 Exemplul 7.4 #include <iostream.h>void XHandler(int test){ try{ 

if(test==0)throw test;

if(test==1)throw "Sir de caractere…";

if(test==2)throw 121.25;

Page 101: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 101/214

}catch(int i){ 

cout<<"Am captat exceptia #:"<<i<<endl; }catch(char *sir){ 

cout<<"Am captat exceptia de tip sir de caractere:" <<sir<<endl;

}

catch(double d){ 

cout<<"Am captat exceptia #:"<<d<<endl;}

 };

void main(){ XHandler(0);XHandler(1);XHandler(2);cout<<"Sfarsit";};

 Blocuri catch generice (utilizarea operatorului puncte de suspensie)Programele scrise de dumneavoastră pot capta excepţii din cadrul mai multor blocuri try (de exemplu un bloc try

care încapsulează mai multe funcţii care lansează excepţii diferite din blocuri try diferite, sau să utilizeze mai multeinstrucţiuni catch într-un singur bloc try. C++ permite, de asemenea, utilizarea operatorului puncte de suspensie (…) pentru a capta orice tip de eroare care apare într-un singur bloc try. Sintaxa care permite captarea tuturor erorilor careapar într-un bloc try este prezentată mai jos.

try{ //Instructiuni

 }catch(…){ //tratarea exceptiei

 }

Pentru exemplificare propun codul de mai jos (Exemplul 7.5).

Page 102: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 102/214

 Exemplul 7.5#include <iostream.h>void XHandler(int test){ try{ 

if(test==0)throw test;

if(test==1)throw 'a';

if(test==2)throw 121.25;

}catch(…){ 

cout<<"Am captat o exceptie"<<endl; }

 };

void main(){ cout<<"Start:"<<endl; XHandler(0);

XHandler(1);XHandler(2);cout<<"Sfarsit";};

Evident, prelucrările din cadrul blocului catch generic trebuie să fie independente de tipul erorii.Mecanismul captării excepţiilor explicite poate fi combinat cu mecanismul excepţiilor generice ca în Exemplul 7.6.

 Exemplul 7.6 #include <iostream.h>void XHandler(int test){ try{ 

if(test==0)throw test;

if(test==1)throw 'a';

if(test==2)throw 121.25;

Page 103: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 103/214

}catch(int i){ cout<<"Am captat o exceptie de tip intreg…"<<endl;

}catch(…){ 

cout<<"Am captat o exceptie generica"<<endl; }

 };

void main(){ cout<<"Start:"<<endl; XHandler(0);XHandler(1);XHandler(2);cout<<"Sfarsit";};

Restricţionarea excepţiilorPe măsură ce programele dumneavoastră devin mai complexe, ele vor apela frecvent funcţii din cadrul unui bloc

try. Atunci când programele dumneavoastră apelează funcţii dintr-un bloc try, puteţi restricţiona tipurile de excepţii pecare funcţia apelată le poate lansa. De asemenea, puteţi preveni lansarea oricărei excepţii dintr-o anumită funcţie.

Sintaxa pentru restricţionare este:

<tip_returnat> <nume_functie>(<lista_arg>) throw (<lista_tipuri> ){ //Cod functie

 }

Sintaxa care inhibă lansarea oricărei excepţii este:

<tip_returnat> <nume_functie>(<lista_arg>) throw (){ //Cod functie

 }

Este bine să subliniem că atunci când declaraţi o funcţie cu clauza throw ea poate să lanseze doar acele tipuri precizate în listă. Dacă funcţia lansează orice al tip, programul este abortat. Un exemplu în continuare (Exemplul 7.7).

Page 104: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 104/214

 Exemplul 7.7 #include <iostream.h>void XHandler(int test) throw(int, char, double){ 

if(test==0)throw test;

if(test==1)throw 'a';

if(test==2)throw 121.25;

 }

void main(){ cout<<"Start:"<<endl;try{ XHandler(0);

}catch(int i){ cout<<"Am captat un intreg…"<<endl;

}

catch(char c){ cout<<"Am captat un caracter…"<<endl;

}catch(double d){ cout<<"Am captat un double…"<<endl;

}cout<<"Sfarsit";

 };

Relansarea unei excepţiiÎn anumite situaţii poate fi necesar să se relanseze o excepţie din interiorul unui handler de excepţii. Dacă relansaţi

o excepţie, C++ o va transmite unui bloc try exterior dacă acesta există. Cea mai probabilă situaţie în care puteţi opta pentru această variantă este atunci când doriţi să trataţi o excepţie în cadrul a două programe handler distincte. Pentrumai multă claritate, urmăriţi exemplul de mai jos (Exemplul 7.8).

 Exemplul 7.8#include <iostream.h>

Page 105: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 105/214

void XHandler(void){ try{ throw "Salve…";}catch(char *){ cout<<"Am captat char* in XHandler… "<<endl;

  throw;

}void main(){ cout<<"Start…"<<endl;try{ XHandler();

}catch(char *){ 

cout<<"Am captat char * in main…"<<endl;}cout<<"Sfarsit…";

 };

Mod de utilizare a excepţiilorToate elementele prezentate au încercat să demonstreze că C++ are o atitudine activă faţă de problema tratării

excepţiilor. Suportul oferit de C++ îl ajută pe programator să definească un comportament al programului când se produc evenimente anormale sau neaşteptate. O idee mai pragmatică de utilizare a suportului C++, în situaţii efective, o puteţi desprinde din Exemplul 7.9.

 Exemplul 7.9#include <iostream.h>void div (double a, double b){ 

try{ 

if(!b) throw b;cout<<"a/b="<<a/b<<endl;

}catch(double b){ 

Page 106: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 106/214

cout<<"Nu se poate imparti la zero…"<<endl;}}

void main(){ double i,j;do{ cout<<”Introduceti numaratorul (0 pentru stop):"<<endl;

cin i;cout<<”Introduceti numitorul :"<<endl;cin j;div(i,j);

} while (i!=0); };

Adevărata utilizare a protocoalelor prezentate mai sus, în context orientat pe obiect, se bazează pe posibilitatea de amodela, conform necesităţilor şi cerinţelor diferitelor tipuri de aplicaţii, excepţiile care pot apare. Practica a impusregula, potrivit căreia, fiecărei clase care face parte din diagrama claselor să îi asociem o clasă care îi modeleazăexcepţiile posibile, în comportament. Astfel că diagrama claselor care însoţeşte soluţia unei aplicaţii orientate peobiecte, va fi dublată de o diagramă a claselor care structurează excepţiile aplicaţiei. În acest mod putem ierarhizaexcepţiile, le personalizăm şi, evident, le integrăm într-o concepţie unitară de planificare a robusteţii unei aplicaţii.Elementele de bază ale unei astfel de abordări sunt ilustrate în Exemplul 7.10, un exemplu de cod C-Builder, în careclasa Poligon este “acompaniată” de clasa ExPol, care, “ar trebui” să modeleze excepţiile care pot apare în evoluţiaobiectelor de tip Poligon.

 Exemplul 7.10 //-----------------------------------------------------------#include <vcl.h>#pragma hdrstop

#include "UEx1.h"  //-----------------------------------------------------------#pragma package(smart_init)#pragma resource "*.dfm" 

 //Clasa Poligon //Insigfnifiantă din punct de vedere informaţional  //şi comportamental  //Expune către clienţi două metode: // constructorul  Poligon()

Page 107: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 107/214

 // metoda getmes()class Poligon{ char *mes;public:Poligon(char m[]){ mes=new char[strlen(m)];strcpy(mes,m);

};

char * getmes(){ return mes;

}; };

 //Clasa ExPol  //Are în dotare operaţiile strict necesare creării //şi manipulării unui obiect excepţie: // -constructorul, care crează o excepţie (  ExPol() ) // -metoda de consultare de către client a // semnificaţiei excepţiei (  getmes() )class ExPol { AnsiString mes;public:ExPol(char m[]){ 

mes=m;};AnsiString getmes(){ return mes;

}; };

TForm1 *Form1; Poligon *pol; //----------------------------------------------------------- _fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

Page 108: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 108/214

{  } //-----------------------------------------------------------

void _fastcall TForm1::Button1Click(TObject *Sender){ 

double numar;

//Bloc de gardă, instituit de cuvântul cheie try try

{ numar=StrToFloat(Edit1->Text);if(numar){ 

pol=new Poligon("Testare");Form1->Caption=pol->getmes();

 }else

 // Creare şi aruncare obiect excepţie de tip ExPol throw new ExPol("Eroare alocare memorie obiect...");

 //Secvenţă de captare şi tratare

 //a excepţiilor de tip ExPol catch(ExPol *e){ 

Form1->Caption="Exceptie..."+e->getmes();}

 } //-----------------------------------------------------------

Adevărul este că problema tratării excepţiilor în C-Builder este rezolvată mult mai bine decât în C++ standard, programatorul dispunând deja de o ierarhie de clase care modelează un mare număr de excepţii care pot apare, ierarhiela care se poate ralia şi programatorul pentru a defini şi trata propriile lui excepţii. Ne apropiem, astfel, destul de mult,de abordarea Java a problemei tratării excepţiilor.

7.3 Maniera Java de tratare a excepţiilorAşa cum am menţionat deja, încercarea de a trata situaţiile de excepţie care pot apare la execuţia unui program,

folosind metode clasice (programarea defensivă) duce la creşterea semnificativă a complexităţii codului, ceea ceafectează, în mod direct, lizibilitatea şi, în mod indirect, corectitudinea codului. Din această cauză cei care au creat Javaau gândit un sistem de tratare a excepţiilor (în continuă evoluţie, de la o versiune la alta a limbajului Java) care să permită programatorului:

Page 109: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 109/214

• Tratarea situaţiilor de excepţie, pe cât posibil, independent de fluxurile de control normale;• Tratarea excepţiilor, la un nivel superior celui în care apar;• Propagarea excepţiilor la nivelele superioare în mod ierarhic;• Tratarea unitară a excepţiilor de acelaşi tip.

În mare parte, asemănător sistemului C++ de tratare a excepţiilor, sistemul Java are, totuşi, o ofertă mai bine pusăla punct din acest punct de vedere. Java se bazează pe un număr restrâns de cuvinte cheie (try, catch, throw, finally,throws) şi pe o ierarhie de clase, specializate în tratrarea unor clase de erori.

Pentru a înţelege mai bine mecanismul tratării excepţiilor în Java, consider că este utilă o scurtă descriere amodului în care apar şi sunt procesate excepţiile în Java. Astfel, când apare o excepţie în interiorul unei metode a uneiclase Java, se creează un obiect excepţie (obiect ce caracterizează excepţia şi starea programului în momentul cândexcepţia apare). Odată creat acest obiect, el este “aruncat” utilizând cuvântul cheie throw. Sarcina creării şi aruncăriiobiectului excepţie aparţine programatorului. Din momentul aruncării unui obiect excepţie, folosind cuvântul cheiethrow, maşina virtuală Java (JVM), prin componenta RuntimeSystem, preia obiectul şi îl transmite secvenţei de codresponsabilă de tratarea excepţiei respective. În acest scop, RuntimeSystem va căuta un handler al excepţiei (=osecvenţă de cod responsabilă de tratarea excepţiei), începând de la nivelul (nivelul este o metodă) în care a apărutexcepţia şi continuând la nivelele superioare. Căutarea se face în urmă (backward), utilizând stiva de apel (call stack ).Primul handler (un bloc try-catch), corespunzător obiectului excepţie, se va ocupa de soluţionarea excepţiei. DacăRuntimeSystem a epuizat stiva de apel, fără a găsi o metodă care să ofere un handler al obiectului excepţie aruncat,RuntimeSystem va fi responsabil de tratarea excepţiei respective (va afişa un mesaj de eroare şi va opri firul deexecuţie). Mecanismul descris mai sus poate fi vizualizat ca în Figura 19.

Problema care se află în faţa programatorului este, evident, următoarea: cum poate folosi raţional mecanismulrespectiv? Spun aceasta deoarece, ca orice facilitate a limbajului şi suportul oferit pentru tratarea excepţiilor poate fiutilizat în mod abuziv. A abuza de tratarea excepţiilor înseamnă a vedea excepţii şi unde nu este cazul, fapt care provoacă complexificarea artificială a codului şi, foarte important, diminuează performanţele programului, deoarece,aşă cum rezultă şi din Figura 19, mecanismul tratării excepţiilor consumă resurse pentru a se desfăşura corespunzător.De aceea, este necesară o disciplinare a gândirii programatorului, în ceea ce priveşte decizia de a consideraexcepţie sau nu un anumit context de prelucrare, în interiorul unei metode şi apoi, decizia de a aborda, într-unanumit mod, problema tratării excepţiei respective. În esenţă, programatorul trebuie să acumuleze suficienţăexperienţă încât să deosebească o excepţie nerecuperabilă de o excepţie din care se poate reveni.

Page 110: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 110/214

Figura 19. Mecanismul Java de tratare a excepţiilor

Pentru a crea un obiect excepţie, Java pune la dispoziţia utilizatorului o ierahie de clase, aflată în pachetul java.lang. Pe lângă clasele de tip excepţie aflate în java.lang, fiecare pachet Java introduce propriile tipuri de excepţii.Utilizatorul însuşi poate defini clase de tip excepţie, care însă pentru a avea instanţe compatibile cu sistemul Java,trebuie să fie descendenţi ai clasei Throwable, clasă care ocupă o poziţie importantă în ierarhia simplificată a claselor de tip excepţie, prezentată în Figura 20.  

RuntimeSuystem - JVM-preia obiectul excepţie-caută, începând cu nivelul j, însus, primul handler corespunzător (=primul handler care rezolvă oexcepţie de tipul celei aruncate)-transferă obiectul excepţiehandler-ului

Nivel_1

Nivel_ i Nivel TratareExcepţieConţine un handler (un bloctry-catch)-preia obiect excepţie-tratează excepţie

Nivel_  j Nivel apariţieexcepţie-crează obiectul excepţieException exc=newException();-aruncă excepţiathrow(exc);

Throwable

Exception Error

RuntimeException

Page 111: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 111/214

Figura 20. Ierarhia simplificată a claselor de tip excepţie din pachetul java.lang

După cum se poate observa în Figura 20, clasa Throwable are doi descendenţi: clasa Error şi clasa Exception. Nici una din cele două clase nu adaugă metode suplimentare, dar au fost introduse pentru a delimita două tipurifundamentale de excepţii care pot apare într-o aplicaţie Java (de fapt, acest mod de gândire este aplicabil în orice limbajde programare care oferă suport pentru tratarea sistematică a excepţiilor).

Clasa Error corespunde excepţiilor care nu mai pot fi recuperate de către programator. Apariţia unei excepţii de tipError impune terminarea programului. Aruncarea unei excepţii de tip Error înseamnă că a apărut o eroare deosebit degravă în execuţia programului sau în maşina virtuală Java. În marea majoritate a cazurilor, aceste excepţii nu trebuie

folosite de către programator, nu trebuie prinse prin catch, şi nici aruncate prin throw de către programator. Acestetipuri de erori sunt utilizate de JVM, în vederea afişării mesajelor de eroare.

Clasa Exception este, de fapt, clasa utilizată efectiv de către programatori în procesul de tratare a excepţiilor.Această clasă şi descendenţii ei modelează excepţii care pot fi rezolvate de către program, fără a determina oprirea programului. Prin urmare, regula este simplă: dacă Java nu conţine o clasă derivată din Exception care poate fiutilizată într-un anumit context, atunci programatorul va trebui să o implementeze, el însuşi, ca o clasă derivatădin Exception.

Există o mare varietate de clase derivate din Exception care pot fi utilizate. Mai mult, fiecare pachet Java adaugănoi tipuri de clase derivate din Exception, clase legate de funcţionalitatea pachetului respectiv. Dacă astfel lucreazăcei de la SUN, de ce n-ar lucra la fel şi un programator oarecare?

Din categoria claselor derivate din Exception, se remarcă clasa RuntimeException12 şi clasele derivate din ea. Dinaceastă categorie fac parte excepţii care pot apare în execuţia unui program, în urma unor operaţii nepermise de genul:operaţii aritmetice interzise (împărţire la zero), acces nepermis la un obiect (referinţă null), depăşirea index-ului unuitablou sau şir, etc.

 Nu ne rămâne decât să prezentăm protocolul de lucru cu excepţii în Java.

Aruncarea excepţiilorAruncarea unei excepţii se face cu ajutorul cuvântului cheie throw, conform sintaxei:

…throw <obiectExceptie>;…

unde <obiectExceptie> este o instanţa a clasei Throwable sau a unei clase, derivată din aceasta. Evident, în loculvariabilei <obiectExceptie> poate fi o expresie care returnează un obiect de tip convenabil. De fapt, în practică, modulde aruncare a unei excepţii urmează schema:

…throw new <clasaExceptie>(“Mesaj”);

12 Detalii cu privire la descendenţii clasei RuntimeException se pot găsi în Călin Marin Văduva, Programarea înJava, Editura Albastră, 2001.

Page 112: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 112/214

Evident, putem avea şi cazuri în care o funcţie poate arunca în mod indirect o excepţie, ceea ce înseamnă că funcţianu va conţine o expresie throw, ci va apela o funcţie care poate arunca o excepţie.

O metodă poate arunca mai multe excepţii. Important este să înţelegem că prin aruncarea unei excepţii se iese dinmetodă fără a mai executa secventele de cod care urmau. În cazul în care o funcţie aruncă o excepţie, fie prin throw ,fie prin apelul unei funcţii, fără a avea o secvenţă try-catch de prindere atunci această funcţie trebuie să specifice clar această intenţie în definiţia funcţiei. Pentru acest caz, sintaxa de definire a funcţie este:

 public void <numeMetoda> throws <clasExcept1>,<clasExcept2>, …

{ …throw <obiectExcep1>;…throw <obiectExcept2>;… };

Prinderea excepţiilorPentru a beneficia de avantajele mecanismului de tratare a excepţiilor, odată ce am aruncat o excepţie este nevoie

să o prindem. Prinderea unei excepţii se face prin intermediul unui bloc try-catch, a cărui sintaxă generică este prezentată mai jos.

…try{ 

 //Cod ce poate arunca o excepţie }catch(<clasExcept1> <idExcept1>){ 

 //handler exceptie de tip <clasExcept1> }catch(<clasExcept2> <idExcept2>){ 

 //handler exceptie de tip <clasExcept2> }…[  finally{ 

 //secvenţa de cod executată oricum }]…

Page 113: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 113/214

După cum se poate observa, structura de prindere a excepţiilor poate fi delimitată în trei blocuri.Blocul try, numit şi bloc de gardă atrage atenţia că secvenţa de cod inclusă în el poate arunca, în anumite condiţii,

excepţii. În cazul în care acest lucru nu se întâmplă, secvenţa din interiorul blocului de gardă se execută în întregime,controlul fiind predat primei instrucţiuni de după construcţia try-catch.

În cazul în care se aruncă o excepţie, execuţia secvenţei din blocul de gardă se întrerupe şi se declanşează procedura de tratare a excepţiei.

Tratarea excepţiei se poate face prin intermeiul blocurilor catch, numite şi handlere de excepţii. În momentul încare apare o excepţie în regiunea de gardă, se parcurge lista blocurilor catch în ordinea în care apar în programul sursă.În cazul în care excepţia aruncată corespunde unui bloc catch, se execută codul eferent blocului şi se termină căutarea în

listă, considerându-se că excepţia a fost rezolvată. Sintaxa ne arată că pot exista mai multe blocuri catch, ceea ceînseamnă că în blocul de gardă pot fi aruncate excepţii de mai multe tipuri.

Situaţiile deosebite care pot apare în utilizarea blocurilor catch sunt următoarele: am putea dori să tratăm excepţiide tip EC1 şi EC2, unde EC2 este o clasă derivată din EC1. Datorită faptului că blocurile catch sunt parcursesecvenţial este necesar să avem handler-ul clasei EC2 înaintea handler-ului clasei EC1, altfel, nu se va ajunge niciodatăla secvenţa catch de tratare a excepţiilor de tipul EC2.

De asemenea, putem avea situaţii în care să dorim tratarea unei excepţii pe mai multe nivele. În acest caz, se poatelua în considerare faptul că, odată prinsă o excepţie într-un bloc catch, o putem re-arunca cu un apel simplu de tipthrow.

În sfârşit, blocul finally, dacă este folosit, cuprinde secvenţa de cod care se va executa, indiferent dacă apare sau nuo excepţie, situaţie reclamată de nenumărate contexte în care apariţia unei excepţii, ca şi lipsa acesteia, presupunrezolvarea unor probleme care pot scuti sistemul de introducerea unor elemente perturbatoare prin nerezolvarea lor.

În Exemplul 7.11 şi în Exemplul 7.12 se pot vedea elementele de bază ale tratării excepţiilor într-o aplicaţie Java.Utilizarea cuvântului cheie finally nu mi se pare o problemă deosebită.

 Exemplul 7.11 //Metoda arunca o exceptie la nivelul superior  //Clasa care modeleaza exceptiile clasei NumarReal @SupressWarnings(“serial”)

class ENumarReal extends Exception{ 

 public ENumarReal(String s){ 

 super(s); };

 }

 //Clasa NumarReal  //o tentativa de modelare a lucrului cu numere realeclass NumarReal { 

 private double numar;

Page 114: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 114/214

 public NumarReal(double nr){ 

numar=nr; };

 public double getNumar(){ 

return numar; };

 //Metoda div() imparte doua numere reale //Suspecta de a arunca o exceptie la impartirea la zero //Declara acest lucru cu ajutorul cuvantului cheie throws  public NumarReal div(NumarReal n) throws ENumarReal { 

if (n.getNumar()==0)throw new ENumarReal("Exceptie...Impartire la zero...");elsereturn new NumarReal(this.getNumar()/n.getNumar());

 }; }

 public class Except1{ 

 public static void main(String [] s){ 

 //Blocul de garda care capteaza exceptia aruncata //de metoda div()try{ NumarReal onr1=new NumarReal(12);NumarReal onr2=new NumarReal(6);System.out.println(onr1.div(onr2).getNumar());onr1=new NumarReal(11);onr2=new NumarReal(0);onr1.div(onr2);

 }catch(ENumarReal e){ 

System.out.println(e.getMessage());

Page 115: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 115/214

 }; };

 };

 Exemplul 7.12 //Metoda arunca o exceptie dar o si capteaza //Clasa care modeleaza exceptiile clasei NumarReal class ENumarReal extends Exception{ 

 public ENumarReal(String s)

{  super(s);

 }; }

 //Clasa NumarReal  //o tentativa de modelare a lucrului cu numere realeclass NumarReal { 

 private double numar;

 public NumarReal(double nr){ 

numar=nr; };

 public double getNumar(){ 

return numar; };

 //Metoda div() imparte doua numere reale //suspecta de a genera o exceptie la impartirea la zero //Are bloc try-catch pentru captarea si tratarea //exceptiei public NumarReal div(NumarReal n){ 

try{ 

if (n.getNumar()==0)throw new ENumarReal("Exceptie...Impartire la zero...");else

Page 116: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 116/214

return new NumarReal(this.getNumar()/n.getNumar()); }catch(ENumarReal e){ 

System.out.println(e.getMessage());return new NumarReal(0);

 }; };

 }

 public class Except { 

 public static void main(String [] s){ 

 NumarReal onr1=new NumarReal(12); NumarReal onr2=new NumarReal(6);System.out.println(onr1.div(onr2).getNumar());onr1=new NumarReal(11);onr2=new NumarReal(0);onr1.div(onr2);

 }; };

Page 117: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 117/214

Capitolul 8Programare generică în C++ şi Java

8.1 Ce este programarea genericăAdeseori, programatorul se află în situaţia de a efectua acelaşi tip de prelucrare asupra unor tipuri de date diferite.

Soluţia începătorului este “scrierea de cod complet pentru fiecare tip de dată”. Vrem să sortăm un fişier după o cheie

Page 118: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 118/214

întreagă? Scriem o funcţie care realizează acest lucru, folosind, de exemplu, metoda bulelor. Vrem să sortăm un fişier după o cheie alfanumerică? Scriem o funcţie care ştie să sorteze fişierul după o astfel de cheie, folosind tot metoda bulelor. Nu ne va fi greu să observăm că, în cele două rezolvări date de noi există un element de invarianţă: codulşablon care efectuează sortarea. Deosebirile se referă la tipurile de date implicate în procesul de sortare ( fişierele potavea înregistrări de lungime diferită şi, evident, cu structură diferită iar cheile de sortare pot fi diferite ca tip ).Problema în faţa căreia ne aflăm nu este o problemă de algoritmică ci una de tehnică de programare. Programarea careare în vedere specificarea unor structuri de prelucrare capabile să opereze asupra unor tipuri variate de date senumeşte programare generică.

Evident, există limbaje de programare în specificarea cărora au fost prevăzute şi elemente suport pentru rezolvareaacestui tip de problemă. De exemplu, în Object Pascal se poate face programare generică apelând la tipuri procedurale

şi la referinţele de tip pointer. În C++ se pot utiliza, în scopuri generice, suprascrierea funcţiilor, conceptul de pointer,funcţiile şablon sau clasele şablon şi pointerii la funcţii. În sfârşit, în Java, utilizând cu abilitate moştenirea şi interfeţele putem simula genericitatea de o manieră destul de acceptabilă.

Aş evidenţia, dintre toate tipurile de elemente suport prezentate mai sus, clasele şablon din C++, socotite abstracţiifoarte puternice, care permit simularea a ceea ce, în ingineria softului, numim metaclase.

8.2 Genericitatea în C++Aşadar, in programare apar nenumărate situaţii în care reutilizarea codului presupune o soluţie de un anumit tip

 pentru o problemă dată. Situaţia la care ne referim în această secţiune este, potenţial vorbind, următoarea: Ce putemface pentru a comprima codul sursă în situaţia în care structuri de date, diferite ca tip, suportă prelucrărisimilare.

Soluţia acestei probleme de stil de programare o reprezintă programarea generică. Exprimându-ne în termeniilimbajului C, o funcţie generică defineşte un set general de operaţii care vor fi aplicate unor tipuri de datediferite.

Ca un exemplu, o soluţie generică pentru modelarea unei stive  este un pretext ideal pentru precizarea ideilor  principale ale programării generice. Altfel spus, dacă dorim o stivă, în care, de la caz la caz, să putem păstra numereîntregi, numere reale sau şiruri de caractere (deci tipuri de date diferite), operaţiile fiind aceleaşi ( push() şi pop() ), esteclar că ne aflăm în situaţia în care avem nevoie de suport pentru scrierea de cod cu proprietăţi generice.

Dacă în Pascal programarea generică se baza pe tipuri procedurale şi programarea la nivel de octet , în C++ existăsuport evoluat pentru programare generică, sub forma şabloanelor. Cu un şablon, în C++ se poate crea o funcţiegenerică sau o clasă generică. Să reamintesc cititorului faptul că în Capitolul 4 am ilustrat modul de utilizare aconceptului de pointer la funcţie, pentru definirea unui membru al unei structuri.

Funcţii TEMPLATEO funcţie template este o funcţie şablon, având unul sau mai mulţi parametri formali de un tip generic. În funcţie de

nevoile de utilizare a acestei funcţii, compilatorul generează funcţii propriu-zise, înlocuind tipul generic cu un tipconcret. Tipul concret poate fi orice tip fundamental, derivat sau clasă.Considerăm un exemplu. Fie funcţia max(x,y) care returnează valoarea maximă a argumentelor sale. Tipul

variabilelor  x şi  y trebuie, obligatoriu, specificat în momentul compilării. Soluţia clasică constă în redefinirea (over-loading) funcţiei max pentru fiecare tip al argumentelor  x şi  y. Trebuie, aşadar, să definim mai multe versiuni alefuncţiei max.

Page 119: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 119/214

int max(int x, int y){ return (x>y) ? x : y;

 }

 float max(float x, float y){ return (x>y) ? x : y;

 }

Mecanismul template permite definirea o singură dată a şablonului de funcţii, după care se generează automatfuncţiile propriu-zise, în concordanţă cu necesităţile de utilizare, dar, evident, în faza de compilare.

Sintaxa la specificare este:

template <class Nume_tip_generic_1 [,…class Nume_tip_generic_n]> Nume_şablondefiniţie_şablon

De precizat următoarele:

Caracterele < şi > fac parte din sintaxa obligatorie, nu îndeplinesc, aşa cum ne-am obişnuit, rolul de elemente demetalimbaj.

Lista de parametri formali ai unei funcţii şablon trebuie să utilizeze toate tipurile de date generice.

În cazul funcţiilor template nu se fac conversii.

Funcţia care are acelaşi nume şi acelaşi număr de parametri cu o funcţie şablon se numeşte caz exceptat(Supraîncărcarea explicită este prioritară).

Sintaxa la utilizare este:

 Nume şablon(Expresie_1[, …,Expresie_n]); 

Prezentăm, în continuare, definiţia funcţiei şablon max , urmată de o secvenţă client de utilizare.

template <class T>T max(T x, T y){ return (x>y) ? x : y;

Page 120: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 120/214

 }

 Exemplul 8.1#include <conio.h>#include<iostream.h>

 //Definire sablon functietemplate<class T>T max(T x,T y){ 

return(x>y) ? x:y; }void main(){ int i,j;float k,l;

clrscr();i=10;j=2;k=13;l=-7;

 //Exemple de utilizare sablon gotoxy(20,10);cout<<"Apel max cu param. variabili de tip float..." << max(k,l); gotoxy(20,12);cout<<"Apel max cu param. variabili de tip int ..."<<max(i,j);gotoxy(20,13);cout<<"Apel max cu parametri valoare …float ..."<<max(13.,-7.);getch();

 }

Prezentăm, totodată, un exemplu de funcţie generică pentru compararea unor date după valoarea unei cheiîncapsulate în aceste date.

 Exemplul 8.2#include <conio.h>#include <iostream.h>#include <ctype.h>

 //Definirea unei <functii generice> pentru compararea

Page 121: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 121/214

 //unor date dupa valoarea unei chei incapsulate //in aceste datetemplate <class T>int comp(T i1,T i2){ if (i1.key<i2.key) return -1;if (i1.key==i2.key) return 0;if (i1.key>i2.key) return 1;

 };

 //Structura aleasa pentru exemplificare //cheia generica incapsulata este campul <key> struct tpers{ char np[30];int key;

 };

 //Instantiere <struct tpers> struct tpers tam,pers[50];void main(){ clrscr();

int i=0;

 //Citire persoane de la tastaturado{ 

gotoxy(20,12);cout<<"Numele persoanei:";clreol();cin>>pers[i].np;gotoxy(20,13);cout<<"Matricola:";clreol();cin>>pers[i].key;gotoxy(20,14);cout<<"Mai aveti(D,N):";i++;

}while(toupper(getch())!='N');

 //Listare persoane pe ecranul monitorului  //in ordinea citirii de la tastatura

Page 122: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 122/214

clrscr();cout<<"Listare pers. in ordinea citirii de la tastatura"<<endl;

cout<<"_________________________________________"<<endl;for(int j=0;j<i;j++){ if (wherey()>10){ cout<<"_________________________________________"<<endl;cout<<"Pentru continuare apasati o tasta..."<<endl;getch();

clrscr();cout<<"Listare pers. in ord. citirii de la tastatura"<<endl;cout<<"_________________________________________"<<endl;

};cout.width(30);cout.setf(ios::left);cout<<pers[j].np<<" "<<pers[j].key<<endl;

};getch();

 //Sortare persoaneint sortat;do{ 

sortat=1;for(int j=0;j<i-1;j++){ 

 switch(comp(pers[j],pers[j+1])){ case 1:{ 

tam=pers[j];pers[j]=pers[j+1];pers[j+1]=tam;sortat=0;

}; };

};}while(!sortat);

 //Listare persoane dupa sortare in ordinea //crescatoare a matricolelor 

Page 123: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 123/214

clrscr();cout<<"Listare persoane dupa sortare..............."<<endl;cout<<"_______________________________________"<<endl;for(int k=0;k<i;k++){ 

if (wherey()>10){ cout<<"_________________________________________"<<endl;cout<<"Pentru continuare apasati o tasta..."<<endl;getch();

clrscr();cout<<"Listare persoane dupa sortare............"<<endl;cout<<"_________________________________________"<<endl;

};cout.width(30);cout.setf(ios::left);cout<<pers[k].np<<" "<<pers[k].key<<endl;

};getch();

 }

Clase TEMPLATEO clasă template defineşte un şablon pe baza căruia se pot genera clase propriu-zise. Din acest motiv, o clasă

template se mai numeşte şi clasă generică , clasă generator sau metaclasă.

Astfel că, o clasă template devine o clasă de clase, reprezentând celmai înalt nivel de abstractizare admis de programarea obiectorientată în C++.

În cadrul clasei şablon se pot declara atribute informaţionale de un tip ambiguu, care sunt particularizate în cadrulclasei generată pe baza şablonului. Evident, şi în acest caz, generarea se face în faza de compilare în concordanţă cucerinţele clientului.

Sintaxa la specificarea unei clase şablon, în cazul în care avem un singur tip generic este:

template <class T>class nume_clasa{ : };

Extinderea la mai multe tipuri generice este imediată.Sintaxa după care se face implementarea funcţiilor membre ale unei clase template:

Page 124: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 124/214

template <class T> Tip returnat nume_clasa <T>::nume_funcţie(…){ : };

Sintaxa la instanţiere este:

nume_clasa <Tip_concret> Obiect;

Pentru mai multă claritate, prezentăm şi exemplul de mai jos.

 Exemplul 8.3#include <iostream.h>#include <stdlib.h>#include <conio.h>

const int SIZE = 10;

 //Definire clasa matrice genericatemplate <class ATip>class genmat { ATip a[SIZE];

 public:genmat();ATip &operator [ ](int i); //Supraîncărcare operator [ ] 

 };

 //Implementare constructor clasa genericatemplate <class ATip> genmat<ATip>::genmat(){ 

register int i;for(i=0;i<SIZE;i++)a[i]=i;

 };

 //Implementare supraincarcare operator [ ] template <class ATip> ATip &genmat<ATip>::operator[ ](int i){ if(i<0 ||i>SIZE-1){ cerr<<"Valoare indice eronata...";

Page 125: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 125/214

getch();exit(1);

};return a[i];

 };

 //Functia principalavoid main(){ genmat<int> intob;

genmat<double> doubob;int i;clrscr();cout<<"Matrice de intregi..."<<endl;for(i=0;i<SIZE;i++)intob[i]=i;

for(i=0;i<SIZE;i++)cout<<intob[i]<<endl;

getch();clrscr();cout<<"Matrice de reali dubla precizie..."<<endl;for(i=0;i<SIZE;i++)doubob[i]=(double)i/3;

for(i=0;i<SIZE;i++)cout<<doubob[i]<<endl;

getch();clrscr();intob[100]=100;

 };

Tot pentru exemplificare, să considerăm şi o situaţie deosebit de simplă. Ni se cere să construim o clasă templatecorespunzătoare conceptului de stivă, din care, ulterior, să se poată concretiza clase care simulează stiva pentru tipuri dedate diferite.

 //Clasa sablon CSTack template <Class T>class CStack { 

T * v;  //pointer la varful stivei T * p;  //pointer la pozitia curenta din stiva

  int dim;  //dimensiunea stivei  public:

Page 126: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 126/214

CStack( int sz){ 

v=p=new T [dim=sz];  //alocare dinamica de memorie pentru p şi v}~CStack(){ 

delete [ ] v;}

  void  push(T a){ 

*p++=a;};T pop(){ 

  return *-p }

 }

După ce o astfel de clasă template a fost declarată şi definită, se poate trece deja la instanţierea de obiecte. Singuradeosebire faţă de folosirea unei clase obişnuite constă în faptul că trebuie specificat tipul concret care înlocuieşte tipulgeneric T. Ca un exemplu, să instanţiem un obiect stivă (de tip CStack ) , în care încap maximum 100 elemente de tipchar.

CStack <char> sc(100);

În acest caz, compilatorul generează clasa ce rezultă prin înlocuirea lui T cu char, după care instanţiază obiectul sc.Constructorul acestuia primeşte ca argument valoarea 100. Pentru mai multe detalii urmăriţi exemplul de mai jos.

 Exemplul 8.4 #include <iostream.h>#include <conio.h>

 // Definirea clasei stack. Se vede că instanţele ei nu sunt //protejate faţă de excepţii.template <class T>class CStack { T *v;T *top;int dims;public://Constructor 

Page 127: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 127/214

CStack( int sz){ 

v=top=new T[dims=sz];}

 //Desctructor ~CStack(){ delete [ ] v;}

 //Inserare elemente in stivavoid push(T a)

{ *top++=a; }

 //Extragere elemente dinstivaT pop(){ 

return *--top; }

 };

 //Functia principalavoid main(){ int i;

 //Primul exemplu de instantiere a stivei generice ;numere întregi CStack<int> st1(20);

 //Încarcare stivafor (i=0;i<=9;i++){ st1.push(i);

}

 //Vizualizare continut stivaclrscr();for (i=0;i<=9;i++){ gotoxy(35, wherey()+1);cout<<st1.pop()<<"*****";

Page 128: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 128/214

}getch();

  //Al doilea exemplu de instantiere a stivei generice; caractere, //începand cu “A” CStack<char> st2(20);

 //Încarcare stivafor (i=65;i<75;i++){ st2.push((char) i);

}

 //Vizualizare continut stivaclrscr();for (i=0;i<10;i++){ gotoxy(35, wherey()+1);cout<<st2.pop()<<"*****";

}getch();

 }

Exemplul 8.5 combină puterea şabloanelor cu puterea pointerilor pentru a arăta cum se poate regăsi elementul de peo poziţie indicată, într-o colecţie omogenă de date.

 Exemplul 8.5 //T este tipul de bază al colecţiei  //buf conţine colecţia de elemente de tip T  //poz indica pozitia elementului care ne intereseaza, 0-bazata#include <iostream.h>#include <conio.h>

 //Functia templatetemplate <class T>T retkey(T *buf,int poz){ for(int i=0;i<poz;i++)buf++;

return *buf; };

void main()

Page 129: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 129/214

{ int nr;int *tab;int *wtab;tab=new int(4);wtab=tab;*tab++=0;*tab++=1;*tab++=2;*tab=3;

clrscr();

 //Utilizare functie templatenr=retkey(wtab,2);cout<<nr;getch();

 };

Exemplul 8.6 schiţează soluţia C/C++ pentru problema despachetării unei înregistrări, dacă operaţiile de citirese fac la nivel de octet. Un astfel de instrument este absolut necesar dacă vrem să scriem cod C/C++ pentru sortareaunui fişier oarecare, cu înregistrarea de lungime fixă, a cărui cheie se specifică prin poziţie (octetul de început, primulcâmp începând la octetul 0).

 Exemplul 8.6 #include <iostream.h>#include <conio.h>#include <alloc.h>

 struct Stud { int matr;char nume[15];float bursa;int varsta;

 };

void *retcamp(void *buf,int poz,int ltot){ unsigned char *rec;rec=(char*)malloc(ltot);memmove(rec,buf,ltot);for(int i=0;i<poz;i++)

Page 130: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 130/214

rec++;return (void*)rec;

 };

void main(){ 

//Declarare initializare inregistrareStud s={12,"Vulcanescu",10000,35};

//Declarare pointer generic

void *sir;

//Pointer receptor la casting catre float float *nrf;

//Pointer receptor la casting catre int int *nri;

//Alocare dinamica memorie pentru pointerii de mai sussir=malloc(15);nrf=(float*)malloc(4);nri=(int*)malloc(2);

//Utilizare retcamp() pentru recuperare nume student sir=retcamp((void *)&s,2,21);clrscr();cout<<(char*)sir<<endl;getch();//Utilizare retcamp() pentru recuperare bursa student sir=retcamp((void*)&s,17,21);nrf=(float*)sir;cout<<*nrf<<endl;getch();

//Utilizare retcamp() pentru recuperare varsta student sir=retcamp((void*)&s,21,23);nri=(int*)sir;cout<<*nri;getch();

 };

Pointeri la funcţii

Page 131: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 131/214

O sursă interesantă de genericitate, în programarea C++ o reprezintă şi pointerii la funcţii sau la metodele membreale unor clase. Declararea unei variabile pointer la o funcţie sau la o metodă membră a unei clase se bazează pe osintaxă care iese oarecum din cadrul general de declarare a variabilelor în C/C++. În esenţă, declaraţia unei variabile pointer la funcţie corespunde sintaxei de mai jos:

<Tip returnat> (*<NumeVariabila>)([<Lista parametri>]);

Utilizarea acestei sintaxe suport şi câteva elemente despre semantica utilizării pointerilor la funcţii în Exemplul 8.7. 

 Exemplul 8.7 

#include <iostream.h>#include <conio.h>

 //Declarare pointer la functie //Numele pointerului este comp //comp este o variabila care poate pastra //adrese catre functii de comparare a doua valori numericeint (*comp )(void*,void*);

 //Functie de comparare specializata in numere intregi int icom(void *o1,void *o2){ if(*(int*)o1<*(int*)o2) return -1;

if(*(int*)o1==*(int*)o2) return 0;if(*(int*)o1>*(int*)o2) return 1;

 };

 //Functie de comparare specializata in numere reale //virgula mobila simpla precizieint fcom(void *o1,void *o2){ if(*(float*)o1<*(float*)o2) return -1;if(*(float*)o1==*(float*)o2) return 0;if(*(float*)o1>*(float*)o2) return 1;

 };

void main(){ int*ip1=new int(100);int*ip2=new int(120);float*fp1=new float(1.75);float*fp2=new float(1.50);

Page 132: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 132/214

//Utilizare pointer la functie cu versiunea icomcomp=&icom;clrscr();cout<<comp(ip1,ip2);getch();

//Utilizare pointer la functie cu versiunea fcomcomp=&fcom;clrscr();cout<<comp(fp1,fp2);

getch(); };

8.3 Genericitatea în JavaJava nu dispune de pointeri şi de template-uri. S-ar putea crede că genericitatea este dificilă sau aproape imposibilă

în Java. Adevărul este că lucrurile nu stau chiar aşa. În programarea orientată pe obiecte Java, putem combina forţareferinţelor la clase cu puterea oferită de moştenire şi interfeţe pentru a obţine un suport interesant pentru programareagenerică. Moştenirea ajută la crearea cadrului organizat în care putem specifica mai multe tipuri de obiecteasupra cărora efectuăm aceleaşi prelucrări. Conversiile down, permise între “rubedeniile” unei ierarhii de clase suntesenţiale pentru a implementa genericitatea. Interfeţele ajută la specificarea cadrului natural de introducere, în Java, areferintelor la metodele membre ale unor clase. Exemplul 8.8 ilustrează rolul moştenirii în scrierea de cod Java pentrucrearea şi vizualizarea unei liste simplu înlănţuite generice.

Exemplul 8.9 ilustrează simularea pointerului la o metodă generică, în Java, cu ajutorul unei instanţe a unei clasesingleton.

Exemplul 8.10 ilustrează simularea pointerului la o metodă generică, în Java, cu ajutorul interfeţelor.

 Exemplul 8.8 //Clasa care modeleaza nodul listei  //capabil sa pastreze orice tip de dataclass Nod { 

 private Object inf; Nod legs; public Object read(){ 

return inf; }; public void write(Object x){ 

inf=x; };

 }

Page 133: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 133/214

 //Clasa care modeleaza comportamentul  //unei liste simplu inlantuiteclass Lista{ 

 Nod start; Nod prec; public Lista(){ 

 start=null;

 }; public void adaugdupa(Object on){ 

if(start==null){ 

 Nod tamp=new Nod(); start=tamp; start.legs=null; start.write(on); prec=start;

 }else{ 

 Nod tamp=new Nod();tamp.write(on); prec.legs=tamp;tamp.legs=null; prec=tamp;

 } }

 //Metoda nu respecta cerintele //care i-ar da dreptul sa figureze //in API-ul clasei. //Am specificat-o din motive didactice. //Se poate observa un prilej potrivit pentru utilizarea //enuntului instance of  //In intentie, aceasta metoda este un iterator  public void PentruToate(){ 

 Nod w=start;int tip=0;

Page 134: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 134/214

 Integer i;String s;do{ 

if(w.read() instanceof Integer) tip=1;if(w.read() instanceof String) tip=2; switch(tip){ case 1:{ 

i=(Integer)(w.read());System.out.println(i);break;

 }case 2:{ 

 s=(String)(w.read());System.out.println(s);break;

 } };w=w.legs;

 }while(w!=null);

 } }

 public class CreLisGen{ 

 public static void main(String[] arg){ 

 Nod obiect; Lista lis=new Lista(); for(int i=0;i<8;i++){ obiect=new Nod();obiect.write(new Integer(i).toString());lis.adaugdupa(obiect.read());obiect=new Nod();obiect.write(new Integer(i));lis.adaugdupa(obiect.read());

}

Page 135: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 135/214

lis.PentruToate(); }

 }

 Exemplul 8.9 //Clasa pretextInt introduce o strategie concreta de comparare //relativ la numere intregi  //Exemplu de clasa SINGLETON class pretextInt { 

 //Constructor privat  //pentru a asigura caracterul de singleton private pretextInt(){  };

 public static final pretextInt INSTANCE=new pretextInt();  public int comp(Object a,Object b){ 

 Integer ia,ib;ia=(Integer)a;

ib=(Integer)b;if(ia.intValue()<ib.intValue())return -1;if(ia.intValue()==ib.intValue())return 0;else return 1;

 }; };

 //Clasa pretextInt introduce o strategie concreta de comparare //relativ la numere reale in virgula mobila //Exemplu de clasa SINGLETON class pretextFlo{ 

 //Constructor privat  //pentru a asigura caracterul de singleton private pretextFlo(){  };

 public static final pretextFlo INSTANCE=new pretextFlo();

Page 136: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 136/214

  public int comp(Object a,Object b){ 

 Float fa,fb; fa=(Float)a; fb=(Float)b;if(fa.floatValue()<fb.floatValue())return -1;

if(fa.floatValue()==fb.floatValue())return 0;else return 1;

 };

 };

 public class Simpfunc{ 

 public static void main(String[] s){ 

 Integer nri1=new Integer(100); Integer nri2=new Integer(200); Float nrf1=new Float(1.75); Float nrf2=new Float(1.0);System.out.println(pretextInt.INSTANCE.comp(nri1,nri2));

System.out.println(pretextFlo.INSTANCE.comp(nrf1,nrf2)); };

 };

 Exemplul 8.10 //Interfata prin intermediul careia se va simula //ideea de pointer la metoda compinterface SimPointMet { 

int comp(Object a,Object b); };

 //Clasa gazda a primei versiuni a metodei comp //Va utiliza interfata SimPointMet class pretextInt implements SimPointMet { 

 public pretextInt(){  };

Page 137: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 137/214

 public int comp(Object a,Object b){ 

 Integer ia,ib;ia=(Integer)a;ib=(Integer)b;if(ia.intValue()<ib.intValue())return -1;if(ia.intValue()==ib.intValue())return 0;else return 1;

 }; };

 //Clasa gazda a celei de-a doua versiuni a metodei comp //Va utiliza interfata SimPointMet class pretextFlo implements SimPointMet { 

 public pretextFlo(){  };

 public int comp(Object a,Object b){ 

 Float fa,fb;

 fa=(Float)a; fb=(Float)b;if(fa.floatValue()<fb.floatValue())return -1;if(fa.floatValue()==fb.floatValue())return 0;else return 1;

 }; };

 public class PointMet { 

 public static void main(String[] s){ 

 //Interfata SimPointMet lucreaza in context pretextInt  Integer ni1,ni2; Float nf1,nf2;SimPointMet INSTANCE1=new pretextInt();

 //Interfata SimPointMet lucreaza in context pretextFloSimPointMet INSTANCE2=new pretextFlo();

Page 138: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 138/214

ni1=new Integer(100);ni2=new Integer(200);nf1=new Float(200);nf2=new Float(100);System.out.println(INSTANCE1.comp(ni1,ni2));System.out.println(INSTANCE2.comp(nf1,nf2));

 }; };

Page 139: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 139/214

Capitolul 9Fluxuri orientate pe obiecte. Perspectiva C++

9.1 Noţiunea de flux

Page 140: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 140/214

Una din problemele importante, care trebuie rezolvată într-o aplicaţie reală, este problema asigurării persistenţeidatelor. Această problemă este rezolvată în mod diferit de limbaje diferite. De fapt, este vorba despre imaginarea unor strategii de păstrare, cu ajutorul memoriilor externe, a rezultatelor prelucrărilor. Memoria internă fiind foarte rapidă înacces, dar volatilă, este mediul ideal pentru reprezentarea unor structuri de date cât mai flexibile şi cât mai eficiente lainterogarea şi în timpul prelucrării datelor. Prelungirea duratei de viaţă a colecţiilor de date (care necesită această prelungire a duratei de viaţă), se bazează pe utilizarea unei varietăţi convenabile de memorie externă, mai lentă din punct de vedere al accesului, dar având capacitatea de a păstra colecţiile de date şi după terminarea execuţiei programelor. Oricât ar părea de ciudat, rezolvarea acestei probleme implică o serie de resurse hard şi soft, precum:echipamente periferice adecvate, controllere, sistem de gestiune a fişierelor, driver-e, cod sursă adecvat. Putem efectuaoperaţii de intrare-ieşire la nivel fizic, eludând, pur şi simplu, drivere şi chiar sistemul de gestiune a fişierelor. Nu cred

că merită să ne asumăm astfel de responsabilităţi, deoarece diminuăm o serie de calităţi de bază ale sistemelor soft( portabilitatea, lizibilitatea şi extensibilitatea fiind cel mai mult afectate). După o evoluţie îndelungată a căutărilor în această direcţie, s-a ajuns la două mari tipuri de rezolvări elegante ale problemei: soluţia fişiere-limbaj de nivel înaltşi soluţia fişier-SGBD. Prima soluţie este tributară ideii de a lăsa programatorului suficientă libertate de mişcare în procesul de manipulare a fişierelor. Preţul libertăţii este o dependenţă prea strânsă a aplicaţiilor de structurafişierelor. A doua soluţie este tributară ideii de a oferi aplicaţiilor o cât mai mare independenţă faţă de structurafişierelor, precum şi soluţii predefinite pentru o serie de tipuri standard de operaţii specifice manipulăriifişierelor şi colecţiilor de fişiere (sisteme de fişiere, care împreună cu aplicaţiile aferente formează ceea ce numim baze de date). Limbajele de nivel, de regulă, nu oferă cuvinte cheie pentru efectuarea de operaţii I/O. Obişnuinţa estede a oferi biblioteci de operaţii care permit efectuarea operaţiilor I/O. În condiţiile în care diversitatea echipamentelor care ocazionează efectuarea operaţiilor I/O este mare, este firească preocuparea specificatorilor limbajelor de programare de nivel înalt de a institui protocoale unitare de efectuare a operaţiilor I/O. În C/C++, conceptul carepermite o abstractizare convenabilă a operaţiilor I/O, în ideea tratării unitare, este conceptul de flux (stream).Prin introducerea acestui concept, programatorul lucrează cu o abstracţie logică (fluxul), nu direct cu fişierul extern,care, în funcţie de echipament, poate avea diferite forme de manifestare. Îm esenţă, un flux este un canal de comunicaţieîntre o sursă de date şi un receptor. Fluxul este o abstracţie logică, care asigură un anumit tip de funcţionalitate lavedere, dar instituie şi reguli, invizibile pentru programator, dar utile pentru optimizarea operaţiilor I/O, precumutilizarea zonelor tampon (buffere) în cursul operaţiilor I/O (vezi Figura 21).

Figura 21. Utilizarea buffer-ului în operaţiile specifice fluxului cout

<<

…000 0000 011001000101000010…

 Reprezentarea uneivariabile în memorie

 Buffer  asociat cu fluxul deieşire cout 

cout estelegat laecranul consolei

Operatorul << converteştereprezentareainternă încaractere

Page 141: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 141/214

 Necesitatea zonelor tampon asociate operaţiilor I/O este indiscutabilă, în condiţiile în care există, în mod sistematic,diferenţe semnificative de viteză de lucru între sursa de date a unui flux şi receptorul datelor fluxului. Aşadar,programatorul are nevoie de un instrument logic care să simplifice la maximum posibil, operaţiile I/O şi să leoptimizeze în mod rezonabil. Acest instrument, în cazul limbajelor de nivel înalt, este fluxul C++ şi Java oferă programatorilor colecţii structurate de clase a căror colaborare furnizează comportamentul primitiv necesar pentrurealizarea de operaţii I/O flexibile.

9.2 Fluxurile C++Sistemul de fişiere din C şi C++ este proiectat să lucreze cu o mare varietate de echipamente, care include:

terminale, drivere de disc, drivere de unitate de bandă, etc.

Chiar dacă echipamentele diferă, sistemul de fişiere din C şi C++ letransformă într-un instrument logic numit flux (stream).

Toate fluxurile se comportă la fel. Deoarece fluxurile sunt independente de echipamente, o funcţie care poate săscrie într-un fişier de pe hard poate fi folosită cu aceeaşi sintaxă pentru a scrie la alt dispozitiv. Sistemul de fişiere C/C++ recunoaşte două tipuri de fluxuri: text şi binar.

Fluxuri de tip textUn flux de tip text este o secvenţă de caractere. Standardul ANSI C permite (dar nu impune) ca un flux de tip text

să fie organizat în linii terminate cu un caracter de linie nouă. Totuşi, caracterul de linie nouă din ultima linie esteopţional, utilizarea sa fiind determinată de modul de implementare a compilatorului (Majoritatea compilatoarelor deC/C++ nu încheie fluxul de tip text cu un caracter de linie nouă. Să mai semnalăm faptul că, într-un flux de tip text potsă apară anumite transformări cerute de mediul de operare gazdă (De exemplu, un caracter de linie nouă poate fiînlocuit cu perechea început de rând-linie nouă . Acesta este motivul pentru care nu există o relaţie biunivocă întrecaracterele care sunt scrise sau citite şi cele de la echipamentul extern.

Fluxuri binareUn flux binar este o secvenţă de octeţi într-o corespondenţă biunivocă cu cei de la echipamentul extern.

FişiereÎn C/C++ un fişier poate să fie: un fişier de pe disc, tastatura, ecranul monitorului, imprimanta, etc. Un flux se

asociază cu un anumit fişier efectuând o operaţie de deschidere. Odată deschis fluxul, este posibil schimbul de dateîntre fişier şi programul utilizator care l-a deschis.

De observat faptul, trivial pentru cunoscători, că nu toate fişierele au aceleaşi posibilităţi. De exemplu, un fişier de pe disc poate să admită un acces aleator la datele stocate în el, în timp ce imprimanta nu o poate face. Astfel că, putemconcluziona, pentru claritate:

Pentru sistemul I/O din C/C++ toate fluxurile sunt la fel dar nu şifişierele.

Page 142: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 142/214

Dacă fişierul admite cereri de poziţionare, deschiderea fişierului iniţializează pointerul de fişier la o valoare careindică începutul fişierului. Pe măsură ce se fac operaţii de citire/scriere, pointerul de fişier este incrementatcorespunzător naturii operaţiei.

Un fişier se disociază de un flux în urma operaţiei de închidere. Dacă este închis un fişier deschis în operaţii descriere, conţinutul buffer-ului fluxului asociat este scris la dispozitivul extern (acest proces se numeşteflushing=golire ).

Toate fişierele se închid automat când programul se termină normal. În caz de blocaj sau dacă programul se terminăca urmare a apelului funcţiei abort(), fişierele nu se închid.

Cu menţiunea că în fişierul antet  stdio.h  se găsesc structurile de control de tip FILE, indispensabile pentru lucrulcu fişiere în C, prezentăm, în continuare contextul C++ referitor la sistemul I/O.

Fluxuri C++ relativ la perifericele standardC++ asigură suportul pentru lucrul cu fluxuri standard în fişierul antet iostream.h. În acest fişier antet sunt definite

două ierarhii de clase care admit operaţii de I/O. Clasa cu nivelul de abstractizare cel mai înalt se numeşte  streambuf şiasigură operaţiile de bază de intrare/ieşire. Ca programatori, nu folosiţi streambuf direct decât dacă veţi deriva propriileclase pentru efectuarea operaţiilor I/O. A doua ierarhie porneşte cu clasa ios, care acceptă operaţii I/O formatate. Din easunt derivate clasele istream, ostream şi iostream. Aceste clase sunt folosite pentru a crea fluxuri capabile să citească,să scrie, respectiv să citească şi să scrie date din/ la echipamentele externe. Clasa ios conţine o serie de alte ramurirelativ la lucrul cu fişiere pe care nu ne propunem să le studiem în cadrul acestei cărţi.

Page 143: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 143/214

Figura 22. Clasele din biblioteca C++ iostream

Se cuvine să observăm (cu referire la Figura 22) că biblioteca iostream este unul dintre exemplele de utilizare amoştenirii multiple în C++. După cum ştim, în C++, o instanţă a unei clase derivate conţine o copie a tuturor membrilor din clasa de bază. De aceea, în cazul unei clase ca iostream, care moşteneşte atât de la istream cât şi de la ostream,fiecare având ca strămoş comun clasa ios, se poate ajunge la două copii ale membrilor din ios. In C++ puteţi evita acestefect prin declararea claselor istream şi ostream ca având pe ios clasă de bază virtuală, astfel:

class istream: virtual public ios {…};class ostream: virtual public ios {…};

În acest fel, ne asigurăm în iostream de o singură copie a resurselor moştenite de la ios.

iosStochează variabilele de stare ale unui flux şi tratează erorile

istream Realizează conversia cu

 format sau fără format acaracterelor dintr-un streambuf 

ostream Realizează conversia

cu format sau fără  format a datelor dintr-un streambuf 

istream_withassign Flux de intrare caredefineşte operatorul = permiţând altui flux sau streambuf să fieatribuit acestui flux

iostream Fluxbidirecţional atât pentruintrare cât şi pentru ieşire

ostream_withassign Flux de ieşire care defineşteoperatorul = permiţând altui flux sau streambuf să fieatribuit acestui flux

iostream_withassign Flux bidirecţional cuoperatorul de atribuire = îndotare

streambuf  Implementează unbuffer 

Page 144: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 144/214

Fluxuri standard în C++Când îşi începe execuţia un program C++, se deschid automat patru fluxuri predefinite, pe care le prezentăm în

tabelul de mai jos.

Flux Semnificaţie Echipamentimplicit

cin Intrare standard Tastaturacout  Ieşire standard Ecrancerr  Ieşire standard pentru eroare Ecranclog  Versiune cu memorie tampon pentru cerr Ecran

Tabelul 9.1. Fluxurile predefinite C++ Fluxurile cin (consol input), cout (consol output), cerr (consol error) corespund fluxurilor stdin, stdout, stderr din C.

Implicit, fluxurile standard sunt folosite pentru a comunica cu consola. Însă, în mediile care admit redirecţionarea I/O,fluxurile standard pot fi redirecţionate spre alte echipamente sau fişiere.

I/O formatate în C++ relativ la fluxurile standardSistemul de I/O din C++ vă permite să formataţi operaţiile I/O, aşa cum se întâmpla şi în cazul utilizării funcţiilor C

 pentru operaţii I/O, precum: printf , cprintf , scanf ,etc. De exemplu, se poate specifica mărimea unui câmp, baza unuinumăr, numărul de cifre după punctul zecimal,etc. Operatorii din C++ utilizaţi pentru introducerea informaţiilor deformatare sunt >> (operator de extracţie dintr-un flux) şi << (operator de inserţie intr-un flux).

Există două căi înrudite, dar conceptual diferite, prin care se pot formata datele. În primul rând, putem avea accesdirect la diferiţi membri ai clasei ios. În al doilea rând, putem folosi funcţii speciale numite manipulatori, care pot fi

incluse în operaţiile I/O.Prezentăm, în continuare, modul de utilizare a manipulatorilor de formate, datorită accesibilităţii mai mari aacestora.

Manipulatorii standard sunt prezentaţi în tabelul de mai jos.

Manipulator Exemplu de folosire Efectdec cout<<dec<<intvar; Converteşte întregi în cifre zecimale;

corespunde formatului %d din Cendl  cout<<endl Trimite o nouă linie în ostream şi

descarcă bufferulends cout<<ends Inserează un caracter nul într-un flux flush cout<<flush Descarcă bufferul fluxului ostreamhex cout<<hex<<intvar;

cin>>hex>>intvar 

Conversie hexazecimală

corespunzătoare formatului %x dinANSI Coct  cout<<oct<<intvar;

cin>>oct>>intvar;Conversie octală (formatul %o din C)

resetiosflags(long  f  ) cout<<resetioflags(ios::dec);

Reiniţializează biţii de formatarespecificaţi de argumentul întreg de tiplong

 setbase(int baza) cout<<setbase(10); Stabileşte baza de conversie la

Page 145: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 145/214

cin>>setbase(8); argumentul întreg (trebuie să fie0,8,10 sau 16). Valoarea 0 este bazaimplicită.

 setfill(int ch) cout<<setfill(‘.’);cin>>setfill(‘ ‘);

Stabileşte caracterul folosit pentrucompletarea câmpurilor de mărimespecificată

 setiosflags(long  f  ) cout<<setiosflags(ios::dec);cin>> setiosflags(ios::hex);

Stabileşte biţii de formatare specificaţide argumentul întreg de tip long 

 setprecision(int p) cout<<setprecision(6);cin>>setprecision(10);

Stabileşte precizia conversiei învirgulă mobilă la numărul specificatde zecimale

 setw(int w) cout<<setw(6)<<var;

cin>>setw(24)>>buf 

Stabileşte mărimea unui câmp la

numărul specificat de caracterews Cin>>ws; Elimină spaţiile libere din fluxul deintrare

Tabelul 9.2. Manipulatori de formatare a operaţiilor I/O în C++

Toţi aceşti manipulatori au prototipul în fişierul antet iomanip.h.

Pentru a utiliza manipulatorii setiosflags() şi resetiosflags() trebuie cunoscuţi indicatorii de formatare din tabelul demai jos.

Nume indicator Ce efect are utilizarea indicatoruluiios :: skipws Elimină spaţiile goale din intrareios :: left  Aliniază ieşirea la stânga în interiorul lăţimii câmpului

ios :: right  Aliniază ieşirea la dreaptaios :: scientific Foloseşte notaţia ştiinţifică pentru numerele în virgulă mobilă.ios :: fixed  Foloseşte notaţia zecimală pentru numere în virgulă mobilăios :: dec Foloseşte notaţia zecimală pentru întregiios :: hex Foloseşte notaţia hexazecimală pentru întregiios :: oct  Foloseşte notaţia octală pentru întregiios :: uppercase Foloseşte litere mari pentru ieşireios :: showbase Indică baza sistemului de numeraţie în cadrul ieşirii (prefixul 0x

 pentru hexazecimal şi prefixul 0 pentru octalios :: showpoint  Include un punct zecimal pentru ieşiri în virgulă mobilăios :: showpos Include şi semnul + la afişarea valorilor pozitiveios :: unitbuf  Goleşte toate fluxurile după inserarea caracterelor într-un flux

Tabelul 9.3. Indicatori de formatare a operaţiilor I/O în C++

 Notaţia ios::<Nume_indicator> este folosită pentru a identifica indicatorul ca pe un membru al clasei ios.Exemplificăm cele spuse mai sus prin codul C++ de mai jos.

 Exemplul 9.1#include<iostream.h>#include<iomanip.h>#include<conio.h>

Page 146: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 146/214

#include<stdio.h>void main(){ 

double nr;clrscr();gotoxy(10,6);nr=7./3.;gotoxy(5,6);cout<<"Afisare nr. in virg. mobila format implicit...";gotoxy(10,7);

cout<<nr;

gotoxy(5,9);cout<<"Afisare nr. in virg. mobila cu precizia specificata...";gotoxy(10,10);cout<<setprecision(10)<<nr;gotoxy(5,12);cout<<"Afisare nr. in virg. mobila format virgula fixa...";gotoxy(10,13);cout.setf(ios::fixed);cout<<setprecision(10)<<nr;

gotoxy(5,15);

cout<<"Afisare nr. in virg. mobila format exponenţial...";gotoxy(10,16);cout.setf(ios::scientific);cout<<setprecision(10)<<nr;

gotoxy(5,18);cout<<"Afisare nr. in virg. mobila format exponential...";cout<<” cu afisare de semn”; gotoxy(10,19);cout.setf(ios::scientific|ios::showpos);cout<<setprecision(10)<<nr;

getch(); }

Fluxuri asociate cu fişiere utilizator în C++Chiar dacă abordarea operaţiilor I/O din C++ formează un sistem integrat, operaţiile cu fişiere (altele decât cele

 predefinite), sunt suficient de specializate pentru a fi necesar să la discutăm separat.

Page 147: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 147/214

Pentru a efectua operaţii I/O cu fişiere conform paradigmei C++, trebuie să includeţi în programul Dvs. fişierulantet  fstream.h. Acesta defineşte mai multe clase, printre care ifstream, ofstream şi fstream. Aceste clase sunt derivatedin istream şi, respectiv, din ostream la care ne-am referit şi mai sus.

Deschiderea şi închiderea unui fişierUn fişier se deschide, în C++, legându-l de un flux. Înainte de a putea să deschideţi un fişier, trebuie, pentru

început, să aveţi un flux. Există trei tipuri de fluxuri: de intrare, de ieşire şi de intrare/ieşire. Pentru a crea un flux deintrare, trebuie să-l declaraţi ca fiind din clasa ifstream. Pentru a crea un flux de ieşire, trebuie să-l declaraţi ca fiind dinclasa ofstream. Fluxurile care efectuiază atât operaţii de intrare cât şi operaţii de ieşire, trebuie declarate ca fiind dinclasa  fstream. Odată declarat fluxul, o modalitate de a-i asocia un fişier extern o reprezintă utilizarea funcţiei open()

având prototipul:

void open(const char *nume_fisier , int mod, int acces=filebuf::openprot);

În sintaxa de mai sus nume_fisier este un nume extern de fişier, care poate include şi specificarea căii de acces.Valoarea parametrului mod determină modul de deschidere a fişierului. Parametrul mod poate avea una sau mai

multe din valorile prezentate în tabelul de mai jos.

Nume mod Operaţieios::app Adaugă date în fişier ios::ate Când se deschide pentru prima dată, operează

 poziţionarea în fişier la sfârşitul fişierului (ate înseamnăla sfârşit)

ios::binary Deschide fişierul în mod binar, inhibând interpretareacaracterelor <CR> <LF>

ios::in Deschide fişierul pentru citireios::nocreate  Nu efectuează deschiderea fişierului dacă acesta nu

există dejaIos::noreplace Dacă fişierul există, încercarea de a-l deschide pentru

ieşire eşuează, cu excepţia cazului în care ios::app sauios::ate sunt operate

Ios::out Deschide fişierul pentru scriereIos:trunc Trunchiază fişierul dacă el există deja

Tabelul 9.4. Diferite valori ale parametrului care stabileşte modul de deschidere a unui fişier

Puteţi specifica mai mult de un mod de lucru pentru un fişier, folosind operatorul pe biţi SAU cu modurilerespective. De exemplu, pentru deschiderea unui fişier pentru ieşire şi poziţionarea pointerului la sfârşitul lui se folosescmodurile ios::out şi ios::ate astfel:

ofstream oflux(“o_fisier”,ios::out | ios::ate);

Page 148: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 148/214

ceea ce ne arată al doilea procedeu de deschidere a unui fişier, utilizând constructorul clasei ofstream sau, de ce nu,ifstream, dacă este cazul.

Pentru a închide un fişier, folosiţi funcţia membru close(). Această funcţie nu preia nici un parametru şi nureturnează nici o valoare. De analizat utilizarea funcţiei close() în exemplele care vor urma.

Scrierea şi citirea fişierelor în mod textSunt două operaţii foarte uşoare, realizate apelând la operatorii >> şi << într-un mod asemănător operaţiilor 

referitoare la consola sistemului, cu deosebirea că în loc să folosiţi cin şi cout apelaţi la un flux legat de un fişier .Codul de mai jos arată cum poate fi afişat pe ecranul monitorului conţinutul unui fişier text.

 Exemplul 9.2#include <fstream.h>#include <stdlib.h>#include<conio.h>

 //Functia principala a programului //citeste linia de comanda a programuluivoid main(int argc,char *argv[]){ 

//Linia de comanda a programului //trebuie sa contina doi parametriif (argc!=2)

{ cerr<<"Mod de utilizare : lisfis <nume fisier CPP>\n";exit(0);

}

// Deschidere fisier text de nume specificat in argv[1]ifstream in(argv[1],ios::in);if (!in){ cerr<<"Fisierul nu poate fi deschis!";exit(0);

}

char c;clrscr();while (in.get(c)){ if (wherey()>20){ 

Page 149: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 149/214

gotoxy(20,24);cout<<"Press any key to continue...";getch();clrscr();

}cout<<c;

}in.close();

 }

În cazul în care dorim o copie pe un suport de memorie externă a unui fişier text, procedăm ca în Exemplul 9.3.

 Exemplul 9.3#include <iostream.h>#include <stdlib.h>#include <fstream.h>

 //Copierea unui fisier text void main(int argc, char **argv){ 

//Buffer-ul de citirechar buffer[1];

  //Deschiderea fluxului input in mod text  //pentru operatii de citireifstream input(argv[1], ios::in);

//Verificare esuareif (input.fail()){ cout << "Eroare deschidere fisier..." << argv[1];exit(1);

}

//Deschidere flux output in mod text //pentru operatii de scriereofstream output(argv[2], ios::out);

//Verificare esuareif (output.fail()){ 

Page 150: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 150/214

cout << "Error opening the file " << argv[2];exit(1);

}  //Copierea efectivado{ input.read(buffer, sizeof(buffer));if (input.good())output.write(buffer, sizeof(buffer));

}while (!input.eof());

//Inchiderea fluxului input input.close();

//Inchiderea fluxului output output.close();

 }

Scrierea şi citirea fişierelor în mod binarExistă două modalităţi de a scrie şi citi date binare într-un fişier. Prima modalitate se referă la utilizarea funcţiilor 

 get() şi put(). Aceste funcţii sunt orientate pe octeţi, ceea ce înseamnă că get() va citi un octet de date iar  put() va scrieun octet de date.

Funcţia  get() are mai multe forme; o prezentăm, în continuare, împreună cu omoloaga ei  put(), pe cea mai desfolosită:

istream &get(char &ch);ostream &put(char ch); 

Funcţia get() citeşte un singur caracter din streamul asociat şi memorează valoarea sa în ch. De asemenea, se maiobservă că funcţia returnează o referinţă către flux. Funcţia  put() scrie ch în flux şi returnează fluxului o referinţă. Unexemplu de utilizare a funcţiei get în Exemplul 9.4. În help-ul kit-ului cu care lucraţi puteţi găsi informaţii relativ la alteforme ale acestor două funcţii (suprascrieri, de fapt).

 Exemplul 9.4 #include <iostream.h>#include <fstream.h>

int main(int argc, char *argv[]){ 

char ch;

Page 151: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 151/214

if(argc!=2){ cout << "Utilizare: DISPFT <nume_fisier>" << endl;return 1;

}ifstream in(argv[1], ios::in | ios::binary);if(!in){ cout << "Cannot open file.";

return 1;}while(in){ in.get(ch);cout << ch;

} } 

A doua modalitate de a citi şi scrie blocuri de date în binar este folosirea funcţiilor din C++ read() şi write().Prototipurile lor sunt:

istream &read(unsigned char *buf, int numar);

ostream &write(const unsigned char *buf, int numar);

Funcţia read() citeşte numar octeţi din fluxul asociat şi îl pune în buffer-ul indicat de buf .Funcţia write() scrie în fluxul asociat numar octeţi citiţi din buffer-ul spre care indică buf .Modul de utilizare a acestor două funcţii în contextul unor fluxuri binare se poate urmări în Exemplul 9.5.

 Exemplul 9.5#include <iostream.h>#include <stdlib.h>#include <fstream.h>

 //Exemplu de copiere binara a unui fisier  //Copierea se face octet cu octet void main(int argc, char **argv){ 

//Buffer-ul utilizator char buffer[1];

//Declarare flux input si deschidere in citire binara

Page 152: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 152/214

ifstream input(argv[1], ios::in | ios::binary);

//Verificare terminare operatie de deschidere fluxif (input.fail()){ cout << "Eroare deschidere fisier..." << argv[1];exit(1);

}

//Deschidere flux output in operatii de scriere binara

ofstream output(argv[2], ios::out | ios::binary);

//Verificare terminare operatie de deschidere fluxif (output.fail()){ cout << "Eroare deschidere fisier..." << argv[2];exit(1);

}

//Copierea propriu zisado{ input.read(buffer, sizeof(buffer));

if (input.good())output.write(buffer, sizeof(buffer));

}while (! input.eof());

input.close();output.close();

 }

Detectarea EOFPuteţi să detectaţi sfârşitul fişierului folosind funcţia membru eof() ,care are acest prototip:

int eof();

Ea returnează o valoare nenulă când a fost atins sfârşitul fişierului; altfel, returnează zero. Utilizarea funcţiei eof()şi alte elemente legate de lucrul cu fişiere, prezentăm în codul de mai jos, care realizează afişarea conţinutului unuifişier atât în hexazecimal cât şi în cod ASCII, atunci când codul asociat este printabil.

 Exemplul 9.6 

Page 153: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 153/214

#include <fstream.h>#include <ctype.h>#include <iomanip.h>#include <stdlib.h>#include<conio.h>void main(int argc,char *argv[]){ if (argc!=2){ cerr<<"Mod de utilizare : lishex <nume fisier CPP>\n";

exit(0);}ifstream in(argv[1],ios::in|ios::binary);if (!in){ cerr<<"Fisierul nu poate fi deschis!";exit(0);

}register int i,j;int count=0;char c[16];cout.setf(ios::uppercase);clrscr();

while(!in.eof()){ for(i=0;i<16 && !in.eof();i++){ in.get(c[i]);

}if (i<16) i--;for(j=0;j<i;j++)cout<<setw(3)<<hex<<(int) c[j];

for(;j<16;j++)cout<<"\t";

for(j=0;j<i;j++)if(isprint(c[j])) cout<<c[j];else cout<<".";

cout<<endl;count++;if(count==16){ count=0;

Page 154: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 154/214

cout<<"Press ENTER to continue!";getch();clrscr();cout<<endl;

}}in.close();

 }

Fluxuri asociate cu fişiere având structura definită de utilizator

Pentru a simula, în C++, lucrul cu fişiere cu tip, uzual în limbaje precum Pascal, Object Pascal sau în SGBD-uri,calea de urmat este arătată în Exemplul 9.7.

 Exemplul 9.7 #include <iostream.h>#include <fstream.h>#include <string.h>#include <stdlib.h>#include <conio.h>

 //Declarare structura inregistrare struct cont { 

char nume[40];float sold;unsigned long numar_cont;

};

void main(void){ 

//Instantiere structurastruct cont c;

//Setare campuri inregistrarestrcpy(c.nume, "Pavaloaie Matei");c.sold = 2500000;c.numar_cont = 98765432;

//Deschide flux binar in opeartii de scriereofstream outsol("sold.nsn", ios::out | ios::binary);if(!outsol)

Page 155: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 155/214

{ cout << "Nu se poate deschide fisier in scriere." << endl;exit (1);

}

//Scrie inregistrare in fluxoutsol.write((unsigned char *) &c, sizeof(struct cont));

//Inchide fluxoutsol.close();

//Deschide flux binar in citireifstream insol("sold.nsn", ios::in | ios::binary);if(!insol){ cout << "Nu se poate deschide fisierul in citire" << endl;exit (1);

}

//Citeste inregistrare din fluxinsol.read((unsigned char*) &c, sizeof(struct cont));clrscr();

//Afisare formatata campuri pe ecrancout << c.nume << endl;cout << "Numar de cont: " << c.numar_cont << endl;cout.precision(2);cout.setf(ios::fixed);cout << "Sold (LEI):" << c.sold << endl;insol.close();getch();

}

Accesul aleator în fişiereÎn sistemul de I/O din C++, accesul aleator se efectuează folosind funcţiile  seekg() şi seekp(). Formele lor cele mai

uzuale sunt:

istream &seekg(streamoff offset, seek_dir origine);ostream &seekp(streamoff offset, seek_dir origine);

unde  streamoff este un tip definit în iostream.h, capabil să conţină cea mai mare valoare validă pe care o poate aveaoffset, iar  seek_dir este o enumerare care are una din valorile:

Page 156: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 156/214

ios::beg ios::cur ios::end 

Sistemul de I/O din C++ operează cu doi pointeri asociaţi unui fişier. Unul este  pointerul de get , care specificăunde va apărea următoarea operaţie de intrare în fişier. Celălalt este  pointerul de put  şi specifică unde va avea locurmătoarea operaţie de ieşire. După fiecare operaţie de intrare sau ieşire, pointerul corespunzător este avansat automat,secvenţial. Dar, folosirea funcţiilor  seekg() şi seekp() permite un acces nesecvenţial la datele din fişier.

Funcţiile  seekg() şi seekp() deplasează pointerul de înregistrare corespunzător cu offset octeţi faţă de origine.

C++ pune la dispoziţie şi două metode care permit determinarea poziţiei curente dintr-un flux: tellp() şi tellg().Cu menţiunea că lucrul cu fluxuri, în C++, are nenumărate alte faţete pentru a căror prezentare nu dispunem de

timpul şi spaţiul necesar, încheiem această scurtă excursie în problematica fişierelor. În fine, pentru curioşi reamintim şifaptul că, însuşi bătrânul C are propria filozofie, extrem de puternică, în ceea ce priveşte lucrul cu fluxuri.

Fluxurile de tip şir de caractereFluxurile pot fi folosite şi pentru operaţii asupra şirurilor de caractere, cu rezultate asemănătoare celor prezentate în

Exemplul 9.8. Încă odată, în Exemplul 9.8 se observă importanţă practică a caracterului unitar al abordării operaţiilor I/O în C++.

 Exemplul 9.8 //Aplicatie la fluxuri de siruri de caractere#include <iostream.h>

#include <strstrea.h>#include <conio.h>#include <string.h>

void main(void){ //Sirul de caractere care va fi asociat cu un fluxchar in_string[] = "Ionescu Valentin 1200000 Zizinului 14";

//Deschidere flux de siruri de caractereistrstream ins(in_string);

char nume[20];char prenume[20];float salar;char strada[30];int nr;

clrscr();

Page 157: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 157/214

//Extragere de date din fluxul asociat cu sirul de caractere//si afisare formatata pe ecranins >> nume;ins >> prenume;cout.setf(ios::left);cout.width(15);cout <<"Nume angajat:";cout.width(30);strcat(nume," ");strcat(nume,prenume);

cout<<nume<< endl;cout.width(15);ins >> salar;ins >> strada;ins >> nr;strcat(strada," nr.");cout.setf(ios::fixed);cout.width(15);cout<<"Strada:"<<strada<<" "<<nr<<endl;cout.width(15);cout<<"Salariu: "<<salar<<endl;getch();

}

Supraîncărcarea operatorilor << şi >> relativ la fluxurile standardOperatorii de inserţie (<<), respectiv, extracţie (>>) pot fi instruiţi să lucreze şi asupra altor tipuri de date decât cele

fundamentale. În speţă, este vorba de faptul că parametrii lor pot fi obiecte utilizator, obiecte a căror clasă definitoaresupraîncarcă, prin una din metodele cunoscute, aceşti operatori. Astfel că devine perfect plauzibil codul prezentat înExemplul 9.9.

 Exemplul 9.9#include <iostream.h>#include <string.h>#include <conio.h>

class Angajat { public:Angajat(void) {};Angajat(char *name, char sex, int age, char *phone){ strcpy(Angajat::name, name);

Page 158: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 158/214

Angajat::sex = sex;Angajat::age = age;strcpy(Angajat::phone, phone);

};friend ostream &operator<<(ostream &cout, Angajat ang);friend istream &operator>>(istream &stream, Angajat &ang);

private:char name[40];char phone[20];int age;

char sex; };

ostream &operator<<(ostream &cout, Angajat ang){ cout << "Nume: " << ang.name <<endl;cout<< "Sex: " << ang.sex<<endl;cout << "Varsta: " << ang.age <<endl;cout<< "Telefon: " << ang.phone << endl;return cout;

}

istream &operator>>(istream &stream, Angajat &ang)

{ cout << "Nume : ";stream >> ang.name;cout << "Sex: ";stream >> ang.sex;cout << "Varsta: ";stream >> ang.age;cout << "Telefon: ";stream >> ang.phone;return stream;

}

void main(void){ Angajat persoana;clrscr();cout<<"Preluare date...."<<endl;cin >> persoana;getch();

Page 159: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 159/214

clrscr();cout<<"Afisare date...."<<endl;cout << persoana;getch();

}

Supraîncărcarea operatorilor << şi >> relativ la operaţiile cu fişiereDe la cele prezentate în Exemplul 9.9 şi până la a spune că obiectele pot fi scrise în fişiere şi, respectiv, citite din

fişiere, nu mai este decât un pas. Prin urmare, o modalitate de a asigura persistenţa colecţiilor de obiecte este săredefinim operatorii de inserţie şi extracţie astfel încât aceştia să ştie să lucreze în contextul obiectelor respective. Mai

mult, putem să ne imaginăm colecţii heterogene de obiecte păstrate în fişiere, cu condiţia să avem strategie de parcurgere a fişierului respectiv, într-o astfel de ipoteză. Exemplul 9.10 ilustrează supraîncărcarea operatorilor << şi >>astfel ca aceştia să lucreze în contextul unui flux asociat cu un fişier a cărui înregistrare are structură dată.

 Exemplul 9.10#include <iostream.h>#include <string.h>#include <fstream.h>#include <conio.h>#include <ctype.h>

 //Clasa care supraincarca operatorii << si >>class Agenda

{ public:char nume[40];char numar[6];Agenda(){};Agenda(char *n,char *nr){ strcpy(nume,n);strcpy(numar,nr);

};

//Metode friend care supraincarca operatorii << si >>friend ostream &operator<<(ostream &stream,Agenda a);friend istream &operator>>(istream &stream,Agenda &a);

 };

 //Implementare supraincarcare operator <<ostream &operator<<(ostream &stream,Agenda a){ 

Page 160: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 160/214

stream<<a.nume;stream<<" ";stream<<a.numar<<endl;return stream;

 };

 //Implementare supraincarcare operator >>istream &operator>>(istream &stream,Agenda &a){ stream>>a.nume;

stream>>a.numar;return stream;

 };

void main(){ Agenda ag;char car;ofstream oat("telefon",ios::out);clrscr();do{ cout<<"Nume :";

cin>>ag.nume;cout<<endl<<"Numar:";cin>>ag.numar;cout<<endl;oat<<ag;cout<<"Continuati(D,N):"<<endl;

}while(toupper(getch())!='N');oat.close();ifstream iat("telefon",ios::in);clrscr();while(!iat.eof()){ strcpy(ag.nume,"");strcpy(ag.numar,"");iat>>ag;cout<<ag.nume<<" ";cout<<ag.numar<<endl;

};

Page 161: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 161/214

getch(); };

Problema asigurării persistenţei colecţiilor de obiecte nu este, întotdeauna, atât de simplă cum rezultă din cele spusemai sus. O astfel de situaţie este cea în care obiectele agregă recursiv alte obiecte, fapt care complică problemaasigurării persistenţei, atât sub aspectul “scriere obiecte” cât şi sub aspectul “citire obiecte”. Acest lucru se va subliniaîn continuare. 

Page 162: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 162/214

Capitolul 10Fluxuri obiect orientate şi serializare în Java

10.1 Scurtă introducereDeşi mai tânăr decât C++, Java a acumulat deja o experienţă apreciabilă în ceea ce priveşte rezolvarea problemei persistenţei datelor. El propune mai multe ierarhii de clase, care pun în valoare conceptul, deja clasic, de flux şi propuneşi elemente suport pentru serializarea colecţiilor de obiecte. La fel ca în C++, stream-urile Java oferă posibiliateatratării unitare a interfeţelor de comunicare între entităţile unui sistem informatic, fie ele entităţi soft sau hard.

Un stream este un canal de comunicaţie generalizat, definit în modunic prin “capetele” sale: sursa şi destinaţia.

De cele mai multe ori, unul din capete este chiar programul în care se declară stream-ul. Şi în Java, există douătipuri fundamentale de stream-uri: input stream-urile, utilizate pentru citirea datelor din diferite surse şi outputstream-urile, utilizate pentru scrierea datelor în diferite destinaţii. Mai putem observa şi alte asemănări între perspectiva Java şi perspectiva C++, în ceea ce priveşte persistenţa: există fluxuri standard şi alte fluxuri decât cele

standard (relativ la fişiere, relativ la şiruri de caractere, relativ la buffe-re de octeţi), există filtre de diferite tipuri.Programatorul care vrea să înveţe să lucreze eficient cu fluxurile în Java, se izbeşte de o situaţie oarecum

asemănătoare celei din C++, dacă nu cumva mai rea:

Instrumentele puse la dispoziţie de Sun sunt extrem de diversificate şise promovează chiar filozofii diferite de lucru cu fluxurile, datorită

Page 163: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 163/214

faptului că prima ierarhie de clase care fundamenta lucrul cu fluxuriera orientată pe 8 biţi (două ierarhii având drept clase rădăcină claseleInputStream şi OutputStream) iar din raţiuni de implementare aconceptului de Internationalization s-a dezvoltat o soluţie alternativăcare este orientată pe 16 biţi (două ierarhii având drept clase rădăcinăclasele Reader şi Writer )13. 

Astfel că, programatorul se confruntă cu două ierarhii de clase, între care există destule asemănări pentru a nudispera cu totul dar şi destule deosebiri pentru a nu putea renunţa la nici una dintre ele deocamdată. Cert este că soluţiaJava pentru lucrul cu fluxuri este puternic orientată pe obiecte, ca soluţie tehnică. În sfârşit, să mai precizăm faptul că

oferta C++ pentru salvarea-restaurarea obiectelor îşi găseşte în Java un răspuns mai îndrăzneţ, sub forma serializării.Despre toate acestea în cele ce urmează.

10.2 Stream-uri standard în JavaJava pune la dispoziţia utilizatorului, în ideea comunicării cu consola, trei stream-uri standard:

• Standard Input• Standard Output• StandardError.

Stream-ul Standard Input este utilizat pentru preluarea datelor, în timpce celelalte două sunt utilizate pentru afişarea datelor şi a mesajelor de eroare. Implicit, Standard Input preia datele de

la tastatură iar celelalte două afişează datele la monitor. Unul dintre avantajele utilizării stream-urilor, în comunicareacu utilizatorul, îl reprezintă şi posibilitatea de a redirecta stream-urile standard spre alte periferice.În Java, toate stream-urile standard sunt accesate prin clasa System: pentru Standard Input avem System.in,

 pentru Standard Output avem System.out, pentru Standard Error avem System.err.System.in este un membru static al clasei System şi este de tipul InputStream, o clasă abstractă din pachetul

 java.io. O parte dintre funcţiile clasei InputStream şi aspecte relativ la redirectare în cele ce urmează.

Funcţii de citire şi de control al poziţiei la citire:

 public abstract int read() throws IOException public int read(byte b[]) throws IOException public int read(byte b[], int off, int len) throws IOException

 public long skip(long n) throws IOException

Funcţii de repetare citire, funcţii de gestiune buffer:

13 Pentru mai multe detalii relativ la structura acestor ierarhii se poate consulta Călin Marin Văduva, Programarea în Java, Editura Albastră, Cluj- Napoca, 2001

Page 164: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 164/214

 public synchronized void mark (int readlimit) public synchronized void reset() throws IOException public boolean markSuported()

Funcţii de informare:

 public int available() throws IOException

Funcţia de închidere stream:

 public void close() throws IOException.

De fapt, aceste metode ale clasei InputStream prefigurează elementele fundamentale ale strategiei Java de lucru cufluxurile.

Funcţia read(), fără nici un parametru, citeşte octetul curent din stream şi îl returnează sub forma unui întreg între 0şi 255. Dacă s-a ajuns la capătul stream-ului, se returnează valoarea -1. Funcţiile read, având ca parametru untablou de octeţi, citesc de la poziţia curentă din stream un număr de octeţi egal cu len sau cu lungimea tabloului b şi îlîncarcă în tabloul b, la poziţia off dacă aceasta este specificată. Ele returnează numărul de octeţi citiţi în buffer-ul b sau-1 dacă s-a ajuns la capătul stream-ului.

Funcţia skip este utilizată pentru a muta poziţia citirii peste un anumit număr de octeţi. Toate aceste metode blochează firul de execuţie în care ne aflăm, până când toate datele care se cer sunt disponibile, s-a ajuns la sfârşitulstream-ului sau s-a aruncat o excepţie.

Redirectarea stream-urilor standard se poate realiza cu ajutorul următoarelor trei funcţii, disponibile în clasaSystem:

 public static void setIn(InputStream in) public static void setOut(PrintStream out) public static void setErr(PrintStream err)

În Exemplul 10.1 sunt arătate elementele de protocol fundamentale pentru lucrul cu stream-uri în Java, cu referirela stream-urile standard.

Este vorba despre următoarele elemente invariabile:

Asocierea fluxului cu un fişier, echipament standard sau altă structură de date.• Efectuarea de operaţii de tipul citire sau scriere de date.• Poziţionarea în flux, când acest lucru este posibil• Închiderea fluxului

Page 165: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 165/214

Aşa cum se va vedea şi în exemplele care vor urma şi cum, de altfel, era previzibil din signatura metodelor pe carele-am anunţat ca făcând parte din structura clasei InputStream, tratarea excepţiilor în cazul operaţiilor I/O esteimperativă.

În Exemplul 10.2 se arată cadrul Java pentru redirectarea stream-urilor standard. Exemplul 10.1 //Utilizare stream-uri standard  //Acestea sunt asociate implicit cu echpamentele periferice //Tastatura – Sistem.in //Ecranul monitorului – Sistem.out / Sistem.err 

import java.io.*;import java.util.*; public class IO1{ 

 public static void main(String[] s){ 

boolean exit=false;System.out.println("Incerc IO\n "+ " Informatii despre sistem");while(!exit){ 

System.out.println("Optiuni....");System.out.println("\t (D) Data");System.out.println("\t (P) Proprieteti sistem");

System.out.println("\t (T) Terminare");try{ 

char readChar=(char)System.in.read();int avlb=System.in.available();System.in.skip(avlb); switch(readChar){ 

case 'D':case 'd': System.out.println("Data:"+

new Date().toString());break;

case 'P':case 'p': Properties prop=System.getProperties();

 prop.list(System.out);break;

case 'T':case 't': System.out.println("La revedere...");

exit=true;

Page 166: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 166/214

break; }

 }catch(IOException e){ 

System.err.println(e.getMessage()); }

 } }

 }

 Exemplul 10.2 // Exemplifică redirectarea stream-urilor standard import java.io.*; public class Redirect { 

 // Arunca exceptii IOException la consola public static void main(String[] args) throws IOException{ 

//Flux de intrare cu buffer asociat cu fisierul  //text care contine programul  BufferedInputStream in = new BufferedInputStream( 

new FileInputStream("Redirect.java"));

 //Filtru asociat cu fluxul definit mai sus PrintStream out =new PrintStream( new BufferedOutputStream( 

new FileOutputStream("test.out")));

 //Redirectare fluxuri standard System.setIn(in);System.setOut(out);System.setErr(out);

 //Filtrarea stream-ului standard cu ajutorul clasei //BufferedReadre pentru a permite utilizarea metodei readLine() //versiune ne-deprecated.

 //Deschidere flux  BufferedReader br = new BufferedReader(new InputStreamReader (System.in));String s;

  //Citire flux pana la terminare

Page 167: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 167/214

while((s = br.readLine()) != null)System.out.println(s);

  //Inchidere fluxout.close();

 } }

10.3 Clasa File în lucrul cu stream-uriClasa File, din biblioteca I/O Java, furnizează o abstractizare independentă de platformă pentru obţinerea

informaţiilor despre fişiere, ca de exemplu: numele de cale, dimensiunea fişierului, data modificării, etc. Pentru a obţineastfel de informaţii despre fişier trebuie ca, mai întâi, să creaţi un obiect File utilizând unul din constructorii de mai jos:

 File (String cale); File (String cale, String nume); File (File dir, String nume);

Parametrul cale din prima versiune de constructor conţine calea către fişier, în timp ce acelaşi parametru, din ceade-a doua versiune, conţine calea directorului. Paramerul nume specifică numele fişierului. Parametrul dir , din ce-a de-atreia versiune permite utilizarea unui alt obiect File, ca director.

Utilitatea clasei File poate fi desprinsă, ca un început, şi din Exemplul 10.3 şi Exemplul 10.4.

 Exemplul 10.3 //Listarea tuturor fişierelor din directorul curent import java.io.*; public class TestFile{ 

 public static void main(String[] sir){ 

 File dc=new File(".");String listaf[]=dc.list(); for(int i=0;i<listaf.length;i++){ 

if(i % 23==0){ 

try{ System.in.read();System.in.read();

 }catch(IOException e){}

Page 168: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 168/214

 };System.out.println(listaf[i]);

 } }

 }

 Exemplul 10.4  //Listarea tuturor fisierelor din directorul curent  //avand o extensie dataimport java.io.*;

class JavaFileFilter implements FilenameFilter { 

 public boolean accept(File dir, String nume){ 

return nume.endsWith(".java"); }

 } public class FiltruF { 

 public static void main(String[] sir){ 

 File dc=new File(".");String listaf[]=dc.list(new JavaFileFilter());

 for(int i=0;i<listaf.length;i++){ 

if(i % 23==0){ try{ 

System.in.read();System.in.read();

 }catch(IOException e){} };System.out.println(listaf[i]);

 } }

 }

Page 169: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 169/214

10.4 Citirea datelor dintr-un streamAşa cum, probabil că s-a înţeles, există două grupuri mari de stream-uri, în funcţie de obiectivul lor: scrierea sau

citirea datelor.Pentru citirea datelor dintr-un flux avem clasele derivate din clasele abstracte InputStream sau Reader.

Amândouă aceste clase sunt clase abstracte care furnizează metode care permit operaţii asemănătoare celor pe care le-am prezentat deja în discuţia referitoare la stream-urile standard.

Referindu-ne la InputStream, fiind o clasă abstractă nu poate fi utilizată în instanţierea unui obiect stream. Pentrucrearea obiectelor de tip stream, pornind de la clasa InputStream, s-au derivat mai multe clase. Aceste clase le-am putea împărţi, la rândul lor, în două grupuri importante:

• clase stream conectate la diferite tipuri de surse;• clase stream care se conectează la cele de mai sus, adăugând noi operaţii şi funcţionând ca “filtre” aplicate

operaţiilor de citire.

Clasele din prima categorie sunt derivate direct din clasa InputStream.Pentru a putea utiliza efectiv interfaţa anunţată de clasa InputStream a fost nevoie de construirea unor clase

derivate din aceasta, clase care să poată fi conectate la diferite tipuri de surse reale. Dintre aceste clase remarcăm cafiind cel mai mult folosite:

• ByteArrayInputStreamEste o clasă care permite conectarea unui stream la un tablou de octeţi. Operaţiile de citire din stream vor permitecitirea datelor din tabloul de octeţi, gestiunea operaţiilor fiind asumată de către instanţa stream.

• StringBufferInputStreamPermite conectarea unui stream la un şir de caractere. Această clasă este considerată deprecated , recomandându-seutilizarea clasei StringReader.

• FileInputStreamEste una dintre cele mai utilizate clase de tip stream şi ne oferă posibilitatea conectării cu un fişier pentru a citidatele înregistrate în acesta. După cum se poate vedea, la analiza atentă a definiţiei clasei FileInputStream, aceastaconţine mai multe versiuni de constructori, care permit asocierea stream-ului cu un fişier în diferite moduri: numelespecificat ca o variabilă sau constantă String, numele specificat ca o variabilă File, numele specificat ca o variabilăFileDescriptor.

O categorie importantă de clase derivate din InputStream o formează clasele de tip “filtru”, derivate din clasa

FilterInputStream, la rândul ei, derivată din clasa InputStream.Dintre clasele din această categorie se cuvine să remarcăm câteva utilizate intens:

• DataInputStreamEste una dintre cele mai utilizate clase dintre cele de tip filtru. Această clasă conţine mai multe funcţii, care permitcitirea unor tipuri fundamentale de date (int, float, double, char, etc) într-un mod independent de maşină. De regulă,

Page 170: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 170/214

această clasă este utilizată împreună cu clasa DataOutputStream, clasă care are operaţii de scriere în stream,orientate pe tipurile fundamentale. Împreună, aceste două clase, oferă o soluţie elegantă la problema gestiuniifişierelor a căror înregistrare are structura definită de utilizator.

Este momentul să remarcăm că, în principiu, în Java, la fel ca în C++, putem avea fluxuri de octeţi, fluxuride caractere şi fluxuri de date cu structură cunoscută.

Revenind la clasa DataInputStream, prezentăm, în continuare, câteva dintre metodele mai mult folosite.

Metoda Rolul

 boolean readBoolean() Citeşte o dată booleană byte readByte Citeşte un octetInt readUnsignedByte() Citeşte un octet unsignedshort readShort() Citeşte un short (16 biţi)char readChar() Citeşte un caracter Unicodeint readInt() Citeşte un întreg pe 32 biţilong readLong() Citeşte un long pe 64 biţifloat readFloat() Citeşte un număr real în virgulă mobilă s implă

 preciziedouble readDouble() Citeşte un număr real în virgulă mobilă dublă

 precizieString readLine() Citeşte o linie

String readUTF() Citeşte un şir de caractere în format UTF(Unicode Text Format)Tabelul 10.1. Metode ale clasei DataInputStream

Dintre clasele de tip filtru merită să mai remarcăm şi clase precum: BufferedInputStream,LineNumberInputStream, ZipInputStream, etc.

10.5 Scrierea datelor într-un streamPentru scrierea datelor într-un stream avem clasele derivate din clasele abstracte OutputStream sau Writer.

Amândouă aceste clase sunt clase abstracte, care furnizează metode care permit operaţii de scriere a datelor în stream-uri, complementare celor de citire, ca funcţionalitate.

Referindu-ne la clasa OutputStream, fiind o clasă abstractă nu poate fi utilizată în instanţierea unui obiect stream.

Totuşi, ea este o ocazie de a specifica o interfaţă general valabilă în operaţiile de scriere în fluxuri, având următoareadefiniţie:

 public abstract class OutputStream{ 

 public abstract void write(int b) throws IOException

Page 171: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 171/214

 public void write(byte b[] ) throws IOException public void write(byre[], int off, int len) throws IOException public void flush()throws IOException public void close()throws IOException

 }

Pentru crearea obiectelor de tip stream, pornind de la clasa OutputStream, s-au derivat mai multe clase. Acesteclase le-am putea împărţi, la rândul lor, în două grupuri importante:

• clase stream conectate la o destinaţie;• clase stream care se conectează la cele de mai sus, adăugând noi operaţii şi funcţionând ca “filtre” aplicate

operaţiilor de scriere.

Clasele din prima categorie sunt derivate direct din clasa OutputStream.Pentru a putea utiliza efectiv interfaţa anunţată de clasa OutputStream a fost nevoie de construirea unor clase

derivate din aceasta, clase care să poată fi conectate la diferite tipuri de destinaţii reale. Dintre aceste clase remarcăm cafiind cel mai mult folosite:

• ByteArrayOutputStreamEste o clasă care permite conectarea unui stream la un tablou de octeţi. Operaţiile de scriere în stream vor permiteadăugare de date în tabloul de octeţi, gestiunea operaţiilor fiind asumată de către instanţa stream.

FileOutputStreamEste clasa pereche a clasei FileInputStream, dintre cele mai utilizate clase de tip stream şi ne oferă posibilitateaconectării cu un fişier pentru a scrie date în acesta. După cum se poate vedea, la analiza atentă a definiţiei claseiFileOutputStream, aceasta conţine mai multe versiuni de constructori, care permit asocierea stream-ului cu unfişier în diferite moduri: numele specificat ca o variabilă sau constantă String, numele specificat ca o variabilă File,numele specificat ca o variabilă FileDescriptor.

O categorie importantă de clase derivate din OutputStream o formează clasele de tip “filtru”, derivate din clasaFilterOutputStream, la rândul ei, derivată din clasa OutputStream.

Dintre clasele din această categorie se cuvine să remarcăm câteva utilizate intens:

• DataOutputStreamEste una dintre cele mai utilizate clase dintre cele de tip filtru. Această clasă conţine mai multe funcţii care permit

citirea unor tipuri fundamentale de date (int, float, double, char, etc) într-un mod independent de maşină. De regulă,această clasă este utilizată împreună cu clasa DataInputStream, clasă care are operaţii de citire în stream, orientate pe tipurile fundamentale. Împreună, aceste două clase oferă o soluţie elegantă la problema gestiunii fişierelor, acăror înregistrare are structura definită de utilizator.

Page 172: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 172/214

Clasa DataOutputStream, are o serie de metode folosite, după caz, la realizarea operaţiilor de scriere în stream-uri.

Metoda Rolulvoid writeBoolean(boolean v) Scrie o dată booleanăvoid writeByte(int v) Scrie un octetvoid writeBytes(String s) Scrie un şir de caractere ca o secvenţă de

octeţivoid writeShort(int v) Scrie un short (16 biţi)void writeChar(int v) Scrie un caracter Unicodevoid writeInt(int v) Scrie un întreg pe 32 biţivoid writeLong(long v) Scrie un long pe 64 biţivoid writeFloat(float v) Scrie un număr real în virgulă mobilă

simplă precizievoid writeDouble(double v) Scrie un număr real în virgulă mobilă

dublă precizievoid writeChars(String s) Scrie un şir de caractere ca o secvenţă de

16 biţivoid writeUTF(String S) Scrie un şir de caractere în format UTF

(Unicode Text Format)Tabelul 10.2. Metode ale clasei DataOutputStream

Dintre clasele de tip filtru merită să mai remarcăm şi clase precum: BufferedOutputStream, PrintStream,ZipOutputStream, etc.

Relativ la lucrul cu fişiere, un rol important îl joacă clasa RandomAccessFile, care nu este subclasă nici a claseiInputStream, nici a clasei OutputStream. Însă, cu ajutorul instanţelor ei, puteţi efectua în acelaşi timp atât operaţii descriere cât şi de citire. În plus, după cum arată şi numele, un obiect RandomAccessFile furnizează acces aleator ladatele dintr-un fişier, ceea ce instanţele descendenţilor claselor  InputStream sau OutputStream nu pot. Pentrucompatibilitate, la utilizare, cu clasele DataInputStream şi DataOutputStream, clasa RandomAccessFileimplementează interfeţele DataOutput şi DataInput, interfeţe pe care le implementează şi clasele DataInputStreamşi DataOutputStream.

O discuţie asemănătoare se poate purta relativ la ierarhiile de clase ale căror rădăcini sunt clasele Reader şi Writer,iearhii care implementează alternativa I/O Java pe 16 biţi. Funcţionalitatea lor, însă, nu elimină cu totul utilitatea

ierarhiilor pe care le-am prezentat mai sus, pe scurt. Înţelegerea exactă a modului de lucru cu oricare dintre ierarhiilemenţionate mai sus poate fi realizată consultând documentaţia aferentă kit-urilor jdk1.o sau jdk1.1.

“Jungla” protocoalelor de lucru cu stream-uri în Java este, după cum se vede, mult mai diversificată decât oferta C++. Programatorul din lumea reală trebuie să se acomodeze cu elementele fundamentale relativ la stream-urile Java,rămânând ca în situaţii excepţionale să înveţe utilizarea unor procedee excepţionale de manevrare a stream-urilor.

Page 173: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 173/214

Exemplele care urmează încearcă să evidenţieze elemente de protocol socotite uzuale  în lucrul cu stream-uri înJava.

 Exemplul 10.5 //Situatii tipice de utilizarea fluxurilor in Javaimport java.io.*;

 public class IOStreamDemo{  // Metoda ridica exceptii la consola

 public static void main(String[] args) throws IOException{ 

 //1a. Citirea orientata pe linii intr-un fisier text BufferedReader in = new BufferedReader( 

new FileReader("IOStreamDemo.java"));String scit;String sImRAM = new String();

  //s2 pastreaza continutul fisierului IOStreamDemo.java//ca imagine RAM while((scit = in.readLine())!= null)

sImRAM += scit + "\n";in.close();

// 1b. Citire de la tastatura:BufferedReader stdin =new BufferedReader( 

new InputStreamReader(System.in));System.out.print("Enter a line:");System.out.println(stdin.readLine());System.in.read();

  // 2. Citire din memorie//Se va folosi sImRAM, creat la 1aStringReader in2 = new StringReader(sImRAM);int c;

  //Afisare imagine memorie a continutului //fisierului IOStreamDemo.javawhile((c = in2.read()) != -1)

System.out.print((char)c);System.in.read();System.in.read();

Page 174: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 174/214

 // 3. Preluare date formatate in memorie//Din nou se apeleaza la imaginea memorie a //fisierului IOStreamDemo.java

 try{ 

DataInputStream in3 =new DataInputStream( new ByteArrayInputStream(sImRAM.getBytes()));

while(true)

System.out.print((char)in3.readByte());}catch(EOFException e){ 

System.err.println("End of stream");}System.in.read();System.in.read();// 4. Creare fisier format output try{ 

BufferedReader in4 =new BufferedReader( new StringReader(sImRAM));

PrintWriter out1 =new PrintWriter( new BufferedWriter( 

new FileWriter("IODemo.out")));int lineCount = 1;while((scit = in4.readLine()) != null )

out1.println(lineCount++ + ":" + scit);out1.close();

}catch(EOFException e){ 

System.err.println("End of stream");}

String sir; BufferedReader inper = new BufferedReader( 

new FileReader("IODemo.out"));System.out.println("################################");while((sir = inper.readLine())!= null)

System.out.println(sir);

Page 175: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 175/214

 inper.close();System.in.read();System.in.read();

// 5. Salvare si consultare date cu tiptry{ 

DataOutputStream out2 =new DataOutputStream( new BufferedOutputStream( 

new FileOutputStream("Data.txt")));out2.writeDouble(3.14159);out2.writeBytes("Acesta este numarul PI\n");out2.writeDouble(1.41413);out2.writeUTF("Radacina patrata a lui 2");out2.close();DataInputStream in5 =new DataInputStream( 

new BufferedInputStream( new FileInputStream("Data.txt")));

BufferedReader in5br =new BufferedReader( new InputStreamReader(in5));

// Trebuie sa folositi DataInputStream pentru date:System.out.println(in5.readDouble());

// Numai metoda readUTF() va recupera // sirul Java-UTF corect:// Cu readLine() se citesc corect date// scrise cu writeBytes.System.out.println(in5br.readLine());System.out.println(in5.readDouble());System.out.println(in5.readUTF());

}catch(EOFException e){ 

System.err.println("End of stream");}

// 6.Citire/scriere fisier in acces aleator RandomAccessFile rf =new RandomAccessFile("rtest.dat", "rw");for(int i = 0; i < 10; i++)

rf.writeDouble(i*1.414);rf.close();

Page 176: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 176/214

rf =new RandomAccessFile("rtest.dat", "rw");rf.seek(5*8);rf.writeDouble(47.0001);rf.close();

rf =new RandomAccessFile("rtest.dat", "r");for(int i = 0; i < 10; i++)System.out.println("Value " +i+":"+rf.readDouble());rf.close();

}

 }

Ca observaţii finale la cele discutate până acum relativ la problema persistenţei datelor în Java, aş menţiona:• Puternica orientare pe obiecte a soluţiilor Java la problema persistenţei.• Flexibilitatea cu care putem utiliza diferitele varietăţi de fluxuri (filtrare, redirectare)• Obligativitatea tratării excepţiilor I/O în codul Java, ceea ce sporeşte coeficientul de robusteţe al codului Java

afectat operaţiilor I/O.

10.6 Serializarea obiectelorJava 1.1 introduce un nou concept, numit serializarea obiectelor. Utilizând serializarea, un obiect poate fi

transformat într-o secvenţă de octeţi ( care poate fi transmisă în reţea sau care poate fi stocată într-o specie dememorie), secvenţă care poate fi folosită pentru refacerea completă a obiectului iniţial.

Avantajul serializării este evident, prin faptul că simplifică procedura de transmitere a unui obiect între douăentităţi ale unui sistem informaţional automatizat.

Prin utilizarea serializării, programatorul a scăpat de grijatransformării obiectului într-o succesiune de octeţi, de ordonarea lor,de problema diferenţei de reprezentare pe diferite platforme, toateacestea făcându-se automat.

În rezumat, putem spune că serializarea introduce un alt nivel de transmitere a datelor, la care unitateafundamentală de transfer este obiectul. În practică, serializarea obiectelor este impusă de situaţii precum:

• RMI (Remote Method Invocation)Comunicare de obiecte între aplicaţii aflate pe calculatoare diferite, într-o reţea.

• Lightweight persistencePosibilitatea stocării unui obiect, ca ansamblu unitar, în vederea utilizării lui în cadrul unei execuţii

ulterioare.• Tehnologia Java Beans

Tehnologie Java de lucru cu componente.

Page 177: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 177/214

Procedeul Java de serializare/deserializare a unui obiect este simplu, dacă acesta îndeplineşte anumite condiţii.

Procedeul Java de serializare/deserializareSerializarea unui obiect este o opereaţie relativ simplă, care implică lucrul cu clasa ObjectOutputStream, care

înfăşoară un stream de tipul OutputStream, conectat la o destinaţie. Conexiunea cu un stream OutputStream se face prin intermediul constructorului:

 public ObjectOutputStream(OutputStream out) throws IOException; 

Clasa ObjectOutputStream este derivată din clasa OutputStream şi implementează interfaţa ObjectOutput

(derivată din DataOutput). Interfaţa ObjectOutput declară metodele specifice serializării unui obiect. Dintre acestemetode, cea mai importantă este metoda writeObject având signatura:

 public final void writeObject(Object obj) throws IOException

Prin intermediul clasei ObjectOutputStream, se pot scrie atât date primitive (cu ajutorul metodelor declarate deinterfaţa DataOutput) cât şi obiecte, folosind metoda writeObject.

Deserializarea (adică reconstituirea unui obiect dintr-un stream) este, de asemenea, simplă şi implică utilizareaclasei ObjectInputStream. Această clasă înfăşoară un stream de tipul InputStream, stream transmis ca şi parametru înconstructorul clasei:

 public ObjectInputStream(InputStream in)

throws IOException, StreamCorruptedException

Clasa ObjectInputStream este derivată din clasa InputStream şi implementează interfaţa ObjectInput (derivatădin interfaţa DataInput). Interfaţa ObjectInput declară metodele specifice deserializării unui obiect. Dintre acestea,cea mai importantă este metoda readObject, definită astfel:

 public final Object readObject()throws OptionalDataException, ClassNotFoundException, IOException

Excepţia OptionalDataException apare în cazul în care, în locul unui obiect în stream se află un tip de dată primitiv.

Excepţia ClassNotFoundException apare atunci când clasa obiectului din stream nu poate fi găsită, în contextulactual de execuţie.

O înţelegere mai bună a serializării / deserializării poate fi obţinută urmărind exemplele de mai jos.

 Exemplul 10.6  // Exemplificarea serializării obiectelor import java.io.*;

Page 178: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 178/214

class Data implements Serializable{ 

private int i;Data(int x){ 

i = x; } public String toString(){ 

return Integer.toString(i);

 } }

 public class Serializ implements Serializable{ 

 //Generare numar aleator intreg  private static int r(){ 

return (int)(Math.random() * 10);}

 private Data[] d = {new Data(r()), new Data(r()), new Data(r())}; private Serializ next;

private char c;// Valoarea lui i indică numarul de elemente din listaSerializ(int i, char x){ 

System.out.println(" Serializ constructor: " + i);c = x;if(--i > 0)next = new Serializ(i, (char)(x + 1));

}Serializ(){ 

System.out.println("Constructor implicit");}public String toString(){ 

String s = ":" + c + "(";for(int i = 0; i < d.length; i++)

s += d[i].toString();s += ")";

Page 179: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 179/214

if(next != null)s += next.toString();return s;

}// Ridica exceptii la consolapublic static void main(String[] args)

throws ClassNotFoundException, IOException{ 

Serializ w = new Serializ(6, 'a');System.out.println("w = " + w);

ObjectOutputStream out =new ObjectOutputStream( new FileOutputStream("serializ.out"));

out.writeObject("Serialize storage");out.writeObject(w);out.close(); // Also flushes output ObjectInputStream in =new ObjectInputStream( 

new FileInputStream("serializ.out"));String s = (String)in.readObject();Serializ w2 = (Serializ)in.readObject();System.out.println(s + ", w2 = " + w2);

  ByteArrayOutputStream bout =new ByteArrayOutputStream();ObjectOutputStream out2 =new ObjectOutputStream(bout);

out2.writeObject("Serializ storage");out2.writeObject(w);out2.flush();

ObjectInputStream in2 =new ObjectInputStream( new ByteArrayInputStream(bout.toByteArray()));s = (String)in2.readObject();Serializ w3 = (Serializ)in2.readObject();System.out.println(s + ", w3 = " + w3);

} }

 Exemplul 10.7 import java.io.*;import java.util.*;

class House implements Serializable {}

class Animal implements Serializable

Page 180: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 180/214

{ String name;House preferredHouse;Animal(String nm, House h){ 

name = nm; preferredHouse = h;

}public String toString(){ 

return name + "[" + super.toString() + "], " + preferredHouse +"\n";

} }

 public class Serializ1{ 

public static void main(String[] args)throws IOException, ClassNotFoundException{ 

House house = new House();ArrayList animale = new ArrayList();animale.add(new Animal("Grivei -cainele", house));

animale.add(new Animal("Coco papagalul", house));animale.add(new Animal("Vasile -motanul", house));System.out.println("animale: " + animale);

ByteArrayOutputStream buf1 =new ByteArrayOutputStream();ObjectOutputStream o1 =new ObjectOutputStream(buf1);o1.writeObject(animale);

  //Inca odatao1.writeObject(animale);

 // Scriem si intr-un stream diferit ByteArrayOutputStream buf2 =new ByteArrayOutputStream();ObjectOutputStream o2 =new ObjectOutputStream(buf2);o2.writeObject(animale);

  // Acum le citimObjectInputStream in1 =new ObjectInputStream( new ByteArrayInputStream(buf1.toByteArray()));

Page 181: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 181/214

ObjectInputStream in2 =new ObjectInputStream( new ByteArrayInputStream(buf2.toByteArray()));ArrayList animale1 =(ArrayList)in1.readObject();ArrayList animale2 =(ArrayList)in1.readObject();ArrayList animale3 =(ArrayList)in2.readObject();System.out.println("animale1: " + animale1);System.out.println("animale2: " + animale2);System.out.println("animale3: " + animale3);

} }

Exemplele 10.6 şi 10.7 arată, printre altele, şi condiţiile pe care trebuie să le îndeplinească un obiect pe care vremsă îl serializăm. În speţă, este vorba de faptul că pentru ca obiectul să poată fi serializat, clasa lui definitoare trebuiesă respecte una din următoarele condiţii:

• Să implementeze interfaţa SerializableÎn această situaţie transformările obiect-stream şi stream-obiect se pot face automat.

• Să implementeze interfaţa  Externalizable  şi să suprascrie metodele acesteia  writeExternal şireadExternal.

În acest caz, programatorul este responsabil (prin specificarea metodelor anterior amintite) de transformareaobiectului în secvenţe de octeţi şi invers.

Evident, spaţiul de care dispunem nu ne permite să tratăm exhaustiv problemele pe care le pune asigurarea persistenţei datelor în aplicaţiile Java. Scopul acestei cărţi a fost de a realiza o deschidere asupra universului  problematic dezvoltat în Java în jurul ideii de persistenţă. Stă în puterea fiecărui cititor în parte să se aplece cutemeinicie asupra aspectelor de detaliu sau , de ce nu, filosofice, neelucidate încă.

Page 182: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 182/214

Capitolul 11Programare concurentă cu suport obiect orientat.Perspectiva Java

11.1 Noţiuni de programare concurentăProgramarea concurentă presupune existenţa mai multor sarcini care trebuie să fie executate în paralel, ceea ce

implică, într-o formă sau alta, partajarea resurselor comune ale sistemului pe care se derulează execuţia sarcinilor încauză.

Făcând abstracţie de arhitectura hard14  care o susţine, programarea concurentă poate fi materializată prin suportpentru programarea multitasking, suport pentru programarea multifir şi suport pentru programareadistribuită.

Atunci când o aplicaţie este implementată pe un sistem multiprocesor, se spune că avem o aplicaţie multiprocesată.În situaţia în care aplicaţia este implementată pe o reţea de calculatoare, spunem că aplicaţia este distribuită.În acest curs nu ne vom interesa de programarea distribuită şi nici de programarea multitasking. Pentru a fi posibilă

 programarea multitasking, mai întâi sistemul de operare trebuie să fie capabil de execuţia simultană a mai multor  programe. În cazul în care aşa ceva este posibil, la nivelul limbajelor de programare ne putem pune probleme de

14 Sistem monoprocesor, sistem multiprocesor, sistem vectorial, sistem distribuit, etc.

Page 183: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 183/214

sincronizare a accesului la resursele comune. Din acest punct de vedere, relaţia dintre Java şi Windows, ca sistem deoperare, nu este extrem de cordială. În schimb Object Pascal, limbajul de programare în mediul de programare vizualăDelphi, gândit pentru a realiza aplicaţii având ca ţintă platforma Windows, posedă înveliş sintactic specific pentrurezolvarea problemelor de partajare a resurselor critice, în spiritul WIN32API15. Pe de altă parte, programarea distribuităeste posibilă, în Java, apelând la tehnologii care susţin corespunzător acest stil de programare(RMI, CORBA, etc.).

În această carte ne vom interesa de posibilităţile pe care le oferă Java pentru a face programare multifir.Majoritatea compilatoarelor de C++, legate de maşina MSDOS, nu oferă suport nativ sau înveliş sintactic corespunzător  pentru programarea multifir, ci doar rudimente sintactice pentru simularea greoaie a multitasking-ului.

În sfârşit, să mai observăm că programarea multifir la care ne referim va fi asociată cu posibilităţile unei maşinimonoprocesor, ceea ce înseamnă, iarăşi, că sistemul de operare este “arbitrul” care stabileşte regulile de bază care

trebuie urmate pentru ca un fir de execuţie să poată accesa reursele partajabile ale maşinii (îndeosebi timpul UC).Arbitrajul exercitat de sistemul de operare (în relaţia cu timpul UC) se reduce, practic, la acordarea unor cuante de timpUC tuturor firelor de execuţie active la un moment dat, eventual, în funcţie de priorităţile asociate acestora la creare.Toate celelalte probleme care decurg din execuţia simultană a mai multor fire de execuţie sunt de competenţa  programatorilor. Aceste probleme se regăsesc, generic, în sintagma “comunicare şi sincronizare”, pentru carelimbajele oferă mijloace a căror întrebuinţare este la latitudinea programatorilor.

Să mai observăm că noţiunea de fir de execuţie se referă la o unitate de prelucrare, asociată cu noţiunea de proces,în sensul că fiecare fir de execuţie este găzduit în spaţiul de adrese al unui proces. În fine, trebuie spus că, referindu-nela Java, funcţia main() a unui program Java este, ea însăşi, un fir de execuţie, care se numeşte firul principal deexecuţie. O situaţie asemănătoare apare şi în Object Pascal unde programul principal, aflat în fişierul cu extensia .dpreste asimilat cu noţiune de fir de execuţie principal.

Lucrul cu fire de execuţie este o necesitate, în foarte multe situaţii de programare. Dacă, de exemplu, ne gândim lao aplicaţie care simulează calculul tabelar, nu este greu de priceput necesitatea mai multor fire de execuţie: unul care seocupă de interactivitatea cu utilizatorul, unul care gestionează implicaţiile modificării conţinutului celulei curenteasupra conţinutului altor celule, etc. Vom încerca, în continuare, să fixăm, cât mai clar posibil, bazele utilizării firelor deexecuţie în Java.

11.2 Fire de execuţie (thread-uri) în JavaPentru ca programatorul Java să poată realiza aplicaţii multifir, Java oferă în pachetul  java.lang, deci chiar în java

core, două clase şi o interfaţă:• clasa Thread• clasa ThreadGroup• interfaţa Runnable

Clasa Thread şi interfaţa Runnable oferă suport pentru lucrul cu fire de execuţie, ca entităţi separate ale aplicaţiei

iar clasa ThreadGroup permite crearea unor grupuri de fire de execuţie, în vederea tratării acestora într-un mod unitar.

15 Interfaţa de Programare a Aplicaţiilor sub sistemul de operare Windows.

Page 184: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 184/214

Figura 23. Resurse Java predefinite pentru programarea multifir. Relaţiile dintre ele.După cum se poate observa, în Figura 23, clasa Thread implementează interfaţa Runnable iar clasa

ThreadGroup se compune din mai multe obiecte Thread. Simbolurile folosite pentru a indica relaţia de compuneredintre ThreadGroup şi Thread, precum şi relaţia de realizare dintre Thread şi Runnable sunt de provenienţă UML.Deoarece discuţia referitoare la grupuri de fire se bazează pe înţelegerea lucrului cu fire independente, în continuare nevom ocupa de problema utilizării firelor de execuţie independente. Pentru a crea un fir de execuţie în Java avem două posibilităţi:

• Definirea unei clase derivate din clasa Thread• Definirea unei clase care implementează interfaţa Runnable

Crearea unui fir de execuţie derivând clasa ThreadAlegând această variantă, avem de efectuat un număr redus de operaţii:

• Definirea unei clase derivate din clasa Thread.Derivarea se face, după cum se ştie, cu o sintaxă de tipul:

class FirulMeu extends Thread { 

 //Date membre //Funcţii membre

 }

• Suprascrierea funcţiei public void run(), moştenită de la clasa Thread, în clasa derivată.

Această metodă trebuie să implementeze comportamentul firului de execuţie. Aşa cum metoda main() estemetoda apelată de Java Runtime System în momentul în care se execută o aplicaţie Java, metoda run() estemetoda apelată când se execută un fir. De fapt, trebuie să subliniem că atunci când se porneşte maşina virtualăJava (JVM), odată cu ea se porneşte un fir de execuţie care apelează metoda main(). JVM îşi va încetaexecuţia în momentul in care nu mai există fire în execuţie sau a fost apelată metoda exit() a clasei System.

• Instanţierea unui obiect fir, folosind operatorul new:

Runnable

ThreadThreadGroup

 Notaţie UML pentruinterfaţă 

 Relaţie de realizare

Page 185: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 185/214

 FirulMeu firulmeu=new FirulMeu();

• Pornirea firului instanţiat, prin apelul metodei start(), moştenită de la clasa Thread.

 firulmeu.start();

Acestea sunt operaţiile strict necesare pentru a începe lucrul cu fire de execuţie în Java, utilizând clasa Thread.

 Exemplul 11.1

 //Clasa care modeleaza firul class TFirPers extends Thread { 

 static int id=0;int[] vect=new int[10];

 //Constructorul clasei public TFirPers(){  };

 //Metoda run() , care modeleaza comportamentul firului public void run(){ 

id++;System.out.println("Lucreaza TFirPers.... "+id); for(int j=0;j<10;j++)

vect[j]=j; };

 };

 //Clasa care modeleaza aplicatia public class Fire{ 

 public static void main(String sir[]){ 

int[] vecmain=new int[20];

 //Declarare referinteTFirPers fir1,fir2;

Page 186: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 186/214

 //Alocare referinte-fir de executie fir1=new TFirPers(); fir2=new TFirPers();

 //Lansarea in executie a firelor  fir1.start(); fir2.start();

try{ 

 //Intarzierea firului principal pentru //a lasa ragaz firelor derivate din Thread  //sa lucrezeThread.currentThread().sleep(2000);

 }catch(InterruptedException e){}

 //Valorificarea rezultatelor furnizate de //cele doua fire de executie for(int k=0;k<10;k++)

vecmain[k]=fir1.vect[k];

 for(int l=0;l<10;l++)vecmain[l+10]=fir2.vect[l]+10;

 for(int i=0;i<20;i++)System.out.println(vecmain[i]);

 }; };

Codul Java, prezentat în Exemplul 11.1, face apel la un mic subterfugiu (adormirea firului principal de executietimp de 2 secunde pentru a lăsa timp firelor de executie, paralele firului principal, să-şi îndeplinească atribuţiile. Dacănu se acordă acest răgaz, se va observa că firul principal va accesa datele corespunzătoare firelor secundare înainte caacestea să fie conforme aşteptărilor noastre. Altfel spus, paralelismul specific lucrului cu mai multe fire de execuţie esteefectiv şi, prin Exemplul 11.1, se atrage deja atenţia asupra modificării atitudinii programatorului faţă de problemaorganizării structurilor de prelucrare.

Crearea unui fir de execuţie utilizând interfaţa RunnableO altă modalitate de a crea fire de excuţie este utilizarea interfeţei Runnable. Această modalitate devine interesantă

în momentul în care se doreşte ca o clasă de tip Thread, pe care o implementăm, să moştenească capabilităţi disponibileîn alte clase. Operaţiile specifice creării unui fir de execuţie utilizând interfaţa Runnable sunt următoarele:

Page 187: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 187/214

• Definirea unei clase care implementează interfaţa Runnable.Aceasta se face utilizând sintaxa adecvată şi implementând cel puţin metodele interfeţei Runnable (de fapt,doar metoda public void run()).

class FirRunnable extends Exemplu implementes Runnable{ 

 //Definitie }

• Clasa care implementează interfaţa Runnable trebuie să suprascrie funcţia public void run().

 public void run(){ 

 //Cod aferent  }

• Se instanţiază un obiect al clasei de mai sus, cu o sintaxă de tipul:

 FirRunnable obiectRunnable=new FirRunnable();

• Se crează un obiect de tip Thread, utilizând un constructor care are ca şi parametru un obiect de tipRunnable. În acest mod se asociază un fir cu o metodă run().

Thread firulMeu=new Thread(obiectRunnable);

• În sfârşit, se porneşte firul, la fel ca în metoda derivării din Thread a firului.

Paşii precizaţi mai sus se pot vedea şi în Exemplul 11.2

 Exemplul 11.2 //Clasa care modeleaza aplicatia public class FirRunn{ 

 public static void main(String s[]){ 

System.out.println("Creare obiect Runnable...");classRunnable obiectRunn=new classRunnable();System.out.println("Creare fir...");Thread fir=new Thread(obiectRunn);System.out.println("Start fir..."); fir.start();

Page 188: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 188/214

System.out.println("Din nou in main()..."); }

 }

 //Clasa auxiliaraclass Display{ 

 public void display(String mesaj){ 

System.out.println(mesaj);

 } }

 //Clasa care implementeaza interfata Runnable si mosteneste //clasa Displayclass classRunnable extends Display implements Runnable{ 

 public void run(){ 

int nrpasi=3;display("Run are "+nrpasi+" pasi de facut..."); for(int i=0;i<3;i++)

display("Pasul: "+i);

display("Run si-a terminat munca..."); }

 }

Controlul unui fir de execuţieProblema controlului unui fir de execuţie este legată de cunoaşterea stărilor posibile ale firelor de execuţie. În

speţă, pe timpul execuţiei unui program Java multifir, o instanţă Thread poate să se afle în una din următoarele patrustări: new, runnable, blocked şi dead. Atunci când creăm un fir de execuţie, acesta intră în starea new. În această starefirul de execuţie aşteaptă apelarea metodei start() a firului. Nici un cod nu rulează încă.

În starea runnable un fir execută codul prezent în metoda sa run(). Pentru ca firul să treacă din starea new în starearunnable trebuie executată metoda start(). Nu se recomandă apelarea directă a metodei run() deoarece face acestlucru, în locul dumneavostră, metoda start(). Când un fir de execuţie este inactiv despre el se spune că este în starea

blocked sau not runnable. Un fir poate deveni inactiv dacă apelăm metode precum sleep(), suspend() sau wait(), oridacă trebuie să aştepte după anumite metode I/O până la finalizarea execuţiei acestora. După cum se va vedea, fiecaredintre aceste metode are un mecanism propriu de refacere a stării runnable pentru fir. În Exemplul 11.1 am folosit dejametoda sleep() pentru a rezolva o problemă banală de sincronizare între firul principal de execuţie şi firele secundare.

Suspendarea şi reluarea execuţiei unui fir

Page 189: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 189/214

Am văzut deja cum putem suspenda execuţia unui fir pentru o perioadă de timp prin utilizarea metodei sleep() aclasei Thread. Putem suspenda execuţia unui fir şi până la apariţia unor condiţii obiective de reluare a execuţiei. Înacest sens putem utiliza metoda suspend() a clasei Thread, care pune un fir în starea not runnable, până la apelareametodei resume(). Ca un exemplu, utilizarea metodei suspend() permite oprirea unei secvenţe de animaţie la apăsarea butonului mouse-ului şi reluarea animaţiei la ridicarea degetului de pe butonul mouse-ului. De asemenea, un gen specialde suspendare/reluare a execuţiei unui fir se realizează şi cu ajutorul perechii de metode wait()/notify() asupra căreiavom reveni mai jos.

11.3 Sincronizarea firelorDacă sunt executate asincron, mai multe fire care partajează anumite date s-ar putea să fie obligate să-şi

sincronizeze activităţile pentru a obţine rezultate corecte. Pe lângă posibilităţile pe care le oferă metode precum sleep()sau suspend()/resume(), în Java a fost introdus modificatorul synchronized, tocmai pentru a introduce un cadruadecvat atomizării activităţilor, în condiţii de concurenţă la resurse.

Ideea de bază a modificatorului synchronized este cât se poate de simplă: primul fir care intră în posesia unuiobiect marcat de modificatorul synchronized rămâne proprietar al obiectului până când îşi termină execuţia. Înacest mod se crează un cadru simplu pentru evitarea coliziunilor în timpul accesului concurent la resurse.

Ceea ce este simplu nu este întotdeauna şi eficient. Uneori, preţul sincronizării s-ar putea să fie mai maredecât poate suporta clientul aplicaţiei (timpii de execuţie pot fi diminuaţi drastic).

Sincronizare bazată pe modificatorul synchronizedModifcatorul synchronized poate fi utilizat pentru a realiza sincronizarea firelor. Orice fir are propia sa memorie

de lucru, unde îşi ţine copii proprii ale variabilelor pe care le utilizează. Când este executat un fir, acesta opereazănumai asupra acestor copii. Memoria principală (main memory), asociată firului principal, conţine copia master afiecărei variabile. Există reguli care condiţionează modul în care se poate efectua schimb de conţinut între cele douătipuri de copii ale variabilelor. Important pentru sincronizare este, însă, faptul că memoria main conţine şi zăvoare, care pot fi asociate obiectelor sau metodelor declarate synchronized. Firele pot intra în competiţie pentru achiziţionareazăvoarelor. Acţiunile de zăvorâre şi dezăvorâre (dacă un astfel de cuvânt există!) sunt atomice, asemenea acţiunilor decitire sau scriere. Aceste zăvoare pot fi utilizate pentru sinconizarea activităţilor unui program multifir.

Declararea ca synchronized a unui obiect sau a unei metode determină asocierea acestora cu un zăvor. Importanteste că un singur fir, la un moment dat, poate să închidă zăvorul, altfel spus, un singur fir poate deţine obiectulasociat cu zăvorul.

Dacă un fir vrea să acceseze un obiect sau o metodă sincronizată, dar găseşte zăvorul închis, el trebuie să aştepteîntr-o coadă, până când zăvorul va fi deschis de către proprietarul lui circumstanţial.

Astfel că, în aplicaţiile Java multifir, putem întâlni: sincronizare cu metode, sinconizare pe blocuri, sincronizare

cu obiecte, pentru a introduce la anumite nivele, disciplina de utilizare mutual exclusivă a acestor trei categorii deconcepte. Elemente de sintaxă şi aspecte referitoare la modul de utilizare a acestor tehnici se pot urmări în Exemplul11.3, Exemplul 1.4 şi Exemplul 11.5.

Modelele teoretice utilizate în limbajele care oferă suport pentru programarea multifir oferă şi alte soluţii la problema sincronizării. Java oferă suport pentr majoritatea acestor modele, remarcându-se, faţă de alte limbaje, prin

Page 190: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 190/214

aducerea problemei concurenţei în interiorul limbajului, spre deosebire de alte soluţii, care se bazează pe enunţurisistem pentru implementarea prelucrărilor multifir. Pentru informarea cititorului, două mari direcţii de rezolvare a problemelor de sincronizare sunt: monitoarele (introduse de C.A.R. Hoare) şi semafoarele (introduse de Dijkstra).Fiecare dintre aceste soluţii pune în discuţie concepte precum secţiunea critică, prin care se înţelege o porţiune de codla care accesul concurent trebuie monitorizat, pentru a evita disfuncţiile în utilizarea anumitor resurse.

Atrag atenţia cititorului şi asupra ofertei limbajului Java în ceea ce priveşte posibilitatea de a defini grupuride fire, a căror manevrare unitară poate constitui un avantaj, în anumite situaţii.

De asemenea, în Java există şi posibilitatea de a defini nişte fire speciale, numite daemon-i, fire a căror destinaţieeste asigurarea de servicii pentru celelalte fire de execuţie. Exemplul clasic de daemon, în Java este firul care asigurăfuncţia de garbage collector.

 Exemplul 11.3 //Ilustreaza sincronizarea bazata pe obiecte //Obiectul monitor este balanta.class unFir extends Thread { 

 //Obiectul monitor  static Integer balanta = new Integer(1000); static int cheltuieli=0; public void run(){ 

int vol;

 for(int i=0;i<10;i++){ 

try{ 

 sleep(100); }catch(InterruptedException e){}int bon=((int)(Math.random()*500));

 //Accesul la blocul de cod de mai jos este //monitorizat cu ajutorul obiectului balanta synchronized( balanta ){ 

if(bon<=balanta.intValue()){ 

System.out.println("Verif:"+bon);balanta=new Integer(balanta.intValue()-bon);cheltuieli+=bon;System.out.print("Balanta: "+balanta.intValue());

Page 191: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 191/214

System.out.println("Cheltuieli: "+cheltuieli); }else{ 

System.out.println("Respins: "+bon); }

 } }

 } }

 public class Lacat { 

 public static void main(String s[]){ 

new unFir().start();new unFir().start();

 } }

 Exemplul 11.4 

 //Ilustreaza sincronizarea cu obiecte sinchronized 

 //apeland la wait() si notify()class Fir1 extends Thread { 

Object ob; Fir1(Object obi){ 

ob=obi; } public void run(){ 

while(true){ 

System.out.println("Firul "+getName());try{ 

 synchronized(ob){ 

ob.wait(); }

Page 192: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 192/214

 }catch(InterruptedException e){}

 } }

 }

class Fir2 extends Thread { 

Object ob;

Object obman=new Object();

 Fir2(Object obi){ 

ob=obi; } public void run(){ 

while(true){ 

System.out.println("Firul "+getName());try{ 

 synchronized(ob){ 

ob.notify(); }

 }catch(Exception e){ 

System.out.println("Exceptie: "+e); }try{ 

 synchronized(obman){ 

obman.wait(2000); }

 }catch(InterruptedException e){}

 }

Page 193: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 193/214

 } }

 public class WaitNoti{ 

 public static void main(String[]s){ 

 //Obiect pretext pentru sincronizareObject obiect=new Object();

 //Obiect pe care se face asteptareaObject obman=new Object(); Fir1 fir1=new Fir1(obiect); Fir2 fir2=new Fir2(obiect); fir1.start(); fir2.start();try{ 

 synchronized(obman){ 

obman.wait(35000); }

 }

catch(InterruptedException e){}

 } }

 Exemplul 11.5 //Ilustreaza sincronizarea cu metode synchronized class Distribuitor { 

int marfa=0;

 //Metoda atomizata cu ajutorul modificatorului // synchronized  public synchronized int consuma(){ 

int temp;while(marfa==0){ 

try

Page 194: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 194/214

{ wait();

 }catch(InterruptedException e){}

 }temp=marfa;marfa=0;System.out.println("Consumat :"+temp);notify();

return temp; }

 //Metoda atomizata cu ajutorul modificatorului // synchronized  public synchronized void produce(int vol){ 

while(marfa!=0){ 

try{ 

wait(); }

catch(InterruptedException e){}

 }marfa=vol;notify();System.out.println("Produs :"+marfa);

 } }

class unFir extends Thread { 

boolean producator=false; Distribuitor distr; public unFir(Distribuitor d,String t){ 

distr=d;if(t.equals("Producator"))producator=true;

 }

Page 195: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 195/214

 public void run(){ 

 for(int i=0;i<20;i++){ 

try{ 

 sleep((int)(Math.random()*1000)); }catch(InterruptedException e){}

if(producator)distr.produce((int)(Math.random()*6)+1);

else distr.consuma(); }

 } }

 public class ProdCons{ 

 public static void main(String s[]){ 

 Distribuitor dis=new Distribuitor();

new unFir(dis,"Consumator").start();new unFir(dis,"Producator").start();

 } }

Exemplul 11.5 ne arată cum putem combina sincronizarea bazată pe metode synchronized cu posibilităţile oferitede sincronizarea bazată pe aşteptare. Esenţiale, în sincronizarea bazată pe aşteptare, sunt metodele wait() şi notify().

Page 196: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 196/214

Capitolul 12Spiritul orientării pe obiecte în două aplicaţii C++

Page 197: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 197/214

12.1 Consideraţii introductiveOricât de mare ar fi emoţia pe care o provoacă o teorie printre curioşi, aceasta nu este suficientă pentru a o menţine

în atenţia practicienilor, fie şi vremelnic.De aceea, în acest capitol voi încerca să arăt cum se pun în mişcare o parte din ideile orientării pe obiecte, în

speranţa că, în acest fel, voi oferi motive în plus cititorilor de a încerca, “pe viu”, gustul orientării pe obiecte. Vomredescoperi, la sfârşitul acestui capitol, ceea ce am semnalat la începutul cărţii:

programarea orientată pe obiecte, în adevăratul sens, este o problemă de atitudine faţă de întreg travaliul derealizare a unui sistem soft sau chiar program.

Pentru a nu ne abate de la spiritul orientării pe obiecte, trebuie să utilizăm, cu răbdare, conceptele şi principiile pecare le-am prezentat deja, precum şi experienţa acumulată de alţi specialişti în realizarea de sisteme orientate pe obiecte.

Prima problemă pe care o supun atenţiei cititorului este relativ simplă, dar foarte potrivită pentru a ilustra spiritulorientării pe obiecte în acţiune.

12.2 Aplicaţia 1EnunţulSă se scrie codul C++ care simulează vizualizarera unui fişier text, în regim de scroll, pe ecranul unui

calculator, utilizat în mod text. Efectul de scroll se va urmări numai pe verticală.

12.2.1 Observaţii introductive

Enunţul pe care ni-l asumăm are, în mod intenţionat, o serie de elemente care ar putea fi taxate drept scăpări decătre programatorii cu simţ critic dezvoltat. Astfel, aceştia se pot întreba: de ce în mod text, într-o lume în care modulgrafic a inundat fiecare aplicaţie şi de ce efectul de scroll numai pe verticală? Pur şi simplu, din raţiuni didactice. Nimeni nu va putea opri elanul creator al cititorului să se manifeste cu puteri înzecite după ce va fi înţeles mesajul pecare vreau să-l transmit în această carte.

12.2.2 Soluţia problemeiCâteva consideraţii relativ la cerinţele faţă de codCodul va fi orientat pe obiecte şi va fi gândit în respect fată de principiul încapsulării. Doar faţă de principiul

încapsulării, deoarece nu vom avea o ierarhie de clase şi prin urmare nici moştenire, nici polimorfism dinamic. Evident,că am fi putut gândi o soluţie ceva mai savantă, care să ia în considerare derivarea clasei care modeleazăvizualizarea unui fişier text dintr-o clasă fereastră, capabilă să asigure un context vizual adecvat vizualizării şi ogestiune flexibilă a evenimentelor adresate acestei ferestre. Se poate reflecta la această posibilitate ca la un exerciţiu.Rămânând la exigenţele pe care ni le-am asumat iniţial, va trebui să specificăm o clasă C++ care să funcţioneze ca un“înveliş” comportamental pentru un fişier text. Acest înveliş va trebui să permită: asignarea la un fişier cu numeextern specificat, şi simularea efectului de scroll. Interfaţă acestei clase, din punct de vedere al utilizatorului,trebuie redusă la minimum.

Totodată, pentru a da un exemplu de organizare a unui proiect în C++, vom păstra în fişiere diferite: interfaţa,implementarea ei şi programul care exemplifică modul de utilizare . Pentru a asigura condiţii optime de efectuare a

Page 198: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 198/214

scroll-ului (viteză şi evitarea uzurii capului de citire al unităţii de memorie externă), vom asocia fişierului text oimagine în RAM, ca listă dublu înlănţuită . Modelul de rezolvare a problemei este, practic, schematizat în Figura 24,unde se poate vedea că, din punct de vedere algoritmic, trebuie doar să găsim o rezolvare elegantă la problemamapării conţinutului fişierului text pe ecranul monitorului, conform dorinţelor utilizatorului.

Să mai menţionăm că problema poate fi abordată şi altfel: dimensiunea ferestrei în care se face scroll să fieconfigurabilă. În acest caz, datele problemei se modifică semnificativ, dar soluţia este evident superioară calitativalegerii noastre. Se poate privi ca un exerciţiu posibil şi această abordare.

Figura 24. Relaţia ecran-Imagine Memorie FişierSpecificarea UML a clasei care modelează comportamentul obiectului “scroll”Pornind de la contextul problematic schiţat în Figura 24 şi ţinând cont de cerinţele asumate mai sus, putem propune

definiţia UML a clasei, să-i spunem, scroll.Această definiţie va urmări:• Furnizarea unei interfeţe simple şi stabile, în acord cu cerinţele formulate mai sus.• Separarea interfeţei de implementare, asigurând protecţia necesară operaţiilor interne ale clasei, prin declararea

lor ca private.• Securizarea accesului la datele membre ale clasei, prin declararea lor ca private.Să mai menţionăm că rămâne deschisă problema fiabilizării codului pe care îl propunem, ceea ce ar însemna

furnizarea de suoort structurat pentru tratarea excepţiilor.Înainte de a prezenta specificarea şi implementarea C++ a clasei scroll, prezentată în notaţie UML în Figura 25, să

mai atragem atenţia cititorului asupra unui “amănunt” important: metoda insert(), gândită ca făcând parte dindefiniţia clasei scroll, putea foarte bine să fie membru într-o clasă specializată în lucrul cu liste dublu înlănţuite.

aple - adresa primei linii care se vede peecran

aule - adresa ultimei linii care se vede peecrancurent - adresa elementului care se află în rezonanţă cu cursorul.

curent  aule

 Imagine memorie fişier (IMF)

 Ecranul monitorului aple

Page 199: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 199/214

De exemplu, o clasă de genul celor pe care le-am pus în discuţie în Capitolele 3, 4 şi 5 sau orice instrument orientat peobiecte echivalent.

Figura 25. Definiţia UML a clasei scroll Specificarea clasei “scroll” în C++Potrivit practicilor legate de gestiunea proiectelor C++ de complexitate mai mare, definiţiile claselor se păstrează în

fişiere antet cu extensia “.h”. Ilustrăm aceasta practică prin fişierul scroll.h. de mai jos.

 //”scroll.h” //Fisierul antet care contine definitia clasei scroll  //si alte definitii ajutatoare //Structura nodului listei dublu inlantuite //in care se pastreaza imaginea memorie a //fisierului(IMF)

 struct Nod { 

char *linie;

struct Nod* legs,*legd; };

 //Clasa care modeleaza un fisier scroll-abil class scroll { 

scroll

-char *numef;

-struct Nod *start;

-struct Nod *prec;

-struct Nod *aple,

-struct Nod *aule,

-struct Nod *curent;

-ifstream fin;

-void insert(char *el);

-void loadfis();

-void initscreen();

-void scrollup();

-void scrolldown();

-void runscroll();

+scroll(char *nf);

+Nod * getstart();

Page 200: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 200/214

//Sectiunea membrilor privatichar *numef;struct Nod *start,*prec;

struct Nod *aple,*aule,*curent;

ifstream fin;

//Inserare element in lista dublu inlantuitavoid insert(char *el);

//Creare imagine memorie fisier void loadfis();

//Initializare ecran pentru scroll void initscreen();

//Derulare scroll void runscroll();

//Efectuare scroll-upvoid scrollup();

//Efectuare scroll-downvoid scrolldown();

//Sectiunea resurse publicepublic:

//Constructor scroll(char *nf);

//Selector adresa de start IMF Nod * getstart();

 };

Implementarea clasei “scroll” în C++Din nou, potrivit practicilor legate de gestiunea proiectelor C++ de complexitate mai mare, implementarea claselor 

se păstrează în fişiere antet cu extensia “.cpp”. Ilustrăm aceasta practică prin fişierul scroll.cpp. de mai jos.

 //”scroll.cpp” //Fisier antet care contine implementarea clasei

Page 201: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 201/214

 //din scroll.h#include <iostream.h>#include <conio.h>#include <fstream.h>#include <string.h>#include <stdlib.h>#include "scroll.h" 

 scroll::scroll(char *nf){ 

numef=new char[strlen(nf)];strcpy(numef,nf);fin.open(numef);start=NULL;loadfis();initscreen();gotoxy(1,1);curent=start;runscroll();

 };

 //Selector adresa de start IMF  Nod * scroll::getstart()

{ return start;

 };

 //Implementare scrollup()void scroll::scrollup(){ if (wherey()>1){ gotoxy(1,wherey()-1);curent=curent->legs;

}else{ if (aple->legs!=NULL){ gotoxy(1,1);insline();gotoxy(1,1);

Page 202: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 202/214

aple=aple->legs;aule=aule->legs;cout<<aple->linie<<endl;gotoxy(1,1);

}};

 };

 //Implementare scrolldown()void scroll::scrolldown()

{ if ((wherey()<21)&(curent!=aule)){ gotoxy(1,wherey()+1);curent=curent->legd;

}else{ if (aule->legd!=NULL){ gotoxy(1,1);delline();gotoxy(1,21);

aule=aule->legd;aple=aple->legd;cout<<aule->linie<<endl;

}}

 };

 //Implementare element in listavoid scroll::insert(char *el){ Nod *w;if (start==NULL){ start=new Nod;start->linie=new char[strlen(el)+1];strcpy(start->linie,el);start->legs=NULL;start->legd=NULL;prec=start;

Page 203: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 203/214

}else{ w=new Nod;w->linie=new char[strlen(el)+1];strcpy(w->linie,el);prec->legd=w;w->legs=prec;w->legd=NULL;prec=w;

}; };

 //Implementare loadfis()void scroll::loadfis(){ char lin[80];clrscr();while(!fin.eof()){ fin.getline(lin,80);insert(lin);

}

 };

 //Implementare initScreen()void scroll::initscreen(){ 

Nod *aloc;aple=aloc=aule=start;clrscr();while((aloc!=NULL)&(wherey()<22)){ cout<<aloc->linie<<endl;aule=aloc;aloc=aloc->legd;

}; };

 //Implementare runscroll() //Se raspunde la: // sageata sus

Page 204: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 204/214

 // sageata jos // ESCAPE  void scroll::runscroll(){ int tasta,tasta1;do{ do{ tasta=getch();

}while((tasta!=27)&(tasta!=0));

switch(tasta){ case 0:{ 

tasta1=getch(); switch(tasta1){ 

case 72: scrollup();break;case 80: scrolldown();break;

 };break;

}case 27:exit(1);

};}while(1);

 };

În sfârşit, prezentăm, mai jos, un exemplu de context C++ în care se poate vedea modul de utilizare a unui obiect detip scroll. Se poate vedea simplitatea modului de utilizare, datorată simplităţii interfeţei.

Se pot, de asemenea, anticipa, în urma anlizei implementării pe care am furnizat-o mai sus, evenimentele neplăcutecare pot apare la o utilizare greşită a interfeţei clasei scroll. De exemplu, intenţia de scroll asupra unui fişier inexistentsau inabordabil din variate motive. Rămâne ca exerciţiu, pentru cititor, fiabilizarea codului sau  îmbunătăţireamodului de comunicare cu clienţii clasei scroll, în caz de apariţie a unor excepţii.

#include "scroll.cpp" void main(){ scroll sco("SCroll.cpp");

Page 205: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 205/214

 };

12.3 Aplicaţia 2EnunţulSă se scrie codul C++ care simplifică operaţiile de intrare/ieşire, relativ la fişiere, care au în vedere tipurile

de date fundamentale.

12.3.1 Observaţii introductive

De data aceasta se doreşte rezolvarea unei probleme, de real interes pentru un număr mare de utilizatori: programatori care consideră că flexibilitatea pe care le-o oferă C++ în gestiunea colecţiilor de date păstrate pe suporturide memorie externă este o provocare care nu poate fi ocolită. Nu toţi programatorii C++ tânjesc după un instrument caresimplifică, şi prin aceasta îngrădeşte, operaţiile I/O. Există, însă suficiente argumente pentru a încerca să furnizăm unînveliş convenabil soluţiei C++ la problema operaţiilor cu datele păstrate în fişiere. Acest înveliş va permite, în final, un protocol de lucru cu tipurile de date fundamentale, asemănător celui întâlnit în Pascal, Object Pascal, Basic, VisualBasic, etc.

12.3.2 Soluţia problemei

Câteva consideraţii relativ la cerinţele faţă de codCodul va fi orientat pe obiecte şi va fi gândit în respect fată de principiul încapsulării. Doar faţă de principiul

încapsulării, deoarece nici în acest caz nu vom avea o ierarhie de clase şi prin urmare nici moştenire, nici polimorfismdinamic. Din experienţa lucrului cu fluxuri în C++ se ştie că acestea pot fi utilizate în citire sau în scriere. Atenţie lainterfaţă şi la funcţionalitatea expusă de aceasta. Utilizatorii interfeţei sunt programatori. Soluţia pe care o propunemtrebuie să simplifice operaţiile I/O cu tipuri fundamentale de date şi, totodată, trebuie să conserve spiritul liberal în carese programează în C++.

Specificarea UML a învelişului pentru operaţiile I/ODecizia pe care am luat-o este, probabil, una din o mie posibile. Serviciile pe care le aşteptăm de la framework vor 

fi expuse prin intermediul a două clase: clasa FileIn, specializată în simularea operaţiilor de citire a tipurilor fundamentale de date din fişiere şi clasa FileOut, specializată în simularea operaţiilor de scriere a tipurilor fundamentale de date în fişiere. Impreună, aceste clase rezolvă problema accesului la tipurile fundamentale de datedintr-un fişier, cu menţiunea că nu s-a luat în calcul posibilitatea de a avea, simultan, acces şi în citire şi în scriere.Cititorul poate studia problema regândirii soluţiei în ideea că se doreşte suport şi pentru situaţiile în care dorim,

simultan, acces I/O. Oricare ar fi situaţia, între fişierul care conţine datele şi programator se află, în imediată apropiere,clasele framework-ului şi, disimulate de aceste clase, fluxurile C++. Figura 26 arată, în notaţie UML, cele două clasediscutate mai sus.

Specificarea claselor înveliş în C++

Page 206: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 206/214

În cele ce urmează, voi prezenta codul C++ care realizează definiţia claselor FileIn şi FileOut, menţionate mai sus.Atrag atenţia cititorului asupra faptului că extensia dată noţiunii de tip fundamental de date este discutabilă. Discutabilăeste şi lipsa unei strategii specifice de tratare a excepţiilor care pot apare în timpul lucrului cu obiectele, având acesteclase drept clase definitoare. Aşadar, subiect de reflexie pentru cititor, care ilustrează o idee deja menţionată în aceastăcarte: în industria de soft, orice problemă, înainte de a fi o problemă de programare este o problemă de modelare în spiritul unei anumite paradigme. Deciziile care se iau în faza de specificare a cerinţelor faţă de un sistem soft, deexemplu, influenţează în mod hotărâtor, arhitectura soluţiei sistemului soft în cauză.

FileIn

-ifstream iflux;-char * numef;

+FileIn();+FileIn(char *numef);+void setNumeF(char *numef);+char *getNumeF();+void fileOpen();+void fileClose();+ int readInt();+float readFloat();+double readDouble();+long int readLInt();

FileOut

-ofstream oflux;-char * numef;

+FileOut();+FileOut(char *numef);+void setNumeF(char *numef);+char *getNumeF();+void fileOpen();

+void fileClose();+void writeInt(int nr);+void writeFloat(float nr);+void writeDouble(double nr);+void writeLInt(long int nr);

Page 207: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 207/214

Figura 26. Specificarea UML a claselor FileIn şi FileOut

//Fişierul file.h#include <fstream.h>

 //Fisierul contine definiţia claselor wrapper pentru operatiile I/O //cu tipuri predefinite, relativ la fisiere //******************************************************

//Simulare operatii INPUTclass FileIn{ 

//Atribute informationale private

//Flux input ifstream iflux;

//Nume fisier extern asociat fluxuluichar * numef;

//Interfata claseipublic:

//ConstructoriFileIn();FileIn(char *numef);

//Setare nume fisier externvoid setNumeF(char *numef);

//Consultare nume fisier externchar *getNumeF();

//Deschidere flux in cazul utilizarii constructorului File()void fileOpen();

//Inchidere fluxvoid fileClose();

//Citire intreg din fisier int readInt();

Page 208: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 208/214

//Citire real simpla precizie din fisier float readFloat();

//Citire real dubla precizie din fisier double readDouble();

//Citire long int din fisier long int readLInt();

 };

//Simulare operatii OUTPUTclass FileOut { 

//Atribute informationale private

//Flux output ofstream oflux;

//Nume fisier extern asociat fluxuluichar * numef;

//Interfata clasei

public:

//ConstructoriFileOut();FileOut(char *numef);

//Setare nume fisier externvoid setNumeF(char *numef);

//Consultare nume fisier externchar *getNumeF();

//Deschidere flux in cazul utilizarii constructorului File()void fileOpen();

//Inchidere fluxvoid fileClose();

//Scriere intreg in fisier 

Page 209: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 209/214

void writeInt(int nr);

//Scriere real simpla precizie in fisier void writeFloat(float nr);

//Scriere real dubla precizie in fisier void writeDouble(double nr);

//Scriere long int in fisier 

void writeLInt(long int nr); };

Implementarea claselor înveliş în C++

//Fişierul iofile.cpp //Fisierul contine implementarea metodelor claselor FileIn si FileOut  //******************************************************

#include "file.h" #include <string.h>

#include <alloc.h> //Implementarea metodelor clasei FileIn

 FileIn::FileIn(char *nf){ 

numef=(char*)malloc(strlen(nf)+1);strcpy(numef,nf);iflux.open(numef,ios::in|ios::binary);

 };

 FileIn::FileIn(){ 

 };

int FileIn::readInt(){ 

int n;iflux.read((signed char*)&n,sizeof(int));

Page 210: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 210/214

return n; };

 float FileIn::readFloat(){ 

float n;iflux.read((signed char*)&n,sizeof(float));return n;

 };

double FileIn::readDouble(){ 

double n;iflux.read((signed char*)&n,sizeof(double));return n;

 };

long int FileIn::readLInt(){ 

long int n;iflux.read((signed char*)&n,sizeof(long int));return n;

 };

void FileIn::setNumeF(char *nf){ 

numef=(char*)malloc(strlen(nf)+1);strcpy(numef,nf);

 };

char *FileIn::getNumeF(){ 

return numef; };

void FileIn::fileOpen(){ 

iflux.open(numef,ios::in|ios::binary); };void FileIn::fileClose(){ 

Page 211: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 211/214

iflux.close(); };

 //Implementarea metodelor clasei FileOut  FileOut::FileOut(char *nf){ 

numef=(char*)malloc(strlen(nf)+1);strcpy(numef,nf);oflux.open(numef,ios::out|ios::binary);

 };

 FileOut::FileOut(){  };

void FileOut::writeInt(int nr){ 

oflux.write((signed char*)&nr,sizeof(int)); };

void FileOut::writeFloat(float nr){ 

oflux.write((signed char*)&nr,sizeof(float));

 };

void FileOut::writeDouble(double nr){ 

oflux.write((signed char*)&nr,sizeof(double)); };

void FileOut::writeLInt(long int nr){ 

oflux.write((signed char*)&nr,sizeof(long int)); };

void FileOut::setNumeF(char *nf){ 

numef=(char*)malloc(strlen(nf)+1);strcpy(numef,nf);

 };char *FileOut::getNumeF(){ 

Page 212: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 212/214

return numef; };

void FileOut::fileOpen(){ 

oflux.open(numef,ios::out|ios::binary); };

void FileOut::fileClose(){ 

oflux.close(); };

Un exemplu de utilizarea a claselor FileIn şi File Out

 //Fisierul contine un program de test pentru clasele FileIn si FileOut  //******************************************************#include <fstream.h>#include <conio.h>#include "filein.cpp" #include <iostream.h>

void main(){ int nri=1024;double nrrd=12.75;long int nrli=10000000;clrscr();

//Creare fisier de test FileOut of("fis.dat");cout<<"Obiect FileOut creat in urma apelului vers. 1 a constructorului"<<endl;of.writeInt(nri);of.writeDouble(nrrd);of.writeLInt(nrli);

of.fileClose();//Prima utilizare statica a clasei FileInFileIn fis("fis.dat");cout<<"Obiect FileIn creat in urma apelului vers. 1 a constructorului"<<endl;nri=fis.readInt();nrrd=fis.readDouble();

Page 213: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 213/214

nrli=fis.readLInt();cout<<nri<<" "<<nrrd<<" "<<nrli<<endl;fis.fileClose();

//A doua utilizare statica a clasei FileIn//Deschiderea fluxului este realizata in mai multi pasiFileIn fis1;fis1.setNumeF("fis.dat");fis1.fileOpen();cout<<endl;

cout<<"Obiect FileIn creat in urma apelului vers. 2 a constructorului"<<endl;nri=fis1.readInt();nrrd=fis1.readDouble();nrli=fis1.readLInt();cout<<nri<<" "<<nrrd<<" "<<nrli<<endl;getch();

 };

Expediţia OO se opreşte aici, în această carte. Ea trebuie să continue, pentru fiecare cititor în parte, în toatedirecţiile în care aceasta se manifestă din ce în ce mai insistent: mediile vizuale de programare, SGBD-urile orientate peobiecte, dezvoltarea orientată pe componente, etc. În orice direcţie ar porni cititorul, în esenţă se va întâlni cu aceleaşi probleme dificile:

• Modelarea respectând spiritul orientării pe obiecte, care are numeroase avantaje dar se învaţă mai greudecât orice manieră de programare “artizanală”.

• Rezolvarea problemelor de “supravieţuire” a obiectelor, între două execuţii ale aplicaţiilor orientate peobiecte.

• Rezolvarea problemelor de transmitere şi partajare a obiectelor între aplicaţii aflate pe acelaşi calculator sau pe calculatoare diferite, într-o reţea.

• Soluţionarea elegantă a problemei tratării excepţiilor care pot apare într-o aplicaţie orientată pe obiecte.• Armonizarea cerinţelor orientării pe obiecte cu exigenţele realizării aplicaţiilor multifir, etc.

Fără să fie un secret prea mare, deprinderea de a programa orientat pe obiecte vine după mult exerciţiu şiefort constant de informare cu privire la şabloanele aplicate de comunitatea programatorilor OO pentrurezolvarea unor probleme tip.

Bibliografie esenţială

[1] Eckel, B., Thinking in Java, 2nd edition, Revision 12, format electronic.[2] Jamsa & Klander, C şi C++ (Manualul fundamental de programare în C 

Page 214: Program Are Obiect Orientata 2 Anul II

5/9/2018 Program Are Obiect Orientata 2 Anul II - slidepdf.com

http://slidepdf.com/reader/full/program-are-obiect-orientata-2-anul-ii 214/214

 şi C++), Editura Teora.[3] Joshua Bloch, Java. Ghid practic pentru programatori avansaţi , Editura

Teora, 2002.[4] Lemay, L., Cadenhead, R., Java 2 fără profesor în 21 de zile, Editura

Teora, 2000.[5] Mark C. Chan, ş.a., Java. 1001 secrete pentru programatori , Editura

Teora[6] Negrescu,L., Limbajele C şi C++ pentru începători, Limbajul C++ 

(volumul II), Editura Albastră, Cluj-Napoca[7] Teixeira, S., Pacheco, X., Delphi 5 Developer’s Guide, SAMS Publishing,

2000