Sunteți pe pagina 1din 48

Syllabus I.

Informatii generale

II.1 Datele de identificare a cursului Datele de contact ale titularului de curs: Nume: Gheorghe Cosmin Silaghi Birou: Campus, etaj 4, sala 431 Telefon: 0722-817582 Fax: 0264-412570 Email: Gheorghe.Silaghi@econ.ubbcluj.ro Consultatii: saptamanal, joia de la 12-14 Datele de identificare curs si contact tutori: Numele cursului: Limbaje de programare Codul cursului: EBI0085 Anul, semestrul: anul III, semestrul 1 Tipul cursului: obligatoriu Pagina web a cursului: www.econ.ubbcluj.ro/~gsilaghi/limbaje2008 Tutori: Gheorghe Cosmin Silaghi, Mircea Moca Adrese de email: Gheorghe.Silaghi@econ.ubbcluj.ro, Mircea.Moca@econ.ubbcluj.ro Conditionari si cunostiinte prerechizite: Se recomanda cunostiinte de programare structurata in C. Aceste cunostinte sunt obtinute la disciplina Algoritmi si Structuri de date, anul II, semestrul 2. Aditional, studentii pot opta pentru cursul facultative de Introducere in Programare, anul II semestru 1. Descrierea cursului Cursul de Limbaje i medii de programare i propune s familiarizeze studenii cu noiunile principale legate de limbaje de programare. Studentii vor deprinde principalele noiuni necesare pentru nvarea unui limbaj de programare. Aici includem considerente legate de structura i componentele unui limbaj de programare, modul de obinere a unui program executabil dintr-un program surs, tehnici de programare utilizate n conceperea eficient a programelor. Pentru exemplificarea acestor notiuni, cursul va parcurge paradigma obiectual i va concretiza notiunile teoretice ale paradigmei prin utilizarea limbajului C++. Alegerea paradigmei obiectuale

ca i inta de exemplificare se datoreaz importanei acestei paradigme n industria software, tehnologia obiectual reprezentnd una din cerintele fundamentale din industrie. Mediul de programare utilizat va fi Visual C 6.0. Organizarea temelor in cadrul cursului Temele cursului sunt organizare conform logicii de invatare a conceptelor de programare obiectuala. Cursul de bazeaza pe logica bulgarelui de zapada. Astfel, la inceput se introduce notiuni facile legate de aceasta disciplina. Pe parcurs, aceste notiuni se folosesc la descrierea si invatarea altor notiuni mai complicate. Studentii sunt rugati sa consulte bibliografia aferenta fiecarei teme, atat din suportul de curs obligatoriu (manualul) cat si din celelalte carti indicate. Pentru fiecare tema, suportul de curs dezvolta conceptele teoretice, prezinta exemple si propune probleme de rezolvat. Pentru o buna aprofundare, studentii trebuie sa parcurga la calculator aceste exemple si sa realizeze problemele date ca si tema. Site-ul disciplinei contine aditional slide-urile pentru fiecare tema. Slide-urile contin informatii sumare, fiind un bun ghid de reamintire a conceptelor dezvoltate la fiecare capitol. Slide-urile nu sunt suficiente ca si mijloc de invatare a acestei discipline. Formatul si tipul activitatilor de curs La intalnirile cu studentii, profesorul va prezenta continutul teoretic al disciplinei. Studentii sunt rugati sa participle la aceste intalniri, pentru ca au posibilitatea sa inteleaga mai bine conceptele disciplinei. Continutul este disponibil si in manual, studentii avnad posibilitatea sa-l insuseasca individual. Studiul individual presupune exercitiu la calculator in limbajul de programare C++, cu exemplele din manual sau cu alte exemple. Pentru o mai buna intelegere, studentii pot sa resolve problemele propuse sau sa realizeze alte programe software, la liberal or alegere. Pentru fiecare tema, studentii trebuie sa trimita problemele propuse rezolvate pentru a fi punctuate de catre tutori. Materiale bibliografice obligatorii 1. G.C. Silaghi, Mircea Moca Limbaje de Programare. Metode Obiectuale. Ghid teoretic si practic. Editia 2-a, Ed. Risoprint, 2008 2. Bruce Eckel, Thinking in C++, ed. Prentice Hall, 2000, vol 1. 3. Bjarne Stroustrup, The C++ Programming Language, Addison-Wesley, 4. Bazil Prv, Al. Vancea, Fundamentele limbajelor de programare, 1996 5. D.L. erbnai, Limbaje de programare i compilatoare, Ed. Academiei, 1987 6. Malcom Bull, Students guide to programming languages, HB Newnes, 1992

Materiale si instrumente necesare pentru curs - Laborator echipat cu MS Visual C 6.0 - videoproiector Calendarul cursului Cursul este impartit in capitole, aferente celor 14 saptamani ale unui semestru: 1. Introducere n limbaje de programare 1.1 Definirea limbajelor de programare 1.2 Clasificarea limbajelor 1.3 Istoricul i evoluia limbajelor 2. Fundamentele limbajelor de programare 2.1 Limbaje abstracte 2.2 Compilatoare 3. Introducere n obiectualitate 3.1 Principii de baz 3.2 Analiza io designul programelor orientate obiect 3.3 Noiuni de baz n C++ 4. Abstractizare i ncapsulare 4.1 Abstractizarea 4.2 Ascunderea implementrii 5. Construirea obiectelor 5.1 Constructori i destructori 5.2 Suprancrcarea funciilor 6. Tipuri de variabile 6.1 Constante 6.2 Funcii inline 6.3 Elemente statice 6.4 Spaii de nume 7. Transmiterea obiectelor ntre funcii 7.1 Referine 7.2 Constructorul de copiere 8. Suprancrcarea operatorilor 8.1 Realizarea suprancrcrii operatorilor 8.2 Excepii de la regula de suprancrcare 8.3 Considerente de design 8.4 Conversie automat de tip

9. Gestiunea dinamic a memoriei 9.1 Crearea dinamic a obiectelor 9.2 Mecanismul de gestiune dinamic a memoriei 10. Compoziie i motenire 10.1 Reutilizarea codului 10.2 Definirea motenirii 10.3 Introducerea diagramelor de clase 10.4 Considerente de design 11. Polimorfism 11.1 Definirea conceptului de polimorfism 11.2 Realizarea polimorfismului de tip n C++ 11.3 Clase abstracte 11.4 Aspecte colaterale ale motenirii 12. Colecii 12.1 Genericitate. Realizarea genericitii 12.2 Colecii heterogene 12.3 Colecii parametrizate 13. Tipuri abstracte de date 13.1 Definirea ADT-urilor 13.2 Specificarea ADT-urilor 14. Paradigme de programare colaterale 14.1 Programarea bazat pe evenimente 14.2 Programarea bazat pe componente 14.3 Programarea logic i funcional Fiecare tema presupune parcurgerea unui material intre 15 si 30 de pagini si rezolvarea a 3 probleme practice. In saptamanile 5, 9 si 14 studentii trebuie sa trimita spre evaluare tutorilor rezolvarile la problemele propuse din capitolele anterioare saptamanii respective. Politica de evaluare si notare Nota la aceasta disciplina este compusa din: 70% examen, 30% evaluarea temelor din timpul semestrului

Termenele pentru teme sunt saptamanile 5, 9, si 14. Pe fiecare tema se acorda o nota de la 1 la 10 si se face media acestor note. Aceasta medie conteaza 30% din nota finala.

Examenul din sesiune are o pondere de 70% din nota finala si este compus din examen scris si practic. Examenul scris se compune dintr-un test grila cu 30 de intrebari, 5 intrebari deschise si o problema. Examenul practice presupune rezolvarea unei probleme la calculator. Problema care se rezolva la calculator are mai multe subpuncte, in ordine crescanda de dificultate. Nota examenului este medie aritmetica a notelor de la proba scrisa si proba practica. Elemente de deontologie academica Stratregii de studiu recomandate Se recomanda studentilor s parcurg cursul gradual pe parcursul semestrului. Astfel, in timpul parcurgerii fiecrui capitol, studentii sunt rugai s ruleze exemplele practice din material i s pun accept pe intelegerea conceptelor i a modului in care programele sunt realizate si executate. Studentii sunt incurajai s comunice cu tutorii in cazul in care exist nelmuriri legate de materialul cursului. Temele i intrebrile recapitulative indicate la fiecare capitol sunt minimale pentru intelegerea si aprofundarea materialului. Recomandm studentilor rezolvarea tuturor problemelelor indicate in curs. II. Suportul de curs propriu-zis

MODULUL 1. FUNDAMENTELE LIMBAJELOR DE PROGRAMARE


Scopul si obiectivele mobulului: n acest capitol vom prezenta succint formalizarea exhaustiv a teoriei limbajelor de programare. Materiale precum [Aho 1977], [erbnai 1987] conin o tratare detaliat a acestui subiect. Teoria limbajelor de programare este necesar pentru specificarea formal corect a limbajelor i reprezint un fundament pentru teoria compilrii.

1.1.
1.1.1.

Limbaje abstracte
Gramatici

Fie o mulime A nevid, finit, numit alfabet. Elementele acestei mulimi se numesc simboluri. Un simbol din A este reprezentat ntr-un limbaj printr-o liter, cifr sau semn, uneori printr-un ir finit de litere, cifre sau semne. Notm prin A * mulimea aranjamentelor cu repetiie ale simbolurilor din A . Astfel, un element din A * este un ir finit de simboluri din A . Simbolurile se pot repeta n ir. Mulimea A *

conine i irul vid; vom nota acest ir cu . Numrul de simboluri dintr-un ir din A * se numete lungimea irului. Se observ c dac avem dou iruri x i y din A * atunci irul
z = xy , obinut prin alturarea simbolurilor din x cu simbolurile din y , va fi de asemenea,

element al mulimii A * . Operaia prin care se obine irul z din irurile x i y se numete
concatenare. Mulimea A * nzestrat cu operaia de concatenare are o structur de monoid. Prin definiie, un limbaj formal peste alfabetul A este o submulime L a lui A * .

Fiind dat un alfabet A i mulimea P( A*) a prilor mulimii A * , pe aceast din urm mulime putem defini urmtoarele operaii de baz: a. intersecie: L1 L2 b. reuniune: L1 L2 c. complementare: L = {x A* | x L} d. produs: L1 L2 = {x1 x2 | x1 L1 , x2 L2 } . Notm cu L2 = LL,...
e. stea: L* = {} L L2 ... Ln ... ~ f. reflectare: L = {~ | x L} unde ~ este imaginea reflectat a lui x x x

n legtur cu un limbaj formal, se pune problema apartenenei unei construcii la limbaj, adic, n condiiile furnizrii unui cuvnt x A * , dac se poate decide (demonstra) una din urmtoarele 2 concluzii: x L sau x L . Se spune c un limbaj L este decidabil, dac rspunsul la ntrebarea de mai sus este pozitiv. Conceptul de algoritm st la baza rezolvrii acestei probleme. Adic, trebuie s decidem rspunsul la ntrebarea de apartenen ntr-un timp finit folosind operaii precis definite. Problema apartenenei unui cuvnt la limbaj, n cazul limbajelor de programare trebuie s fie rezolvat de compilator, adic acesta trebuie s decid dac codul surs furnizat de programator satisface sau nu regulile limbajului, adic poate fi compilat sau nu. n cazul n care limbajul L este finit, atunci limbajul este decidabil. Dac L este infinit, trebuie s folosim alte metode pentru a rspunde la ntrebarea de decidabilitate. Specificarea limbajului nseamn fie enumerarea tuturor elementelor acestuia, fie enunarea unor reguli de construcie a elementelor limbajului. Noiunea de gramatic st la baza specificrii unui limbaj prin generarea tuturor cuvintelor sale. Prin definiie, un sistem formal este un cvadruplu ordonat S =< A, F ,, R > alctuit din: alfabetul sistemului A mulimea decidabil a formulelor corecte, F A *

mulimea decidabil a axiomelor, F mulimea finit a regulilor de deducie (inferen) R . O regul de deducie de aritate n + 1 este o relaie din mulimea F n F , care asociaz o formul unic x cu un n-tuplu y =< y1 , y2 ,..., y n > . Spunem c x se deduce din y1 , y2 ,..., yn i scriem yRx .

Fie formulele corecte y1 , y2 ,..., yn , numite premise. Fie E0 = { y1 , y 2 ,..., y n } . Atunci, E0n reprezint mulimea tuturor n-tuplelor cu formule din E0 . Atunci, aplicnd succesiv regulile de deducie din R putem obine mulimile Ei = Ei 1 U{x | y Ein1 , astfel
n 1

incat

yRx} .

Dac mulimea premiselor e vid, adic E0 = atunci elementele lui Ei se numesc teoreme. Dac x este o teorem, atunci ea s-a obinut prin aplicarea succesiv a unor reguli de deducie asupra unor formule din mulimile Ei . Secvena acestor reguli de deducie alctuiete demonstraia teoremei x . Prin definiie, urmtorul caz particular de sistem formal: a. alfabetul A al sistemului formal este finit i este alctuit din dou mulimi disjuncte N i , alfabetul de simboluri neterminale respective alfabetul de simboluri terminale. b. F = A * : toate irurile finite pe alfabet sunt formule corecte

