Sunteți pe pagina 1din 79

Tudor L.

, Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
LIVIANA TUDOR

BAZELE PROGRAMÃRII

ÎN LIMBAJUL C++

MATRIX ROM
Bucureşti 2010

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
LIVIANA TUDOR

Bazele programãrii în limbajul C++

Editura MATRIX ROM


Bucureşti 2010

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Referent ştiinţific
prof. dr. ing. Mircea Petrescu
Universitatea POLITEHNICA Bucureşti

Tehnoredactare computerizatã
lect. dr. Tudor Nicoleta Liviana
Universitatea Petrol-Gaze din Ploiesti
ltudor@upg-ploiesti.ro
tudorlivia@yahoo.com

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Bazele programãrii în limbajul C++

1. Sisteme de calcul. Reprezentarea datelor în memoria calculatorului 9


1.1. Componenta hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2. Componenta software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3. Reprezentarea datelor în memoria calculatorului . . . . . . . 17
2. Principiile programãrii structurate. Metode de reprezentare a
algoritmilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.1. Principiile programãrii structurate . . . . . . . . . . . . . . . . . . . 22
2.2. Reprezentarea algoritmilor . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3. Aplicaţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3. Limbajul C++. Alfabet şi vocabular . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1. Alfabetul limbajului C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.2. Vocabularul limbajului C++ . . . . . . . . . . . . . . . . . . . . . . . . . 35
4. Tipuri de date. Operaţii de intrare-ieşire . . . . . . . . . . . . . . . . . . . . . . . . 47

4.1. Tipuri fundamentale de date . . . . . . . . . . . . . . . . . . . . . . . . 47

4.2. Structura programelor în limbajul C++ . . . . . . . . . . . . . . . 50

4.3. Funcţii uzuale de intrare-ieşire . . . . . . . . . . . . . . . . . . . . . . 52


57
4.4. Operaţii cu consola ( header <iostream.h>) . . . . . . . . . . . .
5. Structuri decizionale: if, switch, operatorul ?: . . . . . . . . . . . . . . . . . . . 59
5.1. Instrucţiunea if şi directiva #if . . . . . . . . . . . . . . . . . . . . . . . 59
5.2. Instrucţiunea switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
5.3. Operatorul ?: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6. Structuri iterative. Instrucţiuni pentru transferul execuţiei . . . . . . . . 71
6.1. Instrucţiunea for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
6.2. Instrucţiunea while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.3. Instrucţiunea do-while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.4. Instrucţiuni pentru transferul execuţiei . . . . . . . . . . . . . . . 84
7. Tablouri ( vectori, matrice, şiruri de caractere) . . . . . . . . . . . . . . . . . . . 89
7.1. Tablouri unidimensionale ( vectori) . . . . . . . . . . . . . . . . . . . 90
7.1.1. Cãutare în vectori . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
7.1.2. Sortarea unui vector . . . . . . . . . . . . . . . . . . . . . . . . . 99
7.1.3. Interclasarea a doi vectori ordonaţi . . . . . . . . . . . . 102
7.2. Tablouri bidimensionale ( matrice) . . . . . . . . . . . . . . . . . . . 105
7.3. Şiruri de caractere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
8. Structuri şi uniuni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
8.1. Structuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
8.2. Uniuni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
9. Funcţii C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
9.1. Prototipul, definiţia şi apelul unei funcţii . . . . . . . . . . . . . . 129
9.2. Transferul parametrilor unei funcţii . . . . . . . . . . . . . . . . . . 132
9.2.1. Transferul parametrilor prin valoare . . . . . . . . . . 133
9.2.2. Transferul parametrilor prin referinţã . . . . . . . . . 136
9.2.3. Transferul parametrilor de tip tablou . . . . . . . . . 138
9.2.4. Transferul parametrilor de tip structurã . . . . . . . 142
9.3. Funcţii cu un numãr neprecizat de parametri . . . . . . . . . . 145
9.4. Pointeri la funcţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
9.5. Funcţii recursive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
9.5.1. Funcţii direct recursive . . . . . . . . . . . . . . . . . . . . . . 150
9.5.2. Recursivitatea şi metoda reluãrii (backtracking) 155
10. Structuri de date alocate dinamic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
10.1. Operaţii cu variabile de tip pointer . . . . . . . . . . . . . . . . . . 159
10.2. Pointeri cãtre tablouri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
10.3. Structuri autoreferite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
11. Liste şi arbori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
11.1. Liste, stive, cozi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
11.2. Tabele de dispersie (Hash) . . . . . . . . . . . . . . . . . . . . . . . . . 188
11.3. Arbori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
11.3.1. Arbori binari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
11.3. 2. Arbori oarecare . . . . . . . . . . . . . . . . . . . . . . . . . . . 202

Programare orientatã pe obiecte în limbajul C++ . . . . . . . . . . . . . . . . 207


12.
207
12.1. Clase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
211
12.2. Moştenire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
216
12.3. Supraîncãrcare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
229
12.4. Polimorfism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Bibliografie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Capitolul 1

Sisteme de calcul. Reprezentarea datelor


în memoria calculatorului

Un sistem de calcul este un ansamblu de componente hardware


(echipamente fizice) şi componente software (componente logice), ce
coordoneazã şi controleazã executarea operaţiilor prin intermediul programelor
şi oferă servicii utilizatorului:
• componenta hardware (echipamente de calcul, dispozitive) asigurã prelucrarea
automatã a informaţiei, precum şi comunicarea utilizatorului cu sistemul de calcul;
• componenta software (sistem de operare şi programe specializate).
Programele realizeazã prelucrarea automatã, folosind echipamentele de
calcul. Sistemul de operare [Boian F. M., 1994] este un ansamblu de proceduri şi
programe care oferã unui grup de utilizatori posibilitatea de utilizare eficientã a
sistemului de calcul.
În funcţie de metoda de reprezentare a informaţiei, sistemele de calcul au
fost clasificate în:
• sisteme de calcul analogice ( informaţia este codificată sub forma unor
mărimi fizice);
• sisteme de calcul numerice, care codifică informaţia sub formă discretă
(numerică).
Un sistem de calcul numeric prelucrează automat informaţia codificată
sub formă de valori discrete, conform unui program ce indică o succesiune
determinată de operaţii aritmetice şi logice, având la bază un algoritm de
prelucrare. Structura unui calculator numeric a fost definită în anul 1945 de către
von Neumann, ca fiind constituitã din: UI (unitate de intrare), M (memorie),
UAL (unitate aritmetico-logicã), UC (unitate centralã) şi UE (unitate de ieşire).

1.1. Componenta hardware


Schema de principiu a unui sistem de calcul este prezentatã în figura 1:
Unitatea centralã (UC) gestioneazã activitatea componentelor sistemului
de calcul, asigurã execuţia programelor din memoria centralã şi executã
operaţiile de prelucrare automatã a informaţiilor.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
UC = CPU (unitate centralã de prelucrare ) + MI ( memorie internã )

CPU = UCC ( unitate de comandã şi control ) + UAL ( unitate aritmetico-logicã)

Fig. 1. Schema unui sistem de calcul.

Unitatea centralã conţine memoria centralã, unitatea aritmetico-logicã şi


unitatea de comandã şi control.
Memoria centralã conţine regiştrii pentru memorarea temporarã a datelor
programului care se executã şi pãstreazã datele în locaţii codificate binar,
identificate prin adrese de memorie.
Dispozitivele aritmetico-logice executã operaţiile aritmetice şi/sau logice
sau alte operaţii specificate de instrucţiunile executate.
Unitatea de comandã şi control coordoneazã activitatea celorlalte
componente ale sistemului de calcul şi asigurã buna funcţionare a unitãţii
centrale.

Unitãţile de schimburi multiple permit comunicarea între sistemul de


calcul şi exterior, coordonând funcţionarea dispozitivelor periferice.

Dispozitivele periferice sunt imprimanta, monitorul (display – ecran),


unitãţile de discuri, tastatura, mouse, scanner, plotter, boxe, camerã Web.

Unitatea de memorie : Unitatea fundamentalã de mãsurã a memoriei este


bitul.
Bit (binary digit) = cantitatea de informaţie ce poate fi memoratã într-o
celulã binarã.
O locaţie de memorie = o succesiune de celule binare folosite în timpul
operaţiilor de citire din memorie sau scriere în memorie.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Un octet (byte) 1o = 1 B = 8 biţi = cantitatea de informaţie memoratã într-o
locaţie.
Capacitatea totalã a memoriei reprezintã numãrul maxim de octeţi ce pot
fi înregistraţi.
Un Kilo-octet 1 Ko = 1 Kb (kilo-byte) = 1024 o = 210 o
Un Mega-octet (1 Mo) = 1024 Ko = 210 Ko
Un Giga-octet = 1024 Mo = 210 Mo
Un Tera-octet = 1024 Go = 210 Go

Memoria este de douã tipuri :


• memorie internã pãstreazã datele şi instrucţiunile programelor în locaţii de
memorie identificate prin adrese sub formã de cifre binare, grupate în octeţi
(byte), date care sunt prelucrate de procesor.
Din punct de vedere logic, memoria internă este organizată în blocuri de
memorie, 1 bloc = 64 Kb.
Se cunosc urmãtoarele tipuri de memorii interne:
- memoria RAM (Random Access Memory) este memoria cu acces aleator,
ce conţine datele programului ce este executat la momentul curent,
procedurile/programele sistemului de operare. Este volatilã (conţinutul ei
dispare la închiderea calculatorului) şi asigurã accesul rapid la date, prin
operaţii de citire şi scriere. Din punct de vedere fizic, memoria RAM este un
circuit integrat alcãtuit din milioane de tranzistoare şi condensatoare.
Memoria RAM poate fi: SRAM şi DRAM:
SRAM (static) – utilizeazã mai mulţi tranzistori pentru o celulã de memorie
şi este folositã în special în memoria CACHE. Memoria cache stocheazã
datele refolosite de către procesor
DRAM (dinamic) – utilizeazã o pereche tranzistor/condensator pentru
fiecare celulã de memorie şi necesitã un refresh continuu deoarece
tranzistorul se descarcã foarte rapid. O celulã stocheaza 1 bit. Celulele sunt
dispuse într-o matrice de linii şi coloane la intersecţia cãrora se aflã adresa
de memorie.
- memoria ROM (Read Only Memory) din care se pot doar citi date, nu şi
scrie. Nu este volatilã. Include:
PROM (Programmable Read Only Memory)
EPROM (Eraseable Programmable Read Only Memory) – permite în plus
ştergerea datelor
EEPROM (Electricaly Eraseable Programmable Read Only Memory) – pot fi
atât citite cât şi şterse în mod selectiv şi programate de cãtre sistemul care le
utilizeazã.
- memoria CMOS conţine informaţii despre caracteristicile fizice ale
calculatorului (configuraţia calculatorului, tipul şi capacitatea HDD,
capacitatea memoriei interne, data calendaristicã, parola de acces etc.),
informaţii utilizate de BIOS (Basic Input Output System). Memoria CMOS

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
are capacitate foarte micã (64B), permite operaţii de citire şi scriere a datelor
şi este nevolatilã.

• memorie externã constituitã din suporturi electromagnetice sau optice


reutilizabile, pe care se pãstreazã datele codificate în formã binarã. Memoria
externã este mai lentã decât memoria internã, dar conţine cantitãţi mari de date.
Memoria externã utilizeazã:
- suporturi electromagnetice (floppy-disk, hard-disk HDD) – suprafaţa
discului este împãrţitã în piste (cercuri concentrice), care sunt împãrţite în
sectoare egale. Pistele care au aceeaşi razã formeazã un cilindru. Locaţia de
memorare de pe disc este sectorul, care are o capacitate de 512 octeţi
- suporturi optice – discurile optice (discuri compact-CD si discuri DVD-
disc video digital). Suprafaţa discului este împãrţitã în piste continue, în
formã de spiralã. Spaţiul de memorare este divizat în blocuri pentru
adresarea unei locaţii.
- suporturi electronice – cardurile de memorie flash. Celulele binare (biţii)
utilizaţi corespund stãrii anumitor circuite (închis-deschis, prezenţa sau
absenţa curentului electric în circuite).
Hard Disk-ul ( disc dur, rigid) conţine un strat magnetic pe un suport
rigid. Disk-ul hard este construit dintr-un metal dur şi uşor, de obicei din
aluminiu, fiind singura componentã a unui PC care nu este 100% electronicã. Din
aceastã cauzã, ea este şi mai înceatã, în comparaţie cu restul componentelor
calculatorului personal.

1.2. Componenta software


