Oop Curs18feb14

download Oop Curs18feb14

If you can't read please download the document

description

p.o.o.

Transcript of Oop Curs18feb14

OOP Curs========Daniel Dragulicifebruarie - mai 2013==============================================================================Detalii administrative:=======================Notare: - o nota la examenul scris (S); - o nota la laborator (L);Conditii de promovabilitate: S >= 5, L>=5Nota finala la aceasta disciplina (F), care se trece in catalog, se calculeaza dupa regula: F = parte_intreaga_superioara((S + L) / 2) + bonus unde "bonus" este 0 sau 1, valoarea 1 acordandu-se celor care s-au remarcat in mod deosebit de-a lungul semestrului.Bibliografie:* Herbert Schildt: "C++ manual complet", Teora, 1997* Muslea Ionut: "Initiere in C++ Programare orientata pe oiecte", Ed. Cluj-Napoca, 1992, "C++ pentru avansati 33", Ed. Microinformatica, 1994* Bjarne Stroustrup: "The C++ programming language", Addison-Wesley, 1997 (aparuta si la Ed. Teora)* Bruce Eckel: "Thinking in C++" (2 vol), Prentice Hall (dar se gaseste gratis pe Internet)* ANSI/ISO C++ standard (nu este gratis, dar exista draft-uri gratis)* diverse resurse pe Internet: Wikipedia (http://en.wikipedia.org/wiki/Main_Page) http://www.cplusplus.com/ http://publib.boulder.ibm.com/infocenter/lnxpcomp/ http://www.tutorialspoint.com etc.Materialele de referinta pentru examen sunt:* Cartea lui Herbert Schildt mentionata in bibliografie* Acest curs(orice informatie prezenta in reuniunea acestor doua materiale poate fisubiect de examen). Lectia 1 - Conceptul de OOP ===========================I. Paradigme ale programarii============================ O PARADIGMA este un tipar de gandire si de concepte. O PARADIGMA A PROGRAMARII este un stil fundamental de programare acalculatoarelor. Principalele paradigme sunt: - programarea orientata pe obiecte (OOP); - programarea imperativa; - programarea functionala; - programarea logica. Ele au ca fundament modele distincte de calcul: - masina Turing, pentru programarea orientata pe obiecte si cea imperativa; - lambda calculul, pentru programarea functionala; - logica de ordinul intai, pentru programarea logica. Exista si alte paradigme, avand intr-o masura mai mare sau mai micalegatura cu cele patru de mai sus: programarea structurata si ceaprocedurala (variante ale programarii imperative), programarea declarativa(opusa celei imperative), calculul paralel si concurent, etc. - PROGRAMAREA IMPERATIVA descrie calculul in termenii unor INSTRUCTIUNI ce schimba STAREA programului; baza programarii imperative este instructiunea de ATRIBUIRE; programul este constituit din secvente de comenzi (instructiuni) pe care le are de executat calculatorul. In programarea imperativa clasica, programul este o lunga lista de instructiuni ce opereaza pe niste date globale. In PROGRAMAREA STRUCTURATA se cauta imbunatatirea claritatii, calitatii si a timpului de dezvoltare a codului, impunand ca listele de instructiuni sa aiba o organizare in subrutine, blocuri si cicluri (in contrast cu folosirea unor simple teste si salturi, care pot conduce la un "spaghetti code" dificil de inteles si intretinut). In PROGRAMAREA PROCEDURALA lista de instructiuni si datele sunt impartite in mai multe SUBRUTINE (proceduri, functii), avand fiecare o anumita interfata formata din parametri si valoare returnata, si care pot fi apelate (cu parametri actuali adecvati) ca si cand ar fi instructiuni obisnuite (iar atunci se executa codul incorporat, cu parametrii actuali furnizati); din interiorul unei subrutine putem apela alte subrutine; un desiderat urmarit in programarea procedurala este MODULARITATEA, prin care cerem ca instructiunile dintr-o subrutina sa opereze doar pe date locale subrutinei (care nu sunt accesibile din alte subrutine) iar comunicarea subrutinei cu apelantii ei sa se efectueze doar prin interfata acesteia (parametri, valoare returnata) - astfel, codul este mai usor de intretinut si reutilizat. - OOP reprezinta conceptele ca "OBIECTE", avand campuri de date (ATRIBUTE sau PROPRIETATI care descriu obiectul) si proceduri asociate (numite METODE); obiectele sunt manevrate ca un tot unitar, ca si cand ar fi niste date obisnuite; tipul unui obiect s.n. CLASA (obiectele sunt INSTANTE ale claselor); clasele/obiectele se pot defini unele pe baza altora prin MOSTENIRE, formand astfel IERARHII; un program este o colectie de clase si obiecte care interactioneaza si descrie aceasta interactiune. Astfel, daca in programarea imperativa conventionala programul are aspectul unei liste lungi de de instructiuni ce opereaza pe niste date globale, in OOP programul are aspectul unui sistem complex de declaratii organizate ierarhic, care descriu interactiunile dintre niste obiecte ce incapsuleaza date si cod. Exista mai multe variante de OOP: * dupa separarea domeniilor de interes (separation of concerns - principiu de design pentru a separara programul in sectiuni distincte, fiecare adresand un alt dominiu de interes; un dominiu de interes (concern) este o informatie ce afecteaza codul unui program, ex: detalii ale hardware-ului tinta, numele unei clase ce trebuie instantiate, etc.): ** PROGRAMAREA ORIENTATA PE ASPECTE (AOP - aspect-oriented programming): vizeaza cresterea modularitatii prin aceea ca permite separarea domeniilor de interes care afecteaza alte domenii de interes (cross-cutting concerns) - acestea de regula nu pot fi separate de restul sistemului. ** PROGRAMAREA ORIENTATA PE ROLURI (role-oriented programming): vizeaza exprimarea lucrurilor in termeni analogi intelegerii conceptuale umane a lumii; ideea principala este aceea ca oamenii gandesc in termenii unor roluri, cum ar fi relatiile sociale; de exemplu: un student la un curs si acelasi student la o petrecere sunt aceeasi persoana, dar juacand roluri diferite - interactiunea acestei persoane cu lumea exterioara depinde de rolul sau curent. ** PROGRAMAREA ORIENTATA PE SUBIECTE (subject-Oriented Programming): starea (campurile) si comportamentul (metodele) unui obiect nu sunt considerate intrinseci acestuia ci sunt date prin diverse perceptii subiective ("subiecte") ale sale; de exemplu: noi putem percepe un copac ca avand drept caracteristici masurabile inaltimea, greutatea, cantitatea de frunze, etc., in timp ce pentru o pasare el poate avea de asemenea masuri ale valorilor relative pentru scopuri de hranire si cuibarit. * PROGRAMAREA BAZATA PE CLASE: mostenirea este obtinuta definind clase de obiecte (mostenirea este definita la nivelul claselor); este cel mai popular si mai dezvoltat model; exemple de limbaje: C++, Java, ObjectPascal, Turbo Pascal (v5.5+), Visual Basic. * PROGRAMAREA BAZATA PE PROTOTIPURI (prototype-based programming): nu sunt definite clase, iar refolosirea comportamentului (analogul mostenirii, in cazul claselor) este efectuata prin clonarea obiectelor existente, care servesc drept prototipuri; exemple de limbaje: ECMAScript (si implementarile sale JavaScript, JScript si ActionScript 1.0 pentru platforma Flash), Cecil, NewtonScript, Io, MOO, REBOL, Lisaac.- PROGRAMAREA FUNCTIONALA descrie calculul ca evaluarea unor functii matematice, evitand conceptele de stare si date mutabile (i.e. date ce pot fi modificate dupa ce au fost create, intr-un mod observabil din exterior); ea pune in evidenta aplicarea functiilor, in contrast cu programarea imperativa, care pune in evidenta schimbarile de stare. Un program este o colectie de functii, care sunt blocuri de cod ce se doreste a se comporta ca niste functii matematice; rularea programului se face apeland una din functii, cu niste parametri actuali. Exemplu: functia lui Fibonacci poate fi scrisa in Common Lisp astfel: (defun fib (n &optional (a 0) (b 1)) (if (= n 0) a (fib (- n 1) b (+ a b)))) atunci, programul poate fi apelat astfel: (fib 10) si va afisa: 34 In practica, diferenta dintre o functie matematica si notiunea de functie folosita in programarea imperativa este ca functiile imperative pot avea efecte laterale (side effects) ce pot schimba starea programului; de aceea, ele nu au transparenta referentiala (o expresie are transparenta referentiala daca poate fi inlocuita in cod cu valoarea ei fara sa se schimbe comportamentul programului), deci o expresie poate produce valori diferite la momente diferite, pentru aceleasi argumente, in functie de starea de executie a programului. In programarea functionala valoarea furnizata de o functie depinde doar de argumentele acesteia (deci, daca o vom apela de mai multe ori cu aceleasi argumente, va furniza acelasi rezultat); comportamentul programului este astfel mai usor de inteles si mai predictibil.- PROGRAMAREA LOGICA utilizeaza instructiuni logice pentru a descrie un calcul sau modul in care rezolvarea unei probleme se reduce la rezolvarea altor probleme; ea poate fi privita ca o forma de programare declarativa, dar si procedurala. Un exemplu de instructiune logica este clauza Horn; de exemplu: p(X, Y) if q(X) and r(Y) poate semnifica "q(X) si r(Y) implica p(X, Y)" sau "pentru a rezolva p(X, Y), intai rezolvam q(X) si apoi r(Y)". In general, calculul este privit ca un rationament automatizat (automated reasoning) asupra unui corpus de cunostinte; ipotezele asupra domeniului problemei sunt exprimate prin formule logice(scrise ca instructiuni logice) si formeaza programul, iar rularea acestuia consta in aplicarea de reguli de inferenta (deductie) asupra lor pana este gasit un raspuns la problema sau colectia de formule se dovedeste inconsistenta (contradictorie). Exemplu: program Fibonacci recursiv, in Prolog: fib(0, 0). fib(1, 1). fib(X, Y) :- X > 1, X2 is X 2, fib(X2, Y2), X1 is X 1, fib(X1, Y1), Y is Y1 + Y2. atunci, programul poate fi apelat astfel: fib(10, 34). si va afisa: yes sau astfel: fib(10, 35). si va afisa: no- PROGRAMAREA DECLARATIVA descrie logica unui calcul fara a descrie fluxul ei de control (ordinea in care operatiile sunt executate); ea exprima "ce" trebuie sa faca programul, fara a prescrie "cum" sa o faca, in termenii unor secvente de actiuni ce trebuie efectuate. Programarea functionala si cea logica sunt considerate forme de programare declarativa.- PROGRAMAREA GENERICA este un stil de programare in care algoritmii sunt definiti deasupra unor tipuri ce urmeaza a fi precizati mai tarziu si sunt instantiati ulterior, atunci cand este nevoie de ei, pentru niste tipuri particulare date ca parametri; astfel, daca mai multe fragmente de cod difera doar prin tipurile de date asupra carora opereaza, ele nu mai trebuie scrise separat, ci doar o singura data, generic (deasupra unor tipuri date ca parametri) - se evita astfel fenomenul de DUPLICARE A CODULUI (duplicate code), adica aparitia de mai multe ori a unei secvente de cod in cadrul unui program sau al unui grup de programe ce apartin sau sunt intretinute de o aceeasi entitate. Aceasta paradigma poate fi adaugata unor limbaje imperative, ex: Ada, Delphi, C++, Java, C#, Visual Basic .NET, dar si unor limbaje functionale, ex: Haskell, Clean. Multe paradigme ale programarii sunt la fel de bine cunoscute pentrutehnicile pe care le interzic, ca si pentru cele pe care le introduc.De exemplu, programarea functionala interzice utilizarea efectelorlaterale si schimbarea valorii variabilelor prin atribuire (propunandfolosirea in schimb a recursiei), iar programarea structurata interzicefolosirea instructiunii "goto". Interzicerea anumitor tehnici poate fiperceputa ca o constrangere de catre programatori, dar face programele maiusor de inteles si inlesneste demonstrarea unor teoreme privindproprietatile acestora. Unele limbaje de programare suporta mai multe paradigme. De exemplu unprogram in Object Pascal sau C++ poate fi pur procedural, sau pur orientatpe obiecte, sau continand elemente ale ambelor paradigme. Exemple de limbaje de programare:- BASIC, FORTRAN, COBOL: imperative, procedurale;- C, Pascal: imperative, structurate, procedurale;- C++, Java, Object Pascal, Turbo Pascal (v5.5+), Visual BASIC: imperative, structurate, procedurale, OOP;- Lisp: familie de limbaje functionale: Common Lisp, Scheme; CommonLOOPS este o forma de Lisp orientata pe obiecte;- Prolog, Datalog: limbaje de programare logica declarativa, bazata pe clauze Horn; OBJ, CafeOBJ, Maude: limbaje de programare logica declarativa, bazate pe logica ecuationala; Full Maude este o extensie a lui Maude orientata pe obiecte; SQL: limbaj de interogare baze de date; SQL1999 (cunoscut anterior ca SQL3) este un SQL orientat pe obiecte. Evolutia limbajelor de programare a avut urmatoarele etape:- la inceput, cand au fost inventate calculatoarele, se folosea CODUL MASINA, in care instructiunile, datele, adresele sunt reprezentate exact asa cum apar ele memorie, ca secvente de numere; de obicei, programarea se facea introducand instructiunile masina in cod binar, de la panoul frontal al calculatorului; acest mod de lucru a fost convenabil cat timp programele aveau doar cateva sute de instructiuni;- o data cu marirea programelor, au fost inventate LIMBAJELE DE ASAMBLARE, care folosesc o reprezentare simbolica a instructiunilor masina (prin mnemonice) si a adreselor de memorie (prin etichete); astfel, puteau fi scrise mai usor programe de dimensiuni mai mari;- deoarece programele continuau sa creasca, au fost introduse LIMBAJELE DE NIVEL INALT (numite uneori si LIMBAJE PROCEDURALE), care lucreaza cu cocepte si operatii abstracte (independente de o anumita implementare) si au instructiuni puternice, inclusiv lucrul cu subrutine, care ofera un plus e expresivitate; primul dintre ele a fost FORTRAN (anii '50);- in anii '60 a fost introdusa PROGRAMAREA STRUCTURATA (limbaje ca Pascal, C), care permite gestionarea mai usoara a unui cod de mari dimensiuni si inlesneste demonstrarea unor teoreme privind proprietatile acestora (ex: teorema Bohm-Jacopini, logica lui Hoare); limbajul C s-a dovedit foarte util pentru scrierea de cod performant, dar daca dimensiunea unui program trece de la 25000 la 100000 linii el devine dificil de stapanit ca un intreg;- conceptele OOP au inceput sa fie introduse pe la sfarsitul anilor '50 si inceputul anilor '60, si au capacitatea de a creste foarte mult expresivitatea limbajului, a.i. sa poate fi manevrate usor programe si mai mari; fiind vorba de o paradigma, nu de un limbaj, OOP a fost aplicat nu numai limbajelor imperative (Simula67, Object Pascal, C++) ci si celor functionale (CLOS, derivat din Lisp), logice (Full Maude), etc., chiar si limbajelor de asamblare (HLA);- programarea declarativa (in particular programarea functionala si cea logica) a fost dezvoltata independent de ramura programarii imperative; anumite concepte, de exemplu OOP, au fost aplicate insa si aici.II. Caracteristicile OOP======================== In ceea ce priveste trasaturile fundamentale ale OOP, exista mai multepuncte de vedere: Herbert Schildt, in "C++ The Complete Reference" (versiunea in limbaromana este mentionata in bibliografie), evidentiaza trei caracteristici:- INCAPSULAREA (encapsulation): Ca si concept de programare, presupune doua aspecte: * o constructie de limbaj ce faciliteaza impachetarea datelor cu operatiile definite asupra lor (sub forma de metode sau alte functii) * un mecanism de limbaj pentru restrictionarea accesului la unele componente ale pachetului. In C++ codul si datele sunt impachetate in OBIECTE, creandu-se legaturi stranse intre ele; obiectul este apoi manevrat ca un tot unitar, ca si cand ar fi o data obisnuita (putem avea variabile cu valori obiecte). Codul si datele cuprinse intr-un obiect nu sunt accesibile in totalitate din afara in mod direct (sunt ascunse, ca PRIVATE), prevenindu-se astfel accesul incorect sau neutorizat la ele; pentru accesare, obiectul ofera o interfata formata din anumite metode ale sale (considerate PUBLICE) ce pot fi apelate de catre alte clase/obiecte si prin care acestea pot invoca functionalitatea obiectului. De obicei campurile de date sunt private, iar accesul la ele din exterior este permis prin metode publice gen "setter" si "getter". TODO: exemplu de incapsulare in C++;- POLIMORFISMUL (polymorphism): Poate fi descris pe scurt astfel: "o singura interfata, metode multiple"; Este un mecanism general prin care o aceeasi sintagma ce descrie o prelucrare (de exemplu o expresie) va avea automat efecte diferite in functie de tipul operanzilor. In C++ exista mai multe modalitati de a obtine polimorfismul, una dintre ele este SUPRAINCARCAREA functiilor si operatorilor; de exemplu, putem defini un operator "+" pentru matrici, care sa insemne adunarea matricilor si un operator "+" pentru stringuri, care sa insemne concatenarea stringurilor; cei doi operatori "+" se pot defini ca niste functii; atunci, la evaluarea expresiei "a+b" se va apela automat functia de adunare, daca a si b sunt obiecte-matrice, sau functia de concatenare, daca a si b sunt obiecte-string; in C ar fi trebuit sa avem nume diferite pentru functii diferite. In exemplul anterior, interfata este data de operatorul "+", iar metodele date de cele doua functii (adunare, concatenare). La intalnirea expresiei "a+b", functia ce va fi apelata poate fi decisa la momentul compilarii (compilatorul face alegerea in functie de tipurile lui a si b si genereaza o instructiune de apel catre adresa functiei respective, deci o adresa fixata prin cod) sau la momentul rularii (compilatorul genereaza un cod care prin executare determina adresa dorita in functie de valorile curente ale lui a si b si o instructiune de apel catre adresa rezultata, deci o adresa determinata la momentul rularii); primul mod de asociere s.n. "EARLY BINDING", al doilea "LATE BINDING" si conduc la un POLIMORFISM LA MOMENTUL COMPILARII, respectiv la un POLIMORFISM LA MOMENTUL RULARII. Un caz particular de polimorfism este POLIMORFISMUL DE SUBTIP (subtype polymorphism): este un mecanism prin care un tip de date este asociat ca subtip unui alt tip de date in sensul unei notiuni de substitutabilitate, insemnand ca elemente ale programului, de obicei subrutine (proceduri, functii) scrise sa opereze cu elemente ale supertipului vor putea opera automat si cu elemenente ale subtipului. In C++ acest mecanism se aplica claselor si obiectelor obtinute prin mostenire.- MOSTENIREA (inheritance): In OOP, mostenirea este un mod de a refolosi codul unor obiecte existente, si/sau de a stabili un subtip dintr-un obiect existent. In PROGRAMAREA BAZATA PE CLASE, unde obiectele sunt definite prin clase, clasele pot mosteni atribute si comportamente ale unor clase pre-existente, numite CLASE DE BAZA (sau SUPERCLASE, CLASE PARINTE); clasele rezultate s.n. CLASE DERIVATE (sau SUBCLASE, CLASE COPIL); relatia dintre clase determinata de mostenire defineste o IERARHIE. In C++, la definirea unei clase derivate se vor specifica doar clasele de baza pe care le mosteneste si atributele/metodele noi adaugate; clasa derivata va incorpora automat si atributele/metodele claselor de baza si fi subclasa a acestora, in sensul polimorfismului de subtip. TODO: exemplu de mostenire in C++ In PROGRAMAREA BAZATA PE PROTOTIPURI obiectele pot fi definite direct din alte obiecte, fara a fi nevoie sa definim clase; in acest caz avem de a face cu o MOSTENIRE DIFERENTIALA (differential inheritance). Benjamin C. Pierce, in "Types and Programming Languages", MIT Press, 2002, evidentiaza urmatoarele caracteristici ale OOP:- ASOCIEREA DINAMICA (dynamic dispatch): cand o metoda este apelata pentru un obiect, obiectul insusi determina ce cod se va executa, cautand metoda la momentul rularii (run time) intr-o tabela asociata cu obiectul; este un concept de late binding (a se vedea mai sus);- Incapsularea;- Polimorfismul de subtip;- Mostenirea;- RECURSIA DESCHISA (open recursion): existenta unei variabile speciale (numita de obicei "this" (ex. in C++) sau "self" (ex. in Visual BASIC), denumirea sa poate fi un cuvant-cheie) ce permite ca dintr-o metoda a unui obiect sa poata fi apelata o alta metoda a aceluiasi obiect; asocierea se face la run time (variabila este late-bound), a.i. permite ca o metoda definita intr-o clasa sa apeleze o alta metoda definita ulterior, intr-o subclasa. John C. Mitchell, in "Concepts in programming languages", Cambridge University Press, 2003, evidentiaza urmatoarele caracteristici ale OOP:- Asocierea dinamica;- ABSTRACTIZAREA (abstraction): este mecanismul prin care datele si programele sunt definite cu o reprezentare similara in forma cu intelesul (semantica) lor, ascunzand in acelasi timp detaliile de implementare; cu alte cuvinte, forma in care scriem operatiile reflecta semnificatia pe care o au pentru noi si nu mecanismul prin care sunt ele efectuate. Un nivel de abstractizare inferior expune programatorului detaliile hardware-ului unde este rulat programul, in timp ce un nivel de abstractizare superior ascunde aceste detalii si se ocupa doar cu logica de business a programului ("logica de business" este un termen non-tehnic folosit pentru a descrie algoritmii functionali ce manevreaza transferul de informatie intre o baza de date si o interfata utilizator).- Polimorfismul de subtip;- Mostenirea. Michael Lee Scott in "Programming language pragmatics", Edition 2, Morgan Kaufmann, 2006, considera urmatoarele caracteristici ale OOP:- Incapsularea;- Mostenirea;- Asocierea dinamica. In ceea ce priveste stilul de programare intr-un limbaj obiectual, acestadifera de cel specific programarii imperative procedurale clasice - deexemplu sa facem o comparatie C versus C++: In C programatorul priveste prelucrarea din interior, avand o perceptiedinamica, operativa, a acesteia, si o exprima explicitand seria de operatiice trebuie efectuate sub forma unei lungi liste de instructiuni, impartitaeventual in mai multe functii; programul are o dezvoltare pe orizontala,avand aspectul unei colectii de functii, care contin liste lungi deinstructiuni. In C++ programatorul priveste prelucrarea din exterior, avand o perceptiestatica, descriptiva, a acesteia, si o exprima descriind legaturile logice(dependentele) intre operatiile ce trebuie efectuate, sub forma unui sistemcomplex de declaratii; programul are o dezvoltare pe verticala, avandaspectul unei ierarhii de clase si obiecte, care reutilizeaza extensiv codmostenit (metodele noi adaugate contin de fiecare data cod putin). Am putea face o paralela intre modul in care definim un sir prin formulatermenului general sau prin recurenta. Cand folosim formula termenului general suntem in C: scriem o expresiecomlpexa care expliciteaza toate operatiile ce trebuie efectuate pentrucalcularea termenului curent. Cand folosim formula de recurenta, suntem in C++: scriem o expresie multmai simpla care descrie logica dependentei dintre termenul curent si cativatermeni anteriori (declaratie prin mostenire); expresia simpla contine aceeasi informatie ca si cea complexa de mai inainte, dar nu o expliciteaza - toate calculele din expresia complexa se vor generea si se vor executala run time; astfel, putem descrie aceleasi calcule cu cod mai putin(creste expresivitatea limbajului). Evident, deoarece C++ extinde C, putem programa in C++ in stil C (folosindfunctii independente, care nu sunt metode ale obiectelor, punand cod multin metode putine si dezvoltand programul pe orizontala, etc.) dar atunci nuvom putea beneficia de toate avantajele acestui limbaj. Diferenta se vasimti mai ales la programele de dimensiuni mari, unde avem nevoie de oexpresivitate a limbajului si o productivitate a programarii sporite. In continuare, vom studia conceptele OOP pe cazul particular al C++.III. Istoria C++================ C++ a fost dezvoltat de Bjarne Stroustrup de la Bell Labs incepand cu 1979 (initial s-a numit C cu clase). El este un limbaj de programare care extinde limbajul C si este: - de uz general (general-purpose); - de nivel intermediar (intermediate-level language): combina atat trasatauri ale unui limbaj de nivel inalt (high-level, i.e. cu un nivel puternic de abstractizare fata de detaliile calculatorului) cat si ale unuia de nivel scazut (low-level); - compilat: implementarile sale sunt in mod tipic compilatoare (translatoare ce genereaza cod masina din cod sursa) si nu interpretoare (executoare pas-cu-pas ale codului sursa, neavand loc translatari inaintea momentului rularii);- free-form: pozitionarea caracterelor in pagina codului sursa este insignifianta;- cu verificarea static a tipulurilor (statically typed): verificarea tipurilor se face la momentul compilarii; in opozitie, la un limbaj cu verificarea dinamica a tipurilor (dynamic typed) cea mai mare parte a verificarii tipurilor se face la momentul rularii (ex: JavaScript, Lisp, Perl (pentru tipurile definite de utilizatori, nu cele built-in), Prolog, Python, Ruby, etc.);- multi-paradigm; este un limbaj de programare imperativa ce suport programarea structurata, procedural, abstractizarea datelor, programarea orientat pe obiecte, programarea generica. Filozofia C++ este descrisa de B. Stroustrup in "The Design and Evolutionof C++" (1994) prin urmatoarele reguli pe care s-a bazat cand a poiectatlimbajul: - C++ este proiectat a.i. sa fie un limbaj statically typed, general-purpose, care sa fie eficient si portabil ca si limbajul C; - C++ este proiectat pentru a suporta direct si comprehensiv mai multe paradigme (programarea procedurala, abstractizarea datelor, programarea orientata pe obiecte si programarea generica); - C++ este proiectat sa ofere programatorului libertatea de a alege, chiar daca aceasta permite ca programatorul sa aleaga incorect; - C++ este proiectat sa fie compatibil cu C cat mai mult posibil, a.i. sa ofere o tranzitie lina de la C; - C++ evita elemente care sunt specifice unei anumite platforme sau nu sunt de uz general; - C++ nu accentueaza elementele care nu sunt folosite (principiul "zero-overhead"); - C++ este proiectat sa functioneze fara a un mediu de programare sofisticat. Per ansamblu, C++ combina adecvarea la productia de software performant pecare o are limbajul C cu expresivitatea ridicata pe care o aduce orientareape obiecte (expresivitate ridicata inseamna ca cu cod putin poti sa descriimult). Domeniile sale de aplicare includ software de sistem, software deaplicate, drivere de echipament (device drivers), software incorporat(embedded software), aplicatii client si server de inalta performanta,software de entertainment (ex: jocuri video). C++ este folosit inclusivpentru proiectarea hardware (hardware design). Istoricul C++: - B. Stroustrup a inceput sa lucreze la C cu clase in 1979; el a constatatca Simula avea facilitati foarte utile pentru proiecte mari, insa era prealent, in timp ce BCPL era rapid, insa nu era de nivel inalt si eranepotrivit pentru proiecte mari; amintindu-si de experienta sa din perioadalucrarii de doctorat, Stroustrup a inceput sa imbunatateasca C cu facilitatiasemanatoare Simula (C a fost ales deoarece era de uz general, rapid,portabil si folosit pe scara larga). La inceput facilitatile adaugate C-ului au fost clase, clase derivate,verificare puternica a tipului (strong typing - un sistem de tipuri esteastfel daca specifica una sau mai multe restrictii asupra modului in careoperatiile care implica valori de diferite tipuri pot fi intermixate),expansiunea inline (inlocuirea unui apel de functie direct cu o copieadaptata a corpului acesteia, eliminandu-se instructiunile de apel sirevenire) si argumentele cu valori implicite (default arguments). In timp ce a proiectat C cu clase (mai apoi C++), Stroustrup a scris siCfront, un compilator care genera cod sursa C din cod C cu clase. Primalansare comerciala a fost in 1985. - In 1983, numele limbajului a fost schimbat din C cu clase in C++ ("++" fiind operatorul de incrementare din C). Au fost adaugate noi facilitati, inclusiv functii virtuale, supraincarcarea functiilor si a operatorilor, referinte, constante, alocare dinamica, un control al tipului imbnatatit si noua varianta de comentariu pe un singur rand (comentariile care incep cu caracterele '//').- In 1985 Stroustrup a publicat prima editie a cartii sale "The C++ Programming Language" (Limbajul de programare C++), oferind informatii importante despre limbaj, care inca nu era un standard oficial.- In 1989 a fost lansata versiunea 2.0 a C++, iar editia a doua, actualizata, a cartii "The C++ Programming Language" a fost publicata in 1991; au fost adaugate mostenirea multipla, clase abstracte, functii membre statice, functii membre constante si membri protejati (protected). In 1990 a fost publicata lucrarea "The Annotated C++ Reference Manual", care a devenit baza standardizarii ulterioare; ultimele adaugiri includeau sabloane (template), exceptii, spatii de nume (namespace), noi conversii (cast) si tipul boolean.- O data cu evolutia limbajului C++, a evoluat si biblioteca sa standard. Prima adaugire a fost biblioteca de intrari/iesiri stream (I/O stream), care oferea facilitati pentru a inlocui functiile traditionale C cum ar fi printf si scanf; mai tarziu, printre cele mai semnificative adaugiri la biblioteca standard a fost STL (Standard Template Library) (Biblioteca de sabloane standard).- Dupa ani de lucru, un comitet ANSI-ISO a standardizat C++ in 1998 (ISO/IEC 14882:1998). Evolutia standardelor C++ a fost: Anul C++ Standard Nume informal --------------------------------------------------------- 1998 ISO/IEC 14882:1998 C++98 2003 ISO/IEC 14882:2003 C++03 2007 ISO/IEC TR 19768:2007 C++TR1 (TR1 este un raport tehnic care nu este un standard in sine, propunea adaugir la biblioteca standard C++ si a circulat ca draft din 2005) 2011 ISO/IEC 14882:2011 C++11 La ora actuala (2013) versiunea curenta a standardului este C++11, si se afla in pregatire C++14 (o revizie minora) si C++17 (o revizie majora). In anii 1990, C++ a devenit unul din cele mai populare limbaje de programarecomerciale. Mai multe grupuri ofera compilatoare C++ atat free cat si proprietare;exemple: GNU Project, Microsoft, Intel si Embarcadero Technologies. Lectia 2 - Incursiune in C++ : TODO ============================ Caracteristicile limbajului C++ sunt in mare masura corelate intre ele,ceea ce face dificil de descris o caracteristica fara implicarea multoraltora, presupunand astfel existenta unor cunostinte anterioare despre ele. De aceea, in aceasta lectie vom face o prezentarea sumara a principalelorcaracteristici C++, pentru a ne putea referi la ele cand va fi nevoie.Urmatoarele lectii vor prezenta caracteristicile C++ in detaliu. Lectia se doreste a fi totodata si un scurt tutorial de C++, care sapermita abordarea cat mai devreme a problemelor de laborator. In tot acest curs vom presupune cunoscut limbajul C si vom insista maiales pe evidentierea elementelor noi pe care le aduce C++. Lectia 3 - Incompatibilitati intre C si C++ =========================================== Deoarece C++ s-a dezvoltat din C si a fost proiectat sa fie source-and-linkcompatibil with C. Din acest motiv, istrumentele de dezvoltare pentru celedoua limbaje (cum ar fi IDE-urile sau compilatoarele) sunt adesea integrateintr-un singur produs, programatorul avand posibilitatea de a specificalimbajul sursa ca fiind C sau C++ (de ex. prin extensia fisierului sursa: .c pentru C si .cpp pentru C++). Totusi, din cauza unor diferente semanticeminore, anumite constructii C nu sunt acceptate in C++ sau au sensuridiferite. De aceea, C++ nu este un superset al lui C in sens strict. Bjarne Stroustrup a sugerat ca incompatibilitatile dintre C si C++ sa fiereduse la minimum in scopul de a maximiza inter-operabilitatea intre celedoua limbaje, iar argumentarea oficiala a standardului C din 1999 (C99)sustinea principiul mentinerii celui mai larg subset comun intre C si C++,mentinand in acelasi timp o distinctie intre ele si permitandu-le saevolueze separat, si afirma ca autorii erau multumiti sa lase C++ sa fielimbajul cel "mare si ambitios". La ora actuala (2013) versiunea curenta a standardului este C++11(ISO/IEC 14882:2011), iar cea a standardului C este C11 (fost C1X)(ISO/IEC 9899:2011). In continuare prezentam cateva incompatibilitati intre C si C++; au fostluate in considerare versiunile C99 (ISO/IEC 9899:1999) si C++98(ISO/IEC 14882:1998), a se vedea: David R. Tribble: "Incompatibilities Between ISO C and ISO C++", http://david.tribble.com/text/cdiffs.htmUnele dintre incompatibilitatile discutate nu se manifesta la fel pe toatecompilatoarele, asa cum am semnalat in notele inserate in text.I. Constructii valide in C, dar nu si in C++============================================(1) C permite ca un void* sa fie asignat oricarui tip pointer fara cast, in timp ce C++ nu permite acest lucru. O asemenea situatie este adesea intalnita in secventele de cod C cefolosesc alocarea dinamica de memorie cu malloc; exemple de cod valid in Cdar nu si in C++: void* ptr; int *i = ptr; /* Conversie implicita de la void* la int* */si de asemenea: int *j = malloc(sizeof(int) * 5); /* Conversie implicita de la void* la int* */Pentru a face fragmentele de cod de mai sus compilabile in C++, trebuiefolosit un cast explicit: void* ptr; int *i = (int *) ptr;si respectiv: int *j = (int *) malloc(sizeof(int) * 5); De notat insa ca in ambele limbaje orice tip pointer poate fi asignat unuivoid* fara cast; acest lucru permite compilarea in C++ fara modificari asecventelor de cod C care contin apeluri ale unor functii de bibliotecapentru manevrarea blocurilor de memorie, de exemplu: #include int a[]={1,2,3}, b[3]; memcpy(b,a,sizeof(a));(functia memcpy are prototipul: void *memcpy(void *dest, const void *src, size_t n);iar apelul de mai sus presupune ca un int* sa fie asignat unui const void*).(2) C++ are mai multe cuvinte cheie in plus fata de C, ceea ce face ca secventele de cod C care le folosesc drept identificatori sa fie invalide in C++; de exemplu: struct template { int new; struct template* class; }; este un cod valid in C, dar invalid in C++, deoarece "template", "new" si "class" sunt cuvinte cheie.(3) Compilatoarele de C++ interzic utilizarea unui goto sau switch care traverseaza o initializare, ca in urmatorul fragment de cod (valid in C99): void fn(void) { goto eticheta; int i = 1; eticheta: ; } De notat ca intercalarea declaratiilor de variabile cu instructiuni (ca in exemplul de mai sus) nu era permisa la primele versiuni de C (acolo declaratiile de variabile trebuiau puse la inceputul blocului iar instructiunile la sfarsitul sau), dar in C99 este permisa.(4) Daca operandul drept al operatorului virgula este o "l-value" (entitate ce poate fi folosita in stanga unei atribuiri), atunci operatorul va produce o "l-value" in C++ si doar o "r-value" (entitate ce poate fi folosita in dreapta unei atribuiri) in C; exemplu: int i, j, x, y; i = 1; j = 2; x = 3; y = 4; x = (i, j); /* valid si in C si in C++; x primeste valoarea 2 */ (i, j) = y; /* valid in C++ (j primeste valoarea 4), invalid in C */(5) C nu permite duplicarea unui typedef in acelasi domeniu (scope), in timp ce C++ permite typedef-uri repetate; scope = context de includere unde sunt sunt asociate valori si expresii (enclosing context where values and expressions are associated); exemplu: typedef int MyInt; typedef int MyInt; /* valid in C++, invalid in C */ De aceea, typedef-urile care ar putea fi incluse mai mult decat o dataintr-un program (de ex. typedef-uri uzuale care apar in mai multe fisiereheader) trebuie protejate prin directive de preprocesare, daca un asemeneacod sursa urmeaza a fi compilat atat in C cat si in C++; de exemplu: /* Fisierul one.h */ #ifndef MYINT_T #define MYINT_T typedef int MyInt; #endif ... /* Fisierul two.h */ #ifndef MYINT_T #define MYINT_T typedef int MyInt; #endif ... atunci o secventa de cod poate include ambele fisiere header fara saprovoace o eroare in C: /* Include fisiere header multiple care definesc typedef MyInt */ #include "one.h" #include "two.h" MyInt my_counter = 0; (6) Constantele tipurilor enumerare (enum values) in C sunt intotdeauna de tip int, in timp ce in C++ pot fi de tipuri diferite de int si pot avea dimensiuni diferite de cea a lui int. Mai exact, in C constantele tipurilor enumerare sunt doar constante cu nume de tip signed int; in consecinta, ele nu pot avea valori de initializare decat in intervalul [INT_MIN,INT_MAX] iar sizeof-ul lor este egal cu sizeof(int). In C++ compilatoarele pot implementa tipurile enumerare folosind o gama mai larga de tipuri intregi (signed int, unsigned int, signed long, unsigned long); constantele tipurilor enumerare au acelasi tip ca si tipul lor enumerare, deci aceeasi dimensiune (sizeof) si aliniere ca si tipul intreg subiacent, astfel incat dimensiunea (sizeof) lor si intervalul valorilor de initializare ce pot fi folosite nu sunt neaparat cele ale lui int. Aceasta poate provoca incompatibilitati la compilarea unui cod C in C++, daca compilatorul de C++ alege sa implementeze un tip enumerare cu o dimensiune (sizeof) diferita decat ar fi fost in C, sau daca rezultatul programului se bazeaza pe rezultatele unor expresii ca sizeof(RED) (unde RED este o constanta a unui tip enumerare); exemplu: enum ControlBits { CB_LOAD = 0x0001, CB_STORE = 0x0002, ... CB_TRACE = LONG_MAX+1, /* Comportament nedefinit */ CB_ALL = ULONG_MAX }; (7) Identificatorii C++ nu pot contine doi sau mai multi underscore (caracterul "_") consecutivi, in orice pozitie; identificatorii C nu potincepe cu doi sau mai multi underscore consecutivi, dar ii pot contine inalte pozitii.Nota: cateva teste efectuate cu compilatoarele gcc si g++ versiunea 4.5.1 20101208 nu au raportat erori la folosirea identificatorilor de forma mentionata.(8) In fisierele header ale bibliotecii standard C++ unele functii din biblioteca standard C au declaratiile modificate pentru a fi mai sigure din punct de vedere al tipurilor (type-safe) atunci cand sunt folosite in C++; de exemplu sunt adaugati calificatori const suplimentari. Astfel, declaratia functiei din biblioteca standard C: /* */ extern char * strchr(const char *s, int c); este inlocuita in biblioteca C++ cu urmatoarele declaratii: /* */ extern const char * strchr(const char *s, int c); extern char * strchr(char *s, int c); avem deci doua functii strchr prin supraincarcare (overload), iar la apelulstrchr cu niste parametri actuali compilatorul va alege una dintre cele douafunctii in concordanta cu tipurile parametrilor actuali (a se vedea lectia 4). Aceste declaratii usor diferite pot provoca probleme atunci cand un cod Ceste compilat in C++, de exemplu: /* cod C */ const char * s = "abcde"; char * p; p = strchr(s, 'd'); /* valid in C, invalid in C++ */intr-adevar, deoarece primul parametru actual este de tip const char *,si nu char *, compilatorul va alege prima functie strchr; aceasta returneazainsa valori const char *, si nu char *, care sunt incompatibile cu p (deoarecep este char *) - nu este permisa asignarea unui pointer constant uneivariabile non-const. Codul de mai sus se poate corecta insa printr-un simplu cast, devenind validatat in C cat si in C++: /* Corectie pentru C++ */ p = (char *) strchr(s, 'd'); /* valid in C si in C++ */(9) Atat in C cat si in C++ putem declara tipuri structura incuibate (nested) in alte structuri, dar domeniul numelui lor (scope) este interpretat diferit: in C el se extinde si in afara domeniului structurii exterioare, in C++ el este definit doar in domeniul (scope)/spatiul de nume (namespace) structurii exterioare. In general, in C++ declaratiile de structura sau clasa au propriul lor domeniu (scope), ceea ce nu este valabil si in C; aceasta afecteaza toate tipurile structura, uniune, enumerare sau alte clase declarate in interior. Exemplu: struct Outer { struct Inner /* declaratie de structura incuibata */ { int a; float f; } in; enum E /* declaratie de tip enumerare incuibata */ { UKNOWN, OFF, ON } state; }; struct Inner si; /* tipul incuibat este vizibil in C, nu este vizibil in C++ */ enum E et; /* tipul incuibat este vizibil in C, nu este vizibil in C++ */ Pentru a fi vizibile in C++, declaratiile interioare trebuie numiteexplicit folosind ca prefix structura lor exterioara: /* cod C++ */ Outer::Inner si; /* nume de tip explicit */ Outer::E et; /* nume de tip explicit */sau puse in afara structurii exterioare (a.i. sa aiba domeniul (scope) lanivel de fisier): /* cod C si C++ */ struct Inner /* declaratia nu mai este incuibata */ { int a; float f; }; enum E /* declaratia nu mai este incuibata */ { UKNOWN, OFF, ON }; struct Outer { struct Inner in; enum E state; }; (10) Definitiile de functii non-prototip ("K&R"-style) nu sunt permise in C++, iar in C sunt permise, desi sunt considerate invechite (deprecated) din 1990; de exemplu: int foo(a, b) /* sintaxa invechita in C, interzisa in C++ */ int a; int b; { return (a + b); } C++ permite doar definitii de functii prototipate, deci pentru a se compila in C++ codul de mai sus trebuie rescris in forma cu protoip de functie: int foo(int a, int b) { return (a + b); } Similar, declaratiile implicite de functii (utilizarea de functii ce nu au fost declarate anterior) nu sunt permise in C++, iar in C sunt permise doar in versiunile mai vechi, ex: C90 (incepand cu C99 sunt interzise); asemenea functii sunt declarate implicit, in locul primului lor apel, considerand implicit ca returneaza o valoare int. De exemplu, urmatorul cod este valid in C90, dar nu si in C99 sau in C++: /* Nu exista o declaratie anterioara a lui bar() in domeniul (scope) curent */ void foo(void) { bar(); /* declaratie implicita: extern int bar() */ } De obicei, compilatoarele (vechi) de C, la intalnirea unei functii nedeclarate anterior, presupun (implicit) un prototip in care tipurile parametrilor formali coincid cu cele ale parametrilor actuali furnizati (determinati cu ajutorul regulii conversiilor implicite folosite la evaluarea expresiilor) iar tipul returnat este int; ca atare, apelantul va incarca pe stiva valorile parametrilor actuali si va recupera la revenire valoarea returnata in concordanta cu aceste tipuri; cand se face saltul in corpul functiei apelate, aceasta va consulta stiva si va returna o valoare in concordanta cu tipurile folosite la definirea ei (ea poate fi definita cu antet si corp in acelasi fisier, dar sub apelul respectiv, sau in alt fisier linkeditat cu cel in care se afla apelul), iar daca aceste tipuri difera, valorile vor fi comunicate alterat. TODO: exemplu(11) Declararea tipurilor struct, union si enum in prototipurile functiilor este permisa in C, nu si in C++; exemplu: /* cod valid in C, invalid in C++ */ extern void foo(const struct info { int typ; int sz; } *s); int bar(struct point { int x, y; } pt) { ... } De asemenea, declararea tipurilor structura ca tipuri returnate de functii este permisa in C, nu si in C++; exemplu: /* cod valid in C, invalid in C++ */ extern struct pt { int x; } pos(void); Motivul pentru care C++ nu permite declaratiile de mai sus este ca domeniul(scope) unei structuri declarate astfel nu se extinde in afara declaratieisau definitiei functiei, facand imposibila definirea de obiecte de aceltip structura care ar putea fi pasate ca parametri functiei sau asignareavalorilor returnate de functie cu obiecte de tipul respectiv. Atat C cat si C++ permit declararea tipurilor structura incomplete inprototipurile functiilor si ca tipuri returnate de functie: void frob(struct sym *s); // OK, pointer catre tip incomplet struct typ * fraz(void); // idemNota: teste efectuate cu compilatoarele gcc si g++ versiunea 4.5.1 20101208 au raportat urmatoarele: - in cazul functiilor foo, bar si frob, gcc afisaza un warning de tipul: warning: 'struct info'/'struct point'/'struct sym' declared inside parameter list; its scope is only this definition or declaration, which is probably not what you want in cazul functiilor pos si fraz nu semnaleaza warning sau error, iar in main se pot defini variabile de tip struct pt si struct typ *; - g++ semnaleaza eroare in cazul functiilor foo, bar, pos (si accepta frob si fraz).(12) O declaratie struct, union sau enum introduce un typedef implicit al aceluiasi nume in C++, dar nu si in C (in C la fiecare invocare a numelui trebuie sa folosim cuvantul cheie struct, union, sau respectiv enum). Exemplu: /* valid in C, invalid in C++ */ typedef int type; struct type { type memb; /* int */ struct type * next; /* pointer la struct */ }; void foo(type t, int i) { int type; struct type s; type = i + t + sizeof(type); s.memb = type; } (13) C face distinctie intre o functie declarata cu o lista vida de parametri si o functie declarata cu o lista de parametri ce contine doar void; prima este o functie neprototipata ce primeste un numar nespecificat de parametri, in timp ce a doua este o functie prototipata care nu primeste parametri. C++ nu face distinctie intre cele doua declaratii si le considera pe amandoua ca insemnand o functie ce nu primeste parametri. Exemple: /* cod C */ extern int foo(); /* parametri nespecificati */ extern int bar(void); /* fara parametri */ void baz() { foo(0); /* valid in C, invalid in C++ */ foo(1, 2); /* Valid C, invalid C++ */ bar(); /* valid in C si C++ */ bar(1); /* Eroare si in C si in C++ */ } /* cod C++ */ extern int xyz(); extern int xyz(void); /* la fel ca xyz() in C++, diferit si invalid in C */Nota: gcc versiunea 4.5.1 20101208 accepta prezenta ambelor declaratii ale functiei xyz intr-un program C, dar la intalnirea unui apel va lua in considerare declaratia cu void. Daca vrem ca un fragment de cod sa fie compilabil atat in C cat si in C++,cea mai buna solutie este ca functiile ce nu primesc parametrii sa fiedeclarate intotdeauna cu un prototip ce foloseste explicit void: /* se compileaza atat in C cat si in C++ */ int bosho(void) { ... } Prototipurile de functii cu liste vide de parametri sunt considerateinvechite (deprecated) in C99.TODO: exemplu de utilitate a functiilor cu lista vida de parametri in C.(14) C++ este mai strict decat C in privinta atribuirilor de pointeri care inlatura (discard) un calificator const (ex: atribuirea unei valori de tip const int* unei variabile de tip int* ): in C++ aceasta atribuire este invalida si genereaza un error (exceptand cazul cand se foloseste un o conversie de tip (cast) explicita), in timp ce in C ea este permisa (desi unele compilatoare emit un warning).Exemplu: int *p; const int *q; p = q; /* valid in C, invalid in C++ */ p = (int *)q; /* valid in C si C++ */ Sfat: pentru a mari sansele ca un cod C sa fie valid si cu acelsai sens inC++, la scrierea sa nu va mai bazati pe conventiile implicite (de exemplucast-uri implicite) ci explicitati toate operatiile dorite.II. Constructii valide in C si C++, dar cu sensuri diferite===========================================================(1) Literalii caracter, cum ar fi 'a', sunt de tip int in C si char in C++; in consecinta: - sizeof 'a' va produce rezultate in general diferite in cele doua limbaje (anume 1 in C++ si valoarea lui sizeof(int) in C); - in C 'a' va fi intotdeauna o expresie cu semn, indiferent daca char este sau nu un tip cu semn, in timp ce in C++ aceasta depinde de compilator.(2) In C orice variabila globala (i.e. cu file scope) declarata cu calificatorul const este vizibila si din alte fisiere sursa (are external linkage), cu exceptia cazului cand este declarata si cu static. In C++ orice variabila globala (i.e. cu file scope) declarata cu calificatorul const nu este vizibila in afara fisierului sursa in care a fost declarata (are internal linkage), cu exceptia cazului cand este declarata si cu extern. Exemple: /* cod C */ const int i = 1; /* external linkage */ extern const int j = 2; /* 'extern' este optional */ static const int k = 3; /* 'static' este obligatoriu */ /* cod C++ */ const int i = 1; /* internal linkage */ extern const int j = 2; /* 'extern' este obligatoriu */ static const int k = 3; /* 'static' este optional */ De aceea practica recomandata este sa definim constantele cu un specificator explicit static sau extern.(3) Functiile inline (exista atat in C99 cat si in C++) au implicit internal linkage in C si external linkage in C++.(4) Unele diferente prezentate in sectiunea I pot fi exploatate si pentru a crea cod care se compileaza in ambele limbaje dar se comporta diferit; de exemplu, urmatoarea functie va returna valori diferite in C si C++: extern int T; int size(void) { struct T { int i; int j; }; return sizeof(T); /* C: return sizeof(int) C++: return sizeof(struct T) */ } Acest lucru se intampla deoarece in C trebuie sa punem cuvantul struct infata numelui tipurilor structura (astfel ca sizeof(T) se refera la variabilaT), in timp ce in C++ putem omite cuvantul struct (astfel ca sizeof(T) serefera la numele T definit cu typedef-ul implicit) Atentie ca efectul este diferit daca punem declaratia cu extern ininteriorul functiei: atunci, prezenta unui identificator cu acelasi numein domeniul (scope) functiei inhiba ca typedef-ul implicit sa aiba efectin C++, iar functia va produce acelasi rezultat in C si C++ (anume valoarealui sizeof(int)). Observam de asemenea ca ambiguitatea din exemplul de mai sus este cauzatade utilizarea parantezelor impreuna cu operatorul sizeof; daca am fiscris sizeof T (deci fara paranteze) s-ar fi considerat ca T este oexpresie si nu un tip, astfel incat fragmentul de cod de mai sus nu s-arfi compilat in C++.(5) Atat C99 cat si C++ au un tip boolean, cu constantele true si false, dar ele se comporta diferit. In C++ tipul boolean este predefinit (built-in) si desemnat prin cuvantul cheie bool. In C99 tipul boolean este desemnat prin cuvantul cheie _Bool; in multe privinte, el se comporta ca un unsigned int, dar conversiile dinspre alte tipuri intregi sau pointeri inotdeauna sunt fortate la 0 si 1 (conversia este 0 d.d. expresia in cauza se evalueaza la 0 si este 1 in celelalte cazuri); fisierul header stdbool.h furnizeaza macro-urile bool, true si false care sunt definite ca _Bool, 1 si respectiv 0.III. Diferente de stil de programare====================================(1) C foloseste abordarea descendenta (top-down), in timp ce C++ foloseste abordarea ascendenta (bottom-up): in cazul C programul este formulat pas cu pas, fiecare pas este rafinat in detalii, in timp ce in C++ sunt formulate intai elementele de baza, care sunt apoi legate impreuna pentru a obtine sisteme mai largi. (2) C este orientat pe functii (function-driven), in timp ce C++ este orientat pe obiecte (object-driven): blocurile din care este construit un program C sunt functiile, in timp ce blocurile din care este construit un program C++ sunt obiectele.TODO: exemplu de dezvoltare a unei aplicatii C si C++ (eventual ca un curs separat). Lectia 4: Clase si obiecte, incapsulare =======================================I. Clase si obiecte, 'this', structuri, uniuni============================================== Clasele si obiectele sunt conceptele de baza ale OOP. Un OBIECT este o entitate ce poate incorpora date si/sau cod si care sepoate manevra ca un un tot logic, ca si cand ar fi o data obisnuita (putemavea variabile cu valori obiecte). Tipul unui obiect s.n. CLASA. Deci clasa este tipul, obiectul este data (INSTANTA a clasei). Entitatile (date, cod) incorporate in clase/obiecte s.n. MEMBRIIclasei/obiectului; membrii-data s.n. ATRIBUTE, membri-functie s.n. METODE. Capacitatea de a grupa mai multe entitati intr-un tot logic o aveau sistructurile sau uniunile din limbajul C, doar ca ele puteau grupa doar date. Structurile si uniunile sunt prezente si in C++, iar datorita asemanariicu obiectele, ele sunt tratate unitar: clasele propriuzise, tipurilestructura, tipurile uniune sunt considerate toate clase, iar instantele lorobiecte. Tipurile structura si uniune sunt considerate 'clase speciale'. Astfel, toate aceste tipuri se declara si se folosesc asemanator, iar multeproprietati sunt comune; exista si particularitati ale claselor speciale, pecare le vom mentiona la momentul potrivit.I.1. Clase si obiecte, this=========================== Intr-o forma simplificata, o clasa se declara astfel: class { : : ... : } ;In aceasta declaratie: - 'class' este un cuvant cheie; - poate fi unul dintre cuvintele cheie 'private', 'protected', 'public'; - este o lista de declaratii de membri data si/sau membri functie; - este o lista optionala de obiecte declarate de clasa respectiva. Membrii data (atributele) se declara asemanator ca in cazul structurilordin C. Membrii functie (metodele) pot fi definite complet (antet + corp) in cadrulclasei, sau pot fi doar declarate in clasa (prototip) si definite ulterior,sub forma: :: () { }('::' este operatorul de REZOLUTIE (scope resolution operator)). Cand sunt definite complet in cadrul clasei, metodele sunt implicitconsiderate ca fiind declarate 'inline'. Altfel, sunt implicit functiiobisnuite, dar putem cere pentru ele implementarea inline in mod explicit,scriind: inline :: () { }Pentru detalii despre funtiile/metodele inline, a se vedea lectia ***. Atributele si metodele pot avea calificatori auxiliari, ca 'static','const', etc. Atributele statice, pe langa declaratia din cadrul clasei, trebuie sa aibasi o definitie exterioara acesteia (caz in care vom folosi ::),de exemplu: class { ... static ; ... } ; ... ::;Intr-adevar, declaratia clasei contine doar declaratiile atributelor sale(codul care le descrie), nu si definitia acestora (codul care le face saexiste, in particular le aloca memorie); un atribut nestatic are instantedisjuncte pentru fiecare obiect al clasei, carora li se aloca memorie lacrearea obiectelor; un atribut static are o instanta unica pentru toateobiectele clasei si trebuie creat (alocat) inaintea acestor obiecte - deaceea este necesara definitia exterioara. De asemenea, atributele statice pot avea initializari, scrise in cadrulclasei (doar daca sunt si 'const') sau in definitia exterioara. Atributelenestatice nu pot avea initializari. Atributele 'const' trebuie sa fieinitializate (cele statice in interiorul sau exteriorul declaratiei clasei,cele nestatice in listele de initializare ale constructorilor); exemple: #include using namespace std; class cls{ int a = 0; // eroare, atribut nestatic initializat static int b = 1;// eroare, atribut static non-const initalizat in clasa static int c; static const int d = 3; static const int e; const int f; int g; // atribut non-static, non-const; se poate lasa neinitializat // si primeste o valoare implicita public: cls():f(5){g = 6;} void print(){ cout > c.re >> c.im;} void write(complex c){cout > c.im; return s; } ostream& operator> a >> b;; z1 = x + y; z2 = x + a; z3 = b + x; cout