c. conine un singur element, i anume un simbol neterminal S . Acest simbol se numete simbol de nceput. d. Regulile de deducii au la baz producii: O producie este o pereche ( , ) de formule,
notat cu . Regula de producie asociat unei producii este o regul de rescriere, adic PQ PQ unde P i Q sunt 2 iruri din F . Aceasta nseamn c n orice formul corect care conine subirul se poate nlocui cu i se obine tot o formul corect. Notm cu P mulimea finit de producii. n aceste condiii, sistemul formal G =< N , , P, S > se numete gramatic. Procesul de inferen n cazul gramaticilor se numete derivare. Spunem despre dou iruri i din F c deriveaz imediat n n cadrul unei gramatici date, dac exist dou iruri 1 i 2 din F i o producie astfel nct = 1 2 i

= 1 2 . O asemenea relaie de derivare reprezint o derivare ntr-un singur pas. Derivarea se


poate defini pe k pai, n cazul este obinut din prin k derivri. O relaie de derivare a lui din este nebanal, dac obinerea lui se realizeaz ntr-un numr nenul de pai. Relaia de derivare se numete general dac se obine din ntr-un numr nenul de pai sau dac cele 2 formule coincid. Prin definiie, un limbaj generat de o gramatic G este mulimea tuturor propoziiilor L(G ) = {x} cu proprietatea c S deriv general pe x . Dac limbajele generate de dou gramatici coincid, se spune c gramaticile sunt echivalente. Conform definiiei gramaticilor enunat de mai sus, Naom Chomsky le-a clasificat dup forma produciilor. Astfel, avem urmtoarele tipuri de gramatici: 1. Clasa gramaticilor de tip 0: reprezint cea mai general clas de gramatici, sunt cele care respect definiia general furnizat mai sus 2. Clasa gramaticilor de tip 1: produciile sunt de forma: A . A este un simbol neterminal, este ir oarecare, diferit de simbolul vid. Aceste gramatici se mai numesc i dependente de context. 3. Clasa gramaticilor de tip 2: produciile sunt de forma: A , unde A este un simbol neterminal, este ir oarecare. Aceste gramatici se mai numesc i independente de context. 4. Clasa gramaticilor de tip 3 sau regulate: produciile sunt de forma A aB sau A a , unde
A i B sunt simboluri neterminale iar a este simbol terminal. Corespunztor claselor de gramatici, avem clase de limbaje. Astfel, se poate defini o ierarhie Chomsky a limbajelor.

Limbajul independent de context (de tip 2) este modelul limbajelor de programare.

n ceea ce privete utilitatea studiului gramaticilor pentru scrierea compilatoarelor urmtoarea teorem este important: Orice limbaj dependent de context (i n consecin independent de context i regulat) este decidabil. Deci, limbajele de programare sunt decidabile.
1.1.2.
1.1.2.1.

Specificarea limbajelor de programare


BNF

Pentru descrierea limbajelor de programare se folosesc meta-limbaje. Acestea furnizeaz reguli prin care se pot specifica irurile acceptate de un limbaj de programare. BNF (Backus Naur Form) reprezint cel mai utilizat limbaj de specificare a limbajelor de programare. n fond, BND descrie o gramatic independent de context. n BNF, simbolurile neterminare se scriu ntre paranteze unghiulare i se definesc recursiv, prin meta-formule. De asemenea, semnul ::= face parte din limbajul de specificare. El se poate traduce prin: se definete astfel. Simbolul | nseamn alegere, n sensul c permite utilizarea uneia din cele 2 alternative alturate simbolului. Astfel, n BNF, simbolurile <, >, ::=, | se numesc metasimboluri. Pentru a exemplifica utilizarea BNF, vom descrie n acest limbaj de specificare sintaxa de compunere a unei propoziii simple ntr-un limbaj informal. Astfel, avem urmtoarea definiie BNF:
<sentence>::=<subject><verb><object>. <subject>::=<article><noun>|<subject pronoun> <verb>::=sees|hits <object>::=<article><noun>|<object pronoun> <article>::=a|the <subject pronoun>::=he|she <object pronoun>::=him|her

n consecin, se constat faptul c o propoziie este compus prin alturarea unui subiect, verb i a unui obiect (atribut). Propoziia se termin cu simbolul terminal punct. Subiectul poate fi un articol alturat unui substantiv sau (simbolul |) un pronume de tip subiect. Pronumele de tip subiect poate fi unul din simbolurile terminale he sau she etc. Astfel, prin asemenea construcii se pot descrie toate regulile de producie din limbaj. De fapt, prin BNF descriem ntreaga gramatic pe baza creia apoi, putem genera limbajul corespunztor acesteia. Deci, pornind de la specificarea BNF a unei gramatici, putem folosi aceast specificare pentru a genera limbajul i pentru a recunoate sintagmele acceptate de gramatica definit.

Procesul prin care, avnd dat la intrare o propoziie, determinm (decidem) dac propoziia respectiv este acceptabil, n contextul unei gramatici se numete parsare.
1.1.2.2. EBNF

De multe ori, specificarea BNF este greoaie din punct de vedere al lizibilitii, mai ales atunci cnd un simbol neterminal se poate repeta, de un numr finit sau infinit de ori, ntr-o construcie. De exemplu, putem considera definirea unui string ca fiind un ir de una sau mai multe cifre:
<string>::=<digit>|<digit><string>

Pentru a uura asemenea construcii, EBNF introduce urmtoarele meta-simboluri: {} tot ce e inclus ntre acolade se poate repeta, sau poate lipsi [] tot ce e inclus ntre parantezele drepte poate lipsi (este opional) Astfel, construcia de mai sus poate fi scris:
<string>::=<digit>{<digit>}

De exemplu, pentru a defini un numr, care poate avea simbolul de semn, putem folosi urmtoarele construcii alternative:
<numer>::=<sign><unsigned>|<unsigned>

n BNF

sau
<number>=[<sign>]<unsigned>

n EBNF

EBNF introduce i alte meta-simboluri ajuttoare. Astfel avem:

* nlocuiete acoladele, are semnificaia c simbolul precedent se poate repeta de un numr de 0 sau mai multe ori + simbolul precedent se poate repeta de 1 sau mai multe ori _ se subliniaz meta-simbolurile, atunci cnd acestea fac parte din alfabetul limbajului specificat
1.1.2.3. Diagrame de sintax

Reprezint o descriere alternativ vizual, a specificrii unui limbaj. Au fost introduse la specificarea limbajului Pascal. Diagramele de sintax reprezint grafe orientate avnd ca noduri simbolurile din limbaj iar sgeile indic succesiunea acceptat a acestora.

S considerm o gramatic specificat n limbaj EBNF.


<sentence>::=<expression>= <expression>::=<number>[<operator><expression>] <number>::=[<sign>]<unsigned> <operator>::=*|+|-|/ <sign>::=+|<unsigned>::=<string>[.<string>]|.<string> <string>::=<digit>{<digit>} <digit>::=0|1|2|3|4|5|6|7|8|9

Figura 5 prezint cteva diagrame de sintax pentru elementele gramaticii de mai sus.
<sentence> <expression> =

<digit>

0 1 2 3 4 5 6 7 8 9

<string>

<digit>

Figura 18.1 Diagrame de sintax

1.1.3.

Automate de acceptare

Un automat de acceptare este folosit pentru a rspunde la ntrebarea: un ir x aparine limbajului L sau nu? Automatul este definit ca o main cu operaii simple, care primete irul de analizat pe un suport oarecare, l parcurge, i rspunsul final este dat de starea n care rmne unitatea de comand a automatului. Suportul pe care este furnizat irul este denumit generic band de intrare, iar variabila care parcurge irul de analizat n citire se numete cap de citire. Automatul poate folosi o memorie auxiliar pentru pstrarea unor informaii care s fie de folos la un moment dat, n procesul decizional. Asemenea automate sunt definite prin grafe. Nodurile grafului reprezint stri ale automatului, iar arcele reprezint tranziii ntre stri. Arcele sunt marcate cu condiii, cu semnificaia c, dac

automatul se afl ntr-o anumit stare, i se ndeplinete condiia de pe un arc care iese din starea respectiv, atunci automatul va trece n starea de la cellalt capt al arcului selectat. Automatele pot fi: deterministe, dac dintr-o stare se poate realiza cel mult o singur micare nedeterministe, dac dintr-o stare exist mai multe micri posibile. Automatele nedeterministe corespund gramaticilor cu producii cu alternative.

Un ir x este acceptat de un automat U dac, pornind de la configuraia iniial, prin micrile automatului se parcurge ntregul ir de intrare i automatul ajunge ntr-o configuraie final. Pentru exemplificare, vom considera automatul finit din figura 6.
b a a q0 q1

Figura 18.2 Diagrama de tranziii a unui automat finit cu 2 stri

Astfel, automatul din figura 18.2 are 2 stri: q0 i q1. q0 reprezint starea iniial, q1 reprezint starea final. Dac, pe banda de intrare se ntlnete irul a i automatul este n starea q0, atunci automatul trece n starea q1. Dac pe banda de intrare se ntlnete irul b i automatul este n starea q0, atunci automatul rmne n aceeai stare etc. Tabelul 2 prezint matricea de definire corespunztoare acestui automat. a b q0 q1 q1 q1
Tabelul 18.1 Matricea automatului din figura 6

q0 q0

Pentru acest automat, irul aaba este un ir acceptat deoarece: (q0,aaba) a (q1,aba) a (q1,ba) a (q0,a) a (q1, ) Deci, pornindu-se din starea iniial q0, se parcurge irul de intrare i n final, la epuizarea acestuia, se ajunge n starea final q1, cu irul vid . Exemplul din figura 18.1 reprezint un automat finit determinist. n figura 18.2 prezentm un exemplu de automat finit nedeterminist. Tabelul 3 reprezint matricea de tranziii pentru acest automat. Caracteristic automatului nedeterminist este faptul c dintr-un nod pot iei mai multe sgei etichetate cu acelai simbol de intrare, precum i sgei etichetate cu care reprezint tranziii independente de intrare.

a a 0 1 b 3

2 a

Figura 18.2 Diagrama de tranziie a unui automat finit nedeterminist

a 0 1 2 3 {2} -

{2} -

{0,1} {3} -

{2,3} -

Tabelul 18.2 Matricea automatului finit din figura 7

Se poate stabili o relaie ntre automatele finite deterministe i cele nedeterministe. Astfel, pentru orice automat finit nedeterminist exist un automat finit determinist care accept acelai limbaj. Transformarea unui automat finit nedeterminist ntr-un automat finit determinist este important deoarece lucrul cu automatele nedeterministe este dificil, datorit traiectoriilor paralele pe care le poate lua calculul n aceste automate. Dar noi trebuie s privim aceste automate n contextul studiului gramaticilor, care definesc limbajele de programare. Astfel, pornind de la o gramatic, se poate genera un automat finit care s accepte gramatica respectiv. Dac automatul finit obinut pentru o gramatic este nedeterminist, vom aplica procedura pentru construirea automatului finit determinist echivalent. Automatele deterministe ne indic modul n care trebuie s tratm un ir de intrare pentru a identifica dac acesta este acceptat sau nu de automat. Astfel, la construirea compilatoarelor, analizorul sintactic folosete logica automatului pentru a spune dac o construcie de intrare e valid sau nu, i n caz afirmativ, consider mai departe aceast construcie. n practic, ori de cte ori avem de implementat un parser, adic un program care interpreteaz la intrare iruri de caractere cu anumite proprieti, prin descrierea automatului corespunztor putem identifica traiectoriile posibile de intrare i implementa un analizor corect i eficient. n ANSI C exist biblioteca de expresii regulate folosite pentru generare de abloane de iruri de caractere, care urmeaz exact regulile semantice de descriere ale automatelor.

1.2.

Compilatoare

n procesul de comunicare om-calculator intervine un program intermediar, translatorul, care asigur traducerea programelor scrise de utilizator din cod surs ntr-un alt limbaj mai apropiat de calculator. Dac limbajul int este codul main, translatorul se numete compilator. Astfel, execuia unui program surs se realizeaz, n cadrul limbajelor compilative, n 2 faze: compilare, care traduce codul surs n program obiect execuie, care ruleaz codul obiect pe calculator, folosind datele iniiale ale programului i produce rezultate Compilatorul unui limbaj de asamblare se numete asamblor. n practic, pe lng compilatoarele obinuite, exist i alte tipuri de compilatoare. Astfel, preprocesoarele sunt translatoare care traduc dintr-un limbaj de nivel nalt n alt limbaj de nivel nalt. Preprocesorul limbajului C++ reprezint un bun exemplu. Cross-compilatoarele sunt compilatoare scrise pentru un calculator gazd, n vederea generrii de cod pentru alt calculator. Cross-compilatoarele sunt folosite la scrierea de cod pentru diverse dispozitive inteligente, care conin procesoare. n cazul limbajelor interpretative, compilatorul este de tip special, adic incremental. Astfel, programul surs este spart de ctre compilator n poriuni mici numite incremente, care au o oarecare independen sintactic i semantic. Incrementele sunt traduse de compilator. Pe msur ce compilatorul traduce un increment, calculatorul execut incrementul tradus. n mod tradiional, un compilator realizeaz un ir de transformri asupra codului surs n reprezentri din ce n ce mai apropiate de codul main. Figura 10 prezint fazele unui compilator.
Program sursa Sir de atomi lexicali Arbore sintactic Cod intermediar Cod intermediar optimizat Program obiect