Componenta software este formatã din sistemul de operare ( S.O.) şi
programele pentru aplicaţii.
Definiţie 1 – Sistemul de operare este un set de proceduri manuale şi
automate care oferã unui grup de utilizatori posibilitatea sã foloseascã în acelaşi
timp şi în mod eficient sistemul de calcul.
Definiţie 2 – Sistemul de operare este un ansamblu de programe care
faciliteazã accesul la sistemul de calcul unuia sau mai multor utilizatori şi asigurã
o exploatare eficientã a echipamentului de calcul.
Caracteristicile sistemului de operare:
- este rezident în memoria internã (RAM) a calculatorului (se încarcã automat
la fiecare deschidere sau resetare a calculatorului)
- conţine un încãrcãtor (care se aflã pe prima pistã a fiecãrui disc de boot)
- în memoria ROM, existã un preîncãrcãtor care este folosit la iniţializarea
lucrului cu calculatorul (iniţializarea echipamentelor periferice, identificarea
configuraţiei sistemului de calcul, cãutarea unui disc de boot (cu sistemul de

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
operare). Acesta încarcã în RAM nucleul sistemului de operare şi îl lanseazã în
execuţie. Nucleul va încãrca programele de aplicaţie şi utilitarele.

Componentele sistemului de operare sunt:


- nucleul ( Kernel )
- interfaţa ( shell )

Nucleul ( Kernel) conţine programele necesare pentru gestionarea


resurselor calculatorului şi pentru controlarea activitãţii echipamentelor.
Funcţiile nucleului constau în:
- administrarea resurselor fizice: procesorul, memoria internã şi sistemul I/O
(Input/Output)
- depistarea şi tratarea evenimentelor deosebite (inexistenţa hârtiei la
imprimantã, citirea dintr-un fişier inexistent, rezultatul unei operaţii aritmetice ce
depãşeşte capacitatea zonei de memorie alocatã)
- asigurã operaţiile de I/O la nivel fizic (cu echipamentele periferice)
- asigurã operaţiile de I/O la nivel logic (unitatea logicã de acces la
echipamentele periferice este fişierul)
- gestionarea fişierelor de pe disc.

Interfaţa sistemului de operare (SHELL)


- defineşte modul în care utilizatorul interacţioneazã cu S.O.
- interfaţa poate folosi: un limbaj de comandã (ex. s. o. MS-DOS) sau interfaţa
graficã (G.U.I. - graphical user interface, ex. s. o. Windows ).

Funcţiile sistemului de operare sunt:


- pregãtirea şi lansarea în execuţie a programelor de aplicaţii ( figura 2):
- funcţia de gestiune a memoriei ( stabilirea procesului cãruia i se alocã
memorie, momentul de timp şi cantitatea, în cazul multiprogramãrii, alocarea
resursei asigurând accesul şi protecţia proceselor solicitante şi dezalocarea
resursei)
- funcţia de gestiune a procesorului ( U. C. ) – alocã resursele procesorului la
un proces, prin pregãtirea şi încãrcarea unor regiştrii hardware şi dezalocã
resursa
- funcţia de gestiune a dispozitivelor periferice, a unitãţilor de control şi a
canalelor ( I/O Traffic Controller) – alocã resura şi iniţiazã operaţia de I/O şi
dezalocã resursa
- funcţia de gestiune a informaţiei constã în:
• localizarea informaţiei, starea, utilizarea ( File System)
• metode de acces şi protecţie

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Fig. 2. lansarea în execuţie a unui program.

• alocarea resursei prin deschiderea fişierului ( OPEN)


• dezalocarea resursei prin închiderea fişierului ( CLOSE).

Programele S. O.
Componentele majore ale unui S.O. sunt:
• programe de comandã şi control ( PCC ) - coordoneazã şi controleazã
funcţiile S.O., fiind programe supervizoare, monitoare şi executive). Au
componente
- rezidente ( sunt încãrcate în memoria internã încã de la generarea
S.O. şi pãstrate acolo pe tot parcursul execuţiei lucrãrilor de cãtre
S.O., ele formeazã nucleul S.O.)
- tranzitorii ( componente ce rãmân în memoria auxiliarã, fiind apelate
şi executate de cãtre nucleul S.O.)
• programe de servicii ( folosite pentru dezvoltarea programelor de aplicaţie,
fiind executate sub supravegherea PCC ). Ele pot fi clasificate în:
- translatoare (asamblor, macroasamblor, compilator, interpretor )
- editoare de legãturi
- încãrcãtoare
- editoare de texte
- programe pentru organizarea colecţiilor de date ( fişiere, baze de
date)
- alte utilitare.

Translatoarele de limbaje
• traduc programele sursã în programe obiect, ale cãror instrucţiuni în limbaj
maşinã pot fi executate de sistemul de calcul
• sunt douã categorii de translatoare:

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
- compilative ( realizeazã numai traducerea programului sursã în
program obiect), de exemplu:
- asambloare – traduc programele sursã, scrise în limbaje de
asamblare specifice S.C.
- compilatoare – traduc programele sursã scrise în limbaje
evoluate; unele compilatoare efectueazã şi lansarea în execuţie a
programelor ( LOAD and GO)
- interpretative (odatã cu compilarea, are loc si execuţia programului ).

Compilatoarele creeazã o formã intermediarã arborescentã a


instrucţiunilor din programul sursã, astfel:
- orice variabilã este un nod terminal al arborelui
- orice operator creeazã un arbore binar a cãrui ramurã stângã este primul
operand, iar cea din dreapta este operandul 2.
Exemplu: Sã se construiascã arborele binar corespunzator acţiunii unui
compilator, pentru calculul expresiei x ( figura 3):

x = a * ( b – c ) + d * ( e + 10)

Fig. 3. arbore binar corespunzãtor acţiunii unui compilator.

Etapele unui proces de compilare şi componentele implicate sunt


evidenţiate în figura 4:
Analiza lexicalã – descompune programul sursã în atomi lexicali
(identificatori, cuvinte rezervate, constante, operatori ) şi îi introduce în tabela de
simboluri sub formã codificatã.
Analiza sintacticã – şirul de atomi lexicali este analizat pentru depistarea
unor structuri sintactice, cum ar fi expresii, liste, proceduri, plasându-le într-un
arbore de derivare.
Analiza semanticã – genereazã un grup de instrucţiuni simple cu format
fix (cod intern); dacã arborele sintactic nu respectã gramatica limbajului, se
semnaleazã eroare.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Fig. 4. Etapele procesului de compilare.

Optimizarea codului – presupune eliminarea variabilelor inutile, în


vederea unei execuţii mai eficiente.
Generarea codului – alocã zone de memorie pentru pãstrarea datelor în
timpul execuţiei şi produce codul obiect (în limbaj de asamblare).
Gestiunea structurilor de date vizeazã o colecţie de proceduri care creeazã
şi actualizeazã bazele de date cu care lucreazã celelalte faze. În baze de date se
memoreazã tabelele identificatorilor, ale constantelor, ale cuvintelor cheie şi ale
procedurilor standard.
Tratarea erorilor este realizatã de o colecţie de proceduri ce sunt activate
când se depisteazã o eroare în program; utilizatorul primeşte mesaje de
avertizare, iar compilatorul continuã analiza sintacticã pentru a depista alte erori.

Exemple de sisteme de operare pot fi:


• sistemul de operare Windows: are o interfaţã utilizator graficã GUI
(Graphical User Interface) şi cu un set bogat de aplicaţii:
- suprafaţa de lucru se numeşte desktop şi conţine pictograme
(dosare)
- aplicaţia My Computer conţine informaţii referitoare la cele mai
importante componente ale sistemului de calcul ( unitãţi de disc,
imprimante instalate, etc.)
- aplicaţia My Network Places afişeazã informaţii despre conexiunea
la reţele locale şi calculatoarele accesate
- butonul START se aflã pe taskbar şi conţine aplicaţiile instalate
• sistemul de operare Unix este scris în proporţie de 90% în limbajul C++.
Componentele S.O. Unix sunt:
- nucleul (Kernel), care realizeazã funcţiile de bazã ale S.O.
- interfaţa asiguratã de limbajul de comandã Shell, pentru
comunicarea utilizator – sistem de calcul
- programe utilitare, ce oferã posibilitãţi suplimentare de utilizare a
sistemului de calcul
- programe de aplicaţii, pentru dezvoltare de aplicaţii consolã sau
vizuale

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
• sistemul de operare Netware, utilizat pentru administrarea serverelor de
fişiere, stocarea fişierelor, asigurând prelucrarea distribuitã şi centralizatã a
datelor, securitatea sistemului (exemplu, reţele Novell Netware).
Comunicarea este asiguratã de:
- folosirea de protocoale şi drivere LAN
- încãrcarea lui Netware Dos Requester pe fiecare client al reţelei
- folosire Link Support Layer (LSL)
- exemple de tipuri de clienţi acceptaţi de S.O. Netware 3.12. sunt:
clientul DOS, OS/2, Macintosh, Unix
Protocolul de comunicaţie este un set de reguli ce determinã modul de
comunicare în reţea, între staţii de lucru şi server.

1.3. Reprezentarea datelor în memoria calculatorului


Fie p ∈ N, p ≥ 2.
Definiţie. Se defineşte o bazã de numeraţie: Bp={ bi / 0 ≤ i < p},
corespunzãtoare primelor p numere naturale [Perjeriu E., Vaduva I., 1986]:
Np = {0, 1, …. , p-1}.
Funcţia f: Np → Bp asociazã fiecãrui numãr i ∈ Np → simbolul bi = f( i ) ∈
∈ Bp,
f( i ) = bi.
Observaţie: Sistemele de calcul utilizeazã bazele de numeraţie 2 şi 16:
B2 = { 0, 1}
B16 = { 0, 1, 2, ...., 9, A, B, C, D, E, F}.

Reprezentarea numerelor întregi intr-o bazã de numeraţie datã


Fie x ∈ N şi p ∈ N, p ≥ 2, p este o bazã de numeraţie. Ne propunem sã
reprezentãm numãrul întreg x în baza p.
Prin împãrţiri repetate ale numãrului x la p se obţin :
x = p * co + ro, co < x, 0 ≤ ro < p
co = p * c1 + r1, c1 < co , 0 ≤ r1 < p
…………………………………..
cn-1 = p * cn + rn, cn = 0 < cn-1, 0 ≤ rn < p
⇒ x se poate reprezenta ca un polinom:
x = p * co + ro = p * (p * c1 + r1 ) + ro = ... = pn rn + ... + p1r1 + p0r0.
În şirul resturilor : rn, rn-1, ... , r1 , r0, se aplicã funcţia f :
f( ri) = fi ∈ Bp (0 ≤ ≤ i < n) şi se concateneazã ⇒ se obţine reprezentarea
numãrului x în baza p:
xp = fn … f1f0

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
x co c1 … cn = 0
ro r1 … rn
f0 f1 … fn

Exemplul 1: Sã se reprezinte numãrul x = 27 în baza 2

x = 27 co = 13 c1 = 6 c2 = 3 c3 =1 c4 = 0
r0 = 1 r1 = 1 r2 = 0 r3 = 1 r4 = 1
1 1 0 1 1

Reprezentarea numãrului 27 în baza 2 este: 272 = 11011= 1*2o+1*21 + 0*22 +


1* 23+ 1*24 = 1 + 2 + 8 + 16 = 27

Exemplul 2: Sã se reprezinte numãrul x = 6 în baza 2

x=6 co = 3 c1 = 1 c2 = 0
r0 = 0 r1 = 1 r2 = 1
0 1 1

Reprezentarea numãrului 6 în baza 2: 62 = 110 = 0*2o+1*21 + 1*22 = 6

Exemplul 3: Sã se reprezinte numãrul x = 27 în baza 16

x = 27 co = 1 c1 = 0
r0 = 11 r1 = 1
B 1

Scrierea numãrului 27 în baza 16: 2716 = 1B = B*160 + 1*161 = 11 + 16 = 27

Reprezentarea numerelor reale intr-o bazã de numeraţie datã


Fie x ∈ R+ şi p ∈ N, p ≥ 2, p este o bazã de numeraţie. Atunci numãrul
real x se poate scrie:

x = [x] + {x}, 0 ≤ {x} < 1,

unde [x] este partea întreagã a lui x şi {x} este partea fracţionarã a lui x.
Reprezentarea numãrului real x în baza p se reduce la reprezentarea
numãrului {x} în baza p şi foloseşte urmãtorul algoritm:
• se înmulţeşte în mod repetat partea fracţionarã a lui x cu baza p
• se descompune în parte întreagã şi parte fracţionarã, ş.a.m.d.
Notãm x1 = p * {x} = [x1] + {x1} = r -1 + {x1}, 0 ≤ r -1 < p
x2 = p * {x1} = [x2] + {x2} = r -2 + {x2}, 0 ≤ r -2 < p

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
x3 = p * {x2} = [x3] + {x3} = r -3 + {x3}, 0 ≤ r -3 < p
……………………………………………………..
xn = p * {xn-1} = [xn] + {xn} = r -n + {xn}, 0 ≤ r -n < p.

Se obţine reprezentarea polinomialã a lui {x}:

{x} = p-1 r-1 + p-2 r-2 + ... + p-nr-n + ...

Notãm f( r -i) = f -i ∈ Bp (1 ≤ i < n) ⇒ reprezentarea aproximativã a lui {x}p


cu n cifre la partea zecimalã este:

{x}p = p-1 r-1 + p-2 r-2 + ... + p-nr-n + ... = f( r –1) f( r –2) … f( r -n) = f –1 f –2 … f -n

{x}x1 x2 … xn
r -1 r -2 … r -n
f –1 f –2 … f -n
Exemplu: Sã se reprezinte x = 27.513 cu 4 cifre zecimale în baza 16
x = 27.513 = 27 + 0.513 = [x] + {x}
[x] = 27 1 0
11 1
B 1
[x] 16 = [ 27 ]16 = 1B
{x} = 0.513 0513*16 = 8.228 0.228*16 = 3.648 0.648*16 = 10.368 5.888
8 3 10 5
8 3 A 5

{ x } 16 = { 0.513 } 16 = 0.83A5

 x 16 = [x] 16 + { x } 16 = 1B + 0.83A5 = 1B.83A5

Reprezentarea numerelor întregi în memoria calculatorului

Pe un cuvânt-memorie ( 4o = 32 biti), se pot înregistra numere întregi


pozitive cu maximum 32 cifre binare sau 8 cifre hexazecimale < 232 – 1.
Se partiţioneazã intervalul [ 0, 232 – 1] în: [ 0, 231 – 1] U [231, 232 – 1]

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
x, daca 0 ≤ x ≤ 31 − 1
y= 

2  - 231 ≤ x ≤ 231 – 1
232 − | x |, daca − 231 ≤ x < 0 (prin complementare)

0, daca x ≥ 0
Observaţie: Primul bit = 
1, daca x < 0

Exemplul 1: Sã se reprezinte numãrul x = 27 în memorie:

2716 = 1B; 272 = 11011

00000000 00000000 00000000 00011011


0 0 0 0 0 0 1 B

Exemplul 2: Sã se reprezinte numãrul x = 231 – 1 în memorie:

x = 231 – 1 = 7F.FF.FF.FF16

01111111 11111111 11111111 11111111


7 F F F F F F F

Exemplul 3: Sã se reprezinte numãrul x = -231 în memorie:

y = 232 – |x| = 232 – 231 = 231 * 2 – 231 = 231 ( prin complementare) = 8000000016

10000000 00000000 00000000 00000000


8 0 0 0 0 0 0 0

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Capitolul 2

Principiile programãrii structurate.


Metode de reprezentare a algoritmilor

Rezolvarea problemelor cu ajutorul calculatorului presupune existenţa unei


faze premergãtoare în care se concepe algoritmul.
Un algoritm este o secvenţã finitã de operaţii, ordonatã şi complet definitã,
care, pornind de la date de intrare, furnizeazã date de ieşire (rezultate).
Un algoritm trebuie sã satisfacã în general urmãtoarele cerinţe:
• claritate – descrierea algoritmului se realizeazã într-un mod precis, fãrã
ambiguitãţi, conţinând toate etapele de calcul, toate posibilitãţile ce apar, pentru
a obţine o soluţie
• generalitate – un algoritm este util dacã rezolvã o clasã întreagã de probleme
• finitudine - algoritmul trebuie sã furnizeze rezultate pentru orice set de date
de intrare, într-un numãr finit de paşi. O eroare care trebuie evitatã constã în
utilizarea de structuri repetitive infinite ( bucle infinite), care blocheazã
programele.
Operaţiile elementare care apar într-un algoritm sunt:
- operaţii de citire-scriere ( intrare-ieşire) – datele de intrare se citesc, iar
datele de ieşire se scriu
- operaţii de atribuire – unei variabile i se atribuie valoarea unei expresii
- operaţii de decizie – se determinã valoarea de adevãr a unei expresii
logice şi, în funcţie de rezultatul obţinut, se ramificã execuţia
algoritmului.
Algoritmii utilizeazã variabile pentru operaţiile elementare. De exemplu,
variabilele de intrare se citesc, se prelucreazã, iar variabilele de ieşire se afişeazã
(se scriu).

Variabile
O noţiune de bazã în programare este cea de variabilã. O variabilã
reprezintã un ansamblu de patru elemente:
- numele variabilei
- tipul ei
- valoarea ei
- adresa din memorie, unde se salveazã variabila.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Numele unei variabile este format din unul sau mai multe caractere: litere,
cifre, caracterul underscore (de subliniere), primul caracter fiind literã. Referirea
unei variabile se realizeazã prin intermediul numelui sãu. Exemple: a, b, S, min,
maxim, x1, etc.
Tipul variabilei indicã mulţimea de valori posibile ( întreg, real, caracter,
boolean, etc.), operaţiile ce pot fi aplicate acesteia, precum şi modul de
reprezentare în memoria calculatorului. Fiecare limbaj de programare permite
folosirea unor tipuri elementare de date, specifice acestuia. Pentru fiecare
variabilã folositã trebuie declarat în mod explicit tipul de date.
Valoarea unei variabile este valoarea efectivã memoratã la un moment dat. O
variabilã are în orice moment o singurã valoare, care se poate modifica printr-o
instrucţiune de atribuie sau de citire.
Adresa de memorie a unei variabile este adresa fizicã la care se aflã valoarea
variabilei în memoria calculatorului.

2.1. Principiile programãrii structurate


Odatã cu dezvoltarea informaticii a apãrut conceptul de programare
structuratã. Ideea de bazã constã în elaborarea algoritmilor folosind structuri
elementare, având un singur set de date de intrare şi un singur set de date de
ieşire.
Un principiu de bazã al programãrii structurate este enunţat de teorema de
structurã a lui Böhm şi Jacopini, conform cãreia orice algoritm se poate construi
folosind doar trei structuri de control: secvenţialã, alternativã ( decizionalã) şi
repetitivã.
Structurile elementare utilizate în programarea structuratã sunt prezentate
în figura 1.
- structura liniarã ( secvenţialã) – constã în execuţia necondiţionatã a
unei secvenţe de instrucţiuni
- structura alternativã (decizia) – ramificã execuţia algoritmului în
funcţie de valoarea de adevãr a unei condiţii evaluate
- structura repetitivã ( repetiţia) – constã în execuţia repetatã de un
numãr finit de ori a unei secvenţe de instrucţiuni. Existã
posibilitatea utilizãrii de structuri repetitive cu test inţial (se
evalueazã condiţia la început şi dacã este îndeplinitã, se executã
instrucţiunile) sau structuri repetitive cu test final ( se executã
instrucţiunile cel puţin o datã şi la final se evalueazã condiţia).

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Fig. 1. Structuri de control.

Un principiu de bazã al programãrii structurate este programarea


descendentã, care presupune descompunerea unei probleme complexe în
subprobleme mai simple. Fiecãrei subprobleme îi corespunde un modul de
instrucţiuni, realizându-se astfel o structurare modularã a problemelor. Un
avantaj al programãrii modulare constã în extinderea şi modificarea programelor
prin actualizarea sau adãugarea unor module cu instrucţiuni.

2.2. Reprezentarea algoritmilor


Pentru descrierea algoritmilor se pot utiliza:
- schema logicã
- pseudocodul
- limbajul de programare

Schema logicã
Este o reprezentare graficã, ce permite vizualizarea înlãnţuirii şi
subordonãrii secvenţelor de operaţii. Foloseşte simboluri grafice numite blocuri
care prin forma lor, indicã tipul operaţiei.

Pseudocodul
Este o metodã de reprezentare a algoritmilor ce tinde spre un limbaj de
programare, neavând totuşi o sintaxã rigidã, precum limbajele de programare.
Elementele componente ale limbajului pseudocod sunt:

• instrucţiuni pentru scriere


write lista_variabile
Exemple: write x
write (“suma este “, s)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
• instrucţiuni pentru citire
read lista_variabile
Exemple: read n

• instrucţiuni de atribuire
variabila  expresie
Exemple: S  0
S=0

• instrucţiuni decizionale
if condiţie then instructiune_1
else instructiune_2
endif
Exemplu: if x >=0 then write ( “ numar pozitiv”)
else write (“negativ”)
endif

• instrucţiuni repetitive cu contor


for contor = valoare_initiala, valoare_finala
instructiune_1
instructiune_2

endor
sau:
for contor = valoare_initiala, valoare_finala
instructiune_1
instructiune_2

repeat

Exemplul 1) afişarea primelor 100 numere naturale


for i = 1 , 100
write i
repeat

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Exemplul 2) Calculaţi suma primelor n numere naturale ( n este dat):
procedure suma
read n
s0
for i = 1 , n
ss+i
repeat
write (‘suma s =’,s)
end

• instrucţiuni repetitive cu test iniţial


while conditie:
instructiune_1
instructiune_2

repeat
Exemplul 1) afişarea primelor 100 numere naturale
i=1
while i <= 100
write i
i  i +1
repeat
Exemplul 2) Afişaţi primele n numere naturale, unde n este dat.
procedure afisare
read n
i=1
while i <= n
write i
i i+1
repeat
end

• instrucţiuni repetitive cu test final


do
instructiune_1
instructiune_2

until conditie

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Exemplul 1) afişarea primelor 100 numere naturale
i=0
do
i  i +1
write i
until i >= 100
Exemplul 2) Afişaţi primele n numere naturale, unde n este dat.
procedure afisare
read n
i=1
do
write i
i  i+1
until i >= n+1
end

• instrucţiuni pentru apelul procedurilor


procedure nume [ ( lista de parametri formali )]
[ declaratii locale]
[ secvenţã de instrucţiuni ]
[ return]
end
Observaţii:
- apelarea unei proceduri se realizeazã prin instrucţiunea
call nume [ (lista de valori)]
- o apelare corectã are loc dacã între lista parametrilor şi cea a
valorilor existã o bijecţie ( corespondenţã de numãr, tip şi
ordine)
- o procedurã poate apela o altã procedurã
- terminarea execuţiei unei proceduri se face la întâlnirea unei
instrucţiuni return sau end, care determinã întoarcerea în
programul apelant, la instrucţiunea imediat urmãtoare
instrucţiunii call, care a apelat-o.
Exemplu: Sã se calculeze suma a 2 numere a şi b reale
procedure suma
integer a, b, s
read a, b
sa+b

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
write (‘ suma = ‘, s)
return
end
Apelul procedurii într-o aplicaţie se realizeazã asfel:
call suma

• instrucţiuni pentru apelul funcţiilor


function nume [ ( lista de parametri formali )]
[ declaratii locale]
[ secvenţã de instrucţiuni ]
[ return]
end
Observaţii:
- apelarea unei funcţii se realizeazã prin instrucţiuni precum:
call nume [ (lista de valori)]
sau
expresie  nume [ (lista de valori)]
sau alte tipuri de instrucţiuni de scriere sau repetitive, etc., în
funcţie de aplicaţie
Exemplu: Sã se calculeze valoarea funcţiei f definitã astfel
3x − 5, x < 5
f(x) = 10, 5 ≤ x ≤10
9 x + 1, x > 10

function f ( x )
if x < 5 then f = 3 * x – 5
else if x <= 10 then f = 10
else f = 9 * x +1
endif
endif
end
Apelul functiei se poate realiza asfel:
write f(x)
sau
call f(x)
sau se pot utiliza alte variante de apel, în funcţie de aplicaţie.

• instrucţiunea

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
GOTO etichetã
unde eticheta indicã o instrucţiune din aceeaşi procedurã
Este indicat sã evitãm folosirea instrucţiunii goto deoarece îngreuneazã
înţelegerea algoritmului

• declaraţia unui tablou


array A( n )

2.3. Aplicaţii
 Se dau 3 numere reale x, y, z. Sã se calculeze valoarea expresiei:
 x + y, z < 0

E=  x * y, z = 0
0, z > 0

procedure expresie
integer x, y, z, e
read x, y, z
if z < 0 then e  x + y
else if z = 0 then e  x * y
else e  0
endif
endif
write (‘expresia E = ‘, e)
return
end
 Sã se citeascã n numere reale. Calculaţi şi afişaţi suma celor n numere.
Metoda 1: folosnd o structurã repetitivã “for”
procedure calcul
read n
s0
for i = 1 , n
read x
ss+x
repeat
write (‘suma s =’, s)
end
Metoda 2: folosnd o structurã repetitivã “while”

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
procedure calcul
read n
s0
i=1
while i <= n
read x
ss+x
i i+1
repeat
write (‘suma s =’,s)
end
Metoda 3: folosnd o structurã repetitivã “do-until”
procedure calcul
read n
s0
i=0
do
i  i +1
read x
ss+x
until i >= n
write (‘suma s =’,s)
end
 Sã se citeascã n natural. Afişaţi divizorii unui numãr n.
procedure divizori
read n
sw  0
for i = 2 , int ( n/2)
if n /i = int ( n/i)
write ( i, ‘ divizor’)
sw  1
endif
repeat
if sw = 0 then write (‘nu exista divizori’)
endif
end
 Fie vectorul A = ( a[1], a[2], ..., a[n]), unde n este numãr natural dat. Numãraţi
elementele pare.
procedure divizori
array a[n]

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
read n
sw  0
for i = 1 , n
read ( a[i])
if a[i] mod 2 = 0 { restul impartirii la 2 }
write ( a[i], ‘ numar par’)
sw  1
endif
repeat
for i = 1 to n
write { a[i] )
repeat
if sw = 0 then write (‘nu exista numare pare’)
endif
end
 Ordonarea crescãtoare a elementelor unui vector prin interschimbarea elementelor