Analiza lexicala

Analiza sintactica

Analiza semantica

Optimizare de cod

Generare de cod

Tratarea erorilor

Gestiunea tabelelor

Figura 18.3 Fazele unui compilator [erbnai 1987]

Analiza lexical grupeaz caracterele din program n subiruri numite atomi lexicali care reprezint cuvintele cheie, operatori, constante, identificatori i delimitatori. irul de atomi lexicali este preluat de analiza sintactic. Aceasta depisteaz structuri sintactice cum ar fi expresii, liste, instruciuni, proceduri. Aceste structuri sunt plasate ntr-un arbore sintactic conform relaiilor existente ntre aceste structuri.

Analiza semantic folosete structura programului pentru extragerea informaiilor privind obiectele purttoare de date (variabile, proceduri, funcii), verificarea consistenei utilizrii lor. Pe msura parcurgerii arborelui sintactic, analiza semantic construiete o reprezentare a codului surs n cod intermediar. Acesta este de obicei un ir de instruciuni simple cu format fix. Ordinea operaiilor din codul intermediar respect ordinea de execuie a acestora pe calculator. Codul intermediar este prelucrat n faza de optimizare pentru eliminarea redundanelor de calcule, a calculelor i variabilelor inutile, pentru o execuie mai eficient. Generarea de cod aloc celule de memorie pentru memorarea datelor la execuie. Se aloc registre i se produce cod obiect echivalent cu programul n limbaj intermediar. Gestiunea tabelelor este de fapt, o colecie de proceduri care creeaz i actualizeaz datele cu care lucreaz celelalte faze. n aceast tabel, pe lng informaii proprii compilatorului se gsesc i tabele ale identificatorilor, constantelor, cuvintelor cheie. Uneori avem o tabel unic, numit tabela simbolurilor. Tratarea erorilor este o colecie de proceduri care sunt activate ori de cte ori se depisteaz o greeal n program. De obicei, utilizatorul primete un mesaj de diagnostic. Dac greeala este identificat n faza de analiz sintactic, compilatorul poate s-i urmeze analiza pentru a detecta i alte erori. Structura prezentat este mai mult conceptual. Compilatoarele concrete de multe ori prezint abateri fa de aceast structur. Unele componente pot lipsi, sau funcionalitatea lor poate fi preluat de alte componente, sau ordinea activrii componentelor poate fi diferit. Realizarea compilatoarelor presupune un volum mare de munc. Exist unelte software specializate care asigur faciliti de dezvoltare a compilatoarelor. Astfel, avem uneltele LEX i YACC sub Unix care permit descrierea sintactic i semantic a unui compilator, conform regulilor limbajului, utiliznd automatele de acceptare a construciilor de intrare. Programatorul trebuie s descrie regulile limbajului i sintaxa propoziiilor acceptate n format de expresii regulate, iar mai apoi construcia int asociat fiecrei sintagme de limbaj surs. Utilitarele genereaz un cod C care apoi compilat, reprezint de fapt compilatorul pentru limbajul surs considerat. Datele de intrare pentru asemenea unelte sunt: specificaia limbajului surs, n ceea ce privete descrierea lexicului i a sintaxei specificaia limbajului int i a regulilor semantice de traducere

- specificaia mainii int Dac n trecut, timpul de elaborare a unui compilator era destul de mare, azi, utiliznd asemenea tool-uri moderne putem realiza rapid compilatoare pentru diverse limbaje.

1.3.

ntrebri recapitulative

1. Descriei clasificarea gramaticilor dup Naom Chomsky. 2. De ce limbajul independent de context reprezint modelul unui limbaj de programare? 3. Cum se specific un automat? Care sunt tipurile de automate? Explicai importana studierii automatelor cu privire la studiul limbajelor de programare. 4. Explicai structura (fazele) unui compilator. Ce se ntmpl n fiecare faz? 5. Se d urmtoare specificare EBNF pentru un calculator de buzunar:
(a) (b) (c) <expression>::=<number>{<operator><expression>} <sentence>::=<number>{<operator><sentence>}= <number>::={<sin>}<unsigned>

Sunt aceste reguli de specificare corecte? 6. Fie urmtoarele producii:


<unsigned>::=<string>[.<string>] <string>::=<digit>{<digit>} <digit>::=0|1|2|3|4|5|6|7|8|9

Se decid care din urmtoarele numere sunt acceptate sau nu de gramatica specificat mai sus: (a) (b) (c) (d) (e) 8. Fie 1 1. 1.1 .1 12.34 gramatica regulat G=<{B, S}, {a, b}, P, S> unde

7. S se scrie automatul finit determinist care accept urmtorul limbaj: {a, b, ab, abab, } P = {S , S aB, B aB, B bB, B a, B b} . Descriei limbajul aferent acestei gramatici n BNF. Trasai automatul finit care accept aceast limbajul asociat gramaticii. Aplicai procedura de conversie a automatului nedeterminist n automat finit determinist i listai automatul determinist echivalent.

MODULUL 2. INTRODUCERE IN PROGRAMAREA OBIECTUAL


Scopul si obiectivele modulului

In acest modul urmeaz s prezentm descrierea, realizarea si implementarea conceptelor de programare obiectual in C++. Aceste concepte sunt detaliate in curs [Silaghi 2008].
2.1. Paradigma programrii obiectuale Toate limbajele de programare realizeaz abstractizri. Atunci cnd scrie un program,

programatorul trebuie s gndeasc n limbajul neles de calculator pentru a rezolva o problem. Se stabilete astfel o coresponden ntre modelul mainii (n spaiul soluiilor) pe care se ruleaz programul i modelul problemei care se rezolv prin intermediul calculatorului. Activitatea de programare presupune stabilirea acestei asociaii pentru o problem cerut a se rezolva pe calculator. Pentru simplificarea acestei activiti de programare, este necesar inventarea unor limbaje de programare pentru care modelele mainii (spaiul soluiilor) s fie ct mai aproape de percepia uman despre spaiul problemei de rezolvat. Programarea obiectual asociaz elementelor din spaiul problemei obiecte n spaiul soluiilor. Principalele caracteristici ale unui limbaj de programare obiectual sunt: 1. Orice element este un obiect. Putem vedea obiectele ca i variabile care memoreaz date, dar n plus, putem adresa cereri obiectelor, solicitndu-le s-i schimbe starea. 2. Un program este o colecie de obiecte. Obiectele sunt legate unele de altele, transmindu-i mesaje. Putem vedea un mesaj ca i un apel de funcie. 3. Fiecare obiect are propriul spaiu de memorie, i este constituit din alte obiecte. Astfel, se pot crea noi tipuri de obiecte mpachetnd obiecte existente. 4. Fiecare obiect are un tip. 5. Toate obiectele dintr-un anumit tip pot primi acelai mesaj. Nume tip Interfaa
Figura 19.1 Exemplu simplu de clas Ligth on() off()

O clas descrie un set de obiecte care au caracteristici i funcionalitate identice. Clasa este un tip de date, aa cum sunt cunoscute tipurile de date n C. Cererile care pot fi

adresate unui obiect definesc interfaa obiectului. Funciile care compun interfaa unei clase se numesc metode. Figura 19.1 prezint exemplul clasei Ligth. Astfel, dac lt este un obiect de tipul Ligth, atunci putem cere acestui obiect realizarea mesajului on(): Implementarea const n modalitatea concret prin care se realizeaz funcionalitatea descris de interfa. Astfel, n exemplul prezentat anterior, implementarea va consta n aciunile concrete care trebuiesc realizate (programate) pentru a realiza operaia on(). n activitatea de scriere i utilizare a programelor informatice, se disting 2 tipuri de actori: programatori de clase noi programatori care folosesc clasele create de creatorii de clase. Programele scrise de acetia se numesc programe client. Scopul programatorilor de aplicatii client este de a colecta i utiliza un mediu de lucru care s conin cat mai multe clase, pentru a asigura dezvoltarea rapid aplicaiilor. Scopul programatorilor creatori de clase este de a construi clase care s furnizeze programatorilor clieni doar ceea ce este necesar, restul componentelor clasei urmnd s rmn ascunse. Se ajunge astfel la conceptul de ascundere a implementrii, descris n C++ prin cuvintele cheie public, private, protected. Aceste cuvinte cheie se numesc modificatori de acces. Dup ce o clas a fost creat, testat i ncepe s fie utilizat n programe client, se pot construi noi clase care s conin obiecte din clasa iniial. Astfel, se realizeaz reutilizarea implementrii, una din facilitile principale oferite de programarea obiectual. Procesul prin care se compune o nou clas nglobnd de la clase existente se numete compoziie1 (agregare). Dac avem creat o clas, i dorim s crem o clas nou, cu o funcionalitate similar cu a clasei iniiale (o clas care, eventual, s conin aceeai funcionalitate a clasei iniiale, extins cu proprieti noi), se folosete conceptul de motenire. Clasa iniial de la care pornete procesul de motenire se numete clas de baz. n cazul n care prin motenire, clasa nou are exact aceeai interfa ca i clasa de baz, avnd doar o funcionalitate diferit pentru metodele din interfa, spunem ca obiectele din tipul clasei derivate sunt de tipul clasei de baz. Un asemenea tip de relaie este denumit generic relaie de tip is-a.

Composition n lb. Englez

Dac ins, clasa derivat adaug funcionalitate nou prin crearea de noi metode n interfa, atunci spunem c obiectele de tipul clasei derivate se aseamn cu obiectele din clasa de baz. Relaia nou creat se numete generic relaie de tipul is-like-a. Prin motenire, se pot crea ierarhii de clase. ntre obiectele de tipul claselor din ierarhie se pot stabili relaii de tipul is-a sau is-like-a. Astfel, putem considera c obiectele din clasele derivate sunt n acelai timp i obiecte din tipul clasei de baz. Programarea orientat obiect ne permite s utilizm obiecte de tipul claselor derivate n locul obiectelor de tipul clasei de baz. Se obine astfel posibilitatea schimbrii obiectelor din clase diferite ntre ele, realizndu-se polimorfism prin interschimbare de obiecte. Prin polimorfism, compilatorul C++ va determina n momentul execuiei tipul din care face parte obiectul, apelnd funcionalitatea aferent metodei solicitate. Crearea i distrugerea obiectelor reprezint elemente importante de care trebuie s se in seama la scrierea programelor. La crearea obiectelor, memoria care se aloc acestora poate fi determinat la compilare. Variabilele (obiectele) declarate din cadrul programului sunt de acest tip. Acestea sunt obiecte globale: se aloca n zona static de memorie a programului obiecte cu vizibilitate local: se aloc n zona de stiv a programului

determinat la execuie. Variabilele (obiectele) create dinamic sunt de acest tip. Pentru acest tip de obiecte necesarul de memorie nu se poate determina n momentul compilrii. Aceste obiecte sunt alocate n zona de heap a programului. Pentru crearea dinamic a unui asemenea obiect n C++ se folosete cuvntul cheie new iar pentru distrugere delete. Pentru obiectele alocate static sau pe stiv, compilatorul se ocup de distrugerea acestora la terminarea programului sau a unei zone de vizibilitate. Pentru obiectele dinamice, programatorul trebuie s se ocupe de distrugerea acestora. Unele limbaje obiectuale (ex. Java) au un mecanism prin care mediul de execuie caut i identific obiectele alocate dinamic care nu mai sunt utilizate n program, i la identificarea lor, le dezaloc. Mecanismul care realizeaz aceast caracteristic se numete garbage collector i degreveaz programatorul de sarcina de a mai distruge obiectele. De multe ori, la execuia programelor, pot aprea situaii excepionale, care nu au fost prevzute la scrierea programului i care genereaz erori. Cu ct programatorul este mai vigilent la scrierea programelor, cu att mai mult scade probabilitatea ca programul realizat s furnizeze erori. Unele limbaje avansate de programare furnizeaz mecanisme

de evitare a erorilor, numite exception handling. Astfel, n momentul n care apare o eroare, se genereaz un obiect numit excepie care urmeaz s fie tratat n mod special de program ntr-un fir alternativ de execuie.
2.2. Analiza i designul programelor orientate obiect