procedure ordonare
array a[n]
read n
for i = 1 , n
read ( a[i])
repeat
write (‘vectorul initial:’)
for i = 1 to n
write { a[i] )
repeat
for i = 1 to n – 1
for j = i + 1 to n
if a[i] > a[j] then
aux  a[i]
a[i]  a[j]
a[j]  aux
endif
repeat
repeat
write (‘vectorul ordonat crescator:’)
for i = 1 to n
write { a[i] )
repeat
end
 Fie o matrice pãtraticã de ordinul n, cu numere întregi. Sã se calculeze suma
elementelor de pe diagonala secundarã a matricei:

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
procedure diagonala
array a[n, n]
read n
for i = 1 , n
for j = 1 to n
read ( a[i, j])
repeat
repeat
write (‘matricea A:’)
for i = 1 to n
for j = 1 to n
write ( a[i, j])
repeat
writeln
repeat
s0
for i = 1 to n
for j = 1 to n
if i + j = n + 1 then s  s + a[i, j]
endif
repeat
repeat
write (‘s =’, s)
end

• Fie n un numãr întreg. Sã se verifice dacã este prim.


procedure prim
read n
sw  0
for i = 2 , int ( n/2)
if n /i = int ( n/i)
sw  1
endif
repeat
if sw = 0 then write (n, ‘este prim’)
else write (n, ‘nu este prim’)
endif
end

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Probleme propuse

1. Fie o matrice A(m, n), cu m linii şi n coloane, cu elemente numere întregi. Sǎ


se formeze un şir cu elementele pare, respectiv un şir cu elementele impare.
2. Se dǎ o matrice pǎtraticǎ A(n, n), cu n linii şi n coloane, cu elemente numere
întregi. Sǎ se ordoneze crescǎtor elementele de pe diagonala principalǎ, prin
permutǎri de linii şi coloane.
3. Fie un vector A( n), cu elemente numere reale. Sǎ se inverseze elementele
vectorului ( primul ↔ ultimul, al doilea ↔ penultimul, etc.). Exemplu: pentru
A = ( 1.5, 5.7, -2.3, 25.2), rezultǎ A = ( 25.2, -2.3, 5.7, 1.5).
4. Pentru douǎ matrice A(m,n) şi B(m, n), sǎ se determine matricea sumǎ C(m,n),
C = A + B.
5. Fie o matrice A ( m, n), cu elemente de tip char. Sǎ se ordoneze crescǎtor
elementele de pe fiecare linie a matricei.
6. Fie un vector A ( n), cu numere întregi. Sǎ se transforme vectorul A în
mulţimea B ( elementele unei mulţimi sunt unice).
7. Fie un numǎr n întreg dat. Sǎ se calculeze suma cifrelor sale.
8. Se citeşte în mod repetat un numǎr n natural pânǎ la introducerea unui numǎr
n = 0. Sǎ se determine cifra maximǎ a fiecǎrui numǎr n.
De exemplu, n = 48 ( max = 8 )
n = 731 ( max = 7)
n=0
9. Sǎ se citeascǎ în mod repetat un numãr pânǎ la introducerea rǎspunsului ‚N’
sau ‚n’ la întrebarea „Mai citiţi date? ( d/ n)”. Care este cel mai mare numãr?
10. Se citesc n numere naturale. Sǎ se numere câte cifre are şirul de numere.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Capitolul 3

Limbajul C++. Alfabet şi vocabular

În anul 1970, Brian Kerninghan si Dennis Ritchie au definit şi dezvoltat


limbajul C, un limbaj foarte flexibil care permite atât programarea la nivel înalt,
cât şi la nivel scãzut, fiind un limbaj procedural. Principalul scop pentru care a
fost realizat acest limbaj a fost rescrierea sistemului de operare UNIX, pentru a-l
face portabil pe toate platformele existente.
În anul 1980, Bjarne Stroustrup a conceput limbajul "C with Classes", o
variantã îmbunãtãţitã a limbajului C, care permite lucrul cu clase. În 1983, C-
with-classes a fost dezvoltat şi redefinit ca limbaj C++, ce oferã facilitãţi de
programare orientatã pe obiecte.
Aplicaţiile orientate pe obiecte sunt mai uşor şi mai rapid de scris, prin
crearea sau dezvoltarea de tipuri de obiecte aparţinând claselor predefinite sau
definite de utilizator.
Există câteva limbaje dezvoltate ca extinderi ale limbajului C, printre care
se pot enumera Visual C++, C#, Java, Javascript. De exemplu, Visual C++ este o
versiune de compilator C++, produs de Microsoft, care permite crearea de
programe în mediul Windows.
Exemplele din aceastã carte au fost realizate folosind mediul de dezvoltare
Borland C++, versiunea 3.1., care pune la dispoziţie metoda de programare la
consolã, sau programarea sub sistemul de operare DOS. Existã o opţiune DOS
shell în meniul File care asigurã lucrul exclusiv sub sistemul de operare MS-DOS.

3.1. Alfabetul limbajului C++


Alfabetul limbajului C este alcãtuit dintr-o mulţime de simboluri afişabile
şi neafişabile [ Marinoiu C, 2000].

Simbolurile afişabile ( care pot fi reprezentate grafic) sunt:


- litere mici / mari ale alfabetului englez: a, ..., z, A, ..., Z
- cifre zecimale 0, 1, 2, ... , 9
- linia de subliniere _ (underscore)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
- semne de punctuaţie şi semne speciale (unele simboluri
constituie operatori în cadrul expresiilor)
;:,?.“< > =! \&^*+-/%#~
Câteva exemple de simboluri şi semnificaţiile acestora sunt prezentate în
tabelul 1:
semn semnificaţie

# diez

& ampersand

/ slash

\ backslash

~ tilda
Tabelul 1. simboluri C++

Simbolurile neafişabile ( fãrã echivalent grafic)


- reprezentate prin secvenţe escape ( de evitare) sau coduri backslash-caracter
- sunt coduri ASCII care nu pot fi citite de la tastaturã
Exemple de secvenţe escape sunt prezentate în tabelul 2:

secvenţe escape semnificaţie

\n new line

\b backspace ( recul cu o poziţie)

\f form feed ( salt la paginã nouã)

\r carriage return ( retur de car)

\t horizontal tab

\v vertical tab

\ddd caracter ASCII în notaţie octalã ( baza 8)

\xdd caracter ASCII în baza 16


Tabelul 2. secvenţe ESCAPE

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
3.2. Vocabularul limbajului C++
Vocabularul limbajului C++ este alcãtuit din atomi lexicali:
 identificatori
 cuvinte cheie
 constante
 semne de punctuaţie
 simboluri speciale
 operatori

Identificatori – reprezintã secvenţe de litere, cifre, liniuţe de subliniere,


primul caracter fiind obligatoriu literã sau caracterul underscore ( _ ), fiind
folosite pentru numele variabilelor, funcţiilor, etc.
Ex: program_1, a0, S
Exemple de identificatori care nu sunt acceptaţi: x..a, a&b, &a

Cuvinte cheie – cuvinte rezervate în limbajul C++. Ele nu pot fi folosite ca


identificatori. Limbajul standard ANSI C are 32 cuvinte cheie.
Ex: void, if, for, while, do, int, float, char, case, break, continue, else,
include, switch, return, main.

Constante
– pot fi numere, caractere, şiruri de caractere
- valoarea lor nu se modificã în timpul execuţiei programului
- în limbajul C, existã 4 tipuri de constante ( întregi, reale, de tip
caracter, şiruri de caractere)
- modul de declarare: este urmãtorul:
const tip var = valoare;
Printr-o astfel de declaraţie, se permite asignarea unei valori iniţiale unei
variabile ce nu poate fi modificatã ulterior în program.
Exemple:
i.constante întregi: 179, -28
ii.constante octale ( în baza 8) încep cu cifra 0 pentru identificare: 012,
074, 023
iii. constante hexazecimale încep cu ox: oxA4, oxB7
iv.constante reale – în format F (cu punct zecimal: 0.7, .8, 12.59) şi în
format exponenţial ( 1.4E+3, -2.8E-4 ): const float pi= 3.14;
1.4E+3 = 1.4 * 103
-2.8E-4 = -2.8 * 10-4
v.constante şir de caractere: “program ordonare”

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Observaţii:
• limbajul C++ extinde definiţia constantelor la clase şi funcţii
membru
• o constantã poate fi modificatã indirect prin intermediul unui
pointer, ca în exemplul urmãtor:
const x = 41;
*(int *)&x = 32;

Semne de punctuaţie ( separatori)


# (pentru directiva include) – este utilizat numai de preprocesor
: ( douã puncte)
[ ] paranteze drepte
( ) paranteze rotunde
{ } acolade pentru blocuri
spaţiul, tab
; punct şi virgulã

Simboluri speciale
 comentarii
// comentariu pe o linie
/*
comentariu pe linii
multiple
*/
 sfârşit de linie, de paginã

Operatori – combinaţii de semne speciale care aratã modalitatea de


prelucrare sau atribuire a valorilor ( tabelul 3):

++ incrementare || sau logic

-- decrementare ~ not pe bit

+ adunare | sau pe bit

- scãdere & şi pe bit

*, / înmulţire, împãrţire ^ sau exclusiv pe bit

== egalitate % modulo

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
!= diferit , virgulã ( operator de
secvenţiere)

<, >, mai mic, mai mare & adresã


<=, >=

! not logic <<, >> deplasare pe biţi la


stânga şi dreapta

&& şi logic sizeof dimensiunea în octeţi


a unei variabile sau
tip de datã

Tabelul 3.operatori C++

Un operator poate avea mai multe semnificaţii, în funcţie de context. De


exemplu, operatorul ampersand (&) poate fi interpretat ca:
• operator ‘şi’ pe biţi (a & b), care este un operator binar
• operator adresã (&a), care este un operator unar
• sinonim de variabilã
int x=10, &y=x;

Clase de precedenţã
Operatorii definesc operaţiile admise de operanzi. În limbajul C++, se pot
folosi urmãtoarele tipuri de operanzi:
- variabile
- constante
- funcţii
- expresii
O clasificare a operatorilor poate sã ia în considerare criterii precum:
• numãrul de operanzi cãrora li se aplicã ( operatori unari ++, - -,
binari +, -, ternari ?: etc.)
• prioritatea avutã în evaluarea expresiilor ( clase de precedenţã)
• tipul operanzilor ( aritmetici, logici, relaţionali, la nivel de bit)
Prioritãtile operatorilor impun ordinea de evaluare a expresiilor.
O clasã de precedenţã conţine operatori cu prioritãţi egale. Categoria 1 de
precedenţã are prioritatea cea mai mare, categoria 2 conţine operatorii unari, care
au prioritate mai micã decât cei din prima clasã, ş.a.m.d. Operatorul virgulã are
cea mai micã prioritate.
Conform precedenţei operatorilor în Borland C++, operatorii se împart în
15 categorii ( tabelul 4):

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Categoria Operator Descriere

1. operatori cu cea
() apel de funcţie
mai mare prioritate
[] indice în tablouri

 selecţie indirectã de
componente ( în C++)
:: operatorul de rezoluţie ( în
C++)
. selecţie directã de componente
( în C++)
! NOT ( negaţie logicã)
2. operatori unari

~ NOT pe biţi

+ plus unar

- minus unar

++ incrementare

-- decrementare

& adresã

* indirectare

sizeof returneazã dimensiunea unui


operand în bytes

new alocare dinamicã în C++


delete
dezalocare dinamicã în C++

3. operatori
* înmulţire
multiplicativi
/
împãrţire
% restul modulo

+ plus binar
4. operatori aditivi

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
- minus binar

5. operatori shift << shift stânga

>> shift dreapta

6. operatori
< mai mic
relaţionali
<= mai mic sau egal

> mai mare

>= mai mare sau egal

7. operatori pentru == egal


verificarea egalitãţii != diferit

8. & AND pe biţi

9. ^ XOR (sau exclusiv) pe biţi

10. | OR ( sau) pe biţi

11. && AND (şi) logic

12. || OR (sau) logic

13. operator ?: a ? x : y înseamnã


condiţional "if a then x, else y"

14. operatori de = atribuire


atribuire
*= atribuire cu înmulţire

/= atribuire cu împãrţire

%= atribuire cu restul modulo

+= atribuire cu adunare

-= atribuire cu scãdere

&= atribuire cu şi pe biţi

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
^= atribuire cu sau exclusiv pe biţi

|= atribuire cu sau pe biţi

<<= atribuire cu shft stânga

>>= atribuire cu shft dreapta

15. operatorul , operator de secvenţiere


virgulã

Tabelul 4.operatori C++

Toţi operatorii de mai sus pot fi supraîncãrcaţi, cu excepţia urmãtorilor:


. operatorul de selecţie directã a componentelor în C++
.* operator C++
:: operatorul de rezoluţie pentru accesul în C++
?: operatorul condiţional
Reguli de asociere a operatorilor:
- de la dreapta la stânga pentru operatorii unari şi cel condiţional ?:
- de la stânga la dreapta pentru restul operatorilor.