Paradigma programrii obiectuale difer substanial de tipurile de programare anterioar, n sensul c programele trebuie gndite ntr-un mod diferit. Exist o metod de realizare a programelor orientate obiect. Metoda (metodologia) conine un set de procese i euristici prin care se sparge complexitatea unei probleme de programare obiectual. n programarea obiectual s-au dezvoltat multe metode orientate obiect de dezvoltare a programelor. nainte de a considera o asemenea metod pentru rezolvarea unei probleme, trebuie s se neleag tipul problemei pentru rezolvarea creia este destinat metoda. Cnd citim i dorim s nelegem o metod orientat obiect, trebuie s identificm rspunsul urmtoarelor ntrebri: Care sunt obiectele? - Care este interfaa acestor obiecte? Dac se identific obiectele i interfeele acestora, se poate ncepe cu scrierea programelor. Astfel, conform metodologiei obiectuale, procesul de realizare a programelor poate fi descris n 5 pai: Pasul 0: Se alege un plan care va fi urmat la rezolvarea problemei. Trebuie s se decid care sunt paii pe care procesul analizat n conine. Orice program se scrie cu un scop precis. Trebuie s se identifice de ce este necesar programul, care sunt obiectivele pe care acesta trebuie s le realizeze. Pasul 1: Se identific problema de rezolvat. Acest pas corespunde cu scrierea specificaiilor programului. Trebuie identificat ceea ce urmeaz s realizeze programul. Pentru descrierea funcionalitii programului, putem folosi diagramele cazurilor de utilizare (use-case ). Acestea descriu rspunsul la urmtoarele ntrebri: cine va folosi programul care sunt actorii din sistem ce fac aceti actori n (cu) sistem(ul) cum ar evolua sistemul dac actorii din sistem ar avea alte obiective dect cele specifice problemei studiate ce probleme ar putea s apar (cazuri n care sistemul ar furniza erori)

Pasul 2: se rspunde la ntrebarea: cum va fi construit sistemul? Acest pas furnizeaz proiectarea claselor, precum i a interaciunilor dintre ele. Pentru fiecare clasa trebuie identificate: numele clasei responsabilitatea clasei: ce funcionalitate are clasa colaborrile clasei: alte clase cu care clasa sub studiu interacioneaz

Pasul 3: se realizeaz nucleul sistemului. Presupune transcrierea designului furnizat n pasul precedent n cod surs, compilarea i executarea programului. n acest pas este important s se furnizeze un program funcional, care se execut, chiar dac acest program este incomplet, nu realizeaz toate cerinele problemei. Pasul 4: iterarea cazurilor de utilizare. Cnd avem un nucleu funcional, urmeaz s adugam la acest nucleu funcionaliti din cazurile de utilizare a programului. Fiecare nou funcionalitate adugat programului constituie o iterare a programului, respectiv o nou versiune a aplicaiei. Lungimea unei iteraii depinde de complexitatea aplicaiei care se realizeaz. Se ajunge la sfritul iteraiilor atunci cnd se realizeaz toate cerinele descrise n diagramele use-case, respectiv atunci cnd se ajunge la termenul limit de livrare a programului sau cnd programul este acceptat de client.

Pasul 5. Utilizarea programului. n aceast faz se observ modul n care programul rspunde utilizrii curente. Se asigur mentenan programului, rezolvndu-se eventuale buguri (erori semnalate). Analiza i designul programelor orientate obiect reprezint coninutul principal al disciplinelor din categoria software engineering (ingineria programrii i proiectare obiectual). n cadrul acestor discipline s-au dezvoltat metodologii concrete de lucru n medii obiectuale. Intre acestea amintim OMT2 i RUP3 n seciunea urmtoare vom descrie stilul de programare extreme programming (XP), avnd in vedere faptul c acesta permite o organizare eficient a lucrului in echipe cu puini programatori, pe proiecte de dimensiuni rezonabile. 2.2.1. eXtreme Programming

eXtreme Programming (XP) reprezint o filosofie alternativ pentru scrierea programelor, respectiv un set de reguli pentru analiza i realizarea programelor. Autorii

care au propus aceast alternativ o argumenteaz prin obinerea unui ctig de


2 3

Object Management Technology, standardizat de OMG Rational Unified Process, metodologie dezvoltat de Rational Software i preluat de IBM

productivitate respectiv de fiabilitate a activitii de programare. XP se bazeaz pe 2 principii: 1. Write tests first: Imediat ce se obine o bucat de cod care funcioneaz, programatorul trebuie s o testeze, pentru a se obine sigurana corectitudinii codului respectiv. Adoptarea acestei tehnici presupune scrierea de programe de test pentru fraciuni de cod, nainte ca aceste buci de cod s fie integrate n programul principal. Aceasta are 2 consecine eseniale: foreaz o definire clar a interfeei obiectelor testele sunt rulate ori de cte ori se realizeaz integrarea programelor.

2. Pair programming. Programarea trebuie realizat cu 2 programatori pe staie de lucru: una din persoane scrie codul iar cealalt se gndete la cum trebuie s arate codul. De obicei, cel care gndete pstreaz ntotdeauna o vedere de ansamblu asupra aplicaiei care trebuie realizat, nu numai asupra piesei de cod care se scrie la un moment dat. Pair programming este utilizat n firmele de software prin asigurarea unui analist sau a unui senior programmer la o echipa de programatori. Programatorul senior are viziune asupra aplicaiei scrise, cunoate detaliile de design ale aplicaiei, i intr n detaliile de implementare doar atunci cnd un programator membru al echipei nu poate realiza o anume funcionalitate. Recomandm utilizarea acestui stil de programare n activitatea de nvare a programrii obiectuale. Astfel, totdeauna, programatorii vor putea s se corecteze unul pe cellalt. Se va asigura astfel deprinderea mai rapid a cunotinelor necesare programrii, respectiv corectitudinea codului rezultat.
2.3. Formalizarea conceptului de obiect

n C, o structur reprezint o aglomerare de date, un mod de a mpacheta mai multe variabile pentru o utilizare comun a lor. n C++, un obiect este o variabil, adic un spaiu de memorie care are un identificator unic, care pstreaz date i specific operaiile care se pot executa asupra acestor date. Se numete ncapsulare abilitatea de a mpacheta mpreun date cu funcii, n vederea crerii de noi tipuri de date. Astfel, prin definiia lui CppVector s-a creat un nou tip de date. Ne referim la tipurile de date noi create prin sintagma de tipuri abstracte de date deoarece ele permit abstractizarea unor concepte din spaiul problemei de rezolvat. Sintagma
obiect.functieMembra(listaArgumente)

nseamn pentru compilator apelarea funciei membru pentru un obiect, iar n terminologie orientat obiect nseamn transmiterea unui mesaj ctre obiectul respectiv. Astfel, un program n C++ nseamn creare de obiecte i transmitere de mesaje ctre acestea. Mrimea unei structuri este egal cu mrimea adunat a tuturor membrilor structurii. Uneori, compilatorul adaug civa octei pentru a stoca informaii adiionale despre obiecte. Mrimea unui obiect poate fi identificat prin sizeof. La crearea de noi tipuri de date se dorete separarea interfeei de implementare. Astfel, declararea tipului de date se va realiza n fiiere header, iar implementarea (definirea funciilor) n fiiere cpp. Astfel, n programe mai complexe, vor putea schimba implementarea specific anumitor tipuri de date fr a fi nevoii s schimbm restul sistemului. Fiierele header sunt obligatorii pentru dezvoltarea programelor n C++. Fiierele header realizeaz contactul ntre programatorii de biblioteci i utilizatorii acestora. n acest sens, putem enuna o definiie informal de care se ine cont n activitatea de programare obiectual:
C++ one definition rule: pentru fiecare obiect C++ este permisa o singur definiie.

Astfel, n fiierele header trebuie plasate doar declaraii, n timp ce definiiile se vor plasa n fiierele cpp.

2.4.

Ascunderea implementrii

Programarea orientat obiect introduce controlul accesului la membrii unei structuri. Acesta este necesar deoarece: - programatorul client nu trebuie s poat accesa funcionaliti care nu i sunt destinate (cum ar fi manipulrile interne structurii) - programatorul bibliotecii de obiecte trebuie s poat schimba implementarea intern fr s afecteze eventualele programe client scrise deja, care utilizeaz biblioteca
2.4.1. Specificatori de acces

n C++ specificatorii de acces sunt utilizai n declaraii de structuri, i sunt urmai de :. Acetia sunt:

declaraiile care urmeaz acestui specificator sunt disponibile pentru oricine. Membrii public sunt identici cu membrii necalificai ai unei structuri. - private: declaraiile care urmeaz acestui specificator sunt disponibile doar n funciile membre ale tipului respectiv. Dac se ncearc s se acceseze un membru private, compilatorul genereaz eroare. - protected: este similar cu private; are semnificaie doar n contextul utilizrii motenirii. Astfel, clasele care motenesc din tipul n discuie au acces la membrii protected. Membrii protected nu se vd n afara ierarhiei de motenire. Specificatorii pot s apar n orice numr i ordine n cadrul unei structuri (clase). Aceti specificatori de access au rolul de a ascunde implementrile de interfee, i de a asigura un control eficient i o separare a datelor i conceptelor din program.
2.4.2. ncapsulare

public:

Controlul accesului mai este denumit i ascunderea implementrii. ncapsularea i controlul accesului conduce la definirea unor entiti care sunt mai mult dect simple structuri C. Astfel, prin ncapsulare, putem cuprinde mpreun date (proprieti) i funcii (comportament). Prin controlul accesului putem separa interfaa de implementare. Astfel, se poate schimba n orice moment implementarea fr a afecta funcionalitatea programelor care utilizeaz variabile de tipul respectiv (ele interacioneaz doar prin intermediul interfeei). Astfel, apare noiunea de clas, definit n C++ prin cuvntul cheie class. O clas este o structur, cu meniunea c toi membrii acesteia sunt implicit membrii privai, spre deosebire de struct unde implicit toi membrii sunt publici.
2.5. Construirea i distrugerea obiectelor. Suprancrcare
Constructori i destructor

2.5.1.

Un numr mare de erori C provin din faptul c programatorii uit s iniializeze variabilele, respectiv s dezaloce memoria la sfritul execuiei programului. Aceste erori sunt amplificate la utilizarea bibliotecilor, cnd programatorii clieni nu tiu cum s iniializeze datele din structuri, fie din ignoran, fie din lipsa unor documentaii adecvate a bibliotecilor. Constructorii vin s rezolve aceast problem Dac o clas are un constructor, compilatorul invoc n mod automat constructorul la crearea obiectului. Constructorul este o funcie membr a clasei care are acelai nume ca i clasa. Astfel, la definirea clasei avem urmtoarea declaraie de funcie membru:

Ca i orice alt funcie, constructorul poate primi argumente, i anume, elemente care s controleze modul n care este iniializat obiectul. n plus, se pot scrie mai muli constructori i apelul acestora se poate realiza n mai multe modaliti. Constructorii (i destructorii) nu au tip de return. Aceasta nseamn c tipul de return difer de void (care nseamn c funcia nu returneaz nimic). Dac constructorii ar avea tip de return (fie i void) atunci ar fi nevoie ca s se realizeze apelul explicit al acestora, deci constructorii nu s-ar mai putea apela implicit. Destructorii sunt funcii speciale membre ale claselor care se execut pentru a realiza tergerea (distrugerea) obiectelor. Numele destructorului este identic cu numele claselor, fiind precedat de particula ~. Destructorii nu au argumente i nici tip de return. Pentru variabilele alocate pe stiv, destructorul este apelat automat cnd obiectul iese din domeniul de vizibilitate. Aceasta se ntmpl chiar i atunci cnd se folosete saltul automat (goto) pentru a se iei dintr-un domeniu de vizibilitate. Pentru variabilele dinamice, alocate in zona de heap, destructorul este apelat la distrugerea acestor variabile prin operatorul delete. n C, variabilele trebuiau definite ntotdeauna la nceputul blocului de vizibilitate (de ex. la nceputul funciilor). Aceast regul nu se mai pstreaz n C++. Astfel, obiectele (i variabilele) pot fi definite oriunde n cod i definirea acestora se face de regul, ct mai aproape de locul de utilizare. n C++, nu se permite crearea unui obiect pn cnd constructorul acestuia nu va avea disponibile toate informaiile pentru apelul su (argumentele constructorului trebuie s fie definite i iniializate). Cu toate c putem defini variabile n orice loc n cod, alocarea memoriei pentru variabilele respective se realizeaz la nceputul domeniului de vizibilitate n care apare variabila. Variabila respectiv va fi disponibil pentru utilizare doar dup ce se ntlnete locul de definiie, cnd se realizeaz i apelul constructorului. Compilatorul va verifica inclusiv faptul ca definiia obiectului trebuie s se realizeze, deci constructorul trebuie s se poat apela la locul de definire al obiectului. Se numete constructor implicit (default), constructorul care nu are argumente. n cazul n care clasa are constructor, compilatorul va fora crearea obiectelor din clasa respectiv prin intermediul constructorului. In acest caz, este absolute necesar s se foloseasc in mod explicit constructorii la crearea obiectelor. Dac clasa nu are nici un constructor, atunci compilatorul va scrie (crea) automat un constructor implicit pentru clasa respectiv. Cu toate c se creeaz n mod automat un constructor implicit pentru obiect (n cazul n care clasa nu are constructori), comportamentul acestui constructor este nedefinit. n consecin, se recomand scrierea