Operatorii de atribuire
Sintaxa folositã pentru operaţia de atribuire este urmãtoarea:
expresie_unarã operator_atribuire expresie_de_atribuire
unde expresiile pot avea tipuri de date diferite. În limbajul C++ se fac conversii
implicite de tip, existând relaţia:
sizeof ( int) <= sizeof ( float) <= sizeof ( double)
De exemplu, în expresia E1 = E2, E1 trebuie sã fie o valoare-stângã
modificabilã. Valoarea lui E2 ( dupã conversia de tip), este memoratã în obiectul
E1. Pentru ambele tipuri de atribuire ( simplã şi compusã), operanzii E1 şi E2
trebuie sã respecte una dintre urmãtoarele reguli:
1. E1 şi E2 sunt de tip aritmetic
2. E1 şi E2 sunt de tip structurã sau uniune
3. E1 şi E2 sunt de tip pointer
4. unul dintre E1 sau E2 este de tip pointer la un obiect, iar celãlalt este
pointer de tip void
5. E1 este un pointer şi E2 este un pointer null constant.

O valoare-stângã este un identificator sau o expresie care desemneazã un


obiect care poate fi accesat sau modificat în memorie. Exemple de valori-stângi:

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
E1 = 1
E1 = E1 + E2
sau *p ( un pointer), însã expresia E1 + E2 nu este o valoare-stângã
(exemplu: E1 + E2 =7).
Exemplu de atribuire cu conversie de tip:
int a, b;
float m, n;
a = m; // a  [ m ]
// sau variabilei a i se atribuie o valoare aleatoare, dacã se
//depãşesc posibilitãţile de memorare
n = b; // b va fi reprezentat în virgulã mobilã

Atribuirea multiplã poate fi evidenţiatã astfel:


a = b = c = d = 10;
Operatorul de atribuire compusã are forma generalã operator=, unde
operator poate fi unul dintre operatorii de mai jos:
* / % + - << >> & ^ |
Expresia E1 op= E2 are acelaşi efect ca şi expresia E1 = E1 op E2 unde
valoarea-stângã E1 este evaluatã o singurã datã. De exemplu,
E1 += E2 înseamnã E1 = E1 + E2.

Operatorii de incrementare / decrementare


- operatorul de incrementare ( prefix sau postfix)
sintaxa :
++ operand ( prefix)
sau
operand ++ ( postfix)
unde operandul trebuie sã fie de tip scalar ( aritmetic sau pointer) şi sã fie o
valoare-stângã modificabilã
Pentru incrementare prefixatã, valoarea operandului creşte cu 1, iar
valoarea expresiei este valoarea obţinutã dupã incrementare.
Pentru incrementare postfix, valoarea expresiei este valoarea dinainte de
aplicarea incrementãrii. Dupã incrementarea postfix, valoarea operandului creşte
cu 1.
Exemplu :
int x = 10, y, z ;
y = x++ ; // y = x =10 şi x =x + 1 =11
z = ++x ; // x =x + 1 = 11 + 1 = 12 şi z = x = 12
- operatorul de decrementare ( prefix sau postfix)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
sintaxa :
- - operand ( prefix)
sau
operand - - ( postfix)
unde operandul trebuie sã fie de tip scalar ( aritmetic sau pointer) şi sã fie o
valoare-stângã modificabilã.
Pentru decrementare prefixatã, valoarea operandului scade cu 1, iar
valoarea expresiei este valoarea obţinutã dupã decrementare.
Pentru decrementare postfix, valoarea expresiei este valoarea dinainte de
aplicarea decrementãrii. Dupã decrementarea postfix, valoarea operandului
scade cu 1.
Exemplu :
int x = 10, y, z ;
y = x - - ; // y = x =10 şi x = x - 1 = 9
z = - -x ; // x =x - 1 = 9 - 1 = 8 şi z = x = 8

Operatorul de secvenţiere ( virgula)


- permite construirea de expresii, ca liste de alte expresii
- sintaxa: expresie_1, expresie_2, . . . , expresie_n
- expresiile se evalueazã de la stânga la dreapta
- tipul şi valoarea întregii expresii sunt date de ultima expresie din listã
- pentru evitarea ambiguitãţii în utilizarea operatorului virgulã într-o listã cu
argumente ale unei funcţii sau în liste de iniţializãri, se recomandã folosirea
parantezelor.
Exemplu :
int x = 10, y, z ;
z = suma ( x, ( y = 3, y*2 + 1), z) ; // funcţia suma este apelatã cu 3
argumente : 10, 7, z.

Operatorii aritmetici
- operatorii aditivi : + şi -
Sintaxa operatorilor unari + şi – se poate exprima astfel:
+ operand respectiv – operand
unde operandul trebuie sã fie de tip arithmetic.
Exemplu :
int x = 10, y, z ;
z = +x ; // z =10
y = -x; //y = -10
Sintaxa operatorilor binari + şi – respectã regula expresiilor combinate, cu
unul sau mai mulţi operatori:

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
operand_1 + operand_2 respectiv operand_1 - operand_2
unde operanzii trebuie sã fie de tip aritmetic sau unul dintre operanzi poate sã
fie pointer cãtre un anumit tip de obiecte.
Exemplu :
int x = 10, y = 100, z ;
z = x + y ; // z = 110
z = x - y; //z = -90
- operatorii multiplicativi: *, /, %
Sintaxa operatorilor multiplicativi:
operand1 * operand2 ( înmulţirea a douã numere)
operand1 / operand2 ( împãrţirea a douã numere, al doilea fiind nenul)
operand1 % operand2 ( restul împãrţirii a douã numere, al doilea fiind nenul)
unde operanzii trebuie sã fie de tip aritmetic, iar conversiile de tip sunt cele
uzuale. Operatorul / aplicat unor operanzi întregi furnizeazã un rezultat întreg
şi aplicat unor operanzi reali produce un rezultat real.
Exemplu :
int x = 10, y = 7, z ;
z = x * y ; // z = 70
z = x / y ; //z =1
z = x % y ; // z = 3

Operatorii relaţionali <, >, <=, >=, ==, !=


Sintaxa operatorilor relaţionali :
operand1 < operand2 respectiv operand1 > operand2
operand1 <= operand2 respectiv operand1 >= operand2
În expresiile relaţionale operanzii trebuie sã îndeplineascã una dintre
urmãtoarele condiţii:
- ambii operanzi sunt aritmetici, caz în care se efectueazã conversiile uzuale, iar
rezultatul expresiei relaţioanale este de tip int ( 1 – adevãrat şi 0 – fals)
- operanzii pot fi pointeri cãtre obiecte de tip compatibil, caz în care rezultatul
depinde de adresele relative ale celor douã obiecte la care se referã pointerii

Operatorii de egalitate ==, != testeazã egalitatea sau inegalitatea între


valori aritmetice sau pointeri, utilizând reguli similare cu ale celorlalţi operatori
relaţionali. Operatorii de egalitate sunt într-o categorie de precedenţã inferioarã
(prioritate mai micã) decât ceilalţi operatori relaţionali.
Sintaxa operatorilor relaţionali :
operand1 == operand2 ( egalitate) respectiv operand1 != operand2 ( diferit)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Dacã ambii operanzi sunt aritmetici, rezultatul expresiei relaţionale este 1
( true) sau 0 ( false).
Când operanzii sunt pointeri, atunci expresia operand1 == operand2 are
ca rezultat 1 ( true), dacã ambii pointeri sunt NULL sau dacã pointerii se referã la
acelaşi obiect.

Operatorii logici
- negaţie logicã ( ! operand) - expresia ( ! operand) este echivalentã cu expresia
(operand ==0)
- şi logic (operand1 && operand2)
- sau logic (operand1 || operand2)
Operanzii trebuie sã fie de tip scalar. Sunt realizate conversiile aritmetice
uzuale pentru operanzi.
Operatorii && şi || sunt evaluaţi de la stânga la dreapta astfel:
• operand1 este evaluat primul: dacã operand1 este 0, atunci operand1 &&
operand2 este implicit 0 şi operand2 nu se mai evalueazã
• operand1 este evaluat primul: dacã operand1 este 1, atunci operand1 ||
operand2 este implicit 1 şi operand2 nu se mai evalueazã.
Exemplu : fie douã variabile x şi y de tip întreg, atunci expresiile logice
construite cu ajutorul operatorilor !, &&, || sunt evaluate în tabelul 5 :

x y !x x && y x || y
1 1 0 1 1
1 0 0 0 1
0 1 1 0 1
0 0 1 0 0
Tabelul 5.operatori logici

Operatorii logici au prioritate mai micã decât operatorii relaţionali :


x <= y && y >z este echivalent cu
( x <= y) && ( y >z )

Operatorii pe biţi
• operatorii pe biţi sunt:
- negaţie pe biţi ( ~ operand)
- şi pe biţi (operand1 & operand2)
- sau pe biţi (operand1 | operand2)
- sau exclusiv pe biţi (operand1 ^ operand2)
• se aplicã operanzilor de tip int sau char, nu se aplicã valorilor de tip float,
double, long double

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Exemplu : fie douã variabile x şi y de tip întreg, atunci expresiile logice
construite cu ajutorul operatorilor !, &&, || sunt evaluate în tabelul 6 :

x y ~x x&y x|y x^y


1 1 0 1 1 0
1 0 0 0 1 1
0 1 1 0 1 1
0 0 1 0 0 0
Tabelul 6.operatori pe biţi

Exemplu : Fie x = 6 şi y =27. Operaţiile pe biţi efectuate cu x şi y sunt


prezentate în tabelul 7:
x = 62 = 0000 0110 = 0*2o+1*21 + 1*22 = 2 + 4 = 6
y =272 = 0001 1011= 1*20+1*21 + 0*22 + 1* 23+ 1*24 = 1 + 2 + 8 + 16 = 27

x=6 y = 27 ~x x&y x|y x^y


0000 0110 0001 1011 1111 1001 0000 0010 0001 1111 0001 1101
Tabelul 7.operaţii pe biţi

Operatorii shift
• operatorul shift stânga (variabilã << numãr) deplaseazã biţii variabilei cu un
numãr de poziţii la stânga; la deplasarea spre stânga, biţii liberi din dreapta
se completeazã cu 0 ( zero)
• operatorul shift dreapta (variabilã >> numãr) deplaseazã biţii variabilei cu
un numãr de poziţii la dreapta; la deplasarea spre dreapta, biţii liberi din
stânga se completeazã cu:
- 0 ( zero), dacã numãrul este fãrã semn
- 1 ( unu), dacã numãrul este negativ
• operaţiile de deplasare pe biţi la stânga şi dreapta sunt echivalente cu
înmulţirea, respectiv împãrţirea cu 2 la o putere egalã cu numãrul de biţi
deplasaţi:
x << n este echivalentã cu x * 2n
x >> n este echivalentã cu x / 2n
• exemplu: pentru x = 5, n =2
x << n = 5 << 2 = 0000 0101 << 2 = 0001 0100
0001 0100 = 0*20+ 0*21 + 1*22 + 0* 23+ 1*24 = 0 + 0 + 4 + 0 + 16 = 20

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
x * 2n = 5 * 22 = 20
Deci 5 << 2 = 0001 0100 = 20 = 5 * 22
• un exemplu de deplasare shift pe biţi pentru un numãr negativ:
pentru x = -6, n = 3
Se complementeazã cu 1:
-6(2) = ~6(2) + 1 = ~0000 0110 + 1 = 1111 1001 + 1 = 1111 1010
-6(2) >> 3 = 1111 1010 >> 3 ( se pierd ultimii trei biţi) = 1111 1111

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Capitolul 14

Programare orientatã pe obiecte


în limbajul C++

Limbajul de programare C++ oferã facilitãţi de programare orientatã pe


obiecte, în care obiectele aparţin unor tipuri abstracte, denumite clase. În limbajul
C++, clasele constituie tipuri de date structurate ce permit organizarea datelor
eterogene, complexe şi reprezintã colecţii de variabile şi funcţii, grupate sub un
singur nume, pentru manipularea lor unitarã.
Programarea orientatã pe obiecte foloseşte concepte fundamentale
precum:
• încapsulare – un obiect grupeazã atât date, cât şi funcţiile necesare prelucrãrii
acestora; o clasã este un tip abstract de date care realizeazã încapsularea datelor
şi funcţiilor;
• moştenire – datele sau funcţiile pot fi transmise de la o clasã de bazã la clasele
derivate din aceasta;
• derivare – definirea unei clase noi pe baza unei clase existente;
• polimorfism – redefinirea funcţiilor şi a operatorilor.
În acest capitol se vor prezenta noţiunile de clasã, constructor şi
destructor, vor fi descrise conceptele fundamentale utilizate de programarea
orientatã pe obiecte, precum moştenirea şi supraîncãrcarea. Se va exemplifica
modul de realizare a polimorfismului şi se vor evidenţia proprietãţile funcţiilor
virtuale şi claselor abstracte.

14.1. Clase

Un obiect este o variabilã, reprezentând un ansamblu alcãtuit din:


- date membre;
- funcţii membre, numite metode. Obiectele sunt variabile declarate de tip
class, un tip de date abstract, asemǎnǎtor tipurilor de date structurate struct şi
union.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Sintaxa utilizatã pentru declararea tipurilor class, struct şi union poate fi
exprimatã astfel:
<cuvânt_cheie> [ <identificator>] [ : <lista_clase_bazã>]
{
tip1 lista_membri_1;
tip2 lista_membri_2;
..................
} [ listã_variabile];
unde <cuvânt_cheie> este unul dintre cuvintele cheie class, struct sau union;
<identificator> reprezintã numele tipului de date definit ( class, struct sau
union);
<lista_clase_bazã> - lista claselor de bazã din care derivã aceastã clasã, fiind
opţionalã;
lista_membri_1, lista_membri_2, . . . sunt liste de date şi funcţii membre;
tip1, tip2, . . . desemneazã tipurile de date ale elementelor membre.
Un exemplu de clasã definitã pentru reprezentarea numerelor raţionale
poate fi urmãtorul:
class rational
{
int p, q;
};
rational a, *b = &a;

Specificatorii de acces public, private, protected se pot declara, folosind


sintaxa [ Help, Borland C++ - 1990]:
public : <declaraţii>
private : <declaraţii>
protected : <declaraţii>
- atributul public permite accesarea membrilor din orice funcţie; în limbajul
C++, elementele membre ale unei structuri / uniuni au atributul public (în
mod implicit);
- atributul private – un membru cu atributul private este accesibil în
funcţiile membre şi friends ale clasei în care este declarat; membrii unei
clase au în mod implicit atributul private;
- atributul protected ( accesat în interiorul ierarhiei claselor).

p
Exemplu: Sã se defineascã o clasã pentru numere raţionale , unde p, q
q
∈ Z ( clasa conţine date private şi metode publice pentru iniţializarea şi afişarea
numãrãtorului şi numitorului unei fracţii).

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
#include<stdio.h>
#include<conio.h>
class rational
{
int p, q;
public:
void fractie( int x, int y)
{
p = x;
q = y;
}
int numarator()
{
return p;
}
int numitor()
{
return q;
}
}a;
void main(void)
{
clrscr();
a.fractie(7,8);
printf("\n fractia: %d / %d ", a.numarator(), a.numitor());
getche();
}

Operatorul de rezoluţie :: permite accesul la variabile globale ale


programului. Un exemplu de afişare diferenţiatã a unei variabile declarate
global, respectiv local este programul urmãtor:

#include<stdio.h>
#include<conio.h>
int i = 10;
void main()
{
int i = 15;
clrscr();
printf("\n variabila globala ( din exteriorul functiei main) i = %i",::i);
printf("\n variabila locala (din main) i = %i",i);

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
getch();
}

Operatorul de rezoluţie se poate folosi pentru funcţii declarate în


exteriorul unei clase, al cãror prototip este definit în interiorul clasei. Un exemplu
este problema definirii unei clase pentru numere raţionale, rezolvatã astfel:

#include<stdio.h>
#include<conio.h>
class rational
{
int p, q;
public:
void fractie( int, int);
int numarator();
int numitor();
}a;
void main(void)
{
clrscr();
a.fractie(20,42);
printf("\n fractia: %d / %d ", a.numarator(), a.numitor());
getche();
}
void rational::fractie( int x, int y)
{ p = x;
q = y;
}
int rational::numarator()
{ return p;
}
int rational::numitor()
{ return q;
}

Funcţii inline – sunt funcţiile declarate şi definite în interiorul unei clase.


La fiecare apel al funcţiei, aceasta este înlocuitã cu codul ei, mãrind viteza de
execuţie a programului.

Constructori şi destructori
Constructorul generat implicit este o metodã specialã ataşatã în mod
implicit unei clase, pentru declararea obiectelor. Astfel, se alocã spaţiul de

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
memorie necesar obiectelor declarate. O clasã poate avea mai mulţi constructori,
cu restricţia ca metodele constructor sã difere prin numãrul şi tipul parametrilor
formali. Existã un tip special de constructor numit constructor de copiere care
atribuie datele unui obiect altui obiect.
Destructorul este o metodã specialã ataşatã unei clase, ce realizeazã
operatia inversã alocãrii obiectelor, adicã eliberarea memoriei. Numele
destructorului este acelaşi cu numele clasei, dar este precedat de caracterul ~. O
clasã are un singur destructor. Destructorul nu are parametri formali, el fiind
apelat implicit atunci când existenţa unui obiect înceteazã.

Funcţiile prieten sunt funcţiile care nu aparţin unei clase, dar pot accesa
datele private ale acesteia. Pentru a ataşa unei clase o funcţie prieten, se
introduce în interiorul definiţiei clasei prototipul funcţiei prieten, precedat de
cuvântul cheie “friend”, iar definiţia funcţiei se efectueazã în exteriorul clasei.

14.2. Moştenire

Moştenirea este o tehnicã de bazã în programarea orientatã pe obiecte,


prin care se pot reutiliza şi extinde clasele existente. Mecanismul moştenirii este
urmãtorul:
• având o clasã oarecare B, se poate defini o altã clasã D care sã preia toate
caracteristicile clasei B, la care sã-şi poatã adãuga alte proprietãţi proprii;
• clasa B se numeşte clasã de bazã, iar clasa D se numeşte clasã derivatã;
• mecanismul de derivare poate fi aplicat numai claselor definite prin
specificatorii class şi struct;
• se poate forma o ierarhie de clase.
Pentru derivarea claselor, se foloseşte sintaxa:
class | struct clasa_derivatã : { specificator_acces_1} clasã_bazã_1
{, specificator_acces_2} clasã_bazã_2,
.................................
{
.........
}
Controlul accesului la membrii:
- specificatorul de acces poate lipsi; dacã lipseşte, se considerã private
pentru class şi public pentru struct.
Moştenirea de tip privat este modul de moştenire implicit pentru class.
Membrii protected şi public prin moştenire private devin private.
Moştenirea de tip protected:

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
mostenire protected
- membrii private       → private
mostenire protected
- membrii protected şi public       → protected
Moştenirea de tip public:
mostenire public
- membrii private       → private
mostenire public
- membrii protected       → protected
mostenire public
- membrii public       → public.
Moştenirea multiplã presupune crearea unor clase derivate din mai multe
clase de bazã. În aceste cazuri, constructorii se apeleazã în ordinea in care sunt
scrise clasele în liste de moştenire a clasei derivate.

Exemplu: Sã se defineascã o clasã de bazã pentru grafuri neorientate, care


sã conţinã matricea de existenţã, matricea de adiacenţã, metode pentru citirea şi
afişarea unei matrice şi o metodã pentru algoritmul Roy Warshall. Sã se
construiascã o clasã derivatã din prima, care sã conţinã metode pentru:
- verificarea conexitãtii unui graf;
- tipãrirea vârfurilor izolate;
- tipãrirea vârfurilor de grad maxim.
Algoritmul Roy Warshall transformã matricea de adiacenţã a muchiilor
unui graf neorientat in matrice de existenţã a lanţurilor. Pentru determinarea
componentelor conexe ale unui graf neorientat, se foloseşte matricea de existentã
a lanţurilor.

#include<stdio.h>
#include<conio.h>
int i, j, n, m, x, y, k, sw;
class graf
{
public:
int a[10][10]; //matrice de adiacenta a muchiilor
int e[10][10]; // matrice de existenta a lanturilor
void citire();
void tiparire();
void Roy_Warshall();
};
class graf1 : public graf
{
public:
int conex();
int vf_izolate();
void vf_gr_max();

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
}a;
void graf::citire()
{
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
a[i][j] = e[i][j] = 0;
printf("\n Dati muchiile grafului: ");
for(i = 1; i <= m; i++)
{
printf("\n muchia %d \n",i);
scanf("%d %d",&x, &y);
e[x][y] = e[y][x] = 1;
a[x][y] = a[y][x] = 1;
}
}
void graf::tiparire()
{
printf("\n Matricea de adiacenta\n");
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
printf(" %d ",a[i][j]);
printf("\n");
}
printf("\n Matricea de existenta a lanturilor\n");
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
printf(" %d ", e[i][j]);
printf("\n");
}
}
void graf::Roy_Warshall()
{
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if(e[i][j] == 1)
for(k = 1; k <= n; k++)
if(e[i][k] < e[j][k])
e[i][k] = e[k][i] = e[j][k];
// matrice simetrica fata de diagonala principala
}
int graf1::conex()

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
{
sw = 1;
for(i =1; i <=n; i++)
for(j=1; j <= n; j++)
if (e[i][j] == 0)
sw = 0;
return sw;
}
int graf1::vf_izolate()
{
for(i = 1; i<=n; i++)
{
sw = 1;
for(j = 1; j <= n; j++)
if (e[i][j] == 1)
sw = 0;
if (sw == 1)
{ printf("\n %d varf izolat", i);
return sw;
}
}
return 0;
}
void graf1::vf_gr_max()
{
int max, poz;
for(i = 1; i<=n; i++)
{
a[i][n+1] = 0;
for(j = 1; j <= n; j++)
if (a[i][j]) a[i][n+1]++;
}
max = a[1][n+1]; poz = 1;
for ( i = 2; i <= n; i++)
if(a[i][n+1] > max)
{ poz = i;
max = a[i][n+1];
}
printf("\n varful de grad maxim este %d si are gradul %d",poz, max);
}
void main(void)
{
clrscr();

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
printf("\n nr de varfuri n = "); scanf("%d", &n);
printf("\n numarul de muchii: "); scanf("%d",&m);
a.citire();
a.Roy_Warshall();
a.tiparire();
if (a.conex() == 0) printf ("\n graful nu este conex");
else printf("\n graf conex");
if (a.vf_izolate() == 0)
printf("\n nu exista varfuri izolate");
a.vf_gr_max();
getche();
}

Observaţie: Pentru execuţia programelor, se recomandã efectuarea mai


multor teste. De exemplu:
• Test 1:
Pentru graful din figura 8.1., se
pot introduce datele:
- numãrul de vârfuri n = 5
- numãrul de muchii m = 3
- muchia 1: 1 2
- muchia 2: 1 4
- muchia 3: 3 5 Fig. 8.1. Test 1

Rezultate: graful nu este conex


nu exista varfuri izolate
varful de grad maxim este 1 si are gradul 2

• Test 2:
Pentru graful din figura 8.2., se
pot introduce datele:
- numãrul de vârfuri n = 3
- numãrul de muchii m = 3
- muchia 1: 1 2
- muchia 2: 1 3 Fig. 8.2. Test 2
- muchia 3: 2 3
Rezultate: graf conex
nu exista varfuri izolate
varful de grad maxim este 1 si are gradul 2

• Test 3:
Pentru graful din figura 8.3., se
pot introduce datele:

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
- numãrul de vârfuri n = 5
- numãrul de muchii m = 4
- muchia 1: 1 2
- muchia 2: 1 3
- muchia 3: 1 4 Fig. 8.3. Test 3
- muchia 4: 2 4
Rezultate: graful nu este conex
5 varf izolat
varful de grad maxim este 1 si are gradul 3

• Test 4:
Pentru graful din figura 8.4., se
pot introduce datele:
- numãrul de vârfuri n = 6
- numãrul de muchii m = 6
- muchia 1: 1 2
- muchia 2: 1 4 Fig. 8.4. Test 4
- muchia 3: 2 5
- muchia 4: 3 5
- muchia 5: 3 6
- muchia 6: 5 6
Rezultate: graf conex
nu exista varfuri izolate
varful de grad maxim este 5 si are gradul 3

14.3. Supraîncãrcare

Supraîncãrcarea permite atribuirea mai multor semnificaţii anumitor


operatori sau funcţii. De exemplu, operatorii binari precum ‘+’, ‘-‘, ‘*’ sunt folosiţi,
de obicei, în construcţia expresiilor aritmetice, între operanzi întregi, reali sau de
diverse tipuri aritmetice combinate. Însã, prin supraîncãrcarea acestor operatori,
se pot construi expresii cu operatori şi operanzi definiţi de tip class.
Supraîncãrcarea operatorilor se poate realiza utilizând urmãtoarea
sintaxã:
operator <identificator>( <parametrii> )
{
<instrucţiuni>;
}

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
unde operator <identificator> defineşte o nouã acţiune asociatã unui operator
prin supraîncãrcare.

Supraîncãrcarea operatorilor +, *, -
Exemplul 1): Supraîncãrcarea operatorilor + şi * poate fi evidenţiatã în
programul de calculare a sumei şi produsului a douã matrice. Se vor folosi douã
clase:
• o clasã care memoreazã informaţii despre elementele matricelor şi metode
pentru operaţiile de citire şi scriere;
• a doua clasã derivatã din prima clasã, care sã defineascã supraîncãrcarea
operatorilor + şi *.