de constructori pentru clase, i n mod special, definirea explicit a constructorului implicit. C++ garanteaz crearea obiectelor la nivelul unei uniti de compilare (funcie), n ordinea n care acestea sunt scrie. Distrugerea obiectelor se realizeaz n ordine invers crerii. Constructorul de copiere este constructorul clasei care primete ca i argument o referin la un obiect din tipul clasei respective. Astfel, constructorul de copiere creeaz obiectul pe baza unui alt obiect de acelai tip. Constructorul de copiere este esenial la transmiterea prin valoare a obiectelor din tipuri (clase) definite de utilizator. n cazul n care programatorul nu scrie un constructor de copiere n clas, compilatorul va genera n mod automat un asemenea constructor. La transmiterea prin valoare a unui obiect unei funcii , funciei i este transmis o copie a obiectului. Copia obiectului este obinut prin apelarea constructorului de copiere n cazul n care obiectul este de dimensiune mare, procesul de creare a copiilor transmise, respectiv de returnare a unor asemenea obiecte din funcii devine costisitor (din punct de vedere al timpului de execuie i al memoriei consumate). Constructorul de copiere este utilizat n special la transmiterea prin valoare. O alternativ la constructorul de copiere este evitarea transmiterii prin valoare. Pentru a se evita transmiterea prin valoare, constructorul de copiere trebuie declarat ca i membru privat al clasei. n acest mod doar funciile care sunt declarate friend n clasa respectiv vor putea realiza transmiterea prin valoare. n cazul n care nu exist nici o funcie care realizeaz transmitere prin valoare, definiia funciei membru constructor de copiere poate lipsi. O alt modalitate de evitare a constructorului de copiere este nlocuirea transmiterii prin valoare prin transmiterea de referine constante
2.5.2. Suprancrcarea funciilor

2.5.2.1. Conceptul de suprancrcare

Funcia reprezint un nume asociat unei aciuni (sau unui sir de aciuni). De multe ori apare o problem la modelarea spaiului problemei, cnd acelai nume are semnificaii diferite, n funcie de contextul de apel. Conceptul are mai multe nelesuri, este deci suprancrcat. n multe limbaje de programare (inclusiv C) se solicit utilizarea de nume diferite pentru sensuri diferite, sau n alt formulare, nume unice pentru fiecare neles distinct. n C++,

aceast regul nu se mai pstreaz. Un exemplu de nclcare a ei este utilizarea aceluiai identificator pentru numele clasei i numele constructorului. Suprancrcarea funciilor permite folosirea aceluiai identificator pentru a denumi mai multe funcii. La suprancrcarea funciilor, se poate folosi acelai nume, dar lista argumentelor trebuie s difere. Nu se poate realiza suprancrcarea funciilor numai pe tipul returnat. Deoarece constructorii sunt la rndul lor funcii, ei se pot suprancrca. Astfel, se pot scrie mai muli constructori pentru o clas.
2.5.2.2. Suprancrcarea operatorilor

Suprancrcarea operatorilor reprezint o nou modalitate de apel a funciilor, existnd o diferen doar n ceea ce privete modul de scriere a apelului. Astfel, argumentele funciilor nu mai apar ntre paranteze rotunde ci se scriu n jurul unor operatori, la fel ca la scrierea unor expresii care conin operatori. C++ permite definirea unor operatori care s funcioneze n conjuncie cu clasele. Definirea acestor operatori este similar cu definirea unor funcii membre. Pe lng modalitatea de suprascriere a operatorilor prin funcii membre, exist i posibilitatea de a defini operatorii ca funcii globale. Definirea unui operator suprancrcat este similar cu definirea unei funcii membru, cu diferena c numele funciei este operator@ unde @ reprezint operatorul care se suprancarc. Suprancrcarea se poate realiza i prin funcii globale. n acest caz, funcia suprancrcat poate fi declarat ca i friend n clasa pentru care se realizeaz suprancrcarea. La suprancrcarea operatorilor se aplic urmtoarea regul: - n cazul n care se suprancarc un operator ca i funcie membru i operatorul este binar, atunci funcia suprancrcat are un singur argument. - n cazul n care se suprancarc un operator ca i funcie membru i operatorul este unar, atunci funcia suprancrcat nu are argumente. - n cazul n care se suprancarc un operator ca i funcie global i operatorul este binar, atunci funcia suprancrcat are 2 argumente. - n cazul n care se suprancarc un operator ca i funcie global i operatorul este unar, atunci funcia suprancrcat are un singur argument. La suprancrcarea operatorilor, trebuie s se in cont de urmtoarele directive: - nu se pot suprancrca operatori care nu au sens n C (de exemplu operatorul ** - nu exist n C++)

prin supraincrcare nu se poate schimba precedena operatorilor. Aceasta rmne cea definit de limbajul C++ - prin suprancrcare nu se poate schimba numrul operanzilor cerui de un operator. Astfel, un operator C++ binar nu poate fi rescris ca i un operator unar. Se prezint urmtoarele caracteristici ale suprancrcrii operatorilor n C++: - operatorul ++ poate fi apelat att n forma prefixat ct i n forma postfixat. Pentru a suprancrca operatorul ++ n forma prefixat, ca i funcie membru, se scrie funcia n mod obinuit. Pentru a suprancrca ++ ca i operator postfixat, se scrie funcia membru avnd o un argument dummy (care nu se folosete niciodat). Astfel, cele 2 funcii vor avea semnturi diferite i compilatorul poate s discearn ntre ele. - pentru a suprancrca operatorul ++ n forma prefixat, ca i funcie global, se scrie o funcie global obinuit, cu un singur argument. Pentru a suprancrca operatorul ++ n forma postfixat ca i funcie global, se scrie funcia global avnd un argument dummy. Astfel, cele 2 funcii vor avea semnturi diferite i compilatorul poate s discearn ntre ele. - regulile de mai sus se aplic pentru suprancrcarea oricror operatori unari, la care exist forme postfixate i prefixate. Operatorul de atribuire poate fi suprascris doar ca i funcie membr. La operatorul de atribuire se recomand verificarea realizrii atribuirii ntre aceleai 2 obiecte (a=a). Atribuirea ntre aceleai 2 obiecte de obicei nu are sens. Urmtoarele reguli se aplic la transmiterea argumentelor i returnarea valorilor: - dac operatorul suprancrcat doar citete valorile operanzilor, argumentele se vor transmite prin referine (&) constante (ex. operatorul +). n cazul n care valoarea unui operand se modific, acel operand nu va mai fi transmis prin referin constant. - tipul valorii returnate depinde de semnificaia operatorului. Dac operatorul produce o valoare nou, atunci aceasta trebuie returnat prin valoare (i nu prin referin). Astfel, la operatorul + se returneaz un Integer constant (creat prin apelarea constructorului). - operatorii de atribuire trebuie s poat permite modificarea valorii returnate (pentru a permite a=b=c). Astfel, se vor returna referine (neconstante). Referinele neconstante permit utilizarea rezultatului atribuirii ca i operanzi stnga n expresii (ex.
(a=b).func(); )

- operatorii booleeni vor returna valori int i nu bool Din considerente de siguran, pentru a nu nclca principiile de verificrii de tip impuse de C++, unii operatori nu se pot suprancrca. Regulile urmtoare se aplic n ceea ce privete restriciile la suprancrcarea operatorilor:

nu se poate suprancrca operatorul . Dac operatorul . ar putea fi suprancrcat, nu ar mai exista posibilitatea de selecie a membrilor unei clase. - nu se poate suprancrca operatorul .* - nu exist operator pentru operaia exponent. - nu se pot inventa noi operatori fa de cei pe care C ii pune la dispoziie prin suprancrcare nu se poate schimba precedenta operatorilor
2.5.2.3. Considerente de design la suprancrcarea operatorilor

La designul claselor, apare ntrebarea referitoare la modul n care trebuie suprancrcai operatorii, adic la alegerea ntre suprancrcarea operatorilor prin funcii membre sau prin funcii globale. De obicei, dac nu exist vreo cerin expres, se alege suprancrcarea prin funcie membr. Suprancrcarea operatorilor prin funcii membre accentueaz asocierea dintre obiect i operatorul care i se aplic acestuia. Cnd obiectul apare ca i operand stnga n expresie, relativ la operator, atunci aceast abordare e cea mai potrivit. Apar cazuri cnd operandul din stnga este dintr-o alt clas dect cea n care ar trebui suprancrcat operatorul. n acest caz, cel mai uzual este utilizarea funciilor globale pentru suprascrierea operatorilor.
2.5.2.4. Suprancrcarea operatorului de atribuire

Operatorul de atribuire este un operator special care trebuie tratat special. Operatorul de atribuire este cumva similar constructorului de copiere. Astfel, el realizeaz copierea coninutului obiectului din dreapta n zona de memorie a obiectului din stnga atribuirii. Operatorul de atribuire trebuie suprascris ca i funcie membr. n cadrul funciei, trebuie copiat coninutul obiectului din dreapta (cel transmis ca i argument) n obiectul din stnga (cel asupra cruia se realizeaz apelul funciei). La suprascrierea operatorului de atribuire trebuie eliminat cazul de auto-atribuire. Aceasta se realizeaz prin inserarea unei verificri nainte de realizarea copierii membrilor. Realizarea copierii membrilor e mai dificil atunci cnd obiectele conin pointeri. Simpla copiere a valorii pointerilor ar face ca acelai obiect membru s fie referit de 2 pointeri. Distrugerea unuia dintre cele 2 obiecte ar realiza dezalocarea obiectelor referite, i ar introduce buguri n program. Acest comportament a putut fi observat i n cazul n care constructorul de copiere nu ine cont de acest lucru. n concluzie, se impune o abordare diferit n cazul atribuirii ntre obiecte care agreg indirect (prin pointeri) alte obiecte.

O prim abordare presupune copierea a tot ce se afl n spatele pointerilor membrii., n zonele de memorie aferente obiectului din stnga atribuirii. Aceast abordare trebuie considerat att pentru operatorul de atribuire ct i pentru constructorul de copiere. Constructorul de copiere i operatorul de atribuire duplic obiectul din spatele pointerului membru. Din momentul apelrii constructorului de copiere sau a operatorului de atribuire cele 2 obiecte sunt automat separate unul de cellalt. A doua abordare care poate fi considerat la scrierea constructorului de copiere sau la suprancrcarea operatorului de atribuire n cazul obiectelor cu pointeri este numrarea referinelor. Aceasta se aplic atunci cnd obiectele nou create necesit un spaiu de memorie mare sau cnd crearea de noi obiecte este dificil i costisitoare. Numrarea referinelor se realizeaz la nivelul obiectelor agregate indirect (prin pointeri). Acestea vor conine un contor care va numra de cte ori e referit obiectul (de ctre ali pointeri). La fiecare ataare de pointer ctre obiectul respectiv (adic apel de constructor de copiere sau asignare n clasa superioar), contorul se va incrementa; la fiecare distrugere de pointer (apelare de destructor pentru clasa superioar), contorul se va decrementa. n acest caz, acelai obiect va fi referit de pointeri aparinnd de obiecte diferite. Problema care apare n aceast abordare este la scrierea de date n obiectul referit. Dac contorul obiectului referit indic o valoare mai mare ca i 1, nseamn c mai multe obiecte refer obiectul n cauz iar scrierea va modifica datele altui obiect. Astfel, scrierea va fi permis doar n cazul n care obiectul agregat este referit doar o singur dat. n cazul n care dorim s scriem i n cazul general (cnd numrul de referiri este mai mare dect 1), atunci va trebui s duplicm obiectul referit, i s facem scrierea doar pe copia nou creat. Similar ca i la constructorul de copiere, n cazul n care programatorul nu suprancarc operatorul de atribuire compilatorul va genera un astfel de operator n mod implicit. Operatorul de atribuire creat implicit are acelai comportament ca i constructorul de copiere creat implicit. La apelarea operatorului de atribuire creat implicit, se asigur apelarea operatorilor de atribuire pentru membrii clasei respective.
2.6. Gestiunea dinamic a memoriei
Crearea obiectelor

2.6.1.

La crearea unui obiect C++, se realizeaz urmtoarele aciuni: 1. se aloc memorie pentru obiect

2. se apeleaz un constructor pentru iniializarea zonei de memorie alocate n pasul 1. Aceste 2 aciuni se realizeaz ntotdeauna la crearea obiectelor n C++. Alocarea memoriei se poate realiza n urmtoarele moduri: 1. zona de memorie poate fi alocat nainte de nceperea execuiei programului. Aceste zone se aloc n zona static de memorie, i ele exist pe toat durata execuiei programului. 2. zona de memorie poate fi alocat pe stiv, n momentul n care execuia programului ajunge la un nceput de domeniu de vizibilitate. Aceast zon alocat este automat eliberat n momentul in care programul ajunge la sfritul domeniului de vizibilitate. Aceste operaii de alocare - dezalocare de memorie sunt gestionate de compilator i ele sunt foarte eficiente. Programul ns, trebuie s cunoasc la momentul compilrii, numrul i mrimea acestor variabile. 3. zona de memorie poate fi alocat n zona de heap. Alocarea de memorie n zona de heap se realizeaz la execuia programului i se numete alocare dinamic. Alocarea dinamic se realizeaz prin intermediul unor funcii crora li se transmite necesarul de memorie de alocat. Programatorul este cel care controleaz mrimea memoriei astfel alocate precum i momentul alocrii. Dezalocarea este, de asemenea, lsat la decizia programatorului. Domeniul de via a acestor variabile dinamice este determinat de programator i nu intr sub incidena unor reguli de limbaj.
2.6.2. Crearea dinamic a obiectelor n C i C++