#include<stdio.h>
#include<conio.h>
class matrice1
{
public:
int inf[12][12];
void citire();
void tiparire();
};
class matrice2 : public matrice1
{
public:
matrice2 operator+(matrice2);
matrice2 operator*(matrice2);
}a, b, c;
int i, j, n, s, k;
void matrice1::citire()
{
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
printf("\n inf[%d][%d]= ",i,j);
scanf("%d", &inf[i][j]);
}
}
void matrice1::tiparire()
{
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
printf(" %d ",inf[i][j]);
printf("\n ");
}
}
matrice2 matrice2::operator+(matrice2 a)
{
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
c.inf[i][j] = inf[i][j] + a.inf[i][j];
return(c);
}
matrice2 matrice2::operator*( matrice2 a)
{
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
s = 0;
for(k = 0; k < n; k++)
s += inf[i][k] * a.inf[k][j];
c.inf[i][j] = s;
}
return(c);
}
void main(void)
{
clrscr();
printf("\n nr de linii/coloane n = "); scanf("%d", &n);
printf("\n dati matricea A:\n "); a.citire();
printf("\n dati matricea B:\n "); b.citire();
printf("\n matricea A este:\n "); a.tiparire();
printf("\n matricea B este:\n "); b.tiparire();
printf("\n matricea suma A + B:\n ");
c = a + b;
c.tiparire();
printf("\n matricea produs A * B:\n ");
c = a * b;
c.tiparire();
getche();
}

Observaţie: La execuţia programului, se pot folosi urmãtoarele teste:


 1 2  5 2
Test 1: n = 2, A =   , B =  
 3 4  7 1

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Rezultatele compilãrii programului:
6 4  19 4 
matricea suma A + B =   , matricea produs A * B =  
 10 5   43 10 
 1 0 2  1 2 1
   
Test 2: n = 3, A =  3 4 1  , B =  7 0 3 
5 1 2  4 1 5
   
Rezultatele compilãrii programului:
 2 2 3
 
matricea suma A + B = 10 4 4  ,
9 2 7
 
 9 4 11 
 
matricea produs A * B =  35 7 20  .
 20 12 18 
 

Exemplul 2): Sã se realizeze supraîncãrcarea operatorilor +, -, *, = la


mulţimi, pentru operaţiile de bazã cu mulţimi: reuniunea ( +), diferenta ( -),
intersecţia ( *) şi atribuirea ( =).

#include<iostream.h>
#include<conio.h>
char ch;
class multime
{
public:
int inf[10], n;
void citire();
void afisare();
};
class multime1 : public virtual multime
{
public:
multime1 operator*(multime1);
multime1 operator+(multime1);
multime1 operator-(multime1);
void operator=(multime1);
}a, b, c;
int i, j, n, x, sw;
void multime::afisare()
{
if(!n)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
cout<<"multime vida";
for(i=1; i<=n;i++)
cout<<inf[i]<<" ";
}
void multime::citire()
{
if (n <= 0 )
return;
cout<<endl<<"elementele multimii: ";
cout<<"\n inf[1]= ";
cin>>inf[1];
i = 1;
while( i < n)
{
cout<<"\n inf["<<i+1<<"]= ";
cin>>x;
sw = 1;
for(j = 1; j <= i; j++)
if(inf[j] == x)
sw = 0;
if(sw)
{
i++;
inf[i] = x;
}
}
}
multime1 multime1::operator*(multime1 b)
{
sw = 0;
for(i = 1; i <= n;i++)
for(j = 1; j <= b.n;j++)
if(inf[i] == b.inf[j])
{
sw++;
c.inf[sw] = inf[i];
}
if(sw == 0)
cout<<"\n multime vida";
c.n = sw;
return(c);
}
void multime1::operator=(multime1 b)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
{
for(i = 1; i <= b.n;i++)
inf[i] = b.inf[i];
n = b.n;
}
multime1 multime1::operator-(multime1 a)
{
x = 0;
for(i = 1; i <= n;i++)
{
sw = 0;
for(j = 1; j <= a.n;j++)
if(inf[i] == a.inf[j])
sw = 1;
if(!sw)
c.inf[++x] = inf[i];
}
c.n = x;
return(c);
}
multime1 multime1::operator+(multime1 a)
{
x = 0;
for(i = 1; i <= n;i++)
{
sw = 0;
for(j = 1; j <= a.n;j++)
if(inf[i] == a.inf[j])
sw = 1;
if(sw == 0) c.inf[++x] = inf[i];
}
for(i = 1; i <= a.n;i++)
c.inf[++x] = a.inf[i];
c.n = x;
return(c);
}
void main(void)
{
clrscr();
cout<<endl<<"dati numarul de elemente ale multimii A: ";
cin>>a.n;
a.citire();
cout<<endl<<"dati numarul de elemente ale multimii B: ";

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
cin>>b.n;
b.citire();
cout<<endl<<"\n multimea A: ";
a.afisare();
cout<<endl<<"\n multimea B: ";
b.afisare();
c = a;
cout<<endl<<"\n atribuire: C = A = ";
c.afisare();
c = a - b;
cout<<endl<<"\n diferenta: C = A - B = ";
c.afisare();
c = a * b;
cout<<endl<<"\n intersectia: A * B = ";
c.afisare();
c = a + b;
cout<<endl<<"\n reuniune: A + B = ";
c.afisare();
getche();
}

Supraîncãrcarea operatorilor [ ], ( ) şi =

a) operatorul [ ] asigurã accesul la datele unui obiect


De exemplu, prin supraîncãrcarea operatorului [ ], un element a[i] al unui
vector se poate scrie în mod echivalent astfel:
a[i] ⇔ a.operator[ ] (i)
unde a este un obiect aparţinând unei clase, în care funcţia operator[ ] este o
metodã:
class vector
{
int nr[100];
public:
int& operator[](int);
} a;
În programul urmãtor, se propune calcularea sumei elementelor unui
vector, folosind supraîncãrcarea operatorului [ ].

#include<stdio.h>
#include<conio.h>
int i, n, s, p;
class vector

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
{
int nr[100];
public:
int& operator[](int);
void citire();
void tiparire();
};
int& vector::operator[](int i)
{ return nr[i];
}
void vector::citire()
{
for(i = 0; i < n; i++)
{
printf("\n nr[%d] = ",i);
scanf("%d",&nr[i]);
}
}
void vector::tiparire()
{
printf("\n Vectorul\n");
for(i = 0; i < n; i++)
printf("%d ",nr[i]);
}
void main(void)
{
vector a;
clrscr();
printf("\n ne elemente ale vectorului n = ");
scanf("%d", &n);
printf("\n dati vectorul: ");
a.citire();
a.tiparire();
s = 0;
for(i = 0; i < n; i++)
s+= a.operator[](i);
printf("\n suma elementelor = %d", s);
p = 1;
for(i = 0; i < n; i++)
p *= a.operator[](i);
printf("\n produsul elementelor (metoda 1) = %d", p);
p = 1;
for(i = 0; i < n; i++)

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
p *= a[i];
printf("\n produsul elementelor (metoda 2) = %d", p);
getche();
}

Observaţii:
• în program, s-au utilizat notaţiile echivalente:
a.operator[ ] (i) ⇔ a[i]
• metoda operator[ ] declaratã astfel:
int& operator[](int);
returneazã valoarea membrului privat nr. Pentru tipul datelor returnate, se
foloseşte int& (lvalue required).

b) operatorul ( ) este folosit pentru apelul funcţiilor


De exemplu, prin supraîncãrcarea operatorului ( ), un element a[i][j] al
unei matrice se poate scrie în mod echivalent astfel:
a(i, j) ⇔ a.operator( ) (i, j)
unde a este un obiect din clasa matrice, iar funcţia operator( ) este o metodã:
class matrice
{
int nr[20][20];
public:
int& operator( )(int, int);
} a;
În programul urmãtor, se propune determinarea transpusei unei matrice,
folosind supraîncãrcarea operatorului ( ).

#include<stdio.h>
#include<conio.h>
int i, j, n;
class matrice
{
public:
int inf[10][10];
int& operator()(int, int);
void citire();
}a;
int& matrice::operator()(int i, int j)
{
return inf[i][j];

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
}
void matrice::citire()
{
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
{
printf("\n inf[%d][%d]= ",i,j);
scanf("%d",&inf[i][j]);
}
}
void main(void)
{
clrscr();
printf("\n nr de varfuri n = "); scanf("%d", &n);
a.citire();
printf("\n Matricea\n");
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
printf(" %d ",a.operator()(i,j));
printf("\n");
}
printf("\n Matricea transpusa\n");
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
printf(" %d ",a(j,i));
printf("\n");
}
getche();
}

Observaţie: În program, se pot utiliza notaţiile echivalente:


a.operator( ) (i, j) ⇔ a(i, j) ⇔ a.inf[i][j]

c) operatorul = poate fi folosit pentru verificarea egalitãţii a douã obiecte


De exemplu, supraîncãrcarea operatorului ‘=’ permite ca verificarea
egalitǎtii elementelor a douǎ matrice a şi b sǎ se scrie în mod echivalent astfel:
a = b ⇔ a.operator= (b)
unde a şi b sunt obiecte din clasa matrice, iar funcţia operator= este o metodã:
class matrice
{

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
int nr[10][10];
public:
int operator=(matrice);
} a, b;
În programul urmãtor, se propune verificarea egalitǎţii a douǎ matrice,
folosind supraîncãrcarea operatorului =.

#include<stdio.h>
#include<conio.h>
int i, j, n;
class vector
{
public:
int inf[10], n;
int operator=(vector);
void citire();
void afisare();
}a, b;
int vector::operator=(vector b)
{
int sw;
sw = 1;
if(b.n != n)
sw = 0;
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if (inf[i] != b.inf[i])
sw = 0;
return sw;
}
void vector::citire()
{
for(i = 1; i <= n; i++)
{
printf("\n inf[%d]= ",i);
scanf("%d",&inf[i]);
}
}
void vector::afisare()
{
for(i = 1; i <= n; i++)
printf(" %d ",inf[i]);
}

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
void main(void)
{
clrscr();
printf("\n nr de elemente ale vectorului A: n = ");
scanf("%d", &a.n);
a.citire();
printf("\n nr de elemente ale vectorului B: n = ");
scanf("%d", &b.n);
b.citire();
printf("\n Vectorul A\n");
a.afisare();
printf("\n Vectorul B\n");
b.afisare();
if( a = b) printf("\n vectorii au elementele egale");
if(!a.operator=(b)) printf("\n nu exista egalitate");
getche();
}

Observaţie: În program, s-au utilizat notaţiile echivalente:


a.operator= (b) ⇔ a = b

Supraîncãrcarea funcţiilor
Funcţiile pot fi supraîncǎrcate, adicǎ pot exista douǎ sau mai multe funcţii
cu acelaşi nume în clase derivate. Existǎ o restricţie, în sensul cǎ funcţiile trebuie
sǎ difere prin numǎrul şi tipul parametrilor formali.

Supraîncãrcarea funcţiilor în clase derivate: se poate înzestra o clasǎ


derivatǎ cu o metodǎ cu acelaşi nume şi aceeaşi listǎ de parametri formali, ca una
existentǎ în clasa de bazǎ. Exemplu: o funcţie de afişare definitǎ atât în clasa de
bazǎ, cât şi în clasa derivatǎ.

#include<stdio.h>
#include<conio.h>
class A
{
public:
int i;
void afisare()
{
printf("\n clasa de baza A: i = %d",i);
}

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
};
class B : public A
{
public:
int i;
void afisare()
{
printf("\n clasa derivata B: i = %d",i);
}
}y;
void main(void)
{
clrscr();
y.A::i = 99;
y.A::afisare();
y.i = 10;
y.afisare();
getche();
}

Supraîncãrcarea funcţiilor standard presupune redefinirea funcţiilor


standard în interiorul unei clase.
Exemplu: Calculaţi radicalul unui numãr n în mod repetat pânã la
introducerea caracterului ‘n’ sau ‘N’, ca rãspuns la întrebarea “mai daţi un
numãr? (d/n)”. Sã se foloseascã redefinirea funcţiei standard ‘sqrt’.

#include<iostream.h>
#include<math.h>
#include<conio.h>
class radical
{
public:
float sqrt(int);
}x;
float radical::sqrt(int a)
{
return(::sqrt(a));
}
int n;
char c;
void main(void)
{
clrscr();

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
do
{
do
{
cout<<endl<<"dati numarul n:";
cin>>n;
}
while(n<=0);
cout<<endl<<x.sqrt(n);
cout<<endl<<"mai dati un numar? (d/n)";
cin>>c;
}
while(c!='n' && c!='N');
}

14.4. Polimorfism

Polimorfismul se realizeazã prin redefinirea funcţiilor şi a operatorilor.


Un aspect al polimorfismului este capacitatea utilizãrii unei funcţii în mai multe
obiecte diferite, ceea ce înseamnã cã o funcţie poate avea mai multe definiţii.
Compilatorul determinã funcţia care trebuie apelatã în funcţie de lista de
parametri [ M. Williams, 1997]. De exemplu, în programul urmãtor sunt definite
douã versiuni diferite ale funcţiei de afişare:

#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void afisare (int);
void afisare(char[]);
void main(void)
{
int nr;
char sir[20];
clrscr();
cout<<"\n dati un numar: ";
cin>>nr;
cout<<"\n dati un sir de caractere ";
gets(sir);
afisare(nr);
afisare(sir);

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
getche();
}
void afisare (int nr)
{
cout<<"\n Numarul este: "<<nr;
}
void afisare( char sir[])
{
puts("\n Sirul este: ");
puts(sir);
}

Legãtura staticã
Dacã decizia asupra versiunii care se executã la apelul unei funcţii
supraîncãrcate este luatã în momentul compilãrii, atunci spunem cã funcţia
realizeazã o legãturã staticã.

#include<iostream.h>
#include<conio.h>
class punct
{
public:
float aria()
{
return 0;
}
}ob1;
class patrat: public punct
{
float l;
public:
setare(float x)
{
if(x>=0)
l = x;
else l =x;
}
float aria()
{
return l * l;
}
}ob2;

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
void main(void)
{
punct *p;
patrat *q;
int nr;
clrscr();
cout<<"\n dati latura patratului: ";
cin>>nr;
ob2.setare(nr);
cout<<"\n obiectul 1: "<<ob1.aria();
cout<<"\n obiectul 2: "<<ob2.aria();
p = &ob1;
cout<<"\n pointerul p la ob1 (din clasa punct): "<<p->aria();
q = &ob2;
cout<<"\n pointerul q la ob2 (din clasa patrat): "<<q->aria() ;
getche();
}

Observaţie: La redefinirea funcţiilor, în mod implicit se realizeazǎ legǎtura


staticǎ. Versiunea de funcţie executatǎ se stabileşte în momentul compilǎrii, fiind
o metodǎ ineficientǎ în proiectarea unei ierarhii de clase, deoarece varianta
funcţiei din clasele derivate nu poate fi folositǎ.

Funcţii virtuale. Funcţii virtuale pure. Clase abstracte


Legǎtura dinamicǎ realizeazǎ detectarea versiunii funcţiei executate în
momentul execuţiei programului.
Funcţiile virtuale sunt metodele pentru care se efectueazǎ legǎtura
dinamicǎ. Câteva proprietǎti ale funcţiilor virtuale ar fi:
• funcţiile virtuale trebuie sǎ aparţinǎ unei clase;
• nu pot fi statice şi nici inline;
• redefinirea unei funcţii virtuale este posibilǎ la orice nivel al ierarhiei de clase.
În acest caz, funcţiile redefinite rǎmân virtuale, fǎrǎ a mai fi necesarǎ specificarea
cuvântului virtual.
• constructorii nu pot fi funcţii virtuale, însǎ destructorii pot fi funcţii virtuale;
• când se foloseşte o funcţie virtualǎ, compilatorul construieşte tabelul de
functii virtuale pentru pǎstrarea evidenţei functiilor ce trebuie apelate, pentru
fiecare obiect din clasa respectivǎ.
Apelul unei funcţii virtuale presupune:
• determinarea adresei funcţiei virtuale ale clasei din care face parte
obiectul;
• citirea adresei funcţiei virtuale din tabelul de functii virtuale;
• executarea funcţiei apelate.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
Avantajele folosirii claselor virtuale
• flexibilitate crescutǎ în reutilizarea şi dezvoltarea claselor existente;
• funcţiile deja concepute pot fi adaptate unor clase noi, fãrã a fi necesarã
modificarea lor.
Un dezavantaj al utilizãrii funcţiilor virtuale constã în creşterea
consumului de memorie şi a timpului de executie, prin utilizarea tabelului de
funcţii virtuale.

Funcţii virtuale pure. Clase abstracte


Funcţia virtualã purã realizeazã doar declararea prototipului unei funcţii,
urmând ca în clasele derivate sã aparã supraîncãrcarea ei. O funcţie virtualã purã
se declarã folosind sintaxa urmãtoare:
virtual <prototip> = 0
Clasa abstractã este o clasã care conţine cel puţin o funcţie virtualã purã.
Funcţiile virtuale pure sunt destinate creãrii unor clase noi.

Exemplul 1): Sã se defineascã o clasã de bazã cu funcţii virtuale pure


pentru calcularea ariei şi perimetrului unui pãtrat. Sã se construiascã o clasã
derivatã care sã redefineascã funcţiile virtuale pure.

#include<stdio.h>
#include<conio.h>
class forme
{
public:
virtual float aria()=0;
virtual float perimetrul() = 0;
}*a;
class patrat : public forme
{
float l;
public:
patrat(float l);
float aria();
float perimetrul();
};
patrat::patrat(float x)
{
l = x;
}
float patrat::aria()
{

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
return l*l;
}
float patrat::perimetrul()
{
return(4*l);
}
void main(void)
{
float x;
clrscr();
do
{
printf("\n dati latura patratului: ");
scanf("%f",&x);
}
while(x<=0);
patrat p(x);
a = &p;
printf("\n aria = %.2f",a->aria());
printf("\n perimetrul = %.2f", a->perimetrul());
getche();
}

Exemplul 2): Sã se defineascǎ douǎ clase, prima clasǎ de bazǎ, iar a doua
clasǎ, derivatǎ din clasa de bazǎ, care sǎ redefineascǎ o funcţie virtualǎ pentru afişarea
unui mesaj. Sǎ se dfineascǎ pointeri cǎtre cele douǎ clase şi sǎ se evidenţieze
legǎtura dinamicǎ.

#include<iostream.h>
#include<conio.h>
class B
{
public:
virtual void afisare();
};
class D : public B
{
public:
virtual void afisare();
};
void B::afisare()
{
cout<<"\n apel functie din clasa de baza B";

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
}
void D::afisare()
{
cout<<"\n apel functie din clasa derivata D";
}
void main(void)
{
clrscr();
B *p = new B;
p->afisare();
delete p;
D *q = new D;
q->afisare();
delete q;
//legatura dinamica
B *p1;
D p2;
p1 = (B*) &p2;
cout<<"\n legatura dinamica";
p1->afisare();
getche();
}

Observaţie: Instrucţiunea p1->afisare(); evidenţiazǎ legǎtura dinamicǎ - se


apeleazǎ funcţia afisare() din clasa derivatǎ, deoarece funcţia este declaratǎ “virtual”.

Exemplul 3): Sǎ se defineascǎ o clasǎ de bazǎ “tablou” care sã conţinã


funcţii virtuale pure pentru citire, scriere şi calculul sumei elementelor unui
tablou. Sã se declare o clasã derivatã pentru operaţii cu vectori.

#include<iostream.h>
#include<conio.h>
int i, j, n, s, nr;
char ch;
class tablou
{
public:
virtual void citire() = 0;
virtual void scriere() = 0;
virtual int suma() = 0;
};
class vector: public tablou
{

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
int n, inf[12];
public:
vector(int);
void citire();
void scriere();
int suma();
};
vector::vector( int nr)
{
n = nr;
}
void vector::citire()
{
for(i=1;i<=n;i++)
{
cout<<"\n inf["<<i<<"]=";
cin>>inf[i];
}
}
void vector::scriere()
{
for(i=1; i<=n; i++)
cout<<inf[i]<<" ";
}
int vector::suma()
{
s = 0;
for(i=1; i<=n; i++)
s+=inf[i];
return s;
}
void main(void)
{
clrscr();
do
{
cout<<endl<<"numarul de elemente ale vectorului: ";
cin>>n;
}
while(n<=0);
vector v(n);
cout<<endl<<"dati elementele vectorului: ";
v.citire();

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
cout<<endl<<"vectorul: ";
v.scriere();
cout<<endl<<"suma elementelor vectorului: "<<v.suma();
getche();
}

Exemplul 4): Sǎ se defineascǎ o clasǎ de bazǎ “tablou” care sã conţinã


funcţii virtuale pure pentru citire, scriere şi calculul sumei elementelor unui
tablou. Sã se declare o clasã derivatã pentru operaţii cu liste simplu înlãnţuite
(citire, afişare elemente şi concatenarea a douã liste).

#include<iostream.h>
#include<conio.h>
#include<ctype.h>
class lista
{
public:
int nr;
lista* urm;
}*p, *pr, *ul;
int s, nr;
char ch;
class tablou
{
public:
virtual void citire() = 0;
virtual void scriere() = 0;
virtual int suma() = 0;
};
class lista1: public tablou
{
lista *prim, *ultim;
public:
void citire();
void scriere();
int suma();
lista1 operator+(lista1);
}l1, l2, l3;
void lista1::citire()
{
ultim = prim = NULL;
do
{

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
if(ultim ==NULL)
{
ultim = new lista;
cout<<endl<<"Dati nr: ";
cin>>nr;
ultim->nr = nr;
ultim->urm = NULL;
prim = ultim;
}
else
{
p = new lista;
cout<<endl<<"Dati urmatorul element: ";
cin>>nr;
p->nr = nr;
p->urm = NULL;
ultim->urm = p;
ultim = p;
}
cout<<"mai introduceti elemente?(d/n)";
ch = getche();
}while(toupper(ch)!='N');
}
void lista1::scriere()
{
if(prim == NULL)
cout<<"\n lista vida";
else
for(p = prim; p; p = p->urm)
cout<<" "<<p->nr;
}
lista1 lista1::operator+(lista1 l2)
{
pr = prim;
ul = ultim;
ul->urm = l2.prim;
ul= l2.ultim;
l3.prim = pr;
l3.ultim = ul;
return(l3);
}
int lista1::suma()
{

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
s=0;
for(p=prim;p;p=p->urm)
s+=p->nr;
return s;
}
void main(void)
{
clrscr();
lista1 l1, l2;
cout<<endl<<" dati lista l1: ";
l1.citire();
cout<<"\n\n lista 1: ";
l1.scriere();
cout<<"\n\n suma elementelor listei l1 = "<<l1.suma();
cout<<"\n\ndati lista l2: ";
l2.citire();
cout<<"\n\n lista l2: ";
l2.scriere();
cout<<"\n\n l1 + l2 = ";
l3 = l1 + l2;
l3.scriere();
getche();
}

Probleme propuse
9. Sǎ se scrie un program C++ care sǎ redefineascã operatorii de atribuire simplã
şi compusã, ca funcţii membru pentru urmãtoarele clase:
a. numere complexe
b. şiruri de caractere
= ( atribuire)
+= ( concatenarea şirurilor, cu pãstrarea rezultatului în şirul curent)
-= ( ştergerea unui subşir dintr-un şir)
c. liste dublu înlãnţuite
= atribuire simplã ( copierea unei liste în altã listã)
+= atribuire compusã ( adãugarea unui element la o listã şi
concatenarea cu o altã listã)
d. arbori binari
+= inserarea unui element
-+ ştergerea unui element.

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
BIBLIOGRAFIE

1. Boian, F. M., Sisteme de operare interactive, Editura Libris, Cluj-Napoca,


1994
2. Garbacea I., Andonie R., http://www.cwu.edu/~andonie/Cartea de
algoritmi, Brasov, 1995
3. Gonnet G. H., Handbook of Algorithms and Data Structures, Addison
Wesley, 1984
4. Jamsa Dr. K., Klander L., Totul despre C şi C++, Manualul fundamental
de programare în C şi C++, Editura Teora, 1999-2006
5. Kernighan B. W., Ritchie D. M., The C Programming Language, Prentice
Hall Software Series, Second Edition, 1978
6. Knuth D., The Art of Computer Programming, vol. 3, Addison Wesley,
1973
7. Kruse R. L., Data Structures and Program Design, Prentice Hall, 1984
8. Litwin W., Linear Hashing: A new tool for file and table addressing, Proc.
6th Conference on Very Large Databases, 1980
9. Livovschi L., Georgescu H., Sinteza şi analiza algoritmilor, Editura
Ştiinţifică şi Enciclopedică, Bucureşti, 1986
10. Marinoiu C., Programarea în limbajul C, Editura Universitãţii din Ploieşti,
2000
11. Perjeriu E., Vaduva I., Îndrumar pentru lucrari de laborator la cursul de
Bazele Informaticii, anul I, Universitatea din Bucuresti, Facultatea de
Matematica, 1986
12. Smeureanu I., Ivan I., Dârdala M., Limbajul C/C++ prin exemple, Editura
Cison, Bucuresti, 1995
13. Stoilescu D., Culegere de C/C++, Editura Radial, Galati, 1998

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010
14. Tudor N. L., Contribuţii privind optimizarea tehnicilor de accesare a
obiectelor din baze de date relaţionale – tezã de doctorat, Universitatea
POLITEHNICA Bucureşti, 2009
15. Tudor S., Bazele programãrii în C++, Editura L&S INFOMAT, 1997
16. Tudor S., Tehnici de programare, Editura Teora, 1996
17. Williams M., Bazele Visual C++ 4, Editura Teora, 1997
18. Wirth N., Systematic Programming: An Introduction, Prentice Hall, 1972
19. *** Borland C++, versiunea 3.1, Help, 1990

Tudor L., Bazele programãrii în limbajul C++, Editura MATRIX ROM, Bucureşti, ISBN 978-973-755-644-8, 2010

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