C furnizeaz 2 funcii de baz pentru alocare i dezalocare de memorie: malloc i free. Aceste funcii sunt practice dar destul de primitive, n sensul c programatorul trebuie s cunoasc bine mecanismul de alocare / dezalocare a memoriei dinamice pentru a le putea folosi. La apel funcia malloc trebuie s primeasc la intrare mrimea zonei de memorie care se dorete alocat i returneaz un pointer de tip void*. Deci malloc nu returneaz o zon de memorie aferent unui tip anume, iar n acest caz programatorul trebuie s converteasc acest pointer spre tipul dorit. Dup alocarea memoriei cu malloc programatorul trebuie s se ocupe n mod explicit de iniializarea zonei de memorie. C nu asigur o iniializare automat. La dezalocare, apelul funciei free trebuie precedat de apelarea unor destructori care s efectueze operaii uzuale de tergere a obiectului. Efortul de programare solicitat de limbajul C pentru utilizarea alocrii dinamice a memoriei este destul de mare, iar mecanismele de gestiune a memoriei sunt greoaie. De acea muli programatori evit pe ct posibil s foloseasc alocarea dinamic a memoriei, utiliznd mecanisme alternative mult mai ineficiente.

C++ a combinat aciunile necesare crerii dinamice a unui obiect n apelul unui singur operator: new. Acesta asigur alocarea memoriei necesare obiectului n zona de heap i iniializarea obiectului nou creat prin apelarea unui constructor. new poate fi utilizat pentru crearea obiectelor folosind oricare din constructorii definii pentru o clasa anume. Operatorul delete este complementar operatorului new. Acest operator asigur mai nti apelarea destructorului i apoi eliberarea memoriei. delete poate fi apelat doar pentru eliberarea memoriei alocate prin new. Nu se poate apela delete pentru dezalocarea memoriei alocate prin malloc. La tergerea prin delete a unui pointer care indic valoarea 0 (NULL) practic, nu se ntmpl nimic, de acea se obinuiete setarea unui pointer cu valoarea NULL imediat dup ce a fost dezalocat cu delete.
2.6.3. Managementul memoriei la execuie

La crearea obiectelor la momentul compilrii, mrimea i durata de via a obiectelor este strict determinat. Astfel, compilatorul tie n ce moment i unde (locaia exact de pe stiv) s aloce aceste obiecte. El va gestiona stiva ntr-un asemenea mod astfel nct programul s poat rula cu succes. Aceast gestiune a memoriei (a stivei) este realizat n momentul compilrii / link-editrii, atunci cnd se stabilesc locaiile i momentele unde respective cnd se vor aloca obiectele. n cazul alocrii dinamice a memoriei, exist o ncrcare suplimentar a programului pentru a determina locaia unde s se aloce memorie pentru o variabil dinamic. La o cerere de alocare, (malloc), funcia care implementeaz aceast alocare de memorie trebuie s caute un bloc de memorie liber suficient de mare, pentru a satisface nevoia de alocare i, nainte s returneze pointerul ctre zona de memorie alocat, trebuie s marcheze aceast zon ca fiind ocupat ntr-o hart a memoriei. Toate aceste proceduri necesare a fi executate la alocarea dinamic sunt implementate n cadrul unei strategii numite managementul memoriei, i reprezint o ncrcare suplimentar pentru sistem. Diverse compilatoare de C/C++ realizeaz managementul memoriei n mod diferit, ns rezultatul acestor funcii trebuie s fie acelai: s corespund standardului C/C++. Multe limbaje avansate de programare trateaz n mod diferit problema gestiunii dinamice a memoriei. Astfel, se pune la dispoziia programatorului mecanismul denumit garbage collector care adun i dezaloc toat memoria alocat dinamic dar rmas agat, fr posibilitatea de a mai fi referit. Mediile de programare Java i .Net furnizeaz asemenea mecaniste. n prezena garbage collector-ului, programatorul nu mai trebuie s se preocupe de dezalocarea memoriei alocate dinamic, deoarece sistemul va asigura n mod automat acest lucru.

La apelarea operatorului new se aloc memorie pentru obiect i apoi se apeleaz constructorul. La apelul operatorului delete se apeleaz destructorul i apoi se dezaloc memoria. Prin suprascrierea operatorilor new i delete se poate schimba modul de alocare respectiv dezalocare a memoriei, ns mecanismele de apel ale constructorului i destructorului rmne neschimbate. Mecanismul de alocare respectiv dezalocare a memoriei oferite de new i delete este unul de utilizare general. n majoritatea cazurilor acesta satisface nevoile programelor noastre. Unul din motivele care justific rescrierea acestor operatori este cel de eficien. Suprancrcarea operatorilor new i delete permite implementarea unui mecanism de alocare respectiv dezalocare particular, propriu cerinelor problemelor concrete. n cele ce urmeaz dm exemple de probleme concrete care necesit suprancrcarea acestor operatori: - existena unei clase la care frecvena crerii obiectelor s fie foarte mare. n acest caz, apar probleme de rapiditate a apelurilor operatorului new - existena unei frecvene mari a alocrii memoriei pentru obiecte de dimensiuni diferite. n acest caz, se poate ajunge la o fragmentare mare a memoriei, care s nu mai permit alocri de obiecte mari, chiar dac memorie liber (necontigu) exist. - probleme la alocare apar de obicei n sisteme n timp real care lucreaz cu resurse limitate pentru perioade lungi de timp. n astfel de sisteme alocarea memoriei trebuie s dureze un timp foarte scurt i de obicei, constant, iar probleme de epuizare a memoriei trebuie excluse. La supranrcarea operatorului new cnd un obiect este creat prin intermediul noului operator, compilatorul asigur urmtoarea funcionalitate: - se aloc spaiul de memorie folosind noul operator new - se apeleaz constructorul La suprancrcarea operatorului delete, cnd un obiect este distrus prin intermediul noului operator, compilatorul asigur urmtoarea funcionalitate: - se apeleaz destructorul - se dezaloc spaiul de memorie folosind noul operator delete. Trebuie inut cont c la rescrierea acestor operatori trebuie furnizat (rescris) i mecanismul de management al memoriei n cazul n care aceasta se epuizeaz.

2.7.

Programarea cu obiecte din mai multe clase


Compoziia

2.7.1.

Compoziie nseamn a crea o noua clas care conine ca i date membre obiecte din clase existente. Se spune c un obiect din noua clas agreg obiecte din clasele vechi (existente). Compoziia (agregarea) este de dou tipuri: - direct: atunci cnd obiectul membru este n mod efectiv parte component a obiectului din noua clasa - indirect: atunci cnd obiectul din noua clas refer (prin intermediul unui pointer) un obiect din clasa existent n descriere UML, structura de clase de mai sus poate fi reprezentat prin figura 79:
X -i : int +X() +set(in ii : int) : void +read() : int +permute() : int 1 1 Y -i : int -x : X +Y() +f(in ii : int) : void +g() : int +permute() : void

Figura 19.2 Reprezentarea grafic a agregrii

Rombul plin nseamn agregare direct. Agregarea este expresia unei relaii de tipul has-a, i se traduce prin expresia: un obiect din tipul X este membru al unui obiect din tipul Y, sau un obiect din tipul Y se compune dintr-un obiect din tipul X.
2.7.2. Motenirea

Prin motenire se creeaz o clas nou (clasa derivat) care se aseamn cu o clas existent (clasa de baz). Motenirea este expresia unei relaii de tipul is-like-a. Sintaxa motenirii presupune niruirea claselor de baz dup numele clasei care se creeaz, nainte de a se trece la corpul definiiei noii clase. C++ permite motenirea multipl, adic derivarea unei clase utiliznd mai multe clase de baz. Prin motenire noua clas va avea ca i membrii toi membrii clasei de baz. n plus, noua clas poate s i defineasc proprii membrii, sau s rescrie definiiile membrilor din clasa de baz. Subsetul de membrii din clasa de baz care vor fi motenii n clasa derivat se determin utiliznd regulile de combinare a specificatorilor de acces. n rescriere UML, structura de clase din exemplul de mai sus este reprezentat n figura 19.3.

X -i : int +X() +set(in ii : int) : void +read() : int +permute() : int

Y -i : int +Y() +change() : int +set(in ii : int) : void

Figura 19.3 Reprezentarea grafic a motenirii

Noua clas Y motenete toate datele membre ale lui X. De fapt Y conine un subobiect de tipul X ca i cum am fi realizat agregarea tipul X n tipul Y. Astfel, la apelul sizeof se remarc faptul c Y ocup mai mult spaiu dect X. Membrii privai ai lui X exist n continuare ca i membrii privai ai subobiectului, ns mecanismul private funcioneaz, adic nu putem accesa aceti membrii din afara obiectului de care aparin (care este de tip X). Deci, Y motenete doar membrii din interfaa lui X, la care se poate avea acces din afar. Se observ modul n care metoda set din clasa Y redefinete metoda set din clasa X. In acest caz, nu e vorba de suprancrcare, deoarece semnturile celor 2 funcii (cea din clasa X i cea din clasa Y) sunt identice. La invocarea metodei set pe un obiect din clasa Y se va apela metoda set redefinit. Se observ utilizarea cuvntului cheie public nainte de numele clasei de baz. Dac s-ar omite aceast specificare, n mod implicit, motenirea funcioneaz ca i privat, adic, toi membrii publici ai clasei de baz s-ar moteni ca i membrii privai n clasa derivat. Prin folosirea cuvntului cheie public, toi membrii publici din clasa de baz se motenesc ca i membrii publici n clasa derivat.
2.7.3. Combinarea compoziiei cu motenirea

Compoziia i motenirea pot fi combinate la libera alegere a programatorului. Astfel, se pot crea sisteme orict de complexe i extensibile. Figura de mai jos prezint un exemplu de combinare a agregrii cu motenirea.

B -i : int +B() +~B() +f() : void

A -i : int +A() +~A() +f() : void 1 1 -a : A

C +C() +~C() +f() : void

Figura 19.4 Agregare i motenire combinate

Se observ c de multe ori, la crearea obiectelor complexe este nevoie de apel explicit al constructorilor. Apelul destructorilor acestor obiecte se realizeaz n mod automat, de ctre compilator. Seciunea urmtoare va trata n detaliu ordinea de apel automat a constructorilor i destructorilor, n cazul combinrii compoziiei cu motenirea.
2.7.4. Iniializarea obiectelor n cazul folosirii compoziiei i motenirii

La crearea unui obiect, compilatorul C++ garanteaz apelarea constructorilor pentru toate obiectele membre ale obiectului respectiv. Aceasta nseamn apelarea constructorului implicit pentru sub-obiecte. Problema apare n momentul n care clasele agregate nu au definii constructori implicit, sau atunci cnd la iniializare dorim s transmitem un alt argument n locul argumentului implicit. Aceast problem este rezolvat prin utilizarea listei de iniializare. n cazul motenirii, utilizarea listei de iniializare presupune apelarea explicit a constructorului clasei de baz. Constructorii obiectelor agregate trebuie s fie apelai nainte de a se trece la execuia codului din corpul constructorului clasei curente. n momentul n care se execut corpul constructorului curent, obiectele membre trebuie s fie deja iniializate. Regula de apelare a constructorilor i destructorilor n cazul utilizrii combinate a agregrii i motenirii este prezentat n cele ce urmeaz: Mai nti se apeleaz constructorul clasei de baz, apoi se apeleaz constructorii obiectelor agregate, n ordinea in care apar in definiia clasei. Ordinea constructorilor n lista de iniializare nu afecteaz ordinea n care sunt apelai constructorii. Pentru fiecare apel de constructor, aceast regul se aplic ntocmai. Destructorii se apeleaz ntotdeauna n ordine invers a apelului constructorilor, pentru aceleai obiecte.

2.7.5.

Ascunderea numelor prin motenire

n general, se poate spune c ori de cte ori ntr-o clas derivat se redefinete o funcie suprancrcat n clasa de baz, funciile suprancrcate din clasa de baz devin ascunse. Se consider c prin motenire se import interfaa clasei de baz n clasa derivat. Astfel, dac clasa de baz suport polimorfismul prin suprancrcarea funciilor, atunci aceast facilitate rmne prin utilizarea motenirii. Dac, n plus, n clasa derivat, se schimb definiia uneia din funciile importate care intr sub incidena polimorfismului, nseamn c se dorete schimbarea interfeei motenite din clasa de baz, deci aceasta nu se mai motenete deloc in clasa derivat. Redefinirea funciilor membre ale claselor de baz este util la specializarea coleciilor generice. De multe ori este nesigur s returnm pointeri void, deoarece acetia pot fi convertii de ctre programul client ctre orice tip dorit, fr s fim atenionai n vreun fel de compilator. Soluia este s specializm clasa colecie generic pentru un anume tip de elemente. Astfel, vom moteni din clasa generic o nou clas care va avea redefinite funciile din interfa pentru a suporta un anume tip specific. Problema acestei abordri este c prin specializare schimbm n mod drastic interfaa clasei de baz. Se pune problema utilitii motenirii n acest caz. La realizarea operaiei de motenire, urmtoarele funcii membre nu se motenesc din clasa se baz n clasa derivat: - constructorii i destructorii - operatorul de atribuire, deoarece realizeaz o operaie similar constructorului de copiere
2.7.6. Considerente de design a claselor

n aceast seciune se vor prezenta cteva considerente care trebuiesc urmate la alegerea ntre utilizarea compoziiei i a motenirii la crearea aplicaiilor orientate obiect. Compoziia i motenirea reprezint dou modaliti prin care programele existente se pot extinde i reutiliza. Avantajul principal al acestor dou modaliti de reutilizare a codului este posibilitatea de dezvoltare incremental a programelor. Astfel, putem scrie cod nou, respective s adugm faciliti noi programelor existente fr s fie nevoie s rescriem codul deja existent. Astfel evitm introducerea de buguri n programele existente care probabil sunt deja funcionale. Bugurile care apar n programe pot fi astfel izolate la nivelul noului cod scris.

Este important de neles c dezvoltarea incremental a programelor este similar cu procesul uman de nvare. Astfel, referitor la un domeniu anume, putem realiza o activitate de analiz orict de cuprinztoare dar nu vom reui s cuprindem toate aspectele domeniului la momentul realizrii analizei. Astfel, pentru a putea continua i a reui s furnizm software util, dezvoltarea incremental devine esenial.
2.7.7. Subtyping

n general, compoziia se utilizeaz atunci cnd dorim s utilizm caracteristicile unui obiect dintr-o clas existent, dar nu dorim s furnizm aceeai interfa. Astfel, vom agrega obiectul din clasa existent ca i un membru privat al noii clase. O a doua modalitate de utilizare a agregrii este atunci cnd dorim s extindem un tip existent cu o nou funcionalitate. Dac pentru realizarea acestei noi funcionaliti avem nevoie de date noi, o soluie ar fi agregarea unui obiect din tipul existent mpreun cu datele noi i crearea unui tip nou. Tipul nou trebuie s fie echipat cu un mecanism de conversie automat nspre tipul care se dorete extins, pentru a putea utiliza noile obiecte cu funciile client existente deja pentru tipul vechi. Aceast abordare a problemei este depit, datorit faptului c ea solicit rescrierea tuturor metodelor interfeei tipului vechi n noul tip. Chiar dac am echipat noua clas cu un mecanism de conversie automat, aceasta nu se realizeaz n cazul n care obiectul din tipul respectiv este prezent ntr-o expresie ca i operand stnga. n acest caz, soluia este utilizarea motenirii. De exemplu, putem extinde clasa ifstream, adugnd o nou funcionalitate: memorarea numelui fiierului asociat obiectului de tip ifstream. Pentru aceasta, noua clas trebuie s moteneasc din clasa ifstream i s agrege un obiect de tipul string n care s se memoreze numele fiierului asociat. Acest procedeu se numete sub-typing.
2.8. Upcast

Upcast reprezint una din proprietile cele mai importante introduse de paradigma obiectual prin conceptual de motenire. Astfel, upcast nseamn c obiectele din tipul claselor derivate sunt n acelasi timp i din tipul clasei de baz. S considerm o clas de baz Intrument, i o clas derivat Wind. Clasa derivat motenete toate metodele interfeei clasei de baz. Astfel, dac vom putea trimite un mesaj unui obiect de tip Instrument, acelai mesaj l vom putem trimite i unui obiect de tipul Wind. Astfel, putem spune c un obiect de tip Wind este n acelai timp i de

tipul Instrument. Clasa Instrument deine o metod play care este specific claselor derivate, precum clasa Wind. Oricum, la transmiterea argumentelor pentru o funcia redefinit a clasei Instrument, compilatorul realizeaz conversia automat a pointerului de tip Wind n pointer de tip Instrument. Aceasta reprezint n fapt, operaia de upcast. Revenind la ntrebarea referitoare la alegerea ntre compoziie i motenire, una din modalitile cele mai bune de a decide care concept s-l folosim este s ncercm s rspundem la urmtoarea ntrebare: pe parcursul programului, operaia de upcast va fi necesar? n caz afirmativ, se recomand utilizarea motenirii. n caz negativ, utilizarea compoziiei.
2.8.1. Extensibilitate prin funcii virtuale

La apelul unei funcii, aducerea n contextul curent i execuia corpului unei funcii se numete legarea funciilor. Atunci cnd legarea funciilor se face nainte de execuia programului, se spune c avem legare nainte (early binding). Early binding se face ntotdeauna n faza de link-editare a programului. n limbajele procedurale (C) early binding reprezint singura modalitate de legare a corpului unei funcii de apelul acesteia. Alternativa la early binding o reprezint legarea ntrziat (late binding) adic legarea dinamic a corpului funciei de apelul acesteia exact nainte de realizarea apelului. Legarea ntrziat presupune existena unui mecanism care s determine tipul exact al obiectului nainte de apelul funciei. Astfel, prin determinarea exact a tipului nainte de apel, se poate face legare la versiunea corect a funciei, i anume la cea re-definit n cazul n care ne situm ntr-un program cu ierarhii de clase. Pentru a determina activarea mecanismului de legare ntrziat pentru o funcie declaraia acestei funcii n clasa de baz trebuie precedat de cuvntul cheie virtual. Redefinirea unei funcii virtuale ntr-o clas derivat se numete overriding. Prin declararea virtual a unei funcii ntr-o clas de baz, pentru oricare din funciile redefinite n clasele derivate se va realiza legarea ntrziat. In exemplul analizat, aceasta presupune inserarea cuvntului cheie virtual nainte de declaraia metodei play n clasa Instrument. Mecanismul funciilor virtuale funcioneaz indiferent de nivelul de motenire. n contextul polimorfismului, metodele care se apeleaz pentru obiecte din clasele de baz (precum metoda tune) pot fi privite ca i o trimitere de mesaj ctre un obiect i responsabilizarea obiectului destinaie cu privire la modul de tratare a mesajului. Astfel,

obiectul (n funcie de tipul su determinat la execuie) va trata mesajul ntr-o manier proprie, specific.
2.8.2. Mecanismul de implementare a funciilor virtuale

Mecanismul funciilor virtuale se bazeaz pe o tabel numit tabela funciilor virtuale. Aceast tabel exist pentru fiecare clas care conine funcii virtuale i este gestionat de compilator. Astfel, atunci cnd compilatorul ntlnete la compilarea unei clase declaraia unei funcii virtuale, plaseaz n aceast tabel un pointer ctre aceast funcie. Astfel, tabela funciilor virtuale va conine referine ctre toate funciile virtuale, pentru o anume clas. n fiecare clas care conine funcii virtuale, compilatorul va crea un membru (ascuns) care este o referin ctre tabela funciilor virtuale. La apelul unei funcii virtuale printr-o referin de tip upcast, compilatorul genereaz cod (n codul obiect rezultat dup compilare) care se va executa exact nainte de realizarea apelului. Acest cod acceseaz tabela funciilor virtuale prin pointerul membru ascuns i datorit faptului c la execuie se cunoate tipul obiectului sub care se face apelul, se regsete din tabela funciilor virtuale adresa corect a funciei care trebuie s se apeleze i astfel se asigur apelul funciei corespunztoare. Mecanismul descris mai sus este realizat n mod automat de compilator. Singura problem rmas neclarificat este modul n care se realizeaz determinarea tipului la execuie. Aceasta este necesar pentru lucrul cu tabela funciilor virtuale. Modul de memorare a tipului n cadrul obiectelor se poate determina prin crearea de obiecte fr date membre. Astfel, chiar dac avem un tip care nu are date membre, la crearea de obiecte din tipul respectiv vom vedea c obiectele respective ocup memorie. Deci sizeof aplicat pe acele obiecte returneaz o valoare diferit de 0. Zona respectiv de memorie este ocupat de un membru dummy care exist in orice tip i deci n orice obiect. Acel membru dummy este utilizat tocmai pentru a stoca tipul obiectului. Prin interogarea, la execuie, a membrului dummy se poate afla tipul concret al obiectului (la execuie). Operaia de upcast se realizeaz doar n cazul convertirii ntre tipuri-adrese. Astfel, avnd adrese la dispoziie, i nu obiecte efective, compilatorul poate amna realizarea legrii unui apel de funcie cu corpul funciei. Regula de baz dup care funcioneaz compilatorul este c ori de cte ori are posibilitatea, acesta realizeaz legare nainte. Astfel, n cazul obiectelor efective (variabilelor de tip obiect), ntotdeauna se utilizeaz early binding, iar pentru utilizarea mecanismului funciilor virtuale e nevoie de folosirea pointerilor.

Mecanismul funciilor virtuale asigur apelul funciei potrivite la contextul potrivit. Se pune ntrebarea de ce acest mecanism nu este apelat ntotdeauna, pentru orice apel de funcie? Problema este una de eficien. Astfel, un apel de funcie virtual este destul de costisitor ca i timp de execuie deoarece presupune inserare de cod suplimentar la momentul compilrii, i

ca i spaiu de memorie ocupat deoarece e nevoie de o tabel suplimentar, tabela funciilor virtuale. Datorit faptului ca C++ provine din C care este un limbaj orientat spre eficien, alegerea a fost s se ofere mecanismul funciilor virtuale doar la cerere. Deci, implicit o funcie n C++ este non-virtual. Se recomand utilizarea funciilor virtuale doar n cazul crerii de clase polimorfice, deci a utilizrii conceptului de motenire.
2.9. Clase abstracte

De multe ori n designul unei aplicaii dorim s punem n clasa de baz doar interfaa viitoarelor obiecte, i nu s crem obiecte din clasa respectiv. Clasa de baz va fi folosit doar pentru operaia de upcast care va permite astfel tratarea unitar a obiectelor derivate, care au aceeai interfa. Pentru a realiza acest lucru, vom transforma clasa de baz ntr-o clas abstract. O clas se numete abstract dac are cel puin o funcie virtual pur. O funcie virtual pur este ntotdeauna precedat de cuvntul cheie virtual i declaraia e urmat de =0. Compilatorul mpiedic definirea de obiecte din clasele abstracte. Atunci cnd se motenete dintr-o clas abstract, clasa derivat trebuie s implementeze toate funciile virtuale pure. n cazul n care n clasa derivat nu este implementat cel puin o funcie virtual pur, clasa derivat devine la rndul su o clas abstract. Funciile virtuale pure foreaz astfel s fie implementate, n clasele derivate, care se doresc a fi clase efective. n exemplul cu ierarhia de instrumente muzicale, metodele din interfaa acestei clase sunt doar de complezen, adic au fost definite deoarece este nevoie de definirea lor pentru ca programul s funcioneze. Aceste metode nu furnizeaz un rspuns util. Intenia clasei Instrument este s se creeze o interfa pentru clasele care se vor deriva, astfel nct obiectele din clasele derivate s poat fi folosite in mod unitar. Astfel, clasa Instrument este un bun exemplu de posibil clas abstract. De obicei, se creeaz o clas abstract atunci cnd dorim s manipulm obiecte din diverse clase printr-o interfa comun. Clasele abstracte de obicei nu implementeaz interfaa respectiv.

n alte limbaje obiectuale, exist conceptual distinct de interfa. Astfel, n Java o interfa este similar unei clase abstracte, cu deosebirea c interfeele nu agreg obiecte, i toate metodele din interfa sunt metode virtuale pure. Prin utilizarea funciilor virtuale pure i a claselor abstracte se mpiedic crearea efectiv de obiecte din aceste clase. Astfel, tipul unei clase abstracte nu poate fi folosit ca i tip de argument transmis prin valoare, n cazul unei funcii oarecare. Se foreaz astfel utilizarea pointerilor, deci asocierea dintre upcast i pointeri. Cu toate c de obicei funciile virtuale pure nu sunt implementate n clasa abstract, este totui posibil s se scrie implementarea acestor funcii. Chiar dac o clas abstract va implementa o funcie virtual pur (adic funcia este declarat n definiia clasei ca i virtual pur, dar programatorul scrie o definiie pentru aceast funcie), mecanismul clasei abstracte se pstreaz, adic, n continuare, compilatorul mpiedic crearea de obiecte din aceast clas. De multe ori definirea funciilor virtuale pure este convenabil atunci cnd dorim s scriem o bucat de cod care s fie apoi apelat din toate sau din unele clase derivate, eventual din metodele care redefinesc aceast funcie.
2.9.1. Implementarea claselor n contextul funciilor virtuale

n cazul motenirii i a redefinirii, se pune problema modului de funcionare a funciilor virtuale. S presupunem cazul n care n clasa de baz exist funcii virtuale. n acest caz, se creeaz o tabel a funciilor virtuale pentru clasa de baz, tabel care conine locaii pentru toate funciile virtuale declarate n clas. n cazul n care se creeaz o nou clas derivat din clasa de baz, tabela funciilor virtuale pentru noua clas va conine intrri pentru funciile virtuale din clasa de baz exact la aceeai indici ca i tabela funciilor virtuale a clasei de baz. Dac redefinim o funcie virtual a clasei de baz, tabela funciilor virtuale pentru clasa derivat va memora adresa funciei redefinite n locul adresei funciei din clasa de baz. Dac clasa derivat declar are n plus alte funcii virtuale, acestea se vor aduga n locaii succesive n tabela funciilor virtuale din clasa derivat. Astfel, modul de scriere (declarare) a funciilor virtuale nu este identic cu modul de stocare a acestora n tabela funciilor virtuale. Astfel, la realizarea operaiei de upcast, atunci cnd compilatorul vede o referin la un obiect din clasa de baz, el de fapt vede (i acceseaz) zona de tabel virtual corespunztoare obiectului din clasa derivat (la momentul apelului). La utilizarea unui pointer dintr-un tip de baz, chiar dac acesta refer un obiect din clasa derivat, compilatorul nu va ti s acceseze dect funcii din propria tabela virtual. Pentru a se

accesa i alte funcii, e nevoie de realizarea explicit a operaiei de downcast (conversie explicit nspre tipul clasei derivate). La realizarea operaiei de downcast, programatorul trebuie s tie ca ntradevr, la momentul apelului, pointerul respectiv refer un obiect din tipul derivat. Compilatorul nu are de unde s cunoasc tipul obiectului la momentul realizrii apelului. Transmiterea prin referin permite folosirea upcast-ului. Acesta este posibil datorit faptului c, indiferent de tipul actual referit, pointerii au aceeai mrime fizic. n cazul obiectelor, dac ele sunt din tipuri diferite este de ateptat ca ele s ocupe spaii de memorie de mrime diferit. Mai mult, n cazul derivrii, un obiect din clasa derivat ocup cel puin atta memorie ct obiectul din clasa de baz. Astfel, dac transmitem prin valoare un obiect din clasa derivat ntr-un obiect din clasa de baz se realizeaz o transferare efectiv doar a sub-obiectului din clasa de baz, coninut n obiectul din clasa derivat. Deci, tot ce s-a redefinit sau adugat prin derivare se pierde. Compilatorul nu va genera eroare deoarece tipurile sunt compatibile. Suprascrierea unei funcii definite n clasa de baz ascunde toate definiiile i formele funciei respective din clasa de baz. Aceast regul se menine i n cazul n care se utilizeaz funciile virtuale, cu o singur excepie: nu vom putea redefini o funcie virtual prin schimbarea tipului de return. Mai mult, dac redefinim o funcie virtual i schimbm semntura funciei (numrul i tipul argumentelor) atunci n clasa derivat se va vadea numai noua funcie. n schimb, cnd realizm operaia de upcast se vor vedea numai funciile din clasa de baz. Astfel prin redefinire putem schimba tipul de return a funciei din clasa de baz, dac funcia respectiv nu este virtual. Aceast regul e ngrdit puin n cazul n care funcia din clasa de baz returneaz un pointer ctre un tip care la rndul su poate fi vrful unei ierarhii de clase. Astfel, n clasa derivat, dac dorim s schimbm tipul de return, putem cel mult s l schimbm ntr-un pointer ctre o clas derivat din tipul de return a clasei de baz. n cazul claselor care conin funcii virtuale, constructorii acestor clase realizeaz iniializarea tabelei funciilor virtuale. Aceast operaie e realizat n mod automat de constructor. Astfel, compilatorul plaseaz cod la intrarea n orice constructor care s iniializeze tabela funciilor virtuale. La apelul constructorilor, ordinea de iniializare se pstreaz. Astfel, la construirea unui obiect dintr-o clas derivat, mai nti se apeleaz constructorul clasei de baz i apoi se trece la execuia constructorului curent. Apelul constructorului clasei de baz se realizeaz la intrarea n constructorul clasei curente.

n cazul n care din constructor se apeleaz o funcie virtual, se va face legare doar ctre versiunea local (din clasa) a acelei funcii. n cadrul constructorului mecanismul funciilor virtuale e dezactivat. O funcionalitate similar se ntmpl i n cazul destructorilor. Astfel, dac ntr-un destructor se apeleaz o funcie virtual, ntotdeauna de va apela versiunea local a acestei funcii. n cazul constructorilor nu se poate folosi cuvntul cheie virtual. n cazul destructorilor se poate folosi cuvntul cheie virtual i astfel se creeaz destructori virtuali. Apelul destructorilor se realizeaz n ordine invers fa cel al constructorilor. Astfel, destructorii se apeleaz pornind de la clasa cea mai din josul ierarhiei i continu pn la apelul destructorului clasei din vrful ierarhiei. Folosirea destructorilor virtuali intervine atunci cnd dorim s eliberm memoria referit de pointeri generici, care indic ctre obiecte din tipul de baz. Astfel de pointeri, pot referi (prin upcast) obiecte derivate. Dac apelm operatorul delete pentru un asemenea pointer, el va ti s apeleze destructorul clasei de baz, care nu are cum s elibereze corect memoria pentru un obiect din clasa derivat. In acest caz, e nevoie ca obiectele din clasa derivat s conin destructorul n lista funciilor virtuale, pentru a se putea apela destructorul corect.
2.9.2. Downcast

Downcast reprezint operaia de conversie ntre un tip din partea de sus a unei ierarhii i un tip specializat. Downcast este operaia invers upcastului. La upcast realizarea conversiei este o chestiune simpl, datorit faptului c se cunoate i se determin exact tipul destinaie a conversiei. La downcast, problema apare datorit faptului c tipul destinaie nu este unic determinat.
2.10. Design pattern-i

Prin pattern ne referim la o problem (de programare) care se repet foarte frecvent n proiectele pe care trebuie s le realizm. Datorit acestei frecvene a repetrii, putem s presupunem c la fiecare ntlnire a problemei respective vom folosi acelai procedeu rezolvare. Deci, prin pattern putem nelege att problema n sine ct i soluia adoptat generic pentru rezolvarea acestei probleme. Astfel, un design pattern reprezint o soluie conceptual n termeni de programare obiectual furnizat unui tip probleme specifice.

Design pattern-urile reprezint un nivel superior de nelegere a programrii obiectuale i ajut programatorii s realizeze soluii scalabile, flexibile la modificarea cerinelor, reutilizabile n condiiile unor probleme similare.
2.10.1. Singleton

Singleton reprezint unul din cele mai folosite abloane de proiectare (design pattern). Singleton-ul se utilizeaz atunci cnd dorim s ne asigurm c doar un singur obiect dintr-o clas va putea exista la un moment dat n aplicaie. Un singleton se definete prin agregarea ca i dat membru static a unei clase a unui obiect de tipul clasei respective. Prin declararea constructorului clasei respective ca i privat se poate obine existena unui singur obiect din clasa respectiv, pe toat execuia programului. Accesarea acestui obiect se realizeaz prin intermediul unei funcii statice. Astfel, singleton-ul asigur un punct de acces global la obiectul respectiv. Figura 19.5 prezint diagram UML asociat pattern-ului Singleton. Figura 45 prezint implementarea pattern-ului n C++.
1 Singleton -static instance : Singleton +static getInstance() : *Singleton -Singleton() 1

Figura 19.5 Design pattern-ul Singleton n specificaie UML

Declararea privat a unui constructor de copiere este necesar pentru a nltura alte modaliti de creare a obiectelor de tip Singleton. Constructorii de copiere vor fi tratai n capitolul urmtor.
2.10.2. Iterator

Un iterator este un obiect asociat unei colecii de obiecte. Prin intermediul iteratorului putem avea acces la cte un membru al coleciei la un moment dat. Prin intermediul iteratorului se inhib accesul direct la colecia asociat acestuia. Suprancrcarea operatorului de derefereniere se realizeaz printr-o funcie membr. Aceasta trebuie s returneze un obiect (sau o referin ctre un obiect) care poate fi operand n operaia de derefereniere (sau poate returna un pointer care s permit operaia de selecie).

Obj -static i : int -static j : int +f() : void +g() : void ObjContainer -a : vector<Obj*> +add(in obj : Obj*) : void

SmartPointer -oc : ObjContainer& +SmartPointer(in objc : ObjContainer&) +operator++() : bool +operator++(in dummy : int) : bool +operator ->() : Obj*

Figura 19.6 Diagrama UML asociat unui iterator implementat prin suprascrierea operatorilor

2.11.

ntrebri recapitulative

1. Care sunt principalele caracteristici ale unui limbaj de programare obiectual? 2. Descriei actorii care participa la scrierea i utilizarea programelor informatice. Care este scopul acestor actori? 3. Care sunt paii care trebuie urmai pentru realizarea programelor, conform metodologiei obiectuale? 4. Descriei metoda pentru eXtreme Programming, pentru realizarea programelor informatice. 5. Ce este un obiect obiect? n ce const implementarea i interfaa obiectului? 6. Ce nelegei prin separarea interfeei de implementare i cum se realizeaz acest lucru n C++? 7. De ce este necesar ascunderea implementrii? 8. Care sunt specificatorii de acces folosii n C++? 9. Ce este un constructor? Care sunt tipurile de constructori posibili ai unei clase? 10. Ce este un destructor? 11. Ce este un constructor de copiere? De ce este acesta important? 12. Cum se poate evita folosirea constructorului de copiere n programele obiectuale? 13. Ce nelegei prin suprancrcarea funciilor? 14. Ce nelegei prin suprancrcarea operatorilor? 15. Enunai cteva reguli de care trebuie s se in cont la suprancrcarea operatorilor. 16. Care sunt principiile care trebuie aplicate la suprancrcarea operatorului de atribuire? 17. Care este criteriul esenial care trebuie aplicat la alegerea ntre suprancrcarea unui operator prin funcie membr sau funcie global?

18. Descriei metoda numit numrarea referinelor care se poate aplica la suprancrcarea operatorului de atribuire. 19. Care sunt aciunile care se efectueaz la crearea efectiv unui obiect pe parcursul rulrii programului? 20. Cum se realizeaz alocarea memoriei n C++? 21. Cum se realizeaz crearea dinamic a obiectelor n C++? 22. Descriei alternativele existente de gestiune a memoriei n C++? 23. Cum realizeaz limbajul de programare JAVA gestiunea memoriei? 24. Definii compoziia. De cte tipuri este aceasta? 25. Definii motenirea i enuntai principalele caracteristici ale acesteia. 26. Cum se realizeaz iniializarea obiectelor n cazul combinrii compoziiei cu motenirea? 27. Cum se realizeaz ascunderea numelor prin motenire? Ce este specialiarea? 28. Ce nseamn subtyping? Cum se poate realiza acest procedeu prin compoziie respectiv prin motenire? 29. Ce nseamn upcast? 30. Definii conceptul de legare a funciilor i cum se realizeaz acest concept? 31. Ce este o funcie virtual? Care sunt avantajele folosirii acestor funcii? 32. Care este mecanismul de implementare a funciilor virtuale? 33. Ce nseamn determinarea tipului la execuie? 34. Ce este o clas abstract? 35. Definii conceptul de interfa n limbajele obiectuale. 36. Care sunt diferenele ntre suprancrcarea funciilor, refedinirea funciilor n contextul motenirii i overriding? 37. Ce este un design pattern? 38. Descriei design patternul singleton. 39. Descriei design patternul iterator.

III.

Anexe

Bibliografie

1. G.C. Silaghi, Mircea Moca Limbaje de Programare. Metode Obiectuale. Ghid teoretic si practic. Editia 2-a, Ed. Risoprint, 2008 2. Bruce Eckel, Thinking in C++, ed. Prentice Hall, 2000, vol 1. 3. Bjarne Stroustrup, The C++ Programming Language, Addison-Wesley, 4. Bazil Prv, Al. Vancea, Fundamentele limbajelor de programare, 1996 5. D.L. erbnai, Limbaje de programare i compilatoare, Ed. Academiei, 1987 6. Malcom Bull, Students guide to programming languages, HB Newnes, 1992 7. Aho A.V., Ullman J.D, Principles of Compiler Design, Addison-Wesley, 1977
Scurt biografie a titularului de curs Gheorghe Cosmin Silaghi este absolvent al seciei Informatic Economic a Universitii Babe-Bolyai Cluj-Napoca din anul 2000 si doctor in Stiine Economice Cibernetic i

Statistic Economic din anul 2005. Este lector universitar din anul 2006. Gheorghe Cosmin Silaghi are o progtire vast in domeniul informaticii fiind inginer in Stiina Sistemelor si Calculatoarelor, absolvind programul de master of Science in Inteligen Artificial a Universitii Libere din Amsterdam. Pregtirea postdoctoral a titlularului de curs include o participare de 18 luni in proiectul european FP6 CoreGrid fiind detaat la Rutherford Applenton Laboratory Anglia (2006-2007) i Universitatea din Coimbra Portugalia (2007). Activitatea de cercetare este completat de o serie de publicaii relevante realizate i proiecte de cercetare conduse. G.C. Silaghi este titularul acestui curs incepnd cu anul 2005, dup ce a realizat i condus laboratoarele la aceast disciplin incepnd cu anul 2002. Experiena de predare necesar disciplinei este completat de experien practic efectiv, titularul de curs activnd pe rnd ca i programator, analist business i consultant la diverse companii software.