Sunteți pe pagina 1din 147

INTRODUCERE

Limbajul C++ se consider att un limbaj de programare


intermediar de nivel sczut datorit apropierii sale de limbajele de
asamblare cu posibiliti de manipulare a biilor, apel de sistem de
operare, operaii cu memoria, etc., ct i un limbaj de nivel nalt cu
proprieti caracteristice limbajelor din aceast categorie ce permite
de a crea aplicaii n baza principiilor programrii orientate pe
obiect. ndrumarul prezint lucrrile de laborator pe care studenii
trebuie s le execute la disciplina Programarea n limbajul de
programare C++. Pentru fiecare lucrare de laborator este indicat
tema i scopul lucrrii, consideraiile teoretice necesare, ntrebri
pentru verificarea cunotinelor, temele pentru acas i de laborator.
Aceste compartimente mpreun cu bibliografia vor fi utilizate de
studeni pentru executarea lucrrilor de laborator.
Pentru a fi admis la ndeplinirea lucrrii de laborator,
fiecare student trebuie s ndeplineasc urmtoarele condiii:
s execute tema pentru acas, care const din descrierea
algoritmului de rezolvare a problemelor lucrrilor de laborator,
s rspund la ntrebrile de control puse de ctre profesor.
n perioada efecturii lucrrilor de laborator studentul
compileaz i execut programele corespunztoare problemelor
indicate de ctre profesor n conformitate cu ndrumarul de
laborator, efectueaz analiza datelor de intrare i a rezultantelor
obinute, colecteaz datele pentru darea de seam a lucrrii.
Lucrarea de laborator se consider executat dup ce
studentul demonstreaz profesorului funcionarea corect a
programelor la calculator.
Pentru fiecare lucrare studentul pregtete darea de seam
pe care o susine n faa profesorului.
Darea de seam pentru fiecare lucrare de laborator include:
foaia de titlu, tema, scopul lucrrii, coninutul problemei propuse
spre rezolvare, descrierea algoritmului de rezolvare a problemei
1

propuse, listingul programului, datele obinute n urma executrii


lucrrii respective, bibliografia utilizat.
Temele de laborator pentru studeni se indic n
conformitate cu urmtorul tabel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Pe vertical este numrul de ordine al studentului n registru, iar pe


orizontal este numrul de ordine al lucrrii de laborator propuse
pentru executare.

CUPRINS

Introducere ..........................................................................

Lucrarea de laborator nr. 1

................................................

Lucrarea de laborator nr. 2

................................................

61

Lucrarea de laborator nr. 3

................................................

81

Lucrarea de laborator nr. 4

................................................ 107

Lucrarea de laborator nr. 5

................................................ 114

Lucrarea de laborator nr. 6

................................................ 133

Lucrarea de laborator nr. 7

................................................

Bibliografie .........................................................................

148

153

Lucrarea de laborator nr. 1


Tema: Reprezentarea tipurilor de date ale limbajului C++ n
memoria calculatorului. Operatorii limbajului C++. Construciile
elementare ale limbajului C++ (instruciunile for, while, do-while,
if-else, switch-break, goto). Tipuri de date recursive, operaii
asupra listelor, arborilor. Construirea i elaborarea programelor
recursive. Fiierele.
Scopul lucrrii: familiarizarea studenilor cu reprezentarea
tipurilor de date ale limbajului C++ n memoria calculatorului,
operatorii limbajului C++, construciile elementare ale limbajului
C++ (instruciunile for, while, do-while, if-else, switch-break,
goto), tipuri de date recursive, operaii asupra listelor, arborilor,
construirea i elaborarea programelor recursive, lucrul cu fiierele.
Consideraiile teoretice necesare:
Tipurile simple i structurate ale limbajului C++ .
Identificatorii limbajului C++ snt formai cu ajutorul
caracterelor alfanumerice i caracterul de subliniere _. Primul
caracter al unui identificator nu poate fi o cifr.
Pi //legal
mesaj //legal
maxx //legal
x3 //legal
3x //ILEGAL
n cadrul mulimii identificatorilor posibili, remarcm o
clas aparte, reprezentnd cuvintele-cheie. Cele mai frecvente
cuvintele-cheie ale limbajul C++snt
auto
delete float
interrupt
register
template
break
do
for
long
return
this
case
double friend near
short
typedef
char
else
goto
new
signed
union
class
enum
huge
operator
sizeof
unsigned
const
export if
private
static
virtual
continue extern inline protected
struct
void
4

default
far
int
public
switch
while
Cuvintele-cheie nu trebuie utilizai ca nume de variabile.
Declararea variabilelor trebuie efectuat nainte de a fi
folosite, la nceputul programului sau chiar n funcie de contextul
problemei n interiorul programului nemijlocit nainte de utilizare,
cnd apare necesitarea introducerii variabilei. 0 declaraie specific
un tip i este urmat de o list de una sau mai multe variabile de
acel tip, ca n exemplul de mai jos:
int i,n;
char c, linie[80];
Domeniu de aciune a variabilelor. Variabilele pot fi
iniializate n momentul declaraiei lor. Dac numele este urmat de
semnul egal i de o constant, aceasta servete la iniializare, ca n
urmtoarele exemple:
char backslash = '\\';
int i = 0;
float eps = 1.0e-5;
Dac variabila este extern sau static, iniializarea are loc
o singur dat, nainte ca programul s-i nceap execuia.
Variabilele automate, iniializate explicit, snt iniializate la fiecare
apel al funciei n care snt coninute. Variabilele automate pentru
care nu exist o iniializare explicit au valoare nedefinit.
Variabilele externe i statice se iniializeaz implicit cu zero, dar
este un bun stil de programare acela de a efectua iniializarea lor n
orice caz.
Fiecare variabil i constant posed un tip, care determin
dimensiunea spaiului necesar memorrii lor. Tipurile datelor se pot
divide n dou categorii: tipuri fundamentale i tipuri derivate sau
structurate.
Tipurile fundamentale ale limbajului C++ snt
char
reprezentnd tipul caracter
pe 1 octet,
int
ntreg
pe 2 octei
long
ntreg
pe 4 octei
float,
nsemnnd un numr real
pe 4 octei
double,
ataat unui numr real
pe 8 octei
5

Aceste tipuri admit diferite variante, numite tipuri de baz


de date.
Tipurile enumerabile snt introduse prin sintaxa
nume {membrul,membru2, . . . ) varl,var2, . . . ;
De exemplu,
enum CULORI {ROU , VERDE, ALBASTRU }
culoarea_punct, culoare_linie;
CULORI culoare_cerc, culoare_fond;
definete tipul de dat CULORI i declar variabilele
culoarea_punct i culoare_linie urmate de declarrile a nc dou
variabile culoare_cerc i culoare_fond de tipul enumerabil.
Membrii unui tip enumerabil trebuie s fie numai de tip
ntreg. Valoarea fiecruia este obinut prin incrementarea cu 1 a
valorii membrului anterior, primul membru avnd, implicit,
valoarea 0. Iniializarea unui membru cu o valoare oarecare,
avndu-se n vedere c doi membri ai aceluiai tip nu pot avea
aceeai valoare. Valorile membrilor urmtori se stabilesc conform
regulilor menionate. Exemple de tipuri de date enumerabile:
enum ANOTIMP (IARNA=1, PRIMVARA, VARA,
TOAMNA) ;
enum BOOLEAN {fals, adevrat) condiie;
enum DIRECIE {SUS, JOS, DREAPTA, STNGA=5};
Putem defini tipuri enumerabile fr a specifica numele acestora.
Procednd astfel, putem grupa un set de constante fr a denumi
acea mulime, de exemplu,
enum {bine, foarte_bine, cel_mai_bine};
Utilizarea variabilelor de tip enumerabil. Limbajul C++
permite atribuiri de tipul
condiie=0;
while (! condiie)
{ cout <<Utilizarea variabilei enumerabile;
condiie=true; }
Este bine ca astfel de atribuiri s fie nsoii de conversia de tip
corespunztoare.
condiie=false;
6

condiie=(enum BOOLEAN) 0;
Enumerrile, definite n interiorul structurilor limbajului C++, nu
snt vizibile n afara acestora.
Tipurile structurate snt obinute de la tipurile de baz.
Tipurile derivate acceptate de limbajul C++ snt: pointeri, referine,
tablouri, structuri, uniuni i clase.
Pointerul este o variabil care conine adresa unei alte
variabile de orice tip. Pentru a defini un pointer, vom specifica tipul
datei a crei adres urmeaz s o memoreze.
int *ip;
// pointer ctre un ntreg
char **s; // pointer la un pointer pe caractere.
S considerm o variabil de tip int i i un pointer pi ctre un
ntreg.
int i=15, j;
int *pi=NULL;
pi=&i;
*pi=20; // i=20;
Deoarece operatorul adres & furnizeaz adresa unei variabile,
instruciunea pi=&i asigneaz variabilei pi adresa lui i.(de
exemplu, adresa 1000). Un alt operator unar ce nsoete clasa
pointerilor este * care furnizeaz coninutul locaiei de memorie de
pe adresa indicat de ctre pointer, de exemplu,
*pi=i;
// adic 15;
Dac j este un alt int, atunci j=*pi asigneaz lui j coninutul locaiei
indicate de pi. Are loc urmtoarea echivalen: j=*pi; adic j=i;
Pointerii pot aprea n expresii. De exemplu, dac pi
conine adresa lui i, atunci *pi poate aprea n orice context n care
ar putea aprea i, cum ar fi
j=*pi+l;
// adic j=i+l;
printf("%d\n",*pi);
d=sqrt((double)*pi);
n expresii ca j=*pi+1; operatorii unari * i & snt prioritari fa de
cei aritmetici, astfel, aceast expresie adun 1 i asigneaz valoarea
obinut lui j ori de cte ori pointerul pi avanseaz.
7

Referiri prin pointeri pot aprea i n membrul stng al


atribuirilor. Dac pi conine adresa lui i, atunci *pi=0 l pune pe i
ca 0, iar *pi+=1 l incrementeaz pe i, ca i (*pi)++. n ultimul
exemplu parantezele snt necesare, fr ele se incrementeaz pi n
loc
s incrementeze ceea ce indic pi, deoarece operatorii unari * i ++
snt evaluai de la dreapta spre stnga. De exemplu,
void main()
{ int *pi, i=10;
float *pf, f=12.5;
double *pd, d=0.001;
char *pc, c=a;
*pi=i; *pf=f; *pd=d; *pc=c;
printf(pi=%p, pf=%p, pd=%p, pc=%p, pi, pf, pd, pc);
printf(*pi=%i, *pf=%f, *pd=%e, *pc=%c, *pi, *pf, *pd,
*pc);
printf(pi++ =%p, pf++ =%p, pd++ =%p, pc++=%p,
pi++, pf++, pd++, pc++);
printf((*pi)++ =%p, (*pf)++ =%p, (*pd)++ =%p,
(*pc)++ = %p, (*pi)++ , (*pf)++, (*pd)++, (*pc)
++);
}
Rezultatul ndeplinirii programului:
pi=8F1C, pf=0758, pd=074C, pc=1330*pi=10, *pf=12.500000,
*pd=1.000000e-03, *pc=a pi++ =8F1C, pf++ =0758,
pd++ =074C, pc++=1330(*pi)++ =1B57, (*pf)++ =0000,
(*pd)++ =0000, (*pc)++ = 0000
Deoarece pointerii snt variabile, ei pot fi manevrai ca orice
alt variabil. Dac pj este un alt pointer la int, atunci
pj=pi;
copiaz coninutul lui pi n pj, adic pj va indica la variabila adresa
creia este indicat n pi, astfel c pj se va modifica odat cu pi.
Pointerii pot conine adrese ctre elemente fr tip, cu void. Putem
atribui unui pointer void valoarea unui pointer non-void fr a fi
necesar o operaie de conversie de tip typecast.
8

char *cp;
void *vp;
vp=cp;

// pointer ctre un caracter


// pointer ctre void
// legal - pointerul la caracter depus n
//pointerul ctre void
cp=vp;
// ILEGAL - lipsete conversia de tip
cp=(char*) vp; // legal - pointerul ctre void depus n
pointerul ctre caracter cu conversie de tip.
Referina prezint o legtur cu o variabil, coninnd o
adres. Spre deosebire de pointeri, n a cror declarare se utilizeaz
simbolul *, pentru a defini o referin, vom folosi simbolul &.
int i;
// declararea unui ntreg
int *p=&i; // definirea unui pointer la i
int &r=i; // definirea unei referine la i
Att p, ct i r acioneaz asupra lui i.
i=55;
// aciune asupra lui i
*p=13;
// aciune asupra lui i
r=20;
// aciune asupra lui i.
Exist ns o diferen major ntre p i r, nu numai n modul de
apelare, ci i datorit faptului c p poate, la un moment dat, s fie n
legtur cu o alt variabil, a crei locaie de memorie o va conine,
diferit de cea a lui i, n timp ce r nu-i poate schimba referina,
acesta nefiind altceva dect o redenumire a variabilei i. n ceea ce
privete utilizarea referinelor, va trebui s inem cont de
urmtoarele restricii:
referinele trebuie iniializate chiar n momentul declarrii lor,
odat fiind iniializate, referinelor nu li se pot schimba locaiile
la care se refer,
nu snt permise referine la referine i pointeri ctre referine,
dar putem avea o referin la un pointer.
Referinele pot fi utilizate drept constante, pot fi iniializate
cu constante, funcii sau chiar structuri.
Tablourile, din rndul crora fac parte vectorii i matricele,
snt tipuri de date foarte apropiate pointerilor i referinelor. Vom
vedea c orice operaie, care poate fi rezolvat prin indexarea
9

tablourilor, poate fi rezolvat i cu ajutorul pointerilor. Astfel,


declaraia
char linie[80];
definete linie ca fiind un ir de 80 de caractere i, n acelai timp,
linie va constitui un pointer la caracter. Dac pc este un pointer la
un caracter, declarat prin
char *pc;
atunci atribuirea pc=&1inie[0]; face ca pc s indice primul element
al tabloului linie (de indice zero). Aceasta nseamn c pc conine
adresa lui linie[0]. Acum atribuirea
c=*pc;
va copia coninutul lui linie[0] n c. Dac pc indic un element al
lui linie, atunci, prin definiie, pc+1 indic elementul urmtor i, n
general, pc-i indic cu i elemente naintea elementului indicat de
pc, iar pc+i cu i elemente dup acelai element. Dac pc indic
elementul linie[0], *(pc+1) indic coninutul lui linie[1], pc+i este
adresa lui linie[i], iar *(pc+i) este coninutul lui linie[i]. Observm
c operatorul de indexare [], de forma E1[E2], este identic
cu*((E1)+(E2)). Aceste remarci snt adevrate indiferent de tipul
variabilelor din tabloul linie. Definiia adunrii unitii la un pointer
i, prin extensie, toat aritmetica pointerilor const, de fapt, n
calcularea dimensiunii memoriei ocupate de obiectul indicat.
Astfel, n pc+i i este nmulit cu lungimea obiectelor pe care le
indic pc, nainte de a fi adunat la pc.
Corespondena ntre indexare i aritmetica pointerilor este
foarte strns. Referina la un tablou este convertit de ctre
compilator ntr-un pointer spre nceputul tabloului. Numele acestui
tablou este o expresie de tip pointer.
Evalund elementul linie[i], limbajul C++ l convertete n
*(linie+i), cele dou forme fiind echivalente. Aplicnd operatorul &
ambilor termeni ai acestei echivalene, rezult c linie[i] este
identic cu linie+i, unde linie+i fiind adresa elementului i din
tabloul linie. Dac pc este un pointer, el poate fi utilizat n expresii
cu un indice pc[i] fiind identic cu *(pc+i). Un pointer este o
variabil. Deci,
10

pc=linie; // i
pc++;
snt operaii permise. Numele unui tablou este o constant i nu o
variabil, construcii de tipul linie++ fiind interzise. Singurele
operaii permise a fi efectuate asupra numelor tablourilor, n afara
celor de indexare, snt cele care pot aciona asupra constantelor
Aritmetica adreselor pentru pointeri i tablouri constituie
unul din punctele forte ale limbajului C++. Se garanteaz c nici un
pointer care conine adresa unei date nu va conine valoarea zero,
valoare rezervat semnalelor de eveniment anormal. Aceast
valoare este atribuit constantei simbolice NULL pentru a indica
mai clar c aceasta este o valoare special pentru un pointer. n
general, ntregii nu pot fi asignai pointerilor, zero fiind un caz
special.
Exist situaii n care pointerii pot fi separai. Dac p i q
indic elemente ale aceluiai tablou, operatorii <, >, =, etc.
lucreaz conform regulilor cunoscute. p<q este adevrat, de
exemplu, n cazul n care p indic un element anterior elementului
pe care l indic q. Relaiile == i != snt i ele permise. Orice
pointer poate fi testat cu NULL, dar nu exist nici o ans n a
compara pointeri situai n tablouri diferite.
Este valabil i operaia de scdere a pointerilor. Astfel,
dac p i q indic elementele aceluiai tablou, p-q este numrul de
elemente dintre p i q. O funcie, deosebit de util n lucrul cu iruri
de caractere, este strlen(), care returneaz lungimea irului de
caractere transmis ca parametru.
int strlen(char *s)
{ char *p=s;
while (*p!='\0') p++;
return p-s; }
Prin declarare p este iniializat cu s i indic primul caracter
din s. n cadrul ciclului while este examinat coninutul irului de
caractere, indirect, prin intermediul pointerului p, caracter dup
caracter, pn cnd se ntlnete '\0'', acesta din urm semnificnd
sfritul irului. Dac while ar testa doar dac expresia este zero,
11

este posibil omiterea testului explicit, astfel de cicluri fiind deseori


scrise sub forma
while (*p) p++;
Deoarece p indic irul de caractere, p++ face ca p s avanseze de
fiecare dat la caracterul urmtor, iar p-s d numrul de caractere
parcurse (lungimea irului). Aritmetica pointerilor este consistent:
dac am fi lucrat cu float, care ocup mai mult memorie dect
char, i dac p ar fi fost un pointer la float, p++ ar fi avansat la
urmtorul float. Toate manipulrile de pointeri iau automat n
considerare lungimea obiectului referit.
S implementm, de exemplu, o funcie de comparare a
dou iruri de caractere. Funcia strcmp(s, t) compar irurile de
caractere s i t i returneaz valoare negativ, nul sau pozitiv, n
funcie de relaia dintre s i t (care poate fi s<t, s=t sau s>t).
Valoarea returnat este obinut prin scderea caracterului de pe
prima poziie, unde s difer de t. Pentru claritatea problemei, vom
prezenta dou variante, una utiliznd tablourile, iar cea de a doua
utiliznd pointerii.
Varianta cu tablourile:
strcmp(char s[], char t[])
{ int i=0;
while (s[i]==t[i])
if (s[i++]=='\0') return 0;
return s[i]-t[i];}
Varianta cu pointerii:
strcmp(char *s, char *t)
{ for(;*s==*t;s++,t++)
if(*s=='\0') return(0);
return (*s-*t);}
Dac ++ i - - snt folosii ca operatori prefixai, pot aprea alte
combinaii de *, ++ i - -, dei mai puin frecvente. De exemplu:
*++p incrementeaz pe p nainte de a aduce caracterul spre care
indic p. *- - p decrementeaz pe p n aceleai condiii.
Alte operaii, n afara celor menionate deja (adunarea sau
scderea unui pointer cu ntreg, scderea sau compararea a doi
12

pointeri), snt ilegale. Nu este permis adunarea, mprirea,


deplasarea logic sau adunarea unui float sau double la pointer.
Tablourile multidimensionale pot fi definite cu ajutorul
tablourilor de tablouri, de exemplu.:
char ecran [25][80];
excepie fcnd tablourile de referine, acestea din urm nefiind
permise datorit faptului c nu snt permii pointerii la referine.
Dac E este un tablou n-dimensional de dimensiuni i, j, ...,
k, atunci apariiile lui E n expresii snt convertite n pointer la un
tablou n-1-dimensional de dimensiuni j, ..., k. Dac la acesta se
aplic explicit sau implicit (prin indexare) operatorul *, rezultatul
este tabloul n-1-dimensional indicat de pointer, care, la rndul su,
este convertit imediat n pointer.
Tablourile snt memorate pe linii i, deci, ultimii indici, de
la stnga la dreapta, variaz mai repede dect primii. Prima
dimensiune a unui tablou se folosete numai pentru a determina
spaiul ocupat de acesta, ea nefiind luat n consideraie dect la
determinarea unui element de indici dai. Este permis omiterea
primei dimensiuni a unui tablou, dac tabloul este extern, alocarea
fcndu-se n cadrul altui modul sau cnd se efectueaz iniializarea
tabloului n declaraie, n acest caz fiind determinat dimensiunea
din numrul de elemente iniializate.
Iniializarea tablourilor poate avea loc chiar n cadrul
declarrii acestora
int point[2]={10,19};
char mesaj1[6]={'S1,'a','l','u','t','\0'};
char mesaj2[6]="Salut";
Observm c irurile de caractere se comport oarecum ciudat. Att
mesaj1, ct i mesaj2 snt iruri de 6 caractere avnd drept
terminator de ir caracterul nul. Diferena ntre cele dou iruri nu
se afl n coninutul lor, ci n cadrul iniializrii lor. n cazul
iniializrii prin acolade, { }, caracterul nul nu este subneles,
prezena acestuia rmnnd la latitudinea noastr, n schimb,
adoptnd o iniializare prin ghilimele, , va trebui s dimensionm
corespunztor irului de caractere, innd cont de prezena
13

terminatorului de ir. n exemplul mesaj2 avem 5 litere plus


caracterul nul, fiind necesare 6 locaii n vederea memorrii
cuvntului Salut.
Dimensionarea tablourilor se realizeaz n concordan cu
necesitile aplicaiei. Exist posibilitatea iniializrilor pariale,
care nu utilizeaz ntreg spaiu rezervat. n cazul irurilor de
caractere, restul spaiului rmas neutilizat va conine numai
caracterul nul. n restul situaiilor, coninutul tabloului fiind aleator,
se recomand iniializarea acestuia n cadrul unui ciclu.
Tablouri de pointeri. Pointerii snt ei nii variabile, de
aceea ei snt utilizai n tablouri de pointeri. Pentru exemplificare,
vom considera un program care sorteaz un set de linii de text n
ordine alfabetic. Cu toate c algoritmul de sortare este unul
comun, deosebirea dintre sortarea unui tablou de numere i a unuia
de iruri de caractere const n aceea c liniile de text de lungimi
diferite nu pot fi comparate sau deplasate printr-o singur operaie.
Avem nevoie de o reprezentare a datelor care s se poat face
eficient i potrivit regulilor de gestionare a liniilor de text de
lungimi diferite.
Introducem noiunea de tablou de pointeri. Dac liniile de
sortare snt memorate cap la cap ntr-un ir de caractere, atunci
fiecare linie poate fi accesat printr-un pointer la primul su
caracter. Pointerii nii pot fi memorai ntr-un tablou. Dou linii
pot fi comparate prin transmiterea pointerilor respectivi lui
strcmp(). Cnd dou linii neordonate trebuie inversate, se
inverseaz pointerii lor n tabelul de pointeri, nu nsi liniile. Acest
mod de lucru elimin cuplul de probleme legate de gestionarea
memoriei i poate deplasa liniile.
Procesul de sortare const din trei etape:
- citirea tuturor liniilor la intrare,
- sortarea liniilor,
- tiprirea liniilor n ordine.
mprim programul n funcii care efectueaz aceste trei etape.
Funcia de intrare trebuie s colecteze i s salveze caracterele din
fiecare linie i s construiasc un tablou de pointeri pe linii. Va
14

trebui s numere liniile la intrare. Aceast informaie este necesar


pentru sortare i tiprire. Deoarece funcia de intrare poate opera
doar cu un numr finit de linii, ea va returna o valoare, cum ar fi -1,
n cazul n care se vor prezenta mai multe linii. Funcia de ieire
trebuie doar s tipreasc liniile n ordinea n care apar n tabloul de
pointeri.
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define LINII 100
#define MAXLEN 1000
int citeste_linii(char *s[])
{ printf("Introdu un text (maxlen=1000)\n");
printf("Pentru introducerea unei linii noi se utilizeaz
tasta
ENTER.\n");
printf("Sfritul textului se va marca prin '*'. \n\n");
char c;
int i=0, j=0;
while((c=getchar())!='*')
{ if (c=='\n')
{ s[i][j]='\0'; i++;j=0; }
else s[i][j++]=c;
}
return i+1; }
void scrie_linii (char *linieptr[],int maxlinii)
{ for( int i=0; i<maxlinii;i++)
printf("%s\n", linieptr[i]); }
void sortare_linii(char *v[],int n)
{ char *temp;
for(int k=n/2;k>0;k/=2)
for(int i=k;i<n;i++)
for(int j=i-k;j>=0;j-=k)
{ if (strcmp(v[j],v[j+k])<=0) break;
temp=v[j];
v[j]=v[j+k];
15

v[j+k]=temp; } }
void main()
{ clrscr();
char *linieptr[LINII];
int nlinii;
if ((nlinii=citeste_linii(linieptr))>=0)
{ printf("\n Textul pn la sortare:\n");
scrie_linii(linieptr,nlinii);
sortare_linii(linieptr,nlinii);
printf("\n Textul dup sortare \n");
scrie_linii(linieptr,nlinii);
}
else printf("Input prea mare pentru sortare \n"); }
Rezultatul ndeplinirii programului:
Introdu un text (maxlen=1000)
Pentru introducerea unei linii noi se utilizeaz tasta
ENTER.
Sfrsitul textului se va marca prin '*'.
ashdgasghddgjahsdgjaghdjhagsdhgdhjgdh*
Textul pn la sortare:
ashdgasghddgjahsdgjaghdjhagsdhgdhjgdh va marca prin
'*'.
Textul dup sortare
ashdgasghddgjahsdgjaghdjhagsdhgdhjgdh va marca prin
'*'.
Declararea variabilei linieptr:
char *linieptr[LINII];
arat c linieptr este un tablou de LINII elemente, fiecare element
fiind un pointer la char. linieptr[i] este un pointer la caractere, iar
*linieptr[i] acceseaz un caracter. Dac linieptr este el nsui un
tablou care este transmis lui scrie_linii(), el poate fi tratat ca un
pointer, iar funcia poate fi scris.
void scrie_linii(char *linieptr[],int nlinii)
{ while (- - nlinii>=0)
printf("%s\n",*linieptr++); }
16

*linieptr adreseaz iniial prima linie, iar, cu fiecare incrementare,


el avanseaz linia urmtoare pn cnd nlinii se epuizeaz.
Sortarea are loc n cadrul funciei sortare_linii(). Dac orice
element individual din v este un pointer la caractere, temp va fi un
astfel de pointer, nct cei doi pot fi copiai unul n altul.
Fiind date declaraiile
int a[10][10]; int *b[10];
utilizrile lui a i b pot fi similare, n sensul c a[5][5] i b[5][5]
snt referine legale ale aceluiai int. Toate cele 100 celule de
memorie ale tabloului a trebuie alocate, iar gsirea fiecrui element
se face prin calculul obinuit al indicelui. Pentru tabloul b, prin
declararea sa, se aloc 10 pointeri, fiecare dintre acetia urmnd s
indice un tablou de ntregi. Presupunnd c fiecare indic la 10
elemente din tablou, vom obine 100 celule de memorie rezervate,
plus cele 10 celule pentru pointeri. Astfel, tabloul de pointeri
utilizeaz mai mult spaiu i poate cere un mod explicit de
iniializare. Dar exist dou avantaje: accesarea unui element se
face indirect prin intermediul unui pointer, n loc s se fac prin
nmulire i adunare (cum este n cazul tabloului multidimensional),
iar liniile tabloului pot fi de lungimi diferite. Aceasta nseamn c
nu orice element al lui b este constrns s indice la un vector de 10
elemente, unii pot indica la cte 2 elemente, alii la cte 20 de
elemente sau chiar la nici unul.
Structura este o colecie de elemente de tipuri diferite i
care pot fi referii att separat, ct i mpreun. Definirea unei
structuri se realizeaz cu ajutorul cuvntului-cheie struct. Ea are
urmtoarea sintax:
struct [tip structur] { tip_1 element_1;

tip_ n element_n
} obiect_ de_ tip_ structur;
unde tip structur descrie organizarea structurii,
tip1,..., tipn indic tipul elementelor structurii,
element1, ..., element sunt numele elementelor structurii,
17

obiect_ de_ tip_ structur este una sau o list de variabile


pentru care se aloc memorie. De exemplu,
struct punct { float x,y;} p;
S-a definit o structur p ca fiind de tip punct, punctul fiind compus
din dou elemente x i y reale. Asupra componentelor unei structuri
putem aciona prin intermediul operatorului de apartenen, ., de
exemplu:
p.x=10;
p.y=30;
Exist posibilitatea efecturii operaiilor cu ntreaga structur,
atribuirea fiind, de exemplu :
p={10,30);
0 declaraie de structur care nu este urmat de o list de variabile
nu produce alocarea memoriei, ci descrie organizarea structurii., de
exemplu:
typedef struct { char name[25]; int id, age;
char prp; } student;
Definirea unei structuri permite determinarea unui nou tip de date.
n continuare definind pointeri la aceast structur, tablouri, ale
cror elemente snt de tipul acestei structuri, i elemente de acest
tip pot fi definite noi structuri de date mai compuse.
Un alt aspect al utilitii structurilor l constituie tratarea
tablourilor de structuri, de exemplu:
punct hexagon[6];
punct octogon[8];
Accesul ctre membrii componeni ai fiecrui element al vectorului
se realizeaz prin combinarea accesului indexat, caracteristic
tablourilor, cu cel utilizat n cazul structurilor:
hexagon[i].x=10;
n cazul definirii unui pointer la o structur, accesul la
componentele acelei structuri se va efectua prin expresii de forma
punct *pptr;
pptr->x=10; // Echivalent cu p.x=10;
(*pptr) .y=30; // Echivalent cu p.y=30;
Parantezele au rolul de a indica ordinea n care acioneaz cei doi
operatori * i ., prioritar fiind *.
18

Unele elemente ale unei structuri pot fi cmpuri de bii. Un


cmp de bii este o configuraie de bii adiaceni, ce apar ntr-un
element de tip int. Cmpurile snt declarate de tip unsigned, iar
numele cmpului este urmat de dou puncte : i un numr ce
reprezint numrul de bii ocupai de cmpul respectiv:
unsigned nume_cmp:nr_bii;
Cmpurile pot fi accesate ca orice alt element de structur. Orice
cmp trebuie s aib toi biii n interiorul unei zone de tip int (nu
poate avea bii n dou cuvinte diferite). Ordinea de alocare a
memoriei pentru cmpuri este dependent de sistem. Unele sisteme
fac alocarea de la stnga la dreapta, iar altele invers. Nu se pot
utiliza tablouri de cmpuri. Cmpurile nu au adres i nu li se poate
aplica operatorul de adresare &.
Un caz special de structuri l constituie union. Acestea snt
structuri alternative pentru care dimensiunea spaiului necesar
memorrii lor este egal cu cea mai mare dimensiune necesar
memorrii unei componente a acelei structuri. De exemplu,
variabila este de tipul
union un_tip
{ int uint; float ufloat; char uchar;
punct upunct; // upunct este de tipul structurii punct
} variabila;
Toate componentele uniunii ocup aceeai zon n cadrul
memoriei. Spre deosebire de structuri, n uniune este accesibil o
singur component a unei uniuni. Uniunea se definete n aceeai
manier ca i structurile, cuvntul-cheie utilizat fiind union.
Operatorii
Operatori i expresii. Aciunile desfurate n cadrul
oricrui program, n marea lor majoritate, se efectueaz prin
expresiile formate prin combinaii de date i operatori. Limbajul
C++ posed toi operatorii limbajului C i completeaz aceast list
cu operatori proprii. Din lista operatorilor disponibili ai limbajului
C++ indicm operatorii caracteristici lui new pentru alocarea
memoriei, delete pentru eliberarea memoriei alocate cu
operatorul new, :: operatorul de scop sau de rezoliie.
19

n funcie de numrul de operanzi, operatorii se pot clasifica


n trei categorii: operatori unari, binari i ternari.
Operatori unari. Formarea expresiilor n care intervin
operatorii unari se produce de la dreapta la stnga.
Operatorul de indirectare: * se poate aplica unei expresii
de tip pointer (*expresie) i are drept rezultat o valoare (lvalue sau
adres) care se refer la obiectul indicat de pointer.
Operatorul de adresare: & poate fi aplicat unei valori
(&lvalue) i are ca rezultat un pointer la obiectul definit de lvalue i
are acelai tip ca i tipul lvalue.
Operatorul unar minus: - se aplic unei expresii (expresie) n vederea inversrii semnului acesteia.
Operatorul negaie logic: ! se poate aplica unei expresii
aritmetice sau unui pointer (! expresie) i are ca rezultat 1, dac
valoarea operandului este 0, i 0, n caz contrar, tipul rezultatului
fiind int.
Operatorul negaie pe bii: ~ se aplic unei expresii de tip
ntreg (~expresie) i transform 0 n 1 i 1 n 0 n toi biii rezultai
dup conversiile uzuale.
Operatorul de incrementare: ++ incrementeaz cu 1
valoarea operandului.
Operatorul de decrementare: - - decrementeaz cu 1
valoarea operandului.
Operatorul ++, ca i operatorul - -, poate fi utilizat att ca
prefix, ct i ca sufix. n cazul utilizrii lor ca prefix, nti se
acioneaz cu operatorul asupra valorii operandului i apoi se
utilizeaz noua valoare a acestuia. n cazul utilizrii lor ca sufix,
nti se utilizeaz valoarea acestuia, apoi se acioneaz cu
operatorul asupra valorii operandului.
Conversia unei expresii (typecast): este de tipul (tip)
expresie sau (expresia) i produce conversia valorii expresiei la
tipul specificat.
Operatorul dimensiune: sizeof este de tipul sizeof
(expresie) sau sizeof (tip) i ne indic dimensiunea n octei a
20

operandului, determinat din declaraiile elementelor ce apar n


expresie.
Operatorul de alocare a memoriei: new apare sub forma
pointer_la_nume = new nume [ iniializator]
i ncearc s creeze un obiect nume prin alocarea unui numr egal
cu sizeof(nume) de octei n memoria heap, adresa acestuia fiind
returnat. n cazul n care alocarea nu este efectuat cu succes, se
returneaz valoarea NULL
Operatorul de eliberare a memoriei: delete are sintax de
forma
delete pointer_la_nume
i elibereaz memoria alocat ncepnd de la adresa coninut de
pointer_la_nume.
Operatorul virgul: , produce expresii de forma
expresie, expresie;
El efectueaz evaluarea expresiilor de la stnga la dreapta i are ca
rezultat i tip valoarea i tipul ultimei expresii. Gruparea cu
paranteze este permis i produce o singur valoare. De exemplu:
void main()
{int s;
for(int i=0,s=0;i<10,i++) s+=I;
cout<< Suma este de <<s<<endl;
}
Operatori binari
Operatorii aritmetici: +, -, *, / acioneaz respectnd
regulile binecunoscute de calculare a expresiilor. Trebuie fcut o
observaie asupra operatorului de mprire /. n cazul n care ambii
operanzi snt ntregi, rezultatul este ntreg (prin trunchierea
rezultatului real).
Operatorul modulo: % furnizeaz restul mpririi primului
operand la cel de al doilea. De exemplu, un numr este par, dac
este divizibil cu 2. Deci
if (x%2==0) cout "x este par";
else cout "x este impar";
Operatorul de deplasare la stnga: are ca rezultat
deplasarea ctre stnga a valorii operandului stng cu un numr de
21
26

bii egal cu valoarea operandului drept, biii eliberai astfel fiind


completai cu valoarea 0.
Operatorul de deplasare la dreapta: acioneaz n mod
similar cu precedentul, singurul element care difer fa de
operatorul anterior fiind sensul deplasrii. De exemplu, funcia
definit mai jos Biti (x,4,3) returneaz 3 bii din poziiile 4,3 i 2,
aliniai la dreapta.
Biti (unsigned x,unsigned p,unsigned n)
{return (x(p+1-n))&~ (~0n) ; }
Operatorii de comparaie: <, <=, >, >=, = =(egal), !
=(neegal) au ca rezultat o valoare de tip int care este 0 n cazul n
care condiia nu este ndeplinit i 1 n caz contrar. Pointerii pot fi
comparai numai pe aceeai structur de date, iar ultimii doi
operatori permit compararea pointerului cu NULL, care corespunde
adresei vide.
Operatorii logici binari pe bii: & (i), | (sau),^ (sau
exclusiv) furnizeaz un rezultat de tip int (0 pentru valoarea false i
1 pentru valoarea true). De exemplu, funcia numr_biti()
controleaz numrul de bii pe 1 dintr-un argument ntreg
numr_biti (unsigned n)
{ int b;
for (b=0; n!=0; n=1)
if (n&O1) b++;
return b; /}
Operatorii logici binari: && (i), || (or). Pentru ambii
operatori se efectueaz evaluri de la stnga spre dreapta pn la
prima expresie de valoare 0 (pentru &&) sau, respectiv, nenul
(pentru || ), cnd valoarea ntregii expresii devine 0 i, respectiv, 1.
Operatorii de atribuire: op= unde op face parte din
mulimea { +, -, *, /, %, , , &, ^, |} se grupeaz de la dreapta la
stnga, tipul expresiei de atribuire este tipul operandului stng, iar
rezultatul aciunii operatorului se regsete tot n acest operand.
Orice expresie de tipul x op= y este echivalent cu x =x op y.
Operatori ternari
Operatorul condiional: (condiie) ? : produce expresii de
22

forma (expr1) ? expr2 : expr3, n care se evalueaz exp1. n cazul


n care aceasta este nenul, se returneaz valoarea expresiei expr2,
n caz contrar, se returneaz valoarea lui expr3. De exemplu, ciclul
urmtor tiprete N elemente ale unui tablou, 10 pe linie, cu fiecare
coloan separat printr-un blanc i cu fiecare linie (inclusiv ultima)
terminat cu un singur caracter \n linie nou:
for (i=0;i<N;i++)
printf("%6d %c",a[i],(i%10==9||i==N-1)?-\n':' );
Acest exemplu poate fi scris prin intermediul instruciunii if n felul
urmtor:
for (i=0;i<N;i++)
if,(i%10==9||i==N-1)
printf("%6d %c",a[i],-\n');
else printf("%6d %c",a[i],' );
Instruciuni
Expresiile snt utilizate n scrierea instruciunilor. O
instruciune este o expresie care se ncheie cu punct i virgul ;".
Instruciunile pot fi scrise pe mai multe linii program, spaiile
nesemnificative fiind ignorate. Pe o linie de program putem scrie
multe instruciuni. Instruciunile pot aprea n diferite forme: de
atribuiri, de declaraii, instruciuni condiionale, de ciclare, de salt,
instruciuni compuse.
Instruciunea compus (blocul de instruciuni) grupeaz
declaraii i instruciuni n vederea utilizrii unui bloc de
instruciuni echivalent cu o instruciune compus. Forma general
este:
{lista_declaraii lista_instruciuni}
Instruciunea condiional if, if-else are una din formele:
if (expr) instruciune;
if (expr) instruciune_l; else instruciune_2;
Instruciunea if evalueaz expresia expr. n cazul n care se obine o
valoare nenul, se trece la executarea instruciune_1, iar dac
aceast valoare este nul i exist instruciune_2, se va executa
instruciune_2. n cazul absenei variantei else se va trece la
execuia instruciunii imediat urmtoare instruciunii if.
23

Instruciunea de ciclu condiionat anterior while este


while (expr) instruciune;
Att timp ct valoarea expresiei expr este nenul, se execut
instruciune. De exemplu,
i=0;
while (i<n) a[i++]=0.0;
Evaluarea expresiei are loc naintea execuiei instruciunii, fapt
pentru care aceast instruciune este din clasa ciclurilor cu
precondiie. Din acest motiv este posibil ca corpul ciclului s nu se
execute nici mcar o dat, dac condiia ciclului este fals. Execuia
programului va trece la instruciunea imediat urmtoare
instruciunii de ciclu.
Instruciunea de ciclu condiionat posterior do-while are
forma
do instruciune while (expr);
instruciune se va executa pn ce valoarea expresiei expr devine
fals. Spre deosebire de instruciunea while, n ciclul do-while
evaluarea expresiei are loc dup fiecare executare a corpului
ciclului. Datorit acestui fapt instruciune se va executa cel puin o
singur dat, iar instruciunea do se ncadreaz n categoria
ciclurilor cu postcondiie. De exemplu:
i=0;
do
{ a[i++]=0.0; }
while (i<n);
Ciclul do-while este folosit mai puin dect ciclul for. Cu toate
acestea, prezena sa se impune n cazurile n care este necesar
executarea corpului unui ciclu cel puin o dat, urmnd ca ulterior
s se execute n funcie de ndeplinirea condiiei finale, indicate n
contextul ciclului while.
Instruciunea de ciclu aritmetic for are urmtoarea form
general
for (expr_1; expr_2; expr_3) instruciune;
i este echivalent cu urmtoarea succesiune de instruciuni:
expr_1;
while (expr_2)
( instruciune;
24

expr_3; )
Oricare dintre cele trei expresii poate lipsi, absena expresiei
expr_2 fiind nlocuit, implicit, cu valoarea 1. De exemplu,
for (int i=0; i<=n; i++) a[i]=0.0;
for ( int k=0, number_of_nums=0, number_of_chars=0;
k<strlen(text); k++)
{ cout text[k] \n;
if (is_num(text[k]))
number_of_nums++;
if (is_alpha(text[k]))
number_of_chars++;
}
Ciclul for este util de folosit atunci cnd exist o simpl iniializare
i reiniializare, deoarece se pstreaz instruciunile de control al
ciclului mpreun.
Instruciunea switch face parte din categoria instruciunilor
de selectare. Transferul controlului se va efectua la una din
variantele posibile, n funcie de valoarea unei expresii de control.
Sintaxa instruciunii este
switch (expr) instruciune;
unde instruciune este o instruciune compus, n care fiecare
instruciune individual trebuie etichetat cu o etichet de forma
case expresie_constanta:
unde expresie_constanta trebuie s fie de tip int i nu pot fi dou
etichete egale n aceeai instruciune switch. Cel mult o instruciune
poate fi etichetat cu
default:
La execuia unei instruciuni switch se evalueaz expresia
expr i se compar valoarea obinut cu fiecare constant ce apare
n etichetele asociate instruciunii. Dac se gsete o astfel de
constant, controlul este dat instruciunii ce urmeaz ei, n caz
contrar, controlul fiind transferat la instruciunea de dup eticheta
default, dac aceasta exist, sau instruciunii imediat urmtoare
instruciunii switch.
Pentru a se meniona sfritul unei instruciuni ataate unui
caz, se va utiliza una dintre instruciunile goto, break sau return. La
nceputul unei instruciuni switch pot aprea declaraii, dar nu se
vor efectua iniializri ale variabilelor de tip auto sau register. De
exemplu,
25

switch (text[k])
{
case A : numr_caractere++; break;
case B: numr_caractere++; break;

// se vor completa toate cazurile posibile


case 'Z' : numr_caractere++; break;
case ' a : numr_caractere++; break;

// se vor completa toate cazurile posibile


case z: numr_caractere++; break;
case 0: :numr cifre++;

// se vor completa toate cazurile posibile


case '9':numr cifre++; }
Instruciunea break are forma
break;
Are ca efect terminarea execuiei unui ciclu de tip while, do-while,
for sau switch, controlul fiind transferat primei instruciuni din
corpul blocului cel mai interior.
Instruciunea continue are forma
continue;
Are drept efect trecerea controlului urmtorului ciclu ntr-o
instruciune de tip while sau for n care apare i nu are nici un efect
dac nu apare n corpul unor astfel de instruciuni. Cnd este
ntlnit, ea se trece la urmtoarea iteraie a ciclului (while, for, dowhile). n cazul lui while i do-while, aceasta nseamn c partea
de control se execut imediat. n cazul ciclului for, controlul va
trece la faza de reiniializare. De obicei, instruciunea continue nu
se va aplica instruciunii switch. Ca exemplu, fragmentul urmtor
sumeaz numai elementele pozitive dintr-un tablou a, n care
valorile negative snt omise.
int s;
for (int i=0,s=0; i<N; i++)
{ if (a[i]<0) continue; //sare indicii elementelor negative
s+=a[I]; }
Instruciunea return admite urmtoarele dou forme
return; sau
return (expr);
cea din urm fiind echivalent cu urmtoarea
return expr;
26

Efectul instruciunii return este trecerea controlului la funcia care a


apelat funcia respectiv fr transmiterea unei valori n prima
variant sau cu transmiterea unei valori n ultimele -dou variante.
Instruciunea goto i etichete. Limbajul C++ ofer
instruciunea goto pentru ramificare. Formal, instruciunea goto nu
este necesar i uor se poate scrie programe fr ea. Cu toate
acestea, exist cteva situaii n care goto i poate gsi locul. Cea
mai obinuit folosire este aceea de a abandona prelucrarea n
anumite structuri puternic imbricate, de exemplu, de a iei afar din
dou cicluri deodat, instruciunea break nu poate fi folosit,
deoarece ea prsete numai ciclul cel mai din interior. Astfel:
for(...)
for(...)
( ...
if(dezastru) goto error;}
error:;
O posibilitate de cutare a primului element negativ ntr-un tablou
bidimensional ar fi:
for (i=0; i<N; i++)
for(j=0; j<M; j++)
if (v[i][j]<0) goto found;
found: // s-a gsit n poziia i, j
Programul cu un goto poate fi scris ntotdeauna fr goto, chiar
dac preul pentru aceasta este o variabil suplimentar sau nite
controluri repetate. De exemplu, cutarea n tablou devine:
found=0;
for (i=0; i<N && found; i++)
for (j=0; j<M && found; j++) found = v[i][j]<0;
if (found) { .. } // a fost gsit la i-1, j-1
else {..}
// nu s-a gsit
Instruciunea vid are forma ; i este utilizat pentru a
evita existena unei etichete chiar n faa unei acolade de nchidere
a unui bloc sau n cazul n care corpul unui ciclu nu conine nici o
instruciune.
27
32

Tipuri de date recursive, operaii asupra


listelor,
arborilor.
Listele simplu i dublu lnuite, arborii snt formate din elemente
definite de structuri cu autoreferire. Ele snt consecutiviti de
elemente de acelai tip, numrul crora se schimb dinamic n
procesul de executare a programului. Lista liniar F, care const
din elemente D1, D2,...,Dn, grafic se poate reprezenta n modul
urmtor:
D1 D2 D3 ... Dn
Asupra elementelor listelor se pot efectua urmtoarele operaii:
- de cutare a elementului dup criteriul dat;
- de determinare a primului element n lista liniar;
- insertarea unui element nou nainte sau dup o component
indicat a listei liniare;
- eliminarea unui element din list;
- sortarea componentelor listei.
Metodele de stocare a listelor liniare se divid n metode
consecutive i stocare lnuit.
Elementele listei liniare, utilizate de metodele consecutive,
se aloc ntr-un tablou d de dimensiune fix, de exemplu, 100, i
lungimea listei este indicat de variabila l, adic se declar
float d[100]; int l;
Dimensiunea 100 mrginete dimensiunea maximal a listei liniare.
Lista F n tabloul d se formeaz n modul urmtor:
d[0]=7; d[1]=10; l=2;
Lista obinut se pstreaz n memorie n conformitate cu
schema:
l:
2
d: 7 10
...
[0] [1] [2] [3]
[98] [99]
28

Pentru organizarea elementelor n form de list simplu


lnuit, se utilizeaz structurile care snt legate cte o component
n lan, nceputul creia (prima structur) este indicat de pointerul
dl. Structura care definete elementul listei conine n afar de
componenta informaional i un pointer la urmtorul element din
list. Descrierea acestui tip de structur cu autoreferire i pointerul
n cauz se face n modul urmtor:
typedef struct nod // structura cu autoreferire
{float val;
// valoarea componentei informaionale
struct nod *urm ; // pointerul la urmtorul element din lan
} DL;
DL *p;
// pointerul la elementul curent
DL *prim;
// pointerul la nceputul listei
Pentru alocarea memoriei elementelor listei n C++, se utilizeaz
operatorul de alocare: new care apare sub forma
pointer_la_nume = new nume [ iniializator];
care ncearc s creeze un obiect nume prin alocarea unui numr
egal cu sizeof(nume) de octei n memoria heap, adresa acestuia
este returnat i asignat variabilei pointer_la_nume. n cazul n
care alocarea nu este efectuat cu succes, se returneaz valoarea
NULL.
Operatorul de eliberare delete este apelat printr-o
instruciune de forma
delete pointer_la_nume ;
elibereaz memoria alocat ncepnd cu adresa coninut de
pointer_la_nume. De exemplu,
p=new(DL);
p->val=10;
p->n=NULL;
29

dl=new(DL));
dl->val=7;
dl->n=p;
n ultimul element al listei pointerul la elementul vecin are
valoarea NULL. Lista are urmtoarea form:

Operaii asupra listelor simplu lnuite


Fiecare element al listei simplu lnuite reprezint o
structur alctuit din dou componente: val folosit pentru
componenta informaional i p pentru pointer la urmtorul
element din lista lnuit. Pointerul dl indic adresa de alocare
pentru primul element al listei. Pentru toate operaiile asupra listei
se va utiliza urmtoarea descriere a structurii elementelor liste:
typedef struct nod
{ float val;
struct nod * urm;
} NOD;
int i,j;
NOD * prim, * r, * p;
Pentru executarea operaiilor pot fi utilizate urmtoarele fragmente
de program:
1) formarea listei simplu lnuite:
float x=5; int n=1;
p=new(nod);
r=p;
p->val=x;
p->urm=NULL;
prim=p;
while (p->val !=0)
30

{ p=new(nod); n++;
p->val=x-1.0*n;
r->urm=p;
p->urm=NULL;
r=p; }
2) tiparul elementului j:
r=prim;j=2;
while(r!=NULL && j<n-1)
{ if (r==NULL) printf("\n nu este elementul %d ",j);
else printf("\n elementul %d este egal cu %f ",j++,r->val);
r=r->urm; }
3) tiparul ambilor vecini ai elementului determinat de pointerul p :

p=prim;
if((r=p->urm)==NULL) printf("\n nu are vecin din
dreapta");
else printf("\n vecinul din dreapta este %f", r->val);
if(prim==p) printf("\n nu are vecin din stnga" );
else { r=prim;
while( r->urm!=p ) r=r->urm;
printf("\n vecinul de stnga este %f", r->val); }
4) eliminarea elementului care este succesorul elementului n
cauz, la care indic pointerul

p=prim;
if ((r=p->urm)==NULL) printf("\n nu este succesorul ");
p->urm=r->urm; delete(r->urm);
5) insertarea noului element cu valoarea newval=100 dup
elementul determinat de pointerul p:
31

r=new(NOD);
r->urm=p->urm; r->val=100; p->urm=r;
Organizarea listelor dublu lnuite
Lista dublu lnuit este o list n care fiecare element
conine doi pointeri: unul la precedentul element, altul la
succesorul element din list. Lista dublu lnuit n program se
poate determina cu ajutorul urmtoarelor descrieri:
typedef struct ndd
{ float val;
// valoarea informaional a componentei
struct ndd * succesor; // pointer la succesorul element
al //listei n
struct ndd *precedent; // pointer la precedentul element al
//listei m
} NDD;
NDD * prim, * p, * r;
Interpretarea grafic a listei F=< 2,5,7,1 > ca list dublu lnuit
este urmtoarea:

Insertarea noului element cu valoarea newval dup elementul


determinat de pointerul p, se efectueaz de operatorii
r=new(NDD);
r->val=newval;
r->succesor=p->succesor;
(p->succesor)->precedent=r;
p->=r;
Eliminarea elementului urmat de elementul la care indic pointerul
p se efectueaz n modul urmtor:
32

p->succesor=r;
p->succesor=(p->succesor)->succesor;
( (p->succesor)->succesor )->precedent=p;
delete r;
Lista liniar este ciclic, dac ultimul element al listei indic la
primul element, iar pointerul dl indic la ultimul element al listei.
Schema listei ciclice pentru lista F=< 2,5,7,1 > este urmtoarea:

La rezolvarea problemelor pot aprea diferite tipuri de liste lnuite.


Stiv i coad
n funcie de metoda de acces la elementele listei liniare,
pot fi cercetate urmtoarele tipuri de liste liniare: stive, cozi i cozi
de tip vagon.
Stiva este o consecutivitate de elemente de acelai tip
variabile scalare, tablouri, structuri sau uniuni. Stiva reprezint o
structur dinamic, numrul de elemente a creia variaz. Dac
stiva n-are elemente, ea este vid.
Asupra elementelor stivei pot fi efectuate urmtoarele
operaii:
- verificarea dac stiva este vid,
- includerea unui element nou n vrful stivei;
- eliminarea elementului din vrful stivei;
- accesarea elementului din vrful stivei, dac stiva nu este vid.
Astfel, operaia de includere i eliminare a elementului, de
asemenea, accesarea elementului are loc numai asupra elementului
din vrful stivei.
Coada este o list liniar n care elementele listei se elimin
din capul listei i elementele noi se includ prin coada listei.
33

Coad de tip vagon este o list liniar n care includerea i


eliminarea elementelor din list se efectueaz din ambele capete
(vrful i sfritul) ale listei.
Stiva i coada se organizeaz att static prin intermediul
tabloului, ct i dinamic prin list (simplu sau dublu lnuit).
Vom cerceta cum se utilizeaz lista n form de stiv pentru
implementarea calculrii expresiei aritmetice n form invers
polonez. n astfel de mod de prezentare a expresiei operaiile se
nregistreaz n ordinea executrii lor, iar operanzii se afl
nemijlocit n faa operaiei. De exemplu, expresia (6+8)*5-6/2 n
forma invers polonez are forma: 6 8 + 5 * 6 2 / Utiliznd noiunea de stiv, expresia aritmetic n form
invers polonez se execut print-o singur trecere de examinare a
expresiei. Fiecare numr se introduce n stiv, iar operaia se
execut asupra urmtoarelor dou elemente din vrful stivei,
nlocuindu-le cu rezultatul operaiei efectuate. Dinamica
schimbrilor din stiv va fi urmtoarea:
S = < >; <6>; <6,8>; <14>; <14,5>; <70>;
<70,6>; <70,6,2>; <70,3>; <67>.
Mai jos este descris funcia eval, care calculeaz valoarea
expresiei indicate n tabloul m n form de expresie invers
polonez, m[i]>0 indic numrul nenegativ, iar valoarea m[i]<0 operaia. n calitate de coduri pentru operaiile de adunare, scdere,
nmulire i mprire se aleg numerele: -1, -2, -3, -4. Pentru
organizarea stivei se utilizeaz tabloul interior stack. Parametrii
funciei snt tabloul de intrare m i lungimea sa l.
float eval (float *m, int l)
{ int p,n;
float stack[50],c;
for(int i=0; i < l ;i++)
if ((n=m[i])<0)
{ c=st[p--];
switch(n)
34

{ case -1: stack[p]+=c; break;


case -2: stack[p]-=c; break;
case -3: stack[p]*=c; break;
case -4: stack[p]/=c; } }
else stack[++p]=n;
return(stack[p]); }
Arbori
Arborii snt structuri de date dinamice, cu autoreferire. Prin
arbore se nelege o mulime finit i nevid de elemente (noduri):
A={A1, A2,..., An}, n>0 cu urmtoarele proprieti:
exist un nod i numai unul care se numete rdcina arborelui,
celelalte noduri formeaz submulimi ale lui A, care formeaz
fiecare cte un arbore, arborii respectivi se numesc subarbori ai
rdcinii.
ntr-un arbore exist noduri crora nu le corespund
subarbori. Astfel de noduri se numesc terminale.
n multe aplicaii se utilizeaz noiunea de arbori binari.
Dac mulimea de elemente a arborelui binar este vid, se
consider c arborele const numai din rdcin. Dac mulimea de
elemente este nevid, arborele binar se divide n dou submulimi:
subarborele drept i cel de stnga. Arborele binar este ordonat,
deoarece n fiecare nod subarborele stng se consider c precede
subarborele drept. Un nod al unui arbore binar poate s aib numai
un descendent: subarborele drept sau subarborele stng. De
exemplu, un nod al unui arbore binar poate fi o structur care poate
fi definit n felul urmtor:
typedef struct tnod
{ int nr, int f;
//declaraii
struct tnod *st; // este pointerul spre subarborele stng
al //nodului curent
struct tnod *dr; // este pointerul spre subarborele drept
al //nodului curent
} TNOD;
Asupra arborilor binari pot fi definite urmtoarele operaii:
afiarea componentelor informaionale ale nodului,
35

specificarea criteriului de determinare a poziiei n care s se


inserteze n arbore nodul curent;
determinarea echivalenei a doi arbori;
insertarea unui nod terminal ntr-un arbore binar;
accesarea unui nod al arborelui,
parcurgerea unui arbore;
tergerea unui arbore.
Afiarea componentelor informaionale ale nodului se poate
de efectuat prin funcia:
void prelucrare (TNOD *p)
{printf(numrul = %d apariii= %d \n, p->nr, p->f);}
Criteriul de determinare a poziiei, n care s se inserteze n
arbore nodul curent, se definete de funcia:
int criteriu(TNOD *p, *q)
{ if (q->nr < p -> nr )
return 1; // insertarea nodului curent
//n subarborele stng al nodului spre care indic
//pointerul p
if (q->nr > p-> nr )
return 1; // insertarea nodului curent
//n subarborele drept al nodului spre care indic
//pointerul p
}
Insertarea unui nod terminal ntr-un arbore binar poate fi
efectuat prin urmtoarea funcie:
TNOD* insert_nod()
{ TNOD *parb, *p, *q;
int n=sizeof(TNOD);
if (parb ==0)
{ parb=p; return p; }
int i;
q=parb;
for(;;)
if ((i=criteriu(q,p)) <0) {q->st=p; return p; }
else { q=q->st; continue; }
36

if (i>0)
if (q->dr ==0)
{q->dr=p; return p;}
else {q=q->dr; continue; }
return eq(q,p); }
}
if(p==0)
{ printf(eroare: memorie insuficient\n); exit(1);}
elibnod(p);
return 0; }
Accesarea unui nod al unui arbore poate fi realizat prin
urmtoarea funcie:
TNOD * cauta (TNOD *p)
{TNOD *parb, *q;
if (parb==0) return 0;
int i;
for (q=parb;q;)
if ((i=criteriu(q,parb))==0) return q;
else if(I<0) q=q->st;
else
q=q->dr;
return 0; }
Parcurgerea unui arbore poate fi efectuat n trei modaliti:
n preordine; n inordine; n postordine.
Parcurgerea n preordine presupune accesul la rdcin i
apoi parcurgerea celor doi subarbori ai si: mai nti subarborele
stng, apoi cel drept.
void preord (TNOD *p)
{ if (p!=0)
{ prelucrare(p); preord(p->st); preord(p->dr); }
}
Parcurgerea n inordine presupune parcurgerea mai nti a
subarborelui stng, apoi accesul la rdcin i n continuare se
parcurge subarborele drept.
void inord (TNOD *p)
{ if (p!=0)
{inord(p->st); prelucrare(p); inord(p->dr);}
37

}
Parcurgerea n postordine presupune parcurgerea mai nti a
subarborelui stng, apoi a arborelui drept i, n final, accesul la
rdcina arborelui.
void postord (TNOD *p)
{ if (p!=0)
{ postord(p->st); postord(p->dr); prelucrare(p); }
}
tergerea unui arbore poate fi efectuat de urmtoarea
funcie:
void elib_nod(TNOD *p)
{ delete(p); }
void sterge_arbore (TNOD *p)
{ if (p!=0)
{ postord(p->st); postord(p->dr); elibnod(p); }
}
Recursivitatea ca metod de programare
Recursivitatea presupune o repetare. Ea const n apelarea
unei funcii de ctre ea nsi.
Funcia se numete recursiv dac n momentul executrii
sale funcia se apeleaz pe ea nsi, sau indirect, printr-o
succesivitate de apeluri ale altor funcii.
Funcie este nemijlocit recursiv dac ea se apeleaz din
corpul aceleiai funcii. De exemplu:
int a()
{.....a().....}
Funcia este indirect recursiv dac se efectueaz apel
recursiv prin intermediul unei succesiviti de apeluri ale altor
funcii. Toate funciile componente ale acestei succesiviti de
apeluri se socot recursive. De exemplu,
a(){.....b().....}
b(){.....c().....}
c(){.....a().....} .
Funciile a,b,c snt recursive, deoarece la apelul unei din
funcii are loc apelul altor funcii inclusiv i pe ea nsi.
38

Execuia algoritmului recursiv presupune crearea unui


numr (finit) de copii ale algoritmului, care corespund diferitelor
valori ale unei variabile. n construirea algoritmului recursiv este
inclus o condiie de terminare a apelrii recursive de o expresie;
care prin apelri succesive valoarea ei crete pn la o valoare ce
satisface condiia de finalizare a recursivitii. La executarea
programului cu funcii recursive se creeaz copii ale acestora,
fiecare din ele corespunznd unei valori a expresiei de recursie. Att
timp ct expresia recursiei se calculeaz pn cnd crete pn la o
valoare ce satisface condiia de finalizare a recursivitii, se spune
c are loc recursia nainte. Cnd expresia atinge valoarea soluiei
recursiei, se execut copiile create, astfel nct se obine soluia
problemei. n acest caz are loc recursia napoi. Executarea
programelor cu funcii recursive necesit mult memorie i mult
timp de calcul, cu o complexitate mai mare dect cele nerecursive.
Recursivitatea ca metod de programare este mai eficient,
codul programelor cu funcii recursive este mai compact i mai
uor de neles.
n limbajul C++ funciile pot s se autoapeleze. Exemplul
clasic de funcie recursiv este calcularea factorialului numrului
N! = 1*2*3*...*N.
Vom numi aceast funcie factorial().
long factorial(int n) {return((n==1)?1: n*factorial(n-1) ); }
Apelul funciei recursive creeaz noi copii ale variabilelor locale i
ale parametrilor pentru clasa de memorie auto i register, valorile
lor din apelurile precedente se pstreaz. Pentru fiecare moment
snt accesibile numai valorile apelului curent. Variabilele declarate
cu clasa de memorie static nu necesit crearea noilor copii. Valorile
lor snt accesibile n orice moment de executare a programului. n
corpul funciei recursive este necesar de indicat condiia de ieire
din procesul recursiv, n caz contrar sistemul de calcul poate intra
n impas. De exemplu, funcia de tiprire unui numr (ca un ir de
caractere): poate fi apelat de ea nsi, adic s fie recursiv
void print_cifre(int n)
{ int i;
39

if (n<0)
{ putchar(-); n=-n; }
if ((i=n/10)!=0) print_cifre(i);
putchar(n%10+0); }
Programul de mai jos calculeaz funcia Akkerman cu
utilizarea funciei recursive ackr i funciei auxiliare smacc:
// calculul recursiv al funciei kkerman
# include <stdio.h>
int smacc( int n,int x )
// funcie auxiliar
int ackr( int n, int x, int y) // funcie recursiv
void main ()
// funcia n care se apeleaz funcia
{ int x,y,n,t;
int ackr(int, int, int);
scanf("%d %d %d",&n,&x,&y);
t=ackr(n,x,y);
printf("%d",t); }
int smacc( int n,int x )
// funcie auxiliar
{ switch (n )
{ case 0: return(x+1);
case 1: return (x);
case 2: return (0);
case 3: return (1);
default: return (2); }
}
int ackr( int n, int x, int y) // funcie recursiv
{ int z;
int smacc( int,int);
if(n==0 || y==0) z=smacc(n,x);
else { z=ackr(n,x,y-1);
// apeluri recursive ackr(...)
z=ackr(n-1,z,x); }
return z;
}
Rezultatul ndeplinirii programului:
146
// datele iniiale
10

// rezultatul obinut
40

Fiierele input/output ale limbajul C++. Deschiderea i


nchiderea fiierelor. Citirea i scrierea n fiiere.
Limbajul C++ include n sine funciile standard input/output
ale limbajului C de prelucrare a fiierelor la nivelul jos, inferior i
superior.
Funciile de prelucrare a fiierelor de nivel inferior pot fi
utilizate prin includerea fiierelor io.h, fcntl.h i stat.h.
Pentru deschiderea unui fiier se utilizeaz funcia open
care are urmtoarea form sintactic:
df = open();
unde df este variabil de tip int (descriptorul de fiier).
Funcia open are urmtorii parametri: se indic calea de
acces la fiier i modalitatea de accesare a componentelor
fiierului. Modalitatea de accesare a componentelor se indic prin
una din urmtoarele constante:
O_RDONLY
fiierul se deschide numai pentru citirea
componentelor lui
O_WRONLY
fiierul se deschide numai pentru nregistrarea
componentelor lui
O_RDWR
fiierul se deschide pentru citirea i
nregistrarea componentelor lui
O_APPEND
fiierul se deschide pentru adugarea
componentelor noi la sfritul lui
O_BINARY
fiierul se prelucreaz binar
O_TEXT
fiierul se prelucreaz textual
Pentru a crea un fiier, se utilizeaz funcia creat cu urmtorii
parametri: calea de acces la fiierul creat i modalitatea de
utilizare a fiierului. Al doilea parametru se indic de una din
urmtoarele constante:
S_IREAD
fiierul va fi creat numai pentru citire
S_IWRITE
fiierul va fi creat numai pentru nregistrare
S_IEXE
fiierul va fi creat numai pentru executare
Citirea dintr-un fiier se efectueaz prin funcia read
indicndu-se urmtorii parametri:
read(df, buf, lung)
41

unde df este descriptor de fiier; buf pointer spre zona de


memorie n care se va pstra nregistrarea citit din fiier; lung
lungimea n octei a nregistrrii citite.
nregistrarea n fiier se efectueaz prin funcia write.
Aceast funcie are aceiai parametri ca i funcia read.
Poziionarea ntr-un fiier se efectueaz prin funcia
fseek(df, deplasare, origine). Aceast funcie are urmtorii
parametri: df descriptorul fiierului, deplasarea indic numrul de
octei pentru a deplasa capul de citire sau scriere al discului,
origine are urmtoarele valori pentru efectuarea deplasrii: 0 fa
de nceputul fiierului, 1- fa de poziia curent a capului de citire
sau nregistrare, 2 fa de sfritul fiierului.
nchiderea fiierului se efectueaz de funcia close (df).
Exemplu de utilizare ale acestor funcii:
char nfis[]=fisier1.dat;
int df;
char *p;
df=open(nfis,O_RDONLY);
read(df,p,80);
close(df);
Prototipurile funciilor de prelucrare a fiierelor de nivel
superior pot fi utilizate prin includerea fiierului stdio.h.
Fiierele input/output standard se efectueaz prin
intermediul funciilor scanf i printf, gets, getc, getch i puts, putc,
respective.
Funciile getc(), getch() citesc cte un caracter din fiierul
standard input .
Funciile scanf i fscanf, printf i fprintf permit citirea,
respectiv, afiarea uneia sau a mai multor valori la intrarea standard
sau dintr-un fiier, respectiv, ieirea standard sau nregistrare ntrun fiier. Prototipurile acestor funcii se afl n biblioteca stdio.h.
Principiul de utilizare al funciei printf const n asocierea
unei liste, care conine indicaii de formatare, dat sub forma unui
ir de caractere, o list de variabile. Ambele funcii utilizeaz
specificaiile de scriere sau citire plasate ntr-o constant de tip ir
de caractere, urmat de o list de argumente.
42

Funcia de afiare printf utilizeaz ca argumente nume de


variabile, iar funcia de citire scanf utilizeaz drept argumente
adrese de variabile. De exemplu,
#include<stdio.h>
void main()
{printf("intreg:%6i \n real: %9.3f ",316,144.82) ;
int z;
printf("Introdu valoarea z:");
scanf("%d",&z);
printf("%6d",z);
}
Rezultatul ndeplinirii programului:
intreg: 316
real: 144.820 Introdu valoarea z:500
Valoarea z: 500
Lista este parcurs de la stnga la dreapta. Fiecare semn este asociat
cu caracterul care l urmeaz i este interpretat drept caracter de
control. Caracterele de control utilizate snt:
\n
avans la nceput de linie nou;
\r
poziionare la nceputul liniei curente;
\t
tabulator;
\a
emite un semnal sonor .
Fiecare semn % este interpretat ca nceputul descrierii
caracteristicilor de tiprire a unei valori. Cele mau utilizate semne
snt urmtoarele:
Semnul Descrierea
%d,
un ntreg zecimal este ateptat la intrare; argumentul
%i
corespunztor trebuie s fie un pointer la ntreg;
%o
un ntreg octal este ateptat la intrare; argumentul
corespunztor trebuie s fie un pointer la ntreg;
%x
un ntreg hexazecimal este ateptat la intrare;argumentul
corespunztor trebuie s fie un pointer la ntreg;
%h
un ntreg short este ateptat la intrare; argumentul trebuie
s fie un pointer la un ntreg short;
%u
un ntreg fr semn zecimal este ateptat la intrare;
43

argumentul s fie pointer la ntreg;


un numr n virgul flotant este ateptat; argumentul
corespunztor trebuie s fie un pointer la un cmp float.
Caracterul de conversie e este *f. Formatul prezentat la
intrare pentru un float este alctuit dintr-un semn
opional;
%e
un numr n virgul flotant este ateptat; argumentul
corespunztor trebuie s fie un pointer la un cmp
double. Caracterul de conversie e este *e. Formatul
prezentat la intrare pentru un double este alctuit dintrun semn opional, un ir de numere care pot s conin i
un punct zecimal i un cmp de exponent care este
format din E sau e, urmat de un ntreg cu semn;
%c
un singur caracter este ateptat la intrare; argumentul
corespunztor trebuie s fie un pointer la caracter. n acest
caz, ignorarea caracterelor albe este suprimat; pentru a
citi urmtorul caracter, altul dect caracterele albe se va
utiliza %1s;
%s
un ir de caractere este ateptat; argumentul corespunztor
trebuie s fie un pointer al unui tablou de caractere, destul
de mare pentru a ncpea irul i un terminator \0, care
va fi adugat.
Caracterele de conversie d, u, i ,o, i x pot fi precedate de
litera l, pentru a indica un pointer la long, mai degrab dect la int,
care apare n lista de argumente. Similar, litera l naintea lui e sau f
indic un pointer la double n lista de argumente. De exemplu:
int i;
float x;
char nume[50];
scanf (%d%f%s,&i,&x,nume) ;
cu linia de intrare
25 244.32E-1 Mircea
va asigna lui i valoarea 25, lui x valoarea 244.32E-1, iar lui nume
valoarea Mircea. Cele trei cmpuri de la intrare pot fi separate de
oricte spaii, taburi i caractere de linie nou. Apelarea
%f

44

int i;
float x;
char nume[50];
scanf (%2d%4.2f%2s,&i,&x,nume) ;
cu linia de intrare
25 244.32E-1 Mircea
va asigna 25 lui i, 44.32 lui x, iar nume va obine valoarea Mi.
Cele mai utilizate secvene asociate valorilor de tip ntreg
snt %ssNX sau %ssNU, unde s este semnul + dac se dorete
afiarea explicit a semnului, - arat c se va face o aliniere la
stnga. N este un numr care arat pe cte poziii se va face afiarea.
De exemplu,
#include<stdio.h>
void main()
{ printf("% -+5i",3); }
programul indicat va afia valoarea +3 prin aliniere la stnga n
conformitate cu specificaiile date, astfel semnul - cere alinierea la
stnga, n cmpul afectat valorii, semnul + cere afiarea explicit a
semnului, cifra 5 arat c afiarea se va face pe 5 poziii, simbolul i
arat c va fi afiat o valoare de tip ntreg.
Valorile de tip real pot fi tiprite utiliznd secvene asociate
de forma %ssNMf sau %sSN.tte, n care simbolul M semnific
precizia cu care vor fi reprezentate numerele (numrul de cifre
dup punctul zecimal).
Toate caracterele care nu aparin secvenelor de control snt
afiate i snt tratate ca iruri de caractere.
De exemplu,
#include<stdio.h>
void main ()
{ char * p="abracadabra";
char ch=B;
printf("%s %c ", p, ch); }
programul afieaz irul de caractere adresat prin intermediul
pointerului p i valoarea variabilei ch.
45

Funcia scanf se utilizeaz la iniializarea unor variabile.


Funciile scanf i printf snt utilizate mpreun. Prin funcia printf
se afieaz un mesaj care adesea este un comentariu legat de
valoarea care urmeaz s fie introdus. De exemplu, n programul
de mai jos am afiat mesajul numr real, dup care urmeaz
apelul funciei scanf care ateapt introducerea unei valori de tip
real sau ntreg:
#include<stdio.h>
void main()
{ float a;
int i;
printf ("Introdu un numr real: ");//utilizatorul va introduce,
//la
scanf("%f", &a);
//tastatura, un numr urmat de Enter.
printf("\n Introdu un numr intreg: ");
//la fel se
procedeaz //n cazul variabilei i
scanf ("%i,", &i); // afiarea textului "numr intreg"
printf("\n Numr ntreg: %6i \n Numr real: %9.3f", i, a);
} // va fi urmat de introducerea, la tastatur, a numrului
//dorit.
Rezultatul ndeplinirii programului:
Introdu un numr real: 3.14
Introdu un numr intreg: 20
Numr ntreg: 20
Numr real: 3.140
Funciile de scriere i citire anterioare pot fi folosite i n
cazul fiierelor. Biblioteca stdio.h, specific limbajului C, conine
definiia unui tip de date FILE. Accesul la un fiier se face printrun pointer de tip FILE. Etapele care trebuie s fie parcurse snt
definirea unui pointer de tip FILE i asocierea unui fiier fizic.
Pointerul va primi drept valoare adresa unei variabile de tip FILE,
obinut prin intermediul funciei fopen(). Aceast funcie are dou
argumente: un ir de caractere care conine numele fiierului fizic
recunoscut de sistemul de operare i un alt ir de caractere care
46

conine indicaii relativ la modul de utilizare al fiierului. Ultimul


parametru poate conine caracterul
R
pentru fiiere deschise pentru citire,
W
pentru fiiere deschise pentru creare sau scriere,
T
pentru fiiere de tip text sau
B
pentru fiiere binare
n exemplul de mai jos am creat un fiier prin intermediul
unui pointer de tipul FILE i o iniializare prin funcia fopen().
Pointerul p conine o valoare de tip FILE fumizat de funcia
fopen(), care deschide pentru nregistrare fiierul disk.dat. Am scris
n acest fiier dou valori n acelai mod cum am fcut afiarea la
ieirea standard.
#include<stdio .h>
void main()
{ FILE *p;
p = fopen("disk.dat","wt");
fprintf(p,"%6i\n%9.3f", 29, 2.71);
fclose (p) ;
}
Rezultatul ndeplinirii programului:
s-a format fiierul disc.dat (pentru nregistrare) cu urmtorul
coninut:
29
2.710
ntrebrile pentru verificarea cunotinelor:
1. Enumerai tipurile de date fundamentale n limbajul C++?
2. Pentru ce se utilizeaz variabilele n limbajul C++?
3. Prin ce se deosebesc variabilele descrise ca extern de cele
descrise ca static?
4. Prin ce se deosebete o referin de un pointer?
5. De ce nu este permis definirea unui vector de referine?
6. Prin ce se deosebete noiunile union i struct?
7. Care snt operaiile aritmetice admise asupra pointerilor?
47

8. Definii un tablou tridimensional, elementele crora snt de tip


point.
9. Dai exemple de utilizare a operatorilor unari, binari i ternari.
10. Prin ce se deosebete operatorii de incrementare i
decrementare prefixate de cele sufixate? Exemple de expresii.
11. Explicai aciunea instruciunilor de ciclu. Exemple de utilizare.
12. De ce fiecare variant a instruciunii switch se poate termina cu
instruciunea break? Exemple de utilizare a instruciunii switch
cu i fr instruciunea break.
13. Corectai programul de mai jos care efectueaz sortarea parial
a listei simplu lnuite, dup sortare pointerul v indic la
elementul k1.

NOD *v;
float k1;
k1=prim->val;
r=prim;
while( r->urm!=NULL )
{ v=r->urm;
if (v->val; v=v->urm;
v->n=prim;
prim=v; }
else r=v;
}
14. Alctuii un program care organizeaz o list ciclic Fi (1<I)
dintr-o consecutivitate de numere ntregi B1, B2,..., Bn din
intervalul de la 1 pn la 9999, sortate cresctor.
Indicaie: La rezolvarea acestei probleme avem o list sortat
cresctor Fi. La introducerea unui nou element Bi+1, acest
element se inserteaz la locul su n lista Fi. Pentru insertarea
elementului nou n lista Fi, s se cerceteze trei cazuri:
- lista Fi este vid,
48

- elementul se inserteaz la nceputul listei,


- elementul se inserteaz la sfritul listei.
15. Cercetai programul de mai jos
typedef struct str1
{ float val;
struct str1 *n;
} NOD;
void main()
{ NOD *arrange(void); NOD *p;
p=arrange();
while(p!=NULL)
{ cout<< p->val<<endl;
p=p->n; }
}
NOD *arrange() // formarea listei sortate
{ NOD *dl, *r, *p, *v; // dl - nceputul listei, p,v pointeri la
//dou elemente vecine,
float in=1;
// r fixeaz pointerul la elementul
curent //care conine valoarea n
char *is;
dl=new(NOD);
dl->val=0;
// primul element
dl->n=r=new(NOD);
r->val=10000; r->n=NULL; // ultimul element
while(1)
{ cin>> is;
if(* is=='q') break;
in=atof(is);
r=new(NOD);
r->val=in;
p=dl;
v=p->n;
while(v->valn);
}
49

r->n=v;
p->n=r; }
return(dl); }
16. Inversai consecutivitatea de simboluri introduse. De exemplu,
s-a introdus consecutivitatea ABcEr-1, consecutivitatea
inversat va fi 1-rEcBA. Utilizai noiunea de list simplu
lnuit.
17. Cercetai operaiile efectuate asupra stivei n programul de mai
jos:
typedef struct st
// declararea tipului STACK
{ char ch;
struct st *ps;
} STACK;
main()
{ STACK *p,*q;
char a;
p=NULL;
do
// completarea stivei
{ a=getch();
q=new(STR1);
q->ps=p; p=q;
q->ch=a;
} while(a!='.');
do
// tiparul stivei
{ p=q->ps; delete (q); q=p;
cout<< p->ch;
} while(p->ps!=NULL);
}
18. Scriei un program n care numerele din baza 10 din lista dublu
lnuit dat se nlocuiesc cu cele din baza 2.
19. Scriei un program care ar efectua urmtoarele operaii. Se
creeaz o list dintr-un ir de numere ntregi, care se termin
50

cu zero. Din list se terg mai nti elementele negative, apoi


numerele pare.
20. Scriei un program care din trei cozi se selecteaz o coad nou
mai nti numerele negative, zerourile, apoi numerele pozitive.
21. Analizai ce efectueaz programul de mai jos:
typedef struct nod
{ float val;
struct nod *n;
} NOD;
int index (NOD *x[100])
{ NOD *p;
int i,j=0;
float inp;
for (i=0; i<100; i++) x[i]=NULL;
cin>> inp;
while (inp!=0)
{ j++;
p=new(NOD);
i=inp%100+1;
p->val=inp;
p->n=x[i];
x[i]=p;
cin>>inp; }
return j; }
Valoarea returnat de funcia index va fi numrul de elemente
cercetate din list.
22. Scriei un program care s extrag n lista L2 elementele cu
numere impare din lista L1. Lista L1 conine numere ntregi.
23. Cum se utilizeaz funciile standard de citire a valorilor
variabilelor de la tastatur i din fiier?
24. Cum se utilizeaz funciile standard de tipar la ecran i
nregistrare ntr-un fiier a valorilor variabilelor?
25. Care snt caracterele de control i specificare a tiparului
variabilelor la ecran?
51
64

Temele pentru acas:


1. Care dintre exemplele de declaraie i/sau iniializare snt
corecte:
int r;
int 25;
int p=25;
int i;
int r=i;
r=25;
const int j=25;
int r=j;
2. Scriei o versiune de funcie cu pointeri pentru strcat()
concatenare a dou iruri de caractere.
3. Scriei variante de programe cu pointeri care ar efectua funciile
citete_linie(), reverse_linie().
4. Care dintre exemplele de declaraie i/sau iniializare snt
corecte:
int &r;
int &r=25;
int *p=25;
int i;
int &r=i;
r=25; |
const int j=25;
int &r=j;
5. Scriei un program pentru a numra biii de la dreapta spre stnga
pentru un numr dat.
6. Scriei un program care rotete ntregul n la dreapta cu b poziii.
7. Scriei un program care inverseaz cei n bii ai si care ncep de
la poziia p, lsndu-i pe ceilali neschimbai.
8. Scriei un program care convertete literele mari n litere mici
utiliznd o expresie condiional.
9. Scriei un program care convertete numrul ntreg n n baza
zecimal ntr-un ir de caractere.
52

10. Scriei un program care convertete ntregii fr semn n ntr-o


reprezentare binar s.
11. Scriei un program care convertete un ntreg ntr-un numr
hexazecimal.
12. Scriei un program de convertire a unui ir de caractere ntr-un
ntreg.
13. Scriei un program care inverseaz un ir de caractere s.
14. Scriei un program pentru a numra biii de la dreapta spre
stnga pentru fiecare numr citit dintr-un fiier.
15. Scriei un program care rotete un ntreg n (citit dintr-un fiier)
la dreapta cu b poziii. b este un numr aleator de la 1 la 16.
16. Scriei un program care n fiecare numr citit dintr-un fiier
inverseaz cei n bii ai si care ncep de la poziia p, lsndu-i
pe ceilali neschimbai, p ia valoare de la 1 la 10.
17. Scriei un program care convertete literele mari n litere mici
dintr-un fiier textual.
18. Scriei un program care convertete numrul ntreg n n baza
zecimal, citit dintr-un fiier ntr-un ir de caractere.
19. Scriei un program de convertire a fiecrui element dintr-o stiv
ntr-un ir de caractere.
Temele pentru lucrri de laborator:
I.
1. Scriei un program care compar dou stive date.
2. Scriei un program care genereaz o mie de seturi de cinci
numere aleatoare cuprinse ntre 1 i 40, n final afind frecvena
cu care a fost generat fiecare numr.
3. Scriei un program pentru a numra biii de la dreapta spre
stnga pentru un numr introdus de la tastatur.
II.
1. Scriei un program care calculeaz numrul de elemente dintr-o
list simplu lnuit care snt mai mici ca valoarea medie
aritmetic a tuturor elementelor acestei liste.
53

2. Scriei un program care efectueaz nmulirea cifrelor unui


numr dat.
3. Scriei un program care convertete numrul ntreg n n baza
zecimal ntr-un ir de caractere.
III.
1. Scriei un program care determin un numr obinuit din
inversul cifrelor numrului dat.
2. Scriei un program care permite crearea unui arbore binar i
traversarea lui n inordine, preordine, postordine.
3. Scriei un program care convertete ntregii fr semn dintr-o
list dublu lnuit n reprezentare binar.
IV.
1. Scriei un program care din 100 de numere aleatoare se
determin numrul maximal i cel minimal. S se determine
diferena dintre numrul maximal i cel minimal determinat
2. Scriei un program care convertete ntregii fr semn n selectai
dintr-un fiier ntr-o reprezentare binar.
3. Scriei un program care convertete un ntreg ntr-un numr
hexazecimal.
V.
1. Scriei un program care determin numrul de ordine a
numrului minimal dintr-o consecutivitate de numere aleatoare.
Cantitatea de numere aleatoare ale consecutivitii este aleatoare
(N = 1,,100). Valorile numerelor aleatoare ale consecutivitii
snt din intervalul 0 100000.
2. Scriei un program de convertire a unui ntreg ntr-un ir de
caractere.
3. Scriei un program cu o funcie recursiv care calculeaz cel mai
mare divizor comun al elementelor dintr-o consecutivitate.
VI.
1. Scriei un program care determin numrul maximal i cel
minimal ntr-o list circular de 100 de numere aleatoare. S se
determine consecutivitatea de elemente ce se afl ntre numerele
maximal i cel minimal determinate.
54

2. Scriei un program care calculeaz suma cifrelor pentru fiecare


numr din consecutivitatea de 100 de numere aleatoare.
3. Scriei un program care inverseaz un ir de caractere s.
VII.
1. Scriei un program care formeaz o list nou simplu lnuit
dup urmtoarea legitate: din trei liste simplu lnuite mai nti
se selecteaz numerele divizibile la 3, 5 i 7, apoi cele
pozitive pare.
2. Scriei un program care genereaz un fiier al cror valori ale
elementelor snt cuprinse ntre 1 i 100. S se determine
frecvena cu care a fost generat fiecare element n fiierul creat.
3. Scriei un program care inverseaz cei n bii ai elementelor unei
liste simplu lnuit care ncep de pe poziia p, lsndu-i pe
ceilali neschimbai.
VIII.
1. Scriei un program care atribuie unei liste simplu lnuite
elementele altei liste n ordine invers.
2. Scriei un program cu funcie recursiv care calculeaz cel mai
mare divizor comun dintr-un ir de numere date.
3. Scriei un program care din dou fiiere ordonate descresctor se
unesc n unul nou pstrndu-i-se ordinea descresctoare de
sortare.
IX.
1. Scriei un program care determin cte numere din
consecutivitatea de 100 de numere aleatoare snt mai mari ca
vecinii si.
2. Scriei un program care nlocuiesc numerele din baza 10 din
consecutivitatea dat cu cele din baza 2.
3. Scriei un program care decide dac o valoare x aparine unei
liste dublu lnuite v. Elementele lui v trebuie s fie n ordine
cresctoare. Se tiprete numrul elementului din list (un
numr ntre 0 i n-1), dac x apare n v, i 1, dac nu apare.
X.

55

1. Scriei un program care va tipri n ordine invers


subconsecutivitatea de numere dintre valoarea minim i
maxim ale unei liste simplu lnuit.
2. Scriei un program care determin un numr obinuit din
inversul cifrelor numrului dat.
3. Utiliznd funcia recursiv, scriei un program care convertete
un ntreg citit dintr-un fiier n numere hexazecimale.
XI.
1. Scriei un program care formeaz o list dublu lnuit nou din
cea dat dup urmtoarea legitate: elementele listei noi se obine
din inversul cifrelor numrului din lista dat.
2. S se scrie un program care ar conine dou funcii: una recursiv, a doua - nerecursiv pentru numrarea elementelor
unei liste.
3. Scriei un program care inverseaz fiecare element de tip ir de
caractere dintr-o list simplu lnuit.
XII.
1. Scriei un program care convertete literele mari n litere mici
utiliznd din elementele unei stive.
2. S se scrie un program care din lista L1 ce conine numere
ntregi s se extrag n lista L2 elementele cu numere impare din
lista L1.
3. Scriei un program care convertete ntregii fr semn dintr-o
list simplu lnuit n, ntr-o reprezentare binar.
XIII.
1. Scriei un program care calculeaz suma cifrelor pentru fiecare
numr din consecutivitatea de 100 de numere aleatoare.
2. Scriei un program care rotete fiecare element al listei dublu
lnuite n la dreapta cu b poziii.
3. Scriei un program care atribuie unui fiier elementele altui fiier
n ordine invers.
XIV.
1. Scriei un program care creeaz o list circular a cror valori ale
elementelor snt cuprinse ntre 1 i 100. S se determine
frecvena cu care a fost generat fiecare element al listei create.
56

2. Scriei un program care calculeaz suma cifrelor pentru fiecare


numr din consecutivitatea de 100 de numere aleatoare.
3. Scriei un program care convertete fiecare element al listei
dublu lnuite ntr-un numr hexazecimal.
XV.
1. Scriei un program care determin cte numere ale unei cozi de
100 de numere aleatoare snt mai mari ca vecinii si.
2. Scriei un program care formeaz un fiier nou din cel dat dup
urmtoarea legitate: elementele fiierului nou se obine din
inversul cifrelor numrului din fiierul dat.
3. Alctuii un program care ar efectua urmtoarele operaii asupra
listei dublu lnuite:

iniializarea listei;

cutarea elementului dup criteriul dat;

insertarea unui element nou nainte sau dup o component


indicat a listei;

eliminarea unui element din list; sortarea componentelor


listei.

57

Lucrarea de laborator nr. 2


Tema: Clase (constructori, destructori).Funcii i clase prietene.
Scopul lucrrii: familiarizarea studenilor cu noiunea de clase,
utilizarea constructorilor, destructorilor, cu funcii i clase prietene.
Consideraiile teoretice necesare:
Clase
Sintaxa simplificat a declarrii unei clase este urmtoarea:
class NumeClas
{...
declaraii variabile membri...
declaraii funcii membri...
}
Din definirea clasei se poate observa c clasa este asemntoare cu
o structur. Ea are n componena sa membri att de tip variabil, ct
i de tip funcie. Pentru datele din interiorul clasei se utilizeaz, de
regul, termenul de date membri, iar pentru funcii denumirea de
funcii sau metode. O clas permite incapsularea n interiorul sau a
datelor i a codului.
Pentru a putea utiliza efectiv un tip de date (n cazul de fa
o clas), trebuie sa definim o variabil de acel tip. ntr-un mod
similar declaraiei
int i;
putem scrie:
NumeClas variabil
Vom considera c variabil este un obiect. Exprimarea uzual este
c un obiect este instanierea unei clase.
O clas este compus din dou pri: declaraia i
implementarea ei. Declaraia clasei prezint membrii clasei.
Membrii clasei snt variabile de instaniere i funcii membri
indicate prin prototipul lor (tipul returnat, numele funciei, lista de
parametri). Implementarea funciilor membri are loc prin
implementarea clasei. Gradul de accesibilitate la elementele
componente ale clasei este indicat prin cuvintele: private sau
58

protected elementele clasei snt accesate numai prin intermediul


funciilor membri sau prietene friend, public toate elementele snt
disponibile n exteriorul clasei. De exemplu:
#include<iostream.h>
class myclass // se declar un nou tip de date myclass
{private: int a;
// componenta int a se declar implicit
n //zona private
public:
// funciile membri declarate mai joc snt
din //zona public
void set_a (int num); // prin intermediul acestor funcii se
// acceseaz componenta a
int get_a ();
};
void myclass::set_a(int num) { a=num;}
// aceast funcie atribuie valoare componentei
a
int myclass::get_a(){return a; }
// aceast funcie furnizeaz valoarea componentei
a
void main ()
// funcia de baz a programului
{ myclass ob1, ob2; // se declar dou obiecte ob1 i
ob2 //de tipul myclass
ob1.set_a (10); // pentru obiectul ob1 se atribuie
//valoare componentei a egal cu 10
ob2.set_a (99); // pentru obiectul ob2 se atribuie
//valoare componentei a egal cu 99
cout << ob1.get_a ()<< \n; // pentru obiectul ob1 se
//furnizeaz valoarea componentei a
//care apoi se tiprete la ecran
cout << ob2.get_a () << \n; // pentru obiectul ob2 se
//furnizeaz valoarea componentei a
//care apoi se tiprete la ecran
}
Rezultatul ndepliniri programului:
10
59

99
Funciile set_a i get_a, pentru setarea i furnizarea valorii pentru
componenta a, nu snt necesare,dac componenta a va fi inclus n
zona public,. Componenta a va fi explicit accesat i i se va
iniializa sau atribui valoare. Exemplul de mai sus se va modifica n
felul urmtor:
#include<iostream.h>
class myclass // se declar un nou tip de date myclass
{public:
int a;
// componenta int a se declar explicit n
//zona public
// funciile membri declarate mai sus nu snt necesare
};
void main ()
{ myclass ob1, ob2; // se declar dou obiecte ob1 i ob2
//de tipul myclass
ob1.a =10;
// pentru obiectul ob1 se iniializeaz
//valoarea componentei a n mod
//explicit cu valoarea 10
ob2.a = 99;
// pentru obiectul ob2 se iniializeaz
//valoarea componentei a n mod
// explicit cu valoarea 99
cout << ob1.a << \n; // pentru obiectul ob1
// se tiprete valoarea componentei a
cout << ob2.a << \n; // pentru obiectul ob2
// se tiprete componentei a
}
Rezultatul ndepliniri programului:
10
99
Constructorii snt un tip special de funcie membru, avnd
acelai nume ca i numele clasei, nu returneaz rezultat i snt
apelai automat la instanierea unei clase, fie ea static sau
dinamic. Ei au scopul de a atribui valori iniiale elementelor
60

membri, dar pot efectua i unele operaii, cum ar fi, alocarea


dinamic de memorie, deschiderea unui fiier .a. De exemplu:
class persoana
{ private:
char nume[40];
long int telefon;
public:
persoana() {nume=\0; telefon =0;};
//constructorul iniializeaz valori nule elementelor membri
persoana(char*p, long int t) {strcpy(nume,p); telefon=t;}
//constructor iniializeaz
valori
concrete
pentru
elementele //membri ale clasei
persoana(char* nume) {return nume; };
//aceste funcii atribuie valori pentru elementele membri nume
persoana(long int telefon) {return telefon;};
//i telefon
persoana persoana_ input (char *n, long int t=0)
{persoana p;
strcpy(p.nume,n); p.telefon=t;
return p; };
};
Apelul constructorului se efectueaz n momentul declarrii unui
obiect. Dac declarm o variabil de tipul persoana, fie
persoana p = persoana (Vasilina, 743567);
sau
persoana p (Vasilina, 743567);
constructorul va iniializa elementele membri nume i telefon ale
clase persoana respectiv cu valorile Vasilina i 743567. Dac se
va declara un obiect de tipul persoana fr date iniiale,
constructorul va completa elementele membri nume cu stringul vid
\0 i telefon cu valoarea 0.
Destructorii dezactiveaz toate funciile unui obiect, l
distruge i snt apelai automat la eliminarea unui obiect, la
ncheierea timpului de via n cazul static, sau la apelul unui delete
n cazul dinamic. De regul, destructorii snt utilizai n cazul, cnd
constructorii efectueaz alocri dinamice de memorie. Destructorul
61

are acelai nume ca i constructorul, fiind precedat de semnul ~.


De exemplu:
#include<iostream.h>
#include<string.h>
#include<stdlib.h>
#define Size 255
class strtype
{ private:
char *p;
int len;
public:
strtype()
// constructorul
{ p=new char;
if (!p){cout << Eroare la alocarea memoriei \n;
exit(1);}
*p=\0; len=0; };
~strtype() {cout << Eliberarea memoriei\n; delete p; }
// destructorul
void set (char*ptr)
{ if (strlen(ptr)> Size )
cout<<Stringul conine mai mult de 255 de caractere
\n; strcpy(p,ptr); len=strlen(p);};
void show()
{ cout << p << - lungimea << len << \n;}
};
void main()
{ strtype s1,s2;
s1.set (Test); s2.set(Program C++);
s1.show(); s2.show();
}
Rezultatul ndeplinirii programului:
Test- lungimea 4
Program C++- lungimea 11
Eliberarea memoriei
Eliberarea memoriei
62

Destructorii obiectelor membri snt apelai, dup ce destructorul


obiectului principal a fost executat. Dac obiectul membru este
compus din alte obiecte, atunci se va proceda la executarea
destructorilor obiectelor incluse. Destructorii obiectelor membri
snt apelai n ordine invers, n care acetea apar n declaraia
clasei.
Din punct de vedere cronologic, constructorul este apelat
dup alocarea memoriei necesare, deci n faza final a crerii
obiectului, iar destructorul naintea eliberrii memoriei aferente,
deci n faza iniial a distrugerii sale.
Constructorii i destructorii se declar i se definesc similar
cu celelalte funcii membri, dar prezint o serie de caracteristici
specifice:
numele lor coincide cu numele clasei creia ii aparin;
destructorii se disting de constructori prin faptul c numele lor
este precedat de caracterul
nu pot returna nici un rezultat
nu se pot utiliza pointeri ctre constructori sau destructori
constructorii pot avea parametri, destructorii insa nu. Un
constructor fr parametri poart denumirea de constructor
implicit.
n care o clasa nu dispune de constructori sau destructori,
compilatorul de C++ genereaz automat un constructor, respectiv
destructor, implicit.
Membrii unei clase
Accesarea membrilor unei clase se face n felul urmtor:
obiect.VariabiMembru = valoare;
pentru accesul la o variabil membru, i
obiect.FuncieMembru();
pentru apelarea unei funcii membri.
Pentru exemplificare s consideram o implementare a
noiunii de punct. Ca variabile membri avem nevoie doar de
coordonatele x i y care definesc poziia n spaiu a unui punct. Am
mai declarat o funcie care calculeaz aria dreptunghiului avnd
punctele (0, 0) i (x, y).
63

class Point
{unsigned x, y;
unsigned long Arie() {return x * y;};
unsigned GetX();
unsigned GetY();
void SetX(unsigned X);
void SetY(unsigned Y);
};
unsigned Point::GetX() {return x;}
unsigned Point::GetY(){return y; }
void Point::SetX(unsigned X){ x = X; }
void Point::SetY(unsigned Y) { y = Y; }
Am folosit un operator nou, specific C++, ::, numit operator de
rezoluie, numit i operator de acces sau de domeniu. El permite
accesul la un identificator dintr-un bloc n care acesta nu este
vizibil datorit unei alte declaraii locale. Un exemplu de folosire
este urmtorul:
char *sir = "variabil global";
void funcie()
{ char *sir = "variabil local";
printf("%s\n", ::sir); // afieaz variabila global
printf("%s\n", sir); // afieaz variabila local
}
Pentru definiiile funciilor membri aflate n afara declaraiei clasei
este necesar specificarea numelui clasei urmat de acest operator,
indicnd faptul c funcia are acelai domeniu cu declaraia clasei
respective i este membru a ei, dei este definit n afara
declaraiei.
Cuvntul-cheie this. Toate funciile membri ale unei clase
primesc un parametru ascuns, pointer-ul this, care reprezint adresa
obiectului n cauz. Acesta poate fi utilizat n cadrul funciilor
membri. De exemplu:
unsigned long Point::Arie()
{return this->x * this->y; }
64

Crearea i distrugerea obiectelor. S considerm urmtorul


program C++:
void main()
{Point p; }
n momentul definirii variabilei p, va fi alocat automat
spaiul de memorie necesar, acesta fiind eliberat la terminarea
programului. n exemplul de mai sus, variabila p este de tip static.
n continuare vom modifica acest program pentru a folosi o
variabil dinamic (pointer).
void main()
{ Point *p;
p = new Point;
p->x = 5; p->y = 10;
printf("Aria = %d\n", p->Aria());
delete p; }
Operatorul new este folosit pentru alocarea memoriei, iar
sintaxa acestuia este:
variabila = new tip;
variabila = new tip(valoare_iniial);
variabila = new tip[n];
Prima variant aloc spaiu pentru variabil dar nu o iniializeaz, a
doua variant ii aloc spaiu i o iniializeaz cu valoarea
specificat, a treia aloc un tablou de dimensiune n. Acest operator
furnizeaz ca rezultat un pointer coninnd adresa zonei de memorie
alocate, n caz de succes, sau un pointer cu valoarea NULL (practic
0) cnd alocarea nu a reuit.
Eliminarea unei variabile dinamice i eliberarea zonei de
memorie aferente se realizeaz cu ajutorul operatorului delete.
Sintaxa acestuia este:
delete variabil;
Dei aceti doi operatori ofer metode flexibile de gestionare a
obiectelor, exist situaii n care aceasta nu rezolv toate
problemele. De aceea, pentru crearea i distrugerea obiectelor n
C++ se folosesc nite funcii membri speciale, numite constructori
i destructori, despre care s-a menionat mai sus.
65

S completm n continuare clasa Point cu un constructor i


un destructor:
Point::Point() // constructor implicit
{ x = 0; y = 0; }
Point::Point(unsigned X, unsigned Y)
{ x = X; y = Y; }
Point::~Point() { }
Ai remarcat cu aceast ocazie modul de marcare a comentariilor n
C++: tot ce se afl dup caracterul // este considerat comentariu.
Definiii de forma
Point p;
//sau
Point *p = new Point();
duc la apelarea constructorului implicit.
O ntrebare care poate apare este motivul pentru care am realizat
funciile GetX(), GetY(), SetX(), SetY(), cnd puteam utiliza direct
variabilele membri x i y. Deoarece una din regulile programrii
C++ este de a proteja variabilele membri, acestea pot fi accesate
numai prin intermediul unor funcii, care au rolul de metode de
prelucrare a datelor incapsulate n interiorul clasei.
Funcii i Clase friend. Conceptul friend permite abateri
controlate de la ideea proieciei datelor prin incapsulare.
Mecanismul de friend (sau prietenie) a aprut datorita
imposibilitii ca o metod s fie membru a mai multor clase.
Funciile prietene snt funcii care nu snt metode ale unei
clase, dar care au totui acces la membrii privai ai acesteia. Orice
funcie poate fi prieten a unei clase, indiferent de natura acesteia.
Sintaxa declarrii unei funcii prietene n cadrul declaraiei
unei clase este urmtoarea:
friend NumeFuncie
De exemplu:
class Point {
friend unsigned long Calcul(unsigned X, unsigned Y);
public:
friend unsigned long AltClas::Calcul(unsigned X,
unsigned Y);
66

...
};
unsigned long Calcul(unsigned X, unsigned Y)
{return X * Y / 2; }
unsigned long AltClas::Calcul(unsigned X, unsigned Y)
{
...
}
Funcii membri ca prietene. Orice funcie membru nu poate
fi prieten aceleiai clase, dar, posibil, s fie prietena altei clase.
Astfel, funciile friend constituie o punte de legtur ntre clase.
Exist dou moduri de a face ca o funcie membru a unei clase s
fie prietena altei clase. Prima variant este specificarea funciei
membru a unei clase, ca fiind prieten altei clase. Deci, n cea de-a
doua clas, vom declara funcia membru n prima clas ca fiind de
tip friend.
class B;
class A
{..
void Al (B &x) ;
..
);
class B
{ friend void A::A1(B &x); );
A doua variant este declararea unei clase prieten, astfel, c toate
funciile sale membri, snt, de fapt, prietene clasei n care un obiect
de tipul primei clase este declarat friend.
class B;
class A
{ void Al (B &x) ; );
class B
{
friend A;
};
Indiferent de metod, se impune predeclararea clasei, care va fi
prieten sau va conine funcii, care snt prietene unei alte clase.
Clasele prietene snt clase care au acces la membrii privai ai
unei clase. Sintaxa declarrii unei clase prietene este:
67

friend class NumeClasPrieten


De exemplu:
class PrimaClas {
...
};
class ADouaClas {
...
friend class PrimaClas;
};
Clasa PrimaClas are acces la membrii privai ai clasei
ADouaClas.
Relaia de prietenie nu este tranzitiv. Daca o clasa A este
prietena a clasei B, i clasa B este prieten a unei clase C, aceasta
nu nseamn ca A este prieten clasei C. De asemenea, proprietatea
de prietenie nu se motenete n clasele derivate. Clase prietene
snt utile n situaia n care avem nevoie de clase, care s comunice
ntre ele deseori, acestea aflndu-se pe acelai nivel ierarhic. Pentru
exemplificare, presupunem c vom implementa o stiv de caractere
ca o list simplu nlnuit. Vom utiliza dou clase, una ataat
nodurilor din list i una stivei propriu-zise.
#include<conio.h>
#include<stdio.h>
class stiva;
class nod
{ private:
friend stiva;
nod(int d, nod *n);
int data;
nod *anterior;
};
class stiva
{ private:
nod *virf;
public:
stiva () {
virf=NULL; }
68

~stiva() { delete virf; }


void push (int c);
int pop ();
};
nod::nod (int d, nod *n) {data=d; anterior=n;}
void stiva::push (int i) {nod *n=new nod(i, virf); virf=n; }
int stiva::pop ()
{ nod *t=virf;
if (virf)
{ virf=virf->anterior;
int c= t->data;
delete t;
return c; }
return -1;
}
void main()
{ int c;
stiva cs;
printf("Introdu un sir de caractere, ce se termina in *");
while ((c=getch ())!='*')
{ cs.push (c);
putch(c); }
putch(c);
while ((c=cs.pop ())!=-1)
{ putch (c); }
c='\n'; putch(c);
}
Rezultatul ndeplinirii programului:
Introdu un sir de caractere, ce se termina in *ertyuioppoiu*uiop
poiuytre
Prototipul unei funcii friend cu o clas se afl, de regul, n cadrul
clasei respective. Funcia friend nu este membru a acestei clase.
Indiferent de poziia declaraiei unei asemenea funcii, n cadrul
declaraiei clasei funcia va fi public. De exemplu:
class punct
69

{ private:
int x, y;
public:
punct (int xi, int yi) {x=xi; y=yi; };
friend int compara (punct &a, punct &b);
};
int compara (punct &a, punct &b)
{ //returneaz <0, dac a este mai aproape de origine
//
>0, dac b este mai aproape de origine
//
=0, dac a i b snt egal deprtate.
return a. x*a. x+a. y*a. y-b. x*b. x-b. y*b. y; }
void main()
{ punct p (14,17), q(57,30);
if(compara(p,q)<0) printf("p este mai apropiat de
origine\n");
else printf (q este mai apropiat de origine. \n") ; }
Orice funcie friend a unei clase poate fi transformat ntr-o funcie
membru a acelei clase, renunndu-se ns la gradul de prietenie.
Exemplul de mai sus se modific n felul urmtor:
#include<stdio.h>
class punct
{ private:
int x,y;
public:
punct (int xi, int yi) { x=xi; y=yi; }
int compara (punct &b);
};
int punct:: compara (punct &b)
{ return x*x+y*y-b.x*b.x-b.y*b.y; }
void main ()
{ punct p(14,17), q(57,30);
if (p.compara (q)<0)printf ("p este mal apropiat de
origine\n");
else printf ("q este mai apropiat de origine.\n");
}
70

Rezultatul ndeplinirii programului:


p este mal apropiat de origine
ntrebrile pentru verificarea cunotinelor:
1. Ce se va afia la ecran?
#include <iostream.h>
int a=1,b=2, c=43;
class numere
{ public:
int a,b;
void Actiune(int b)
};
void numere:: Actiune(int b) { a=14; b=56; c=3; }
void main ()
{numere doua_numere;
doua_numere.Actiune(56); }
2. Care este deosebirea dintre constructor i un destructor al unei
clase? Cum snt activai constructorii i destructorii?
2. Ce se numesc clase prietene?
3. Ce se numesc funcii prietene?
Temele pentru acas:
1. Introducei i lansai n execuie urmtorul program. Ce rezultat
furnizeaz?
#include <stdio.h>
class numr
{public:
int n;
numr(int i) { printf( "num() %d \n",n); };
-numr() { printf("-num() %d \n",n); };
};
class numere
{ public:
numr a,b,c;
numere(int x, int y, int z);
71
8

-numere();
};
numere::numere(int x, int y, int z) : c(z), a(x), b(y)
{ printf("A fost apelat un constructor \n"); }
numere::~numere {printf("A fost apelat un destructor\n"); }
void main ()
{numere bon(1, 2, 3);)
2. Introducei i lansai n execuie urmtorul program. Ce rezultat
se afieaz?
#include. <stdio.h>
class 0_clasa
{public:
o_clasa ()
{ printf("Apel constructor\n"); }:
~o_clasa() { printf("Apel destructor \n"); }
};
class alta_clasa2
( public:
alta_clasa *ac;
};
void main()
{ alta_clasa acc;}
3. Scriei un program n C echivalent cu urmtorul program C++.
Creai funcii n limbajul C echivalente constructorului i
destructorului i verificai apelul lor la momentul oportun.
#include <stdio.h>
class calculator
{ public:
float memorie;
calculator () ;
~calculator ();
float aduna (float f);
};
calculator::calculator ()
{ printf("S-a pornit calculatorul\n") ;
72

memorie=0 .0; }
calculator::~calculator(){printf("S-a oprit calculatorul\n");
}
float calculator::aduna (float f)
(memorie+=f; return memorie; }
void main ()
{calculator c;
c.aduna(lO.O); c.aduna(30.0); c.aduna(2.0);
printf ("Memoria este %f\n" ,c.memorie) ; }
4. Se va compila corect urmtoarea clas?
class num
{ public:
int data;
num(int i) { data=i; )
int set (int i) { return data=i; }
};
5. Descriei funciile de modificare a stringului (copiere, includere
a unui substring, concatenare i eliminare a unui substring)
pentru clasa:
class sir
{ private:
char continut[80];
int lungime;
public:
sir ();
char *contine() (return continut;}
};
Temele pentru lucrri de laborator:
1. S se scrie un program care s defineasc un nou tip de variabile
- tipul complex i s construiasc funcii adecvate pentru
operaiile de baz cu acest tip de date (adunare, scdere,
nmulire, calculul modulului numrului complex).
73

2. S se scrie un program care ar evalua o funcie, a crei expresie


analitic se introduce de la terminalul calculatorului ca un ir de
caractere.
3. S se scrie un program n care se definete o clas stiv
elementele creia snt de un tip abstract de date cu urmtoarele
funcii:
empty(Q) care cur stiva Q,
if_is_empty(Q) care verific dac stiva Q este vid,
in_query(Q,x) care adaug elementul x n stiva Q,
out_query(Q,x) care scoate elementul x din stiva Q,
error (k) care indic eroarea cu numrul k (k=1 dac stiva este
suprancrcat, k=2 dac stiva este vid).
4. Scriei un program care determin pentru o clas list simplu
lnuit cu urmtoarele funcii:
member(x,L) care determin apartenena elementului x listei L;
equal(L1,L2) care determin echivalena a dou liste L1 i L2;
print(L) care tiprete toate elementele listei L;
readlist(L,fin) care citete elementele din fiierul fin n lista L.
5. Scriei un program care determin o clas coad n care snt
determinate urmtoarele funcii:
empty(Q) care cur coada Q,
if_is_empty(Q) care verific dac coada Q este vid,
in_query(Q,x) care adaug elementul x n coada Q,
out_query(Q,x) care scoate elementul x din coada Q,
error (k) care indic eroarea cu numrul k (k=1 dac coada este
suprancrcat, k=2 dac coada este vid).
6. Scriei un program care la o singur trecere prin fiierul fin fr
utilizare a fiierelor suplimentare va tipri elementele fiierului
fin n urmtoarea ordine:
toate elementele mai mici ca valoarea a,
elementele din segmentul [a,b],
restul elementelor pstrnd aceeai ordine din fiierul fin. (a<b,
a i b snt cunoscute i snt de acelai tip ca i elementele
fiierului fin).
74

7. Scriei un program care determin o clas stiv n care snt


determinate urmtoarele funcii:
empty(S) care cur stiva S,
if_is_empty(S) care verific dac stiva S este vid,
pop(S,x) care adaug elementul x n stiva S,
push(S,x) care scoate elementul x din stiva S,
error (k) care indic eroarea cu numrul k (k=1 dac stiva este
suprancrcat, k=2 dac stiva este vid).
8. Scriei un program care efectueaz asupra elementelor fin fiierului de tip text - urmtoarele operaii:
tiprete inversat coninutul fiecrui cuvnt al liniei fiierului
fin,
sorteaz lexicografic att cuvintele din fiierul fin, ct i
cuvintele inversate,
determin cuvintele simetrice din fiierul fin.
9. Scriei un program care determin clasa arbore. Asupra
elementelor arborelui s se determine urmtoarele operaii:
repeat (A,x) care determin numrul de repetri ale elementului
x n arborele A,
media(A) care calculeaz media aritmetic a elementelor de tip
ntreg sau real. Dac elementele snt de alt tip, media (A) =0,
dac elementele arborelui A snt de tip ntreg sau real, valorile
negative ale elementelor se nlocuiesc cu valorile lor absolute,
dac elementele arborelui A snt de tip ntreg sau real valorile
maximale i minimale se schimb cu locurile,
dac elementele arborelui A snt de tip string, elementele de
lungime minimal se schimb cu locurile cu elementele de
lungime maximal.
10. Scriei un program care determin pentru o clas list dublu
lnuit urmtoarele funcii:
member(x, L) care determin apartenena elementului x listei
L,
equal(L1, L2) care determin echivalena a dou liste L1 i L2,
min_max(L, x, y) care determin elementele cu valoare minimal
x i cu valoare maximal y din lista L,
75

sum(L) care determin suma elementelor din lista L,


substract(L) care determin diferena elementelor din lista L,
multiply(L) care determin produsul elementelor din lista L,
sum(L,x,y) care determin suma elementelor din lista L n
intervalul elementelor cu valorile x i y, n caz contrar
sum(L,x,z)=0,
print(L) care tiprete toate elementele listei L,
readlist(L,fin) care creeaz lista L din elementele fiierului fin.
11. Scriei un program care efectueaz urmtoarelor operaii asupra
unitilor bneti (de exemplu, lei, bani):
adunarea,
nmulirea cu un coeficient,
scderea,
mprirea la un coeficient,
valoarea numeric a unitilor bneti s se tipreasc cu
cuvinte.
12. Scriei un program care efectueaz urmtoarele operaii asupra
numerelor fracionare:
transformarea unui numr fracionar compus ntr-o fracie
supraunitar,
adunarea numerelor fracionare,
nmulirea numerelor fracionare,
scderea numerelor fracionare,
mprirea numerelor fracionare.
13. Scriei un program care efectueaz urmtoarele operaii asupra
unitilor de lungime (de exemplu, metri, centimetri, milimetri):
adunarea,
nmulirea cu un coeficient,
scderea,
mprirea la un coeficient,
valoarea numeric a unitilor de lungime s se tipreasc cu
cuvinte.
14. Scriei un program care efectueaz urmtoarele operaii asupra
unitilor de greutate (de exemplu, tone, kilograme, grame):
adunarea,
76

nmulirea cu un coeficient,
scderea,
mprirea la un coeficient,
valoarea numeric a unitilor de greutate s se tipreasc cu
cuvinte.
15. Scriei un program care efectueaz urmtoarele operaii asupra
unitilor de timp (de exemplu, anul, luna, ziua, ceasul, minutul,
secunda):
adunarea,
nmulirea cu un coeficient,
scderea,
mprirea la un coeficient,
valoarea numeric a unitilor de timp s se tipreasc cu
cuvinte.

Lucrarea de laborator nr. 3


Tema: Clase derivate, funcii virtuale, suprancrcarea funciilor i
operatorilor.
Scopul lucrrii: familiarizarea studenilor cu noiunile de clase
derivate, funcii virtuale i redefinite, operatori suprancrcai,
obiecte
Consideraiile teoretice necesare:
Clase derivate.
Motenirea este o relaie ntre clase, caracterizat prin
trecerea atributelor de la o clas, de baz, la alta, derivat. Clasele
derivate posed toate caracteristicile clasei de baz. Ele pot fi
mbogite att structural, ct i funcional. Totodat se observ o
ierarhizare datorit faptului c exist posibilitatea ca o clas
derivat s aib mai multe clase de baz, ordinea importanei
77

nivelelor rmnnd aceeai.


Noiunea de derivare este o abstractizare a noiunii de
motenire. O clas care adaug proprieti noi la o clas deja
existent vom spune ca este derivata clasei de baz. Clasa derivat
motenete toate datele i funciile membri ale clasei de baz; ea
poate aduga noi date la cele existente i poate suprascrie sau
aduga funcii membri. Clasa de baz nu este afectat n nici un fel
n urma acestui proces de derivare i, ca urmare, nu trebuie
recompilat. Declaraia i codul obiect snt suficiente pentru
crearea clasei derivate, ceea ce permite reutilizarea i adaptarea
uoar a codului deja existent, chiar dac fiierul surs nu este
disponibil. Astfel, nu este necesar ca programatorul unei clase
derivate s cunoasc modul de implementare a funciilor membri
din componenta clasei de baz.
n funcie de necesiti, derivarea claselor va fi un proces cu
durat variabil. n acest sens, se prefer conceperea unor clase de
baz simple, n locul unora dezvoltate.
Dintr-o clas de baz pot fi derivate mai multe clase i
fiecare clas derivat poate servi mai departe ca baz pentru alte
clase derivate. Se poate astfel realiza o ierarhie de clase, care s
modeleze adecvat sisteme complexe. Pornind de la clase simple i
generale, fiecare nivel al ierarhiei acumuleaz caracteristicile
claselor "printe" i le adaug un anumit grad de specializare. O
clas poate s moteneasc simultan proprietile mai multor clase,
procedur numit motenire multipl. Construirea ierarhiei de clase
reprezint activitatea fundamental n realizarea unei aplicaii
orientate obiect. Sintaxa simplificat a derivrii este:
class NumeClasDerivat : NumeClasaDeBaz
n continuare vom deriva din clasa Point o clas specializat,
GraphicPoint, care va "ti" s deseneze punctul pe ecran:
class GraphicPoint : public Point
{unsigned color;
GraphicPoint(unsigned X, unsigned Y, unsigned Color);
~GraphicPoint();
void Draw();
78

void SetX(unsigned X);


void SetY(unsigned Y);
};
GraphicPoint::GraphicPoint(unsigned X, unsigned Y,
unsigned Color) : Point(X, Y) {color = Color; }
GraphicPoint::~GraphicPoint() {}
GraphicPoint::Draw()
{
// apelarea funciilor grafice pentru desenarea punctului
}
GraphicPoint::SetX(unsignedX)
{Point::SetX(); // funcia SetX() este membru a clasei de baz
Draw();
}
GraphicPoint::SetY(unsigned Y)
{Point::SetY();
Draw();
}
n exemplul de mai sus s-a adugat o variabil nou fa de
clasa Point, color, pentru a putea memora culoarea cu care se face
desenarea punctului. De asemenea, s-a suprascris constructorul i
destructorul clasei printe. n constructorul derivat s-a apelat
constructorul original folosind construcia:
ClasaDerivat::ClasaDerivat() : ClasaDeBaz()
n clasa GraphicPoint s-a adugat o funcie membru nou,
Draw(), care deseneaz punctul pe ecran. Am suprascris funciile
SetX() i SetY(), apelnd n ambele funciile originale, utiliznd
sintaxa:
ClasaDeBaz::FuncieMembru()
apelnd apoi funcie de desenare, Draw().
Regulile de funcionare ale constructorilor i destructorilor,
descrise n lucrarea de laborator nr. 2, rmn valabile i n cazul
claselor derivate, inndu-se cont de urmtoarele observaii privind
ordinea de apelare a acestora:
79

la instanierea clasei derivate, se apeleaz mai nti constructorul


clasei de baz, apoi se apeleaz propriul constructor.
la distrugerea unui obiect al unei clase derivate, este apelat mai
nti propriul destructor, i apoi destructorul clasei de baz (n
ordine invers crerii obiectului).
Controlul accesului la clase
Limbajul C++ permite controlul accesului la membrii
claselor. n acest scop s-au creat trei specificatori de control al
accesului:
public, membrul poate fi accesat de orice funcie din domeniul
declaraiei clasei;
private, membrul este accesibil numai funciilor membri i
prietene ale clasei;
protected, similar cu private, ns accesul se extinde i la
funciile membri i prietene ale claselor derivate.
O funcie membru a unei clase are acces la toi membrii
clasei, indiferent de specificatorul de acces.
Aa dar, sintaxa declaraiei unei clase derivate, incluznd
controlul accesului, este:
class NumeClasDerivat : SpecificatorAcces
NumeClasaDeBaz
unde SpecificatorAcces poate fi public sau private.
Accesul
Atributul din Modificator
Accesul din
motenit de clasa
clasa de baz de acces
exterior
derivat
private
private
inaccesibil
inaccesibil
protected
private
private
inaccesibil
public
private
private
inaccesibil
private
public
inaccesibil
inaccesibil
protected
public
protected
inaccesibil
public
public
public
accesibil
Pentru a oferi clasei derivate acces la un membru al clasei de
baz, acesta trebuie declarat protected sau public. Elementele
declarate cu specificatorul public n clasa de baz snt accesibile
elementelor n clasa derivat. Elementele declarate cu
80

specificatorul private sau protected n clasa de baz nu snt


accesibile n mod direct elementelor din clasa derivat, ele pot fi
accesate doar prin unele funcii declarate special (care returneaz
valorile elementelor din clasa de baz descrise cu specificatorul
private sau protected). Pentru respectarea principiului incapsulrii
datelor, datele membri pentru care se ofer acces claselor derivate
se declar n clasa de baz cu atributul protected. De asemenea,
pentru a conserva dreptul de acces n urma derivrii, se utilizeaz
derivarea public. Accesul poate fi stopat pe orice nivel al ierarhiei
de clase printr-o derivare cu specificatorul de acces private.
Stabilirea atributelor de acces ale membrilor unei clase,
precum i ale derivrilor, dezvoltarea ierarhiei de clase, trebuie s
se fac astfel ca s nu afecteze incapsularea datelor.
S cercetm exemplul urmtor, completat cu specificatori de
acces:
class Point
{ protected:
unsigned x, y;
public: Point();
Point(unsigned X, unsigned Y);
~Point();
unsigned long Arie();
unsigned GetX();
unsigned GetY();
void SetX(unsigned X);
void SetY(unsigned Y);
};
class GraphicPoint : public Point
{unsigned color;
public: GraphicPoint(unsigned X, unsigned Y, unsigned
Color);
~GraphicPoint();
void Draw();
void SetX(unsigned X);
81

void SetY(unsigned Y);


};
Variabilele membri x i y snt declarate protected, aa nct
vor fi vizibile i vor avea acelai atribut n clasa GraphicPoint
(dei nu snt utilizate). n mod normal, x i y ar trebui sa fie
declarai private, ntruct nu snt utilizai dect n interiorul clasei
Point. Funciile din GraphicPoint nu acceseaz aceti doi membri
direct, ci prin intermediul metodelor publice de accesare a lor
oferite de clasa Point.
Implicit, dac nu este utilizat nici un specificator de acces,
membrii snt considerai private.
void main()
{Point *p;
p = new Point;
p->x = 5; // operaie imposibil: x este membru privat
p->y = 8; // operaie imposibil: y este membru privat
p->SetX(5); // corect: acces la variabila x prin intermediul
//funciei SetX()
p->SetY(8); // corect: acces la variabila x prin intermediul
//funciei SetY()
printf("Aria = %d\n", p->Aria());
delete p;
}
Deci din exteriorul unei clase nu pot fi accesate datele membri
private sau protected.
Atunci cnd funciile unei clase de baz snt rescrise ntruna derivat, spunem c aceste clase snt polimorfe, vom avea o
singur denumire i mai multe aciuni, adic, o singur interfa cu
metode multiple. Aceast noiune legat de derivare este cea de
suprancrcare sau suprascriere a funciilor membri. Ea se refer la
redefinirea unor funcii a clasei de baz n clasa derivat. Funciile
din clasa printe snt n continuare accesibile n clasa derivat.
S vedem cum arat obiectele polimorfe. Pentru aceasta,
determinm clasele de baz Punct i cea derivat Cerc i funcia
82

membru Aria(), ce va avea ca efect determinarea ariei obiectului


respectiv:
#include <stdio.h>
class Punct
{ float x,y;
public:
void Incarc_punct(float xi,float yi) {x=xi;y=yi;};
virtual float Aria() { return 0.0; };
};
const float pi=3.14159;
class Cerc : public Punct
{float raza;
public: void Incarc_raza (float r) { raza=r; }
float Aria(){ return pi*raza*raza; } ; // funcie redefinit
};
void main()
{ Punct p;
float a=p.Aria();
printf("Aria unui punct este: %5.2f\n",a);
Cerc c;
c.Incarc_raza(3.65637);
a=c.Aria();
printf("Aria cercului este: %5.2f\n",a);
}
Rezultatul ndeplinirii programului:
Aria unui punct este: 0.00
Aria cercului este: 42.00
Clasa Cerc este derivat de la clasa Punct. Cerc i Punct snt
obiecte din aceeai categorie, snt polimorfe. Pentru a obine
obiecte polimorfe, va trebui s construim o ierarhie de clase i apoi
s redefinim funciile, aparinnd clasei de baz n clasele derivate.
Aceast operaie poate fi realizat n dou moduri:
rescriind funciile respective, efectund, deci o nou
implementare a acestora,
utiliznd funciile virtuale.
83

S vedem cum are loc rescrierea funciilor. Este evident c


funcia membru Aria() a clasei Punct este motenit de clasa Cerc,
dar nu convine din punctul de vedere al valorii returnate. Astfel, s-a
impus reimplementarea acesteia.
Punct *p;
Cerc c;
p=&c;
float aria=p->Aria ();
n instruciunea n care este apelat funcia Aria() este apelat
funcia Cerc::Aria(), p indic spre obiectul c de tipul Cerc.
Ataarea codului unei funcii la numele su poate fi efectuat
static sau dinamic. Acest proces poart denumirea de identificare a
funciilor, existnd, deci dou metode de identificare: static i
dinamic.
Identificarea static are loc la un apel normal de funcie.
Compilatorul preia numele funciei, argumentele sale i, n cazul n
care aceasta este membru, numele clasei obiectului.
Identificarea dinamic se va realiza n momentul execuiei,
funcia nefiind identificat. Cum? O posibilitate ar fi de a utiliza
pointeri la funcii, astfel, c doar n momentul rulrii vom ti
funcia, spre care a indicat acel pointer. Vom defini un pointer n
interiorul clasei Punct, ce va indica spre funcia Aria().
Reinem c acest pointer va fi motenit de ctre Cerc. Dup
crearea unui obiect de tip Punct sau Cerc, vom iniializa pointerul
spre funcia corect.
O a doua posibilitate este aceea de a utiliza funciile virtuale.
Funciile virtuale snt utilizate pentru reimplementarea unor
funcii membri ale unor clase de baz, astfel, nct aceast
redefinire de funcii s funcioneze n ambele situaii.
const float pi=3.14159;
class Cilindru : public Cerc
{ float inaltime;
public:
void Incarca_ inaltime(int h) {inaltime =h;};
float Aria() ; };
84

float Cilindru::Aria()
{return 2*pi*raza*inaltime +2 *Cerc::Aria(); }
n implementarea noii versiuni a funciei membri Cilindru::Aria()
se utilizeaz versiunea anterioar motenit de la clasa de baz
Punct.
Evident c Punct::Aria() nu va modifica rezultatul furnizat, aportul
su la aceasta fiind nul, dar se sugereaz c este permis apelarea
funciilor motenite pentru oricare nivel al ierarhiei, innd cont de
nivelurile de protecie ( private, protected i public).
n procesul de lucru cu clase derivate putem foarte uor
grei, transformnd o funcie virtual n funcie redefinit datorit
faptului c cele dou categorii se aseamn. Totui, exist cteva
diferene dintre aceste dou categorii de funcii:
funciile membri redefinite snt ataate obiectului, urmnd
procedura static (la compilare), n timp ce funciile virtuale fac
parte din cea de a doua categorie, legturile cu obiectele fiind
realizate dinamic (n timpul execuiei);
funciile membri redefinite pot avea liste diferite de parametri,
n timp ce funciile virtuale trebuie s posede aceeai list de
parametri.
Dac, n cadrul ierarhiei de clase, funciile nu se comport
exact cum vrem noi, va trebui s verificm toate funciile virtuale,
pentru a ne asigura c, ntr-adevr, snt virtuale i nu redefinite.
# include <stdio.h>
class scade
{public:
virtual int executa (unsigned char c) { return --c; };
};
class aduna : public scade
{ public:
int executa ( char c) { return ++c;
};
};
void main()
{scade *p=new aduna;
85

int k=p->executa(43);
printf(k = %d \n,k);
}
Rezultatul ndeplinirii programului:
k = 42
n acest exemplu programul va afia rspunsul 42.
Versiunea clasei scade accept un argument unsigned char, iar
versiunea clasei aduna un argument de tip char. Datorit acestei
schimb de tip, a doua versiune a funciei executa() nu este virtual,
ea este redefinit. Chiar dac prin intermediul lui p acionm asupra
unui obiect aduna, apelnd funcia executa(), ne referim la
versiunea scade. Deci programul va afia valoarea 42.
O funcie operator are aceleai componente pe care le are
orice funcie, include un nume, un tip returnat, argumente, corp i,
eventual, apartenena la o clas. Exist trei elemente care trebuie
stabilite la declararea operatorului, i anume, este operator unar sau
binar, este postfixat sau prefixat ca poziie i este funcie membru
sau nu domeniu de aciune.
Funciile operator membri vor avea cu un argument mai
puin dect cele non-membri. Apelul unui astfel de operator
membru va fi
p+=5;
sau
p. operator+=(5);
Redefinirea operatorilor
Limbajul C++ permite programatorilor s defineasc
operatori pentru a lucra cu propriile clase. Sintaxa suprancrcrii
unui operator este:
operator Simbol
unde Simbol este simbolul oricrui operator C++, exceptnd: . *adresare la componenta prin pointer, ::- operatorul de rezoluie, ()
?:- operatorul condiional, operatorul sizeof, etc.. Aceast definire
86

se face n cadrul clasei, ntocmai ca o funcie membru (vezi


Tabelul 1.)
Exist dou variante de definire a operatorilor:
ca funcie membru a clasei;
ca funcie prieten a clasei.
Tabelul 1.
Tipul
Simbolul
Asociativitate Observaii
operatorului operatorului
Se definesc ca
Binar
() [] ->
->
funcii membri
Unar
+ - ~ * & (tip)
<Nu se poate disUnar
++ -<tinge ntre pre- i
postfixare
Poate fi supraUnar
new, delete
<definit i pentru o
clas
-> * / % + - & |
Binar
->
&& ||
<< >> < <= >
Binar
->
>= == !=
= += -= *= /=
Se definesc ca
Binar
%= &= ^= |=
<funcii membri
<<= >>=
Binar
,
->
Pentru exemplificare, vom extinde clasa Point cu utilizarea
unor operatori.
class Point
{// ...
Point& operator += (Point p);
Point& operator -= (Point p);
Point operator + (Point p);
Point operator - (Point p);
Point& operator = (Point p);
int operator == (Point p);
87

int operator != (Point p);


int operator < (Point p);
int operator > (Point p);
int operator <= (Point p);
int operator >= (Point p);
};
Point& Point::operator += (Point p)
{x += p.x; y += p.y; return *this;}
Point& Point::operator -= (Point p)
{x -= p.x; y -= p.y; return *this;}
Point Point::operator + (Point p)
{return Point(x + p.x, y + p.y);}
Point Point::operator - (Point p)
{return Point(x -p.x, y -p.y);}
int Point::operator == (Point p)
{return x == p.x && y == p.y;}
int Point::operator != (Point p)
{return !(*this == p);}
int Point::operator < (Point p)
{return x < p.x && y < p.y;}
int Point::operator > (Point p)
{return x > p.x && y > p.y;}
int Point::operator <= (Point p)
{return x <= p.x && y <= p.y;}
int Point::operator >= (Point p)
{return x >=p.x && y >= p.y;}
Am utilizat mai sus varianta cu funcii membri. Vom descrie
implementarea operatorului + folosind cea de-a doua variant.
class Point {
// ...
friend Point operator + (Point p1, Point p2);
};
Point operator + (Point p1, Point p2)
{return Point(p1.x + p2.x, p1.y + p2.y);}
88

Definirea operatorilor ca funcii membri a unei clase prezint


o restricie major: primul operand este obligatoriu s fie de tipul
clasa respectiv.
n limbajul C++ supradefinirea operatorilor este supus unui
set de restricii:
nu este permis introducerea de noi simboluri de operatori;
patru operatori nu pot fi redefinii (vezi mai sus);
caracteristicile operatorilor nu pot fi schimbate: pluralitatea (nu
se poate supradefini un operator unar ca operator binar sau
invers), precedena i asociativitatea, prioritatea lor;
funcia operator trebuie sa aib cel puin un parametru de tipul
clasa cruia i este asociat operatorul supradefinit.
Programatorul are libertatea de a alege natura operaiei
realizate de un operator, ns este recomandat ca noua operaie s
fie apropiat de semnificaia iniial.
Redefinirea operatorului +=. Aciunea acestuia este aceea de
a aduga o valoare unui numr de tip char, int, float sau double.
Putem redefini acest operator, pentru a opera asupra obiectelor, de
exemplu, de tip persoana.
# include <stdio.h>
# include <string.h>
class persoana
{ private:
char nume[40];
long int telefon;
int virsta;
public:
persoana () {strcpy(nume,'\0');telefon=0; virsta=0;};
persoana(long int Telefon) { telefon= Telefon; };
persoana(char *Nume) { strcpy(nume,Nume); };
persoana(int Virsta) { virsta= Virsta; };
persoana(char *n, long l) { strcpy(nume,n);telefon=l; };
void Citeste(char *n,long t=0,int v=0)
{ strcpy(nume,n); telefon=t; virsta=v;};
void Tipar(persoana s)
89

{printf("\n nume %s, telefon %ld, virsta %d ",s.nume,


s.telefon, s.virsta);};
int Seteaza_Virsta(int v) { return(virsta=v); };
};
void main()
{ persoana p;
p.Citeste("Cristina",234567,p.Seteaza_Virsta(20));
p.Tipar(p);
}
Rezultatul ndeplinirii programului:
nume Cristina, telefon 234567, virsta 20
Pentru aceasta, vom defini o funcie avnd numele operator
+=() cu doi parametri. Aceti parametri snt cei doi operanzi ai
operatorului +=.
void operator +=(persoana &p, int v)
{ p.Seteaza_Virsta(p.Virsta()+v); }
Utilizarea operatorului definit se realizeaz prin iniializarea
persoana p('Mircea" , 0 , 9) ;
i apelul
p+=5;
sau apelndu-l ca funcie
operator+=(p,5);
Bineneles, funcia operator poate fi membru a clasei asupra creia
acioneaz
class persoana
{ public:
void operator+=(int v);
};
void persoana::operator+=(int v)
{Seteaza_Varsta(varsta+v); }
Redefinirea operatorului =. Operatorul = este deja predefinit
n C++, pentru operanzi de tip clas. Dac nu este supradefinit,
atribuirea se face membru cu membru n mod similar cu
iniializarea obiectului efectuat de ctre compilator. n caz de o
atribuire specific a clasei, operatorul = poate fi supradefinit.
Point& Point::operator = (Point p)
90

{x = p.x; y =p.y; return *this;}


Redefinirea operatorului [].Operatorul de indexare [] se
definete astfel:
int &operator[](int)
De exemplu
Point Array_Point::operator []= (Point *p, int j) {return
p[j];}
Redefinirea operatorilor new i delete poate fi efectuat
pentru a realiza operaii specializate de alocare/eliberare dinamic a
memoriei. Funcia operator new trebuie sa primeasc un argument
de tipul size_t care s precizeze dimensiunea n octei a obiectului
alocat i s returneze un pointer de tip void coninnd adresa zonei
alocate:
void *operator new(size_t)
cu meniunea c size_t este definit n stdlib.h. Chiar dac
parametrul de tip size_t este obligatoriu, calculul dimensiunii
obiectului n cauz i generarea sa se face de ctre compilator.
Funcia operator delete trebuie sa primeasc ca prim
parametru un pointer de tipul clasei n cauz sau void, coninnd
adresa obiectului de distrus, i un al doilea parametru opional de
tip size_t. Funcia nu ntoarce nici un rezultat.
void operator delete(void *, size_t)
Operatorii new i delete supradefinii pstreaz toate
proprietile operatorilor new i delete standard.
Redefinirea operatorilor unari poate fi efectuat utiliznd o
funcie membru fr parametri sau o funcie prieten cu un
parametru de tipul clasei respective. Pentru operatorii ++ i -dispare distincia ntre utilizarea ca prefix i cea ca postfix, de
exemplu, intre x++ i ++x, respectiv, x-- i x.
De exemplu:
Point Point::operator++ ()
{x++; y++; return *this;}
Conversii de tip definite de programator. n limbajul C++
este definit un set de reguli de conversie pentru tipurile de baz de
date. C++ permite definirea de reguli de conversie pentru clasele
91

create de programator. Regulile astfel definite snt supuse unor


restricii:
ntr-un ir de conversii nu este admis dect o singur conversie
definit de programator;
se recurge la aceste conversii numai dup ce se verific existena
altor soluii (de exemplu, pentru o atribuire, se verific mai nti
suprancrcarea operatorului de atribuire i n lipsa acestuia se
face conversia).
Exista dou metode de a realiza conversii de tip.
Suprancrcarea operatorului unar "cast". Sintaxa este:
operator TipData()
respectiv:
operator (TipData)
Operatorul "cast" este unar, aadar, are un singur parametru,
adresa obiectului n cauz, i ntoarce un rezultat de tipul
operatorului. Ca urmare, prin aceast metod se pot defini numai
conversii dintr-un tip clas ntr-un tip de baz sau un alt tip clas.
n cazul conversiei dintr-un tip clas ntr-un alt tip clas,
funcia operator trebuie s aib acces la datele membri ale clasei
de la care se face conversia, deci trebuie declarat prieten a clasei
respective.
Conversiile de tip folosind constructori const n definirea
unui constructor ce primete ca parametru tipul de la care se face
conversia. Constructorul ntoarce ntotdeauna ca rezultat un obiect
de tipul clasei de care aparine, ca urmare, folosind aceast metod
se pot realiza numai conversii dintr-un tip de baz sau un tip clas
ntr-un tip clas.
n cazul conversiei dintr-un tip clas ntr-un alt tip clas,
constructorul trebuie s aib acces la datele membri ale clasei de la
care se face conversia, deci trebuie declarat prieten a clasei
respective.
Constructorul de copiere. O situaie care poate aprea
deseori este iniializarea unui obiect cu datele membri ale unui
obiect de acelai tip. Exista totui situaii n care operatorul de
atribuire nu poate fi utilizat, de exemplu, la transferul unui obiect
ca parametru sau la crearea unei instane temporare a unei clase,
92

cnd copierea membru cu membru nu este adecvat. Pentru a


rezolva aceste situaii, n limbajul C++ a fost introdus un
constructor special, numit constructorul de copiere. Sintaxa este:
NumeClas::NumeClas (NumeClas &NumeObiectSurs)
n continuare vom completa clasa Point cu un constructor de
copiere:
Point::Point(Point &p)
{p.x = x;
p.y = y;}
n cazul n care clasa nu dispune de constructor de copiere,
compilatorul genereaz automat un constructor de copiere care
realizeaz copierea membru cu membru.
Clase abstracte. n limbajul C++ exist posibilitatea de a
defini clase generale, care snt destinate crerii de noi clase prin
derivare. Ele nu pot fi instaniate i utilizate ca atare. Acest gen de
clase se numesc clase abstracte. Ele se constituie ca baz n cadrul
elaborrii de ierarhii de clase, putnd fi folosite, de exemplu, pentru
a impune anumite restricii n realizarea claselor derivate.
n vederea construirii unor astfel de clase, s-a introdus
conceptul de funcie virtual pur. O astfel de funcie este declarat
n cadrul clasei, dar nu este definit. O clas care conine o funcie
virtual pur este considerat abstract. Sintaxa definirii acestor
funcii este:
virtual TipData NumeFunctieMembru() = 0
Funciile virtuale pure trebuie definite n clasele derivate,
altfel i acestea vor fi considerate abstracte.
Membrii statici ai unei clase. n mod normal, datele membri
ale unei clase snt alocate n cadrul fiecrui obiect. n C++, se pot
defini date membri cu o comportare special, numite date statice.
Acestea snt alocate o singur dat, existnd sub forma unei singuri
copii, comun tuturor obiectelor de tipul clasei respective, iar
crearea, iniializarea i accesul la aceste date snt independente de
obiectele clasei. Sintaxa este:
static DeclarareMembru
93

Funciile membri statice efectueaz, de asemenea, operaii care nu


snt asociate obiectelor individuale, ci ntregii clase. Funciile
exterioare clasei pot accesa membrii statici ale acesteia astfel:
NumeClas::NumeMembru
Obiect::NumeMembru
Funciile membri statice nu primesc ca parametru implicit
adresa unui obiect, aadar, n cadrul lor cuvntul-cheie this nu poate
fi utilizat. De asemenea, membrii normali ai clasei nu pot fi referii
dect specificnd numele unui obiect.
ntrebrile pentru verificarea cunotinelor:
1. Care dintre instruciunile de mai jos snt legale?
a: class sir
{private:
static char eos;
char *continut;
int dimensiune;
public:
sir(int sz);
void copy(sir &s);
};
b: char sir::eos=Ox1A;
void sir::copy(sir 63)
delete continut;
continut = new char[3.dimensiune];
char *p=continut;
char *q=s.continut;
while <*qt=eos)
c: *p++=*q++;
*p=eos;
void main()
{sir s(80);}
d: sir::eos=0;
e: s.eos='$';
2. Dup cum tim, atunci cnd redefinim funcii, listele de
94

argumente trebuie s difere de la implementare la


implementare. De ce acest lucru nu se impune atunci cnd
redefinim funcia Aria() din cadrul claselor Punct i Cerc?
3. Dac redefinim operatorul+ ataat clasei persoana i facem
aceast funcie membri, cte argumente explicite va avea
aceasta?
4. Scriei o funcie operator membru a clasei persoana pentru a
rescrie operatorul ==. Exist mai multe variante ale acestei
funcii?
Temele pentru acas:
1. Ce va afia programul urmtor?
#include<iostream.h>
class Bunic
{ public :
virtual void sfat()
{
cout<< Distreaz-te;
}
};
class Tata : public Bunic
{ public:
void sfat()
{ cout "F-i leciile'\n"; }
}
class Fiu : public Tata
{ public:
void sfat()
{ Bunic::sfat(); }
};
void main()
( Fiu lon;
lon.sfat(); }
2. Ce se va afia la ecran dup executarea programului urmtor?
#include <iostream.h>
95
108

class Mesaje_bune
{ public:
virtual void act1()
{
cout"Prinul vede prinesa\n"; act2(); }
void act2()
{
cout"Prinul o srut\n"; act3();
}
virtual void act3()
{
cout"Prinesa se trezete\n"; act4();
}
virtual void act4 ()
{
cout"Si au trit fericii . . . \n" ; act5();
)
void act5()
{
cout "Sfrit '\n";
}
};
class Mesaje rele : public Mesaje bune
{ public:
void act3()
{
cout"Prinesa rmne eapn\n" ;act4 () ;
}
void act4()
{
cout"Prinul fuge ngrozit\n";act5();
}
void act5()
{
cout"Un sfrit, nefericit' \n" ;
}
};
void main ()
{
char c;
Mesaje bune *mes;
cout"Care variant doriii s vedei (L/B) ?\n" ;
cinc;
if (p=='L') | | (c=='l)) mes=new Mesaje_bune;
else mes=new Mesaje rele;
mes->act1();
delete mes;}
Temele pentru lucrri de laborator:
1. Scriei un program care ar defini clasa de baz num. n aceast
clas determinai un numr ntreg i funcia shownum(). Creai
96

dou clase derivate outhex i outoct care motenesc num.


Funcia shownum() se va redefini n clasele derivate astfel ca ea
s afieze la display respectiv, valorile din sistemele de
numeraie hexazecimal i octal, s se efectueze toate operaiile
aritmetice asupra numerelor din aceste sisteme de numeraie.
2. Scriei un program care care ar defini clasa de baz num. n
aceast clas determinai un numr ntreg i funcia shownum().
Creai clasa derivat outbin care motenete num. Funcia
shownum() se va redefini n clasa derivat astfel ca ea s afieze
la display valorile din sistemul de numeraie binar, s se
efectueze toate operaiile aritmetice i logice asupra numerelor
binare.
3. Scriei un program care definete clasa de baz distance pentru a
pstra n variabila de tipul double distana dintre dou puncte. n
clasa distance s se creeze funcia virtual trav_time(), care
afieaz valoarea timpului necesar pentru a parcurge distana
msurat n mile, viteza fiind de 60 mile/or. n clasa derivat
metric se va redefini funcia trav_time(), astfel ca ea s afieze
timpul necesar pentru parcurgerea distanei msurat n
kilometri, viteza fiind de 100 km/or.
4. Scriei un program care ar defini clasa de baz vector. n aceast
clas determinai un vector de numere ntregi i funcia
showvector(). Creai clasa derivat array care motenete vector.
Funcia showvector() se va redefini n clasa derivat, astfel ca ea
s afieze la display valorile tabloului pe linii i pe coloane. S
se calculeze suma elementelor tabloului, s se efectueze
operaiile algebrice asupra a dou tablouri (adunarea, scderea,
nmulirea).
5. Scriei un program care ar defini clasa de baz punct. n aceast
clas determinai un punct n plan i funcia showpoint(). Creai
clasa derivat poligon care motenete punct. Funcia
showpoint() se va redefini n clasa derivat, astfel ca ea s
afieze la display punctele cu coordonatele date. S se determine
poziia punctului fa de celelalte puncte din poligon, s se
determine distana minim de la punctul dat pn la primul punct
97

ce aparine poligonului.
6. Scriei un program care ar defini clasa de baz string. n aceast
clas determinai funcia showstring(). Creai clasa derivat
newstring care motenete string. Funcia showstring() se va
redefini n clasa derivat, astfel ca ea s afieze la display
simbolurile prin codurile lor interioare. S se efectueze
urmtoarele operaii asupra codurilor:
s se determine spaiul pentru stringul dat,
s se compare dou stringuri,
s se extrag un substring din stringul dat,
s se lichideze un substring din stringul dat din poziia dat,
s se inverseze un string dat.
s se caute un substring din stringul dat.
7. Scriei un program care ar defini clasa de baz bit. n aceast
clas determinai valorile logice true i false i funcia
showbit(). Creai clasa derivat outbit care motenete bit.
Funcia showbit() se va redefini n clasa derivat, astfel ca ea s
afieze la display valorile unui ir de bii. S se efectueze
urmtoarele operaii asupra irului de bii:
s se determine lungimea irului de bii, s se determine spaiul
pentru irul de bii dat,
s se compare dou iruri de bii,
s se extrag un subir de bii din irul de bii dat,
s se lichideze un subir de bii din irul de bii dat din poziia
dat,
s se inverseze un ir de bii dat,
s se caute un subir de bii din irul de bii dat.
8. Scriei un program care ar defini clasa de baz set_bit. n aceast
clas determinai funcia showset_bit(). Creai clasa derivat
mulime care motenete set_bit. Funcia showset_bit() se va
redefini n clasa derivat, astfel ca ea s afieze la display
valorile unei mulimi. S se efectueze urmtoarele operaii
asupra mulimii:
s se determine numrul de elemente a mulimii
s se determine spaiul pentru mulimea dat,
98

9.

s se compare dou mulimi,


s se extrag o submulime din mulimea dat,
s se adauge un nou element la mulime,
s se tearg un element din mulime,
s se caute o submulime din mulimea dat.
Scriei un program care ar defini clasa de baz int. n aceast
clas determinai valorile ntregi i funcia showint(). Creai
clasa derivat longint care motenete int. Funcia showint() se
va redefini n clasa derivat, astfel ca ea s afieze la display
valorile unui numr de tip longint..S se efectueze urmtoarele
operaii asupra tipului longint:
s se determine numrul de cifre din numrul dat,
s se compare dou numere longint,
s se extrag numerele de tip int din numrul longint (partea
inferioar i partea superioar),
s se efectueze operaiile algebrice asupra numerelor date,
s se inverseze un numr de tip longint (partea inferioar cu cea
superioar).
10. Scriei un program care ar defini clasa de baz real. n aceast
clas determinai valorile reale i funcia showreal(). Creai
clasa derivat double care motenete real. Funcia showreal()
se va redefini n clasa derivat, astfel ca ea s afieze la display
valorile unui numr de tip double. S se efectueze urmtoarele
operaii asupra tipului double:
s se determine numrul de cifre din partea ntreag a
numrului dat,
s se determine numrul de cifre din partea fracionar a
numrului dat,
s se compare dou numere double,
s se transforme numrul dat ntr-un ir de caractere,
s se efectueze operaiile algebrice asupra numerelor date.
11. Scriei un program care ar defini clasa de baz int n sistemul de
numeraie p. n aceast clas determinai valorile ntregi i
funcia showint(). Creai clasa derivat longint n sistemul de
numeraie p care motenete int. Funcia showint() se va
99

redefini n clasa derivat, astfel ca ea s afieze la display


valorile unui numr de tip int. n sistemul de numeraie p. S se
efectueze urmtoarele operaii asupra tipului longint n
sistemul de numeraie p:
s se determine numrul de cifre din numrul dat,
s se compare dou numere longint,
s se extrag numerele de tip int din numrul longint (partea
inferioar i partea superioar),
s se efectueze operaiile algebrice asupra numerelor date,
s se inverseze un numr de tip longint (partea inferioar cu cea
superioar).
12. Scriei un program care ar defini clasa de baz real n sistemul
de numeraie p. n aceast clas determinai valorile reale n
sistemul de numeraie p i funcia showreal(). Creai clasa
derivat double n sistemul de numeraie p care motenete
real n sistemul de numeraie p. Funcia showdouble() se va
redefini n clasa derivat, astfel ca ea s afieze la display
valorile unui numr de tip double n sistemul de numeraie. S
se efectueze urmtoarele operaii asupra tipului double n
sistemul de numeraie p:
s se determine numrul de cifre din partea ntreag a
numrului dat,
s se determine numrul de cifre din partea fracionar a
numrului dat,
s se compare dou numere double,
s se transforme numrul dat ntr-un ir de caractere,
s se efectueze operaiile algebrice asupra numerelor date.
13. Scriei un program care ar defini clasa de baz int. n aceast
clas determinai valorile ntregi i funcia showint(). Creai
clasa derivat fraction care motenete int. Funcia
showfraction() se va redefini n clasa derivat, astfel ca ea s
afieze la display valorile unui numr fracionar. S se
efectueze urmtoarele operaii asupra numerelor fracionare:
transformarea unui numr fracionar mixt ntr-o fracie
supraunitar,
100

adunarea numerelor fracionare,


nmulirea numerelor fracionare,
scderea numerelor fracionare,
mprirea numerelor fracionare.
14. Scriei un program care ar defini clasa de baz list. n aceast
clas determinai valorile ntregi ale listei i funcia showlist().
Creai clasa derivat stiva care motenete list. Funcia
showlist() se va redefini n clasa derivat, astfel ca ea s afieze
la display valorile unei stive. S se efectueze urmtoarele
operaii asupra stivei:
empty(S) care cur stiva S,
if_is_empty(S) care verific dac stiva S este vid,
pop(S,x) care adaug elementul x n stiva S,
push(S,x) care scoate elementul x din stiva S,
error (k) care indic eroarea cu numrul k (k=1 dac stiva este
suprancrcat, k=2 dac stiva este vid).
15. Scriei un program care ar defini clasa de baz int. n aceast
clas determinai valorile ntregi i funcia showdate(). Creai
clasa derivat date care motenete int. Funcia showdate() se va
redefini n clasa derivat, astfel ca ea s afieze la display
valorile unei date. S se efectueze urmtoarele operaii asupra
datei:
adunarea,
nmulirea cu un coeficient,
scderea,
mprirea la un coeficient,
valoarea datei calendaristice s se tipreasc cu cuvinte.

101

Lucrarea de laborator nr. 4.


Tema: Clase derivate cu motenire multipl.
Scopul lucrrii: familiarizarea studenilor cu clasele derivate cu
motenire multipl.
Consideraiile teoretice necesare:
Motenirea multipl
Limbajul C++ permite crearea de clase care motenesc
proprietile mai multor clase de baz. Dintr-o clas de baz pot fi
derivate mai multe clase i fiecare clas derivat poate servi mai
departe ca baz pentru alte clase derivate. Se poate astfel realiza o
ierarhie de clase, care s modeleze adecvat sisteme complexe.
Pornind de la clase simple i generale, fiecare nivel al ierarhiei
acumuleaz caracteristicile claselor "printe" i le adaug un
anumit grad de specializare. O clas poate s moteneasc simultan
proprietile mai multor clase, procedur numit motenire
multipl. Construirea ierarhiei de clase reprezint activitatea
fundamental de realizare a unei aplicaii orientate obiect.
Motenirea multipl permite formarea unei ierarhiei de
clase. Dac derivarea normal duce la construirea unei ierarhii de
tip arbore, derivarea multipl va genera ierarhii de tip graf. Sintaxa
complet pentru operaia de derivare este urmtoarea:
class NumeClasDerivat : ListaClaseDeBaz
unde ListaClaseDeBaz este:
SpecificatorAcces NumeClasaDeBaz, ...
Clase virtuale. Utilizarea motenirii multiple se poate
complica odat cu creterea dimensiunii ierarhiei de clase. O
situaie care poate apare este derivarea din dou clase de baz,
Clasa1 i Clasa2, care la rndul lor snt derivate dintr-o clas
comun, ClasaDeBaz. n acest caz, noua clas, ClasaNou, va
conine datele membri ale clasei ClasaDeBaz duplicate. Dac
prezena acestor date duplicate este util, ele pot fi distinse evident
cu ajutorul operatorului de rezoluie, ::. Totui, n cele mai multe
cazuri, aceast duplicare nu este necesar i duce la consum inutil
102

de memorie. De aceea, n C++ a fost creat un mecanism care va


evita aceast situaie, prin intermediul conceptului de clas
virtual. Sintaxa este:
class NumeClasaDerivat : SpecificatorAcces virtual
NumeClasaDeBaz
Aceast declaraie nu afecteaz clasa n cauz, ci numai
clasele derivate din aceasta. Astfel, clasele Clasa1 i Clasa2
considerate vor fi declarate virtuale. Declararea virtual a acestor
clase va afecta definirea constructorului clasei ClasaNou,
deoarece compilatorul nu poate hotr care date vor fi transferate
ctre constructorul ClasaDeBaz, specificate de constructorii
Clasa1 i Clasa2. Constructorul ClasaNou va trebui modificat
astfel, nct s trimit datele pentru constructorul ClasaDeBaz.
ntr-o ierarhie de clase derivate, constructorul clasei virtuale este
ntotdeauna apelat primul. De exemplu,
class A
{ };
class B1: virtual public A
{}
class B2: virtual public A
{};
class C1: public B1, public B2
{ };
Grafic acest exemplu se poate de prezentat n modul urmtor:
class A
virtual
class B1

virtual
class B2
class C

ntrebrile pentru verificarea cunotinelor:


1. Ce se numete motenire multipl? Dai exemple.
2. Ce se numete clas virtual? Dai exemple.
103

Temele pentru acas:


1. Ce se va afia la ecran dup rularea programului urmtor?
#include <iostream.h>
cassBl
{ public :
Bl() { cout "Constructorul B1 \n";}
~B1() { cout "Destructorul B1 \n";}
class B2
{ int b;
public :
B2 ( ) { cout "Constructorul B2\n"; }
~B2 ( ) { cout "Destructorul B2 \n"; }
};
// Motenirea a dou clase de baz
KOHCTp
( cout "
yKTOpa
cout
main ()
{
C ob;
return 0;
class D : public Bl, public B2
{ public:
D() { cout "Constructorul D \n";}
~D() { cout "Destructorul D\n";}
};
void main()
{ D obj; }
2. Care va fi rezultatul lansrii programului de mai jos? Corectai
greelile din program.
#include <iostream.h>
class A
{ int i;
104

public :
Al(int a=0) { i=a;cout "Constructorul A \n";}
~B1() { cout "Destructorul B1 \n";
class B
{ int j;
public :
B2 (int a=0 ) { j=a; cout "Constructorul B2\n"; }
~B2 ( ) { cout "Destructorul B2 \n"; }
};
// Motenirea a dou clase de baz
KOHCTp
( cout "
yKTOpa
cout
main ()
{
C ob;
return 0;
class C : public Bl, public B2
{ int k,
public:
/* Scriei constructorul pentru clasa C astfel ca el s
activeze constructorii claselor de baz A i B*/
c() { cout "Constructorul D \n";
~C() { cout "Destructorul D\n";
};
void main()
{ C obj; }
Temele pentru lucrri de laborator:
1. La un depozit a fost adus marf de export = {denumire, ara de
exportare, cantitatea, preul, data livrrii}. i anume, procesor
= {tip, viteza de lucru}, monitor = {tipul, diagonala}, wincester
= {firma, dimensiune}. S se determine suma de bani necesar
105

pentru achitarea mrfii aduse. Plata se efectueaz n lei innd


cont de cursul valutar {valuta, data, vnzarea, cumprarea}.
2. S se efectueze urmtoarele operaii asupra figurilor geometrice:
de rotire a figurii, de mutare pe ecran, de colorare, de decupare a
unei pri din obiect, de a scrie text n figur. Figurile
geometrice au urmtoarele structuri:. triunghi = {vrfl, vrf2,
vrf3}, dreptunghi ={vrfl, vrf2}, cerc = {centru, raza}, elipsa =
(centru, raza1, raza2}.
3. S se calculeze ct timp a trecut de la nceputul erei noastre.
Structurile de baz snt deceniu = {veac, era}, timp = {ora,
minutul, secunda}, data = {zi, luna, an}}.
4. S se efectueze operaii algebrice i conversii asupra
urmtoarelor structuri: numr complex= {partea real, partea
imaginar}, numr raional= {numrtor, numitor}, punct din
plan = {coordonata x, coordonata y}.
5. S se efectueze operaii de conversie a urmtoarelor structuri:
punct din scatiu = { coordonata x, coordonata y. coordonata
z} i coordonate polare = {raza, unghiul}, unde unghi = {grad,
minuta, secunda),
6. ntr-un ora a fost construit un centru de prestare a serviciilor
telefonice. Informaia despre ora are urmtoarea structur
ora= {denumire, cod telefonic, cod potal}. La acest centru au
fost conectai 100 de utilizatori cu adresa: {strada, numrul
casei, scara, apartamentul}. Fiecare utilizator este abonat
telefonic, pentru care se indic {numele, adresa, numrul
telefonului, data montrii}. Informaia despre convorbirea
telefonic a utilizatorului are urmtoarea structur: convorbire
telefonic = {codul rii, numrul solicitatului, oraul, numrul
solicitantului, numrul de minute (durata conversaiei)}. S se
calculeze plata pentru achitarea serviciilor prestate acestor
utilizatori dac ei au inut convorbiri telefonice cu alte orae.
Plata pentru servicii se primete n diferite uniti valutare. cost
= {lei., bani}, sau {ruble, copeici}, sau {dolari, ceni}....
7. La competiii sportive de diferite probe sportive au participat
persoane din mai multe ri. Denumirea rii are urmtoarea
106

structur ar= {denumire, cod telefonic, cod potal}. Fiecare


participant are greutatea = {kilogram, gram} i poate participa
numai la una din probele sportive propuse. S se determine cele
mai bune rezultate sportive obinute n diferite probe sportive.
Rezultatele sportive pot fi estimate n diferite uniti, cum ar fi
{minute, secunde, sutimi} {kilogram, gram}, {metri, centimetri},
.a.
8. O bibliotec s-a completat cu 100 de cri. Fiecare carte a fost
pus la eviden cu urmtoarea structur: carte ={autor,
denumire, anul de editare, locul de editare}. S se determine
frecvena de utilizare a fiecrei cri. Cititorul este nregistrat la
bibliotec dup urmtoarea structur: {strada, numrul casei,
scara, apartamentul, numrul de telefon}.
9. n municipiul Chiinu sunt multe cinematografe unde ruleaz
filme. Filmele sunt nregistrate n baza de date cu urmtoarea
structur: film = {denumire, ara, regizor, gen, anul filmrii}.
Fiecare cinematograf este nregistrat cu urmtoarea structur =
{denumire, telefon, adresa, numrul de locuri}. S se determine
care gen de filme este mai solicitat de vizitatorii cinematografele
din Chiinu.
10. Hotelurile din Chiinu presteaz servicii pentru mai multe
persoane din mai multe ri. Pentru fiecare hotel n baza de
date se va introduce urmtoarea structur {denumirea, adresa,
numrul de telefon, numrul de stele}. Fiecare numr la hotel
are structura: {numr , numele locatarului, data sosirii, data
plecrii, costul}. Fiecare persoan este nregistrat la hotel:
{ara, strada, numrul casei, scara, apartamentul, numrul de
telefon}. S se determine din ce ar ne viziteaz mai mult.
11. La depozitele unor farmacii a fost adus marf de export =
{denumire, tara de exportare, cantitatea, preul mrfii, data
livrrii}. Medicamentele snt nregistrate n baza de date cu
urmtoarea structur: {denumire, tip, ambalaj, cantitate, cost}.
Fiecare farmacie este pus la eviden cu urmtoarea structur
farmacie={numr, telefon, adres, deschiderea, nchiderea
farmaciei}. Medicul prescrie reet pacientului. Pacientul este
107

nregistrat la policlinic dup urmtoarea structur: {nume, adres,


diagnostic, data mbolnvirii}. Pacientul dorete s cumpere aceste
leacuri. S se afle adresele farmaciilor unde snt depozitate
medicamentele solicitate. S se determine frecvena de solicitare a
medicamentelor.
12. Se se afle ruta cea mai optimal (din punct de vedere al costului, orei
sosirii la destinaie, timpului) dintre dou orae. Comunicarea ntre
aceste dou orae are loc cu autocarele (autocar ={model, data
fabricrii, punctul de destinaie, costul rutei), cu trenul (mersul
trenurilor ={numr, destinaie, ora plecrii , ora sosirii,
categoria}), cu avionul (ruta de avion = {numr, destinaia, ora
decolrii, ora aterizrii}).
13. La Universitatea Tehnic din Moldova snt specialiti la care se
nva obiecte ce in de informatic: specialitatea={facultatea,
catedra, obiectul}, obiect ={denumire, an, tipul leciei, numr ore).
S se determine din punct de vedere geografic ci studeni din
diferite judee la faculti au ore de informatic (studentul =
{numele, grupa, data i locul naterii, media }.)
14. n Chiinu snt multe muzee. Informaia despre un muzeu poate fi
introdus n urmtoarea structur: muzeu ={ denumire, adresa,
telefon, nceputul lucrului, sfritul lucrului}. Pentru diferite
categorii de vizitatori (pensionari, studeni, oameni maturi, copii
mici, elevi) costul biletului de intrare este diferit. S se determine
frecvena de vizitate a muzeului innd cont de numrul de bilete de
intrare vndute. Informaia despre bilet are urmtoarea structur
bilet_de_intrare={muzeu, tip_bilet, costul}.
15. La aeroportul din Chiinu, la depozitul de lucruri pierdute, se afl
bagaje uitate de pasageri. Fiecare bagaj este etichetat cu urmtoarea
informaie: bagaj = {numr rut, stpn, data, greutate}. Pentru
recuperarea bagajului uitat pasagerul trebuie s prezinte paaportul
(buletinul de identitate). S se determine persoanele a crei ri mai
des uit bagajul n aeroportul din Chiinu.
16. La o cas de vindere a imobilului se duce evidena caselor
(casa.={adresa, telefon, numr camere, cost, comoditi}} i a
apartamentelor de vnzare (apartament.={adresa, telefon, numr
108

camere, etaj, cost}). S se determine cele mai solicitate tipuri de


vnzri efectuate de casa de vindere a imobilului.

Lucrarea de laborator nr. 5.


Tema: Fluxurile Input i Output standard i definite de utilizatori.
Formatarea fluxurilor numerice i textuale. Fluxurile stringuri i de
memorie.
Scopul lucrrii: familiarizarea studenilor cu fluxurile input i
output standard i definite de utilizatori, cu formatarea fluxurilor
numerice i textuale, cu fluxurile stringuri i de memorie.
Consideraiile teoretice necesare:
Noiune de Fluxuri
Limbajul C++ folosete conceptul abstract de stream (flux)
pentru realizarea operaiilor input/output. Din punctul de vedere al
limbajului C++, fluxul este o clas n sens obinuit. El ofer
metode de scriere i citire a datelor independente de dispozitivul
I/O. Operaiile de input/output se fac prin intermediul obiectelor de
tip flux. Acestea pot fi clasificate n funcie de dispozitivul fizic
asociat respectivei operaii. Din acest punct de vedere, limbajul C+
+ distinge trei categorii de fluxuri:
input/output standard (de exemplu, tastatura i ecranul);
input/output prin intermediul fiierelor;
input/output n memorie.
Fluxurile incapsuleaz (ascund) problemele specifice
dispozitivului cu care se lucreaz, sub biblioteca standard
iostream.h.. Biblioteca iostream.h. este scris nsi n limbajul C+
+ i este o bibliotec a claselor.
Alt avantaj al utilizrii fluxurilor se datoreaz implementrii
bibliotecii iostream.h, care utilizeaz un sistem de zone tampon.
Operaiile de intrare/ieire cu dispozitivele periferice snt
consumatoare de timp. Informaiile trimise ctre un flux nu snt
scrise imediat n dispozitivul n cauz, ci snt transferate ntr-o zon
109

de memorie tampon, din care snt descrcate ctre dispozitiv n


momentul umplerii acestei zone de memorie.
In limbajul C++ fluxurile au fost implementate utiliznd
clase, dup cum urmeaz:
clasa streambuf gestioneaz zonele tampon,
clasa ios
este clasa de baz pentru clasele de fluxuri de
intrare i de ieire. Clasa ios are ca variabil
membru un obiect de tip streambuf,
clasele istream isnt derivate din ios,
ostream
clasa iostream
este derivat din istream i ostream i ofer
metode pentru lucrul cu terminalul,
clasa fstream
ofer metode pentru operaii cu fiiere.
.Obiecte standard. La lansarea n execuie a unui program
C++, care include iostream.h, in mod automat compilatorul
limbajului C++ creeaz i iniializeaz patru obiecte:
cin
gestioneaz intrarea de la intrarea standard (tastatura),
cout gestioneaz ieirea ctre ieirea standard (ecranul),
cerr gestioneaz ieirea ctre dispozitivul standard de eroare
(ecranul), neutiliznd zone tampon,
clog gestioneaz ieirea ctre dispozitivul standard de eroare
(ecranul), utiliznd zone tampon
Expresia "cout " se utilizeaz pentru afiarea diverselor
valori. De fapt, cout este un obiect de tip flux, i anume obiectul
flux standard output. Operaia output (afiare) se realizeaz prin
intermediul operatorului suprancrcat .
Obiectul de tip flux standard input este cin, iar operaia input
(citirea) se realizeaz prin intermediul operatorului suprancrcat .
Obiectele cout i cin snt declarate n biblioteca iostream.h.
Redirectri. Dispozitivele standard de intrare, ieire i
eroare pot fi redirectate ctre alte dispozitive. Erorile snt, de
obicei, redirectate ctre fiiere, iar intrarea i ieirea pot fi conduse
("piped") ctre fiiere utiliznd comenzi ale sistemului de operare
(utilizarea ieirii unui program ca intrare pentru altul). Sintaxa
pentru operaii de ieire, cout:
110

cout << InformatieDeTrimisLaIesire;


Respectiv pentru intrare, cin:
cin >> NumeVariabil;
De fapt, cin i cout snt nite obiecte definite global, care au
suprancrcat operatorul >> respectiv << de mai multe ori, pentru
fiecare tip de parametru n parte (int, char *, etc.):
istream &operator >> (TipParametru &)
De exemplu:
#include <iostream.h>
void main()
{int IntegerNumber=50;
cout << "IntegerNumber = "; cin >> IntegerNumber;
cout<<"\nWhat you entered = "<<IntegerNumber<<endl;
}
Rezultatul ndeplinirii programului:
IntegerNumber = 200
What you entered = 200
Acest scurt program citete de la intrarea standard o valoare
ntreag, pe care o trimite apoi ctre ieirea standard. Se observ
posibilitatea de a utiliza simbolurile '\n', '\t', s.a.m.d (ca la printf,
scanf, etc.). Utilizarea simbolului endl va fora golirea zonei
tampon, adic trimiterea datelor imediat ctre ieire.
Att operatorul >>, ct i << returneaz o referent ctre un
obiect al clasei istream. Deoarece cin, respectiv cout, este i el un
obiect istream, valoarea returnat de o operaie de citire/scriere
din/n stream poate fi utilizat ca intrare/ieire pentru urmtoarea
operaie de acelai fel.
Operaia de intrare cin. Funcia cin.get() poate fi utilizat
pentru a obine un singur caracter din intrare, apelnd-o fr nici un
parametru, caz n care returneaz valoarea utilizat, sau ca referin
la un caracter.
get();
//fr parametri
n aceast form, funcia ntoarce valoarea caracterului gsit. Spre
deosebire de operatorul >>, funcia nu poate fi utilizat pentru a
111

citi mai multe intrri, deoarece valoarea returnat este de tip ntreg,
nu un obiect istream. Un exemplu de utilizare:
#include <iostream.h>
void main()
{char c;
while((c = cin.get()) != *)
{cout << "c = " << c << endl;}
}
Rezultatul ndeplinirii programului:
asdfgh*
c=a
c=s
c=d
c=f
c=g
c=h
Citirea de iruri de caractere utiliznd get(). Operatorul >>
nu poate fi utilizat pentru a citi corect iruri de caractere de la
intrare, deoarece spaiile snt interpretate ca separator ntre diverse
valori de intrare. n astfel de cazuri trebuie folosit funcia get().
Sintaxa de utilizare a funciei get n acest caz este urmtoarea:
cin.get(char *PointerLaSirulDeCaractere, int Lungime
Maxim, char Sfrit);
Primul parametru este un pointer la zona de memorie n care va fi
depus irul de caractere. Al doilea parametru reprezint numrul
maxim de caractere ce poate fi citit plus unu. Cel de-al treilea
parametru este caracterul de ncheiere a citirii, care este opional
(implicit considerat '\n').
n cazul n care caracterul de ncheiere este ntlnit nainte
de a fi citit numrul maxim de caractere, acest caracter nu va fi
extras din flux. Exist o funcie similar funciei get(), cu aceeai
sintax, numit getline(). Funcionarea sa este identic cu get(), cu
excepia faptului c acel ultim caracter menionat mai sus este i el
extras din flux.
112

Funcia cin.ignore() se utilizeaz pentru a trece peste un


numr de caractere pn la ntlnirea unui anume caracter. Sintaxa
sa este:
cin.ignore(int NumrMaximDeCaractere, char Sfrit);
Primul parametru reprezint numrul maxim de caractere ce vor fi
ignorate, iar al doilea parametru caracterul care trebuie gsit.
Funcia cin.peek() returneaz urmtorul caracter din flux,
fr ns a-l extrage.
Funcia cin.putback() insereaz n flux un caracter.
cout . Funcii membri ale cout
Funcia cout.flush()) determin trimiterea ctre ieire a
tuturor informaiilor aflate n zona de memorie tampon. Aceast
funcie poate fi apelat i n forma cout << flush.
Funcia cout.put()) scrie un caracter ctre ieire. Sintaxa sa
este urmtoarea:
cout.put(char Caracter);
Deoarece aceast funcie returneaz o referin de tip ostream, pot
fi utilizate apeluri succesive ale acesteia, ca n exemplul de mai jos:
#include <iostream.h>
void main()
{cout.put('H').put('i').put('!').put('\n');}
Funcia cout.write() are acelai rol ca i operatorul <<, cu
excepia faptului c se poate specifica numrul maxim de caractere
ce se doresc scrise. Sintaxa funciei cout.write() este:
cout.write(char *SirDeCaractere, int CaractereDeScris);
Formatarea ieirii
Funcia cout.width() permite modificarea dimensiunii
valorii trimise spre ieire, care implicit este considerat exact
mrimea cmpului n cauz. Ea modific dimensiunea numai pentru
urmtoarea operaie de ieire. Sintaxa este:
cout.width(int Dimensiune);
Funcie cout.fill() permite modificarea caracterului utilizat
pentru umplerea eventualului spaiu liber creat prin utilizarea unei
113

dimensiuni mai mari dect cea necesar ieirii, cu funcia


cout.width(). Sintaxa acesteia este:
cout.fill(char Caracter);
Opiuni de formatare a ieirii. Pentru formatarea ieirii snt
definite dou funcii membri ale cout, i anume:
Funcia cout.setf() activeaz o opiune de formatare a
ieirii, primit ca parametru:
cout.setf(ios::Opiune);
unde Opiune poate fi:
Showpos
determin adugarea semnului plus (+) n faa
valorilor numerice pozitive;
left,
right,schimb alinierea ieirii (la stnga. La dreapta,
internal
centreaz);
dec, oct, hex
schimb baza de numeraie pentru valori numerice;
showbase
determin adugarea identificatorului bazei de
numeraie n faa valorilor numerice.
Funcia cout.setw() modific dimensiunea ieirii, fiind
similar funciei cout.width(). Sintaxa sa este:
cout.setw(int Dimensiune);
n continuare vom exemplifica utilizarea funciilor pentru
formatarea ieirii:
#include <iostream.h>
#include <iomanip.h>
void main()
{int number = 783;
cout << "Numr = " << number<<endl;
cout.setf(ios::showbase);
cout<<"Numr n sistem hexazecimal = "<<hex <<
number<<endl;
cout.setf(ios::left);
cout << "Numr n sistemul octal, aliniat la stnga = " <<
oct << number<<endl;
}
Rezultatul ndeplinirii programului:
114

Numr = 783
Numr n sistem hexazecimal = 0x30f
Numr n sistemul octal, aliniat la singa = 01417
Redefinirea operatorilor de intrare i ieire pentru fluxul
standard. Operatorii de intrare i ieire pentru fluxul standard pot fi
redefinii pentru citirea i nregistrarea obiectului de tipul clasei
definite de utilizator.
Operatorul de intrare a fluxului standard pentru un obiect
din clasa obj se redefinete n modul urmtor:
istream & operator >> (istream &s, class obj)
{ //citirea componentelor din clasa obj
return s; }
Operatorul de ieire a fluxului standard pentru un obiect din
clasa obj se redefinete n modul urmtor:
ostream & operator<< (ostream &s, class obj)
{ // tiprirea componentelor din clasa obj
return s; }
De exemplu, vom redefini operatorii menionai pentru clasa
persoana.
# include <stdio.h>
# include <iostream.h>
# include <string.h>
class persoana
{ private:
char nume[40];
char prenume[40];
long int telefon;
int virsta;
public:
persoana(char *Nume=NULL, char *n=NULL, int v=0,
long int t=0)
{strcpy(nume,Nume); strcpy(prenume,n);
virsta=v; telefon= t; }
friend istream & operator >> (istream &s, persoana &P);
friend ostream & operator<< (ostream &s, persoana &P);
115

void set(char* Nume, char *n, int v, long int t)


{strcpy(nume,Nume); strcpy(prenume,n);
virsta=v; telefon= t; };
};
istream & operator >> (istream &s, persoana &P)
{ if((s >>P.nume) && (s >>P.prenume) &&
(s >>P.virsta) && (s >>P.telefon))
P.set(P.nume,P.prenume,P.virsta, P.telefon);
return s; }
ostream & operator << (ostream &s, persoana &P)
{return(s<<P.nume<<' '<<P.prenume<<' '<<P.virsta<<
' '<<P.telefon);}
void main()
{ persoana p;
cout<<"Introdu datele despre persoana:"<<endl;
cin >>p; cout<< p;
}
Rezultatele ndeplinirii programului:
Introdu datele despre persoana:
Bradu
Maria
20
123456
Bradu Maria 20 123456
Operaii de intrare/ieire cu fiiere. n afar de fluxurile
standard input/output se pot defini fluxuri ale utilizatorului definite
prin:
ifstream
ofstream
fstream

nume pentru un flux input (citire),


nume pentru un flux output (scriere),
nume flux utilizat i pentru citire i pentru scriere n
oricare din cazurile de mai sus.
Numele va fi un obiect de tipul clasei corespunztoare. Lucrul cu
fiierele se face prin intermediul clasei ifstream pentru citire,
116

respectiv ofstream pentru scriere. Pentru a utiliza fiiere, aplicaiile


trebuie s includ fstream.h. Clasele ofstream i ifstream snt
derivate din clasa iostream, ca urmare toi operatorii i toate
funciile descrise mai sus snt motenite i de aceast clas.
Definirea fluxurilor se poate face numai prin includerea n
program a fiierului fstream.h. ifstream, ofstream i fstream snt
clase. Declararea unui flux al utilizatorului este o declarare a unui
obiect din clasa respectiv. Clasele pot conine att date, ct i
metode (funcii). Operaiile input/output se fac prin intermediul
unor funcii membri ale claselor respective. Sintaxele pentru
constructorii acestor dou clase snt:
ofstream Variabila(char *NumeFiier, ios::Mod);
ifstream Variabila(char *NumeFiier);
Funcia de deschidere a unui stream este funcia open. Fiind
o funcie membru, ea va fi apelat numai prin intermediul unui
obiect declarat de tipul uneia din clasele de mai sus. De exemplu:
#include<fstream.h>
void main()
{ ofstream scriere;
scriere.open(disk.dat");
scriere.close();
}
Programul de mai sus exemplific faptul, c nu exist nici o
diferen ntre lucrul obinuit cu clase i definirea unui flux output.
Astfel, variabila scriere a fost declarat ca fiind de tipul (clasa)
ofstream. Definiia clasei ofstream poate fi gsit n fiierul
fstream.h. Funcia membru open, apelat prin intermediul
obiectului scriere, creeaz un fiier cu numele disk.dat. n
continuare acesta este nchis prin apelul funciei membru close(),
prin intermediul obiectului scriere. Execuia programului va
determina crearea unui fiier, care, ns nu va conine nimic.
Scrierea propriu-zis se face cu operatorul (suprancrcat) , iar
citirea cu operatorul , la fel ca n cazul fluxurilor standard
input/output.
117

Ideea de a utiliza noiunea abstract de flux s-a impus din


dorina de a asigura independena operaiilor input/output fa de
calculator sau de sistemul de operare. Productorii de compilatoare
livreaz (mpreun cu compilatorul) biblioteci, care conin clase,
funcii, variabile, care permit ca, n mare msur, aceast
independen s fie asigurat.
Funcia open are primul parametru de tip ir de caractere
modificat prin modificatorul const. Acesta reprezint numele
fiierului, care va fi asociat fluxului. Al doilea parametru specific
modul de acces la fiierul asociat fluxului i poate avea urmtoarele
valori:
ios:: app;
accesul se face prin adugare la sfritul
fiierului,
ios:: ate;
poziionarea se face la sfritul fiierului,
ios:: binary;
fiierul este interpretat ca fiier binar,
ios::in;
se asociaz unui flux de intrare,
ios::out;
se asociaz unui flux de ieire,
ios::nocreate;
fiierul trebuie s existe deja,
ios::noreplace; fiierul trebuie s nu existe,
ios::trunc;
distruge un fiier preexistent, avnd acelai nume.
Aceti constructori au rolul de a deschide fiierul specificat ca
parametru.
Valorile de mai sus snt constante definite n clasa ios,
definite n fiierul ifstream.h. Al treilea parametru este ignorat n
cazul n care parametrul al doilea este ios :: nocreate.
Caracteristicile de tip text i binary (binar) trebuie privite n
legtur cu operatorii folosii n operaiile input/output. Operatorii,
pe care i-am folosit pn acum ( i ), utilizeaz codificarea
ASCII a datelor. De exemplu:
#include<fstream.h>
void main()
{ofstream s1;
s1.open("dl.dat",ios::binary);
s1<<"text \n"<<12<<"\n"<<4.2;
s1.close();
118

ofstream s2("d2.dat");
s2<<"text \n"<<12<<"\n"<<4.2;
s2.close ();
}
Rezultatul ndeplinirii programului:
Coninutul fiierului d1.dat:
text
12
4.2
Coninutul fiierului d2.dat:
text
12
4.2
Funciile specializate pentru operaii input/output, care realizeaz
copii ale memoriei, snt read i write.
Funciile read i write.
Funcia write scrie ntr-un fiier coninutul unei zone de
memorie, care trebuie s fie adresat printr-un pointer de tip
caracter. 0 zon de memorie poate fi privit ca un ir de octei,
indicat prin adres de nceput i lungime. De exemplu:
#include<fstream.h>
void main ()
{ofstream s1;
int i;
s1. open ("d1. dat", ios:: binary) ;
s1.write((char *) &i, sizeof(i)) ;
s1.write("\n",4) ;
s1.close();
ofstream s2;
s2.open("d2.dat");
s2.write((char *) &i, sizeof(i));
s2. write (" \n", 4);
s2. close ();
}
119

Funcia de conversie (char *) se utilizeaz pentru a converti


adresele oricror obiecte la tipul adres de caracter. Astfel, se poate
de interpretat orice adres din memorie ca fiind adresa unui ir de
caractere. Operatorul sizeof se utilizeaz pentru determinarea
lungimii acestei zone de memorie.
Citirea unui fiier, utiliznd funcia read, se face respectnd
aceleai principii ca n cazul funciei write.
Diferena ntre fiierele de tip text i binary se pstreaz i
n cazul utilizrii funciilor read i write i const n reprezentarea
diferit a caracterelor de control. De exemplu:
#include<fstream.h>
void main()
{char *p=''\n";
ofstream s1;
s1.open("d1.dat",ios::binary);
s1.write(p,sizeof(p));
s1.close();
ofstream s2;
s2.open("d2.dat") ;
s2,write(p,sizeof(p));
s2.close() ;
}
Reprezentarea datelor ntr-un fiier depinde exclusiv de
funciile care se utilizeaz pentru nregistrarea (<< sau write)
respectiv, citirea acestora (>> sau read).
De cte ori citim un fiier, despre care tim cum a fost creat,
este bine s-l citim cu aceleai caracteristici i cu aceeai operatori.
Cnd vrem s citim din fiier, despre care nu tim cum a fost creat,
este bine s-l citim n mod binar, caracter cu caracter. De exemplu:
#include<fstream.h>
void main()
{int i,j; float k;
char p[10];
ofstream s1;
s1.open("d1.dat") ;
120

s1 122 "\n" 147;


s1 "\n abcd\n" 9.3;
s1.close();
ofstream s2;
s2.open("d.dat",ios::binary);
s2 i 3 p k;
s2.close();
}
Rezultatul ndeplinirii programului:
n fiierul textual d1.dat s-a nscris urmtoarele
122
147
abcd
9.3
n fiierul binar s-a nscris urmtoarele:
102273BO39 _3.138909e-42
n alt exemplu:
#include<fstream>.h>
void main()
{ char p[20];
ifstream s;
s.open("d.dat",ios::binary);
s.read(p,19);
s.close();
p[19]=NULL; cout p;
}
fiierul creat poate fi citit n mod binar, utiliznd funcia read. n
acest mod coninutul fiierului este considerat copia unei zone de
memorie. Deoarece fiierul a fost creat printr-o codificare ASCII,
coninutul acestuia se ia ca un ir de caractere. Instruciunea read
copie coninutul fiierului n irul de caractere p. Ultima
instruciune din programul de mai sus afieaz la ieirea standard
coninutul vectorului p. Atribuirea explicit p[19]=NULL este
obligatorie pentru a marca sfritul irului de caractere.
121

Pentru a nchide aceste fiiere, trebuie apelat funcia


membru close().
Fluxuri n memorie constituie o interfa ntre program i
un dispozitiv fizic. Am utilizat fluxurile standard i operatorii ,
i, de asemenea, fluxurile asociate cu fiiere. Exist posibilitatea de
definire a unor fluxuri n memorie. Acestea snt fiiere, care fizic
snt localizate n memorie. Un flux n memorie este un ir de
caractere, care are exact aceeai structur ca un fiier obinuit.
Clasele, care definesc aceste fluxuri, snt:
istrstream(input string stream);
flux input,
ostrstream(output string stream);
flux output,
strstream (string stream);
flux input/output.
Funcii de formatare. Clasele bazate pe fluxuri conin o
serie de funcii, care ofer o mare flexibilitate a operaiilor de
scriere cu formatare. Pentru datele numerice cele mai importante
snt funciile, care permit tiprirea ntr-un cmp de lungime fix,
alinierea (la stnga sau la dreapta) i precizia, cu care se face
afiarea.
Funcia width stabilete dimensiunea cmpului, calculat n
caractere, pe care se va face scrierea. Funcia are un singur
parametru de tip ntreg i trebuie apelat prin intermediul unui
obiect de tip flux. Astfel, obiectul de tip flux n memorie, declarat
prin simbolul a, va avea funcia asociat a. width, prin care am
cerut ca fiecare dat, s fie nregistrat ntr-un cmp format din 8
caractere.
Funcia setf are, de asemenea, un singur parametru n cazul
dat ios::right, avnd semnificaia de aliniere la dreapta.
Funcia precision are un singur parametru de tip ntreg, prin
care se specific numrul de poziii, scrise dup punctul zecimal.
De exemplu:
#include<fstream.h>
#include<strstream.h>
void main ()
{ float a[4][5];
int i, j;
122

for ( i=0; i<4; i++)


for ( j=0; j<5; j++)
a[i][j]=(float) (i+2)/(j+1);
char s[200];
ostrstream scrie(s,sizeof(s));
for ( i =0; i<4; i++)
{for ( j=0; j<5; j++)
{scrie.width(8);
scrie.setf(ios::right);
scrie.precision(2);
scrie << a[i][j];
}
scrie << "\n";};
s[164]=NULL;
cout << s;
}
Rezultatul ndeplinirii programului:
2
1
0.67
0.5 0.4
3
1.5
1 0.75 0.6
4
2
1.33
1 0.8
5
2.5
1.67 1.25
1
n programul de mai sus parametrul funciei precision este 2, deci
numerele vor fi scrise cu dou semne zecimale. Programul
reprezint un bun exemplu, prin care putem scoate n eviden
utilitatea fluxurilor de memorie.
Rezultatul operaiilor de intrare/ieire poate fi testat prin
intermediul a patru funcii membri:
eof() verific dac s-a ajuns la sfritul fiierului;
bad() verific dac s-a executat o operaie invalid;
fail() verific dac ultima operaie a euat;
good() verific dac toate cele trei rezultate precedente snt
false.
Funciile de formatare pot fi aplicate oricrui obiect de tip
flux, fie c este un flux standard, un flux de tip fiier sau un flux n
memorie.
123

ntrebrile pentru verificarea cunotinelor:


1. Care snt tipurile de fluxuri standard definite de utilizator?
2. Scriei un exemplu de utilizare a funciilor read i write a
coninutului unei zone de memorie.
3. Definii parametrii funciei membru open ale unei clase flux.
4. Cum se definesc fluxurile de memorie?
5. Care snt funciile de formatare pentru fluxuri?
Temele pentru acas:
1. Corectai greelile i lansai urmtoarele exemple la execuie. Ce
rezultate vor aprea pe ecran?
Exemplul 1:
#include <iostream.h>
define N 80
void main(0
{ inc c;
int cnt=0; charcnt=0;
While(1)
{ c=cin.get();
if (c==EOF) break;
if (c=/ && cin.peek() ==/)
{ cnt++;
cin.ignore(n,\n);
charcnt++=cin.gcount();
charcnt++;
}
}
cout<<In << cnt << comentarii avem << charcnt
<< caractere;
}
Exemplul 2 .
#include <iostream.h>
void main()
{While(1)
124

{ char c; cin.get;
if(cin.eof()) break;
cout.put( c);
}
Exemplul 3.
#include <iostream.h>
void main()
{cout <<setfill(%}<<setw(4)<< 17;}
Exemplul 4.
#include <iostream.h>
#include <fstream.h>
void main()
{ int I=42;
fstream f (dat.txt,ios::out|ios::binary);
f.seekp(17,ios::beg);
f.write((const char*)&I,2) ;
f.close();
f.open(dat.txt, ios::in|ios::binary);
f.seekg(17,ios::beg);
f,read((char*)&I,2);
f.close();
cout<<I;
}
Exemplul 5.
#include <iostream.h>
#include <strstream.h>
void main()
{char buffer [80];
strstream s (buffer,80,ios::out);
float pret=123.45;
s<<Preul stocului este de;
s;;serw(6)<<setprecision(2) ;
}
Temele pentru lucrri de laborator:
125

1. Scriei un program care compar dou fiiere date.


2. Scriei un program care calculeaz numrul de elemente ale unui
fiier care snt mai mici ca valoarea medie aritmetic a tuturor
elementelor acestui fiier.
3. Scriei un program care tiprete toate cuvintele diferite de
ultimul cuvnt dintr-un fiier. Cuvintele din fiier snt separate
prin virgul, iar.dup ultimul cuvnt se pune punct.
4. Scriei un program care determin numrul maximal i cel
minimal dintr-un ir de 100 de numere aleatoare dintr-un fiier.
Subconsecutivitatea de elemente dintre numrul maximal i cel
minimal determinat s se nregistreze ntr-un nou fiier.
5. Scriei un program care formeaz un fiier nou dup urmtoarea
legitate: din trei fiiere date mai nti se selecteaz numerele
divizibile la 3, la 5 i la 7, apoi numerele pozitive pare de pe
locuri impare.
6. Scriei un program care formeaz un fiier nou dup urmtoarea
legitate: din trei fiiere date mai nti se selecteaz numerele
negative, zerourile, apoi numerele pozitive.
7. Scriei un program care ordoneaz lexicografic o consecutivitate
de nregistrri (dintr-un fiier) de tipul
struct { char nume [30];
int ani} nregistrare;
Rezultatul ordonrii s se nscrie ntr-un nou fiier.
8. Scriei un program care din dou fiiere ordonate descresctor se
va forma unul n care se va pstra ordinea descresctoare de
sortare.
9. Scriei un program care sorteaz lexicografic cuvintele dintr-un
text. Pentru fiecare element sortat s se indice numrul de
repetri ale cuvntului n textul dat.
10. Scriei un program care calculeaz suma nmulirii numerelor
vecine pe pe locuri pare dintr-un fiier dat.
11. Scriei un program care va tipri n ordine invers
subconsecutivitatea de numere dintre valoarea minim i
maxim ale unei consecutiviti de numere citite dintr-un fiier.
126

12. Scriei un program care formeaz un fiier nou din cel dat dup
urmtoarea legitate: elementele fiierului nou se obine din
inversul numerelor din fiierul dat.
13. Scriei un program care determin frecvena cu care a fost
generat fiecare element n fiierului creat. Valorile elementelor
snt cuprinse ntre 1 i 100.
14. Scriei un program care determin numrul maximal i cel
minimal din numerele unui fiier dat. S se determine
elementele mai mari ca cel minimal i mai mici ca numrul
maximal.
15. Scriei un program care efectueaz reformatarea unui fiier
textual n felul urmtor. Lungimea rndului de caractere n
fiierul nou are lungimea de 60 de caractere. Dac n rndul dat
se depisteaz punctul, restul rndului din fiierul dat se scrie din
rnd nou.
16. Scriei un program care din dou fiiere date ordonate cresctor
se va forma unul nou, n care se va pstra ordinea cresctoare
de sortare.

Lucrarea de laborator nr. 6.


Tema:Templates: Template pentru clase i funcii.
Scopul lucrrii: familiarizarea studenilor cu clase i funcii
generice.
Consideraiile teoretice necesare:
Clase i funcii generice
Template-ul implementeaz aa-zisul concept de "tip
parametrizat" ("parametrized type"). Un template reprezint o
familie de tipuri sau funcii, cu alte cuvinte, un ablon sau model.
Acest concept a fost introdus, n primul rnd, pentru a crete gradul
de reutilizare a codului. De exemplu, pentru a implementa o list de
numere ntregi este necesar realizarea unei clase speciale (s
spunem ListOfIntegers), iar pentru o list de iruri alt clas (s
127

spunem ListOfStrings). Conceptul de template permite realizarea


unei clase generale (s spunem List), care s accepte orice tip de
element, inclusiv tipuri necunoscute la momentul implementrii
acesteia. Tipul template este stabilit n momentul instanierii sale.
Template-urile snt foarte utile pentru realizarea de biblioteci care
trebuie s ofere metode generice de prelucrare a datelor. Sintaxa
general de declarare a unui template este urmtoarea:
template < ListaDeParametri > Declaraie
unde Declaraie reprezint declararea sau definirea unei clase sau
unei funcii, definirea unui membru static al unei clase template,
definirea unei clase sau funcii membri al unei clase template, sau
definirea unui membru template al unei clase.
Clasele parametrizate (sau clasele template) se declar
astfel:
template <class NumeParametru>
class NumeClasa
{ // ...
// definirea clasei
}
Stabilirea tipului clasei template se face prin intermediul unei
construcii de genul:
NumeClasa <NumeParametru>
unde NumeParametru reprezint tipul obiectului.
Funciile template se declar astfel:
template <class NumeParametru>
//
...
// declaraia funciei
S considerm n continuare ca exemplu implementarea unei stive
generice folosind template-uri.
#include <iostream.h>
template <class T> class StackItem
{ public:
StackItem *Next;
Tip *Data;
128

StackItem(Tip Data_new, StackItem <Tip> *Next_new)


{ Data = new Tip(Data_new);
Next = Next_new; }
};
template <class Tip> class Stack
{public:
Tip pop()
{ Tip result = *(Data->Data);
StackItem <Tip> *temp = Data;
Data = Data->Next;
delete temp;
return result;
}
Tip top()
{ return *(Data->Data); }
void push(Tip Data_new)
{ Data = new StackItem <Tip>(Data_new, Data); }
int isEmpty()
{
return Data == 0; }
Stack()
{
Data = 0; }
private:
StackItem <Tip> *Data;
};
void main()
{ Stack <int> anIntegerStack;
anIntegerStack.push(5);
anIntegerStack.push(7);
if(anIntegerStack.isEmpty())
cout << "Stiva goala" << endl;
else
cout << anIntegerStack.pop() << endl;
cout << anIntegerStack.top() << endl;
}
Rezultatul ndeplinirii programului:
129

7
5
n exemplul urmtor a fost implementat o list generic
(List). Ca elemente a listei s-au folosit obiecte de tip Point. Pentru
parcurgerea uoar a listei a fost implementat o clas de tip
"iterator", care poate fi considerat ca fiind un "cursor" care
strbate lista. Funcia List.begin() returneaz un iterator poziionat
pe primul element al listei, List.end() pe ultimul element al listei.
Saltul la urmtorul element al listei se face cu ajutorul operatorului
++ din clasa Iterator.
#include <iostream.h>
class Point
{friend ostream& operator << (ostream& output, Point p);
protected:
unsigned x, y;
public:
Point() {x = 0;y = 0;}
Point(unsigned X, unsigned Y) {x = X;y = Y;}
~Point() {}
unsigned GetX() {return x;}
unsigned GetY() {return y;}
void SetX(unsigned X) {x = X;}
void SetY(unsigned Y) {y = Y;}};
ostream& operator << (ostream& output, Point p)
{output<<"(" << p.x <<", " << p.y << ")"; return
output;}
template <class Tip> class Item
{public:
Item *Next;
Tip *Data;
Item(Tip __Data, Item <Tip> *__Next)
{Data = new Tip(__Data); Next = __Next;}
};
template <class Tip> class List
{public:
130

Tip pop_front()
{Tip result = *(Data->Data);
Item <Tip> *temp = Data;
Data = Data->Next;
delete temp;
return result;}
Tip front() {return *(Data->Data);}
void push_front(Tip __Data)
{Data = new Item <Tip>(__Data, Data);}
int empty() {return Data == 0;}
List() {Data = 0;}
class Iterator
{ friend class List <Tip>;
protected:
Item <Tip> *Current;
Iterator(Item <Tip> *x) {Current = x;}
public:
Iterator() {}
int operator == (Iterator& x){return Current ==
x.Current;}
int operator != (Iterator& x){return Current != x.Current;}
Tip operator *(){return *(Current->Data);}
Iterator& operator ++(int)
{Current = Current->Next; return *this;}
};
Iterator begin(){return Iterator(Data);}
Iterator end()
{Item <Tip> *temp;
for(temp = Data; temp; temp = temp->Next);
return Iterator(temp);}
private:
Item <Tip> *Data;
};
void main()
{List <Point> anPointList;
131

List <Point>::Iterator index, end;


anPointList.push_front(Point(1, 1));
anPointList.push_front(Point(3, 14));
index = anPointList.begin(); end = anPointList.end();
if(anPointList.empty()) cout << "Lista vida" << endl;
else
for(; index != end; index++)
cout << *index << " ";
cout << endl;
}
Rezultatul ndeplinirii programului:
(3, 14 ) (1, 1)
Clasele template pot avea trei tipuri de prieteni (friends):
o clas sau funcie care nu este de tip template;
o clas sau funcie template;
o clas sau funcie template avnd tipul specificat.
Dac este necesar particularizarea unei funcii template sau a unei
funcii membri a unei clase template pentru un anumit tip, funcia
respectiv poate fi suprancrcat pentru tipul dorit.
Trebuie de remarcat, de asemenea, c n cazul n care o
clas template conine membri statici, fiecare instan a templateului n cauz va conine propriile date statice.
ntrebrile pentru verificarea cunotinelor:
1. Ce reprezint un template? Dai exemple de funcie template,
clas template.
2. Care este corelaia dintre clase derivate i clase template?
3. Pot oare fi redefinite funciile template?
4. Clasele template pot avea trei tipuri de prieteni (friends). Care
snt ele? Dai exemple.
Temele pentru acas:
1. Ce efectueaz urmtoarea funcie template?
template <class X> void swap(X &a, X &b)
{X temp; temp=a; a=b; b=temp;}
132

void main()
{int 1=10, j=20;
float x=10.1, y=23.3;
cout<<Valorile i, j snt:<< i << ' '<< j << endl;
cout<<Valorile , snt<< x<< ' '<< <<endl;
swap(i,j); swap (x,y); // schimb de variabile
cout<<Valorile i, j dup schimb:<<i<<' '<<j<<endl;
cout<<Valorile , dup schimb:<<x<<'
'<<
<<endl;
}
2. Ce rezultate obinem la rularea urmtorului program?
#include<iostream.h>
template <class data_t> class list
{ data_t data;
list *next;
public:
list (data_t d);
void add(list *node) {node->next=this; next-0;}
list *getnext() {return next;}
data_t getdataO {return data;}
}
template <class data_t> list<data_t>::list(data_t d)
{data=n; next=0; }
void main()
{list<char> start('a');
list<char>*p, *last;
// crearea listei
last=&start;
for(int i=l; i<26; i++)
{p=new list<char>(a+1); last=p;}
//tiparul listei
p=&start;
while(p)
{cout<<p->getdata(); p=p->getnext();}
return 0;
133

}
Temele pentru lucrri de laborator:
1. Sortare prin selecie. Se d consecutivitatea de obiecte a1, , an.
Fie elementele consecutivitii snt aranjate n ordine
cresctoare: a1 a2 an. Aceast problem poart denumirea de
problem de sortare a consecutivitii care poate fi aranjat i n
ordine descresctoare: a1 a2 an.; dac numerele dou cte
dou snt diferite, consecutivitatea poate fi aranjat n cretere
sau descretere. S se afle elementul tabelului care are valoare
minimal. El se va nlocui cu primul element din
consecutivitate, apoi se procedeaz cu restul elementelor din
consecutivitate ncepnd cu al doilea element .a.m.d.
2. Sortarea prin interclasare. Se d consecutivitatea de obiecte a1,
, an. Fie elementele consecutivitii snt aranjate n ordine
cresctoare: a1 a2 an. Aceast problem poart denumirea de
problem de sortare a consecutivitii care poate fi aranjat i n
ordine descresctoare: a1 a2 an.; dac numerele dou cte
dou snt diferite, consecutivitatea poate fi aranjat n cretere
sau descretere. Prin analiza consecutiv a elementelor a1, , an
s se afle cel mai mic i, astfel ca ai > ai+1. S se schimbe ai i
ai+1 cu locul. S se efectueze aceast procedur, s se renceap
analiza consecutivitii cu elementul ai+1 .a.m.d. Prin aceste
manipulrii elementul cel mai mare se va mica pe ultimul loc al
consecutivitii. Urmtoarele analize se vor ncepe de la nceput
micornd cantitatea de elemente cercetate cu o unitate.
Consecutivitatea va fi sortat dup analiza elementelor , n care
au participat numai elementul unu i doi.
3. Sortarea prin inserie. Se d consecutivitatea de obiecte a1, ,
an. Fie elementele consecutivitii snt aranjate n ordine
cresctoare: a1 a2 an. Aceast problem poart denumirea de
problem de sortare a consecutivitii care poate fi aranjat i n
ordine descresctoare: a1 a2 an.; dac numerele dou cte
dou snt diferite, consecutivitatea poate fi aranjat n cretere
sau descretere. S se cerceteze consecutiv a2, , an i fiecare
134

element nou ai inclus la locul potrivit n consecutivitatea deja


sortat a1, , ai-1. Acest loc se determin prin compararea
consecutiv a elementului ai cu elementele sortate a1, , ai-1 .
4. S se cerceteze i s se calculeze numrul de comparri i de
schimbri (adic permutri dintr-un loc n altul) ale elementelor
a1, , an n procesul de utilizare a algoritmilor descrii n
varianta 1. S se demonstreze c numrul de schimbri pentru
algoritmul de sortare prin selectare este mrginit de o funcie
liniar de n. n acelai timp i numrul de comparri pentru
algoritmul de sortare prin selectare i pentru algoritmii de
sortare prin interclasare i prin inserie, n unele cazuri, (de
exemplu, dac consecutivitatea iniial este de tipul a1>a2>
>an) snt funcii ptratice de n.
5. Din definiia problemei din punctul 1 rezult c algoritmul de
sortare prin selectare se deosebete de cellali algoritmi n acele
cazuri cnd schimbarea locului elementului este cu mult mai
dificil dect compararea elementelor. S se utilizeze acest fapt
la executarea urmtoarelor probleme. Se d un obiect matrice
de numere reale de dimensiunea nm; s se sorteze (s se
schimbe cu locul) liniile matrice:
) dup creterea valorilor primelor elemente ale liniilor matricei;
b) dup descreterea sumelor elementelor liniilor matricei;
c) dup descreterea valorilor minimale ale elementelor liniilor
matricei;
d) dup descreterea valorilor maximale ale elementelor liniilor
matricei.
Pentru punctele b), c), d) s se utilizeze o consecutivitate
auxiliar de numere a1, , an.
6. Fie o consecutivitate de numere ntregi sau reale a1 a2 an se
d n ordine descresctoare i fie se d un numr b (respectiv
ntreg sau real), pentru care trebuie s-i cutm locul ntre
numerele a1, , an, astfel ca, dup introducerea numrului b n
acest loc, consecutivitatea s rmn sortat n aceeai ordine.
Dac unele elemente snt egale dup valoare cu numrul b,
acesta poate fi introdus n diferite locuri mai aproape de
135

nceputul consecutivitii. Aceast problem poart numele de


problem de cutare a locului elementului.. Pentru b snt n+1
posibiliti: b a1, a1<b a2, an-1 <b an, an < b i ca soluie a
acestei probleme de cutare a locului elementului b poate fi
corespunztor unul din numerele 1, ..., n+1. Pentru rezolvarea
acestei probleme va fi util urmtorul algoritm care se numete
algoritmul mpririi n jumti (algoritmul cutrii binare). Se
ia mai nti 1 i n + 1 n calitate de hotare de cutare a locului
elementului, apoi pn cnd valorile hotarelor nu coincid, pas cu
pas se mic aceste hotare n modul urmtor: se compar b cu as,
unde s este partea ntreag mediei aritmetice a valorilor
hotarelor; dac s<b, atunci se nlocuiete hotarul de jos
precedent cu s+1, iar cel de sus rmne fr schimbare, n caz
contrar, se las fr nici o schimbare hotarul de jos, iar hotarul
de sus se schimb cu s. Cnd valorile hotarelor coincid, fiind
egale cu careva numr t, executarea algoritmului descris se
finalizeaz cu rezultatul t. (Numrul de comparri necesare
pentru acest algoritm nu exced [log2 (n +1)]+1)
a) Sunt date numere reale a1, , an, b1, , bm (a1 a2 an). S se
obin numerele naturale k1, , km astfel, nct ki s fie soluia
problemei cutrii locului bi printre a1, , an (i= 1, ..., m). S se
utilizeze algoritmul cutrii binare.
b) Tabelul de ctiguri a loteriei este reprezentat prin tabelul de
numere ctigtoare a1, , an i tabelul de ctiguri n lei p1, ,
pn (pi este ctigul pentru numrul ai (i = 1, ..., n)). S se
determine suma ctigurilor pentru biletele cu numerele b1, ,
bm. S se utilizeze algoritmul cutrii binare.
c). Fie locul numrului b printre cele ale consecutivitii sortate
cresctor a1, , an se va alege ca cel mai ndeprtat loc de la
nceputul consecutivitii neafectnd legitatea sortrii
cresctoare. S se introduc schimbri n descrierea algoritmului
de mprire n jumti i respectiv s se rezolve problema a).
7. Cutare binar. Fie T[1..n} un vector sortat cresctor i x un
obiect care se afl printre obiectele lui T. S se determine locul
lui x n T. Consecutivitatea se organizeaz n form de list
136

dublu lnuit. S se foloseasc algoritmul de sortare a


vectorului T[1..n], divizndu-l n doi vectori F i V, sortndu-i pe
acetia i apoi interclasndu-i (amestecndu-i).
8. Se presupune c numerele a1, , an snt elementele unui fiier.
Valoarea n nu se cunoate. S se rezolve urmtoarele probleme:
s se afle valoarea maximal din consecutivitatea dat a1, , an,
dup ce se elimin din ea:
a) un element cu valoarea m (a1, , an);
b) toate elementele cu valoarea max(a1, , an). Se subnelege c
nu toate numerele a1, , an snt egale ntre ele.
c) s se afle max (a1, , an) i min (a1, , an) utiliznd urmtorul
algoritm. Pas cu pas s se obin perechile max(a1, , ai),
min(a1, , ai) (i= 1, ..., n). Ca s se obin max(a1, , ai+1),
min(a1, , ai+1), se compar ai+1 cu max(a1, , ai), apoi, dac
ai+1 < max(a1, , ai), suplimentar se compar ai+1 cu min(a1, ,
ai).
9. Se presupune c numerele a1, , an snt elementele unui fiier.
Valoarea n nu se cunoate. S se rezolve urmtoarele probleme:
s se afle valoarea maximal din consecutivitatea dat a1, , an,,
dup ce se elimin din ea:
a) un element cu valoarea m (a1, , an);
b) toate elementele cu valoarea max(a1, , an). Se subnelege c
nu toate numerele a1, , an snt egale ntre ele.
c) s se afle max (a1, , an) i min (a1, , an) utiliznd urmtorul
algoritm. Fie n este un numr par, adic n = 2k. Atunci pas
dup pas s se obin max (a1, , a2l), min(a1, , a2l) (l=1,..., k).
Ca s se obin max(a1, , a2l+2), min(a1, , a2l+2), mai nti se
compar ntre ele a2l+1, a2l+2 i max(a2l+1, a2l+2) se compar cu
m(a1, , a2l), iar min(a2l+1, a2l+2) cu min(a1, , a2l). Dac n
este un numr impar, se va efectua nc un pas suplimentar:
compararea ultimului element an cu max(a1, , an-1) i, posibil,
cu min(a1, , an-1).
10. Algoritmul de insertare simpl poate fi schimbat astfel. Locul
unde trebuie insertat n consecutivitatea sortat a1, , an, se
determin prin algoritmul mpririi n jumti (V. 4). Se obine
137

un nou algoritm de sortate care se numete algoritm de sortate


prin insertare binar (mbinarea de cuvinte insertarea binar se
subnelege ca insertare prin mprirea n jumti). Acest
algoritm necesit aproximativ n*log2 n comparri ale
elementelor consecutivitii. S se scrie programul care
realizeaz acest algoritm.
11. Sunt date obiectele a1, , an. S se obin n ordine cresctoare
toate numerele diferite ce intr n a1, , an. Pentru aceasta s se
foloseasc algoritmul de sortare prin insertare binar. n
procesul de sortare s se elimine elementele care se repet. Dac
n urma cutrii locului ai n consecutivitatea deja sortat a1, ,
ak (k < i) se va depista c printre a1, , ak este deja un element
egal cu ai, trebuie de cercetat urmtorul ai+1 fr schimbarea
consecutivitii a1, , ak.
12. Algoritmul von Newmann de sortare a tabelului a1, , an n
ordine nedescresctoare (algoritm de sortare prin unire) se
bazeaz pe unirea de mai multe ori ale grupelor de elemente deja
sortate ale tabelului dat. Mai nti tabelul este privit ca o
totalitate de grupe sortate ce conin cte un element. Unirea
grupelor vecine ne dau noi grupe deja sortate care conin cte
dou elemente (poate, posibil, cu excepia ultimei grupe pentru
care nu s-a gsit pereche). Apoi grupele se mresc prin aceeai
metod, pn cnd obinem o grup care conine toate elementele
consecutivitii iniiale deja sortate. Pentru sortare, la etapele
intermediare, se utilizeaz nu numai tabelul a1, , a, dar i
unul auxiliar b1, , bn. Figura 1 ne ilustreaz

Fig.1.
cum se unesc dou etape ale tabelelor a1, , an i b1, , bn
reprezentndu-le n form de segmente mprite n pri
corespunztoare grupelor de elemente sortate. Numrul de grupe
sortate se micoreaz. Deci se va obine acel moment cnd
138

tabelul a1, , an sau b1, , bn va conine o grup de elemente


deja sortate. Aceasta nseamn c tabelul este sortat. Pentru
unirea a dou grupe sortate, care conine corespunztor i q
elemente, este suficient de a produce nu mai mult de p+q
comparri. Rezult c pentru o singur etap de sortare este
suficient de a efectua nu mai mult de n comparri i tot attea
permutri. Demonstrai c algoritmul lui fon Newmann necesit
aproximativ n log2 n comparri i tot attea permutri. Spre
deosebite de ali algoritmi de sortare numai algoritmul de
insertare binar necesit acelai numr de comparri. ns
algoritmul lui fon Newmann se deosebete de cel menionat prin
utilizarea a mai puine permutri ale elementelor a1, , an (cu
toate c necesit un tabel suplimentar b1, , bn). De scris
programul care realizeaz algoritmul lui von Newmann.
13 Fie se d tabelul de obiecte a1, , an. Pentru sortarea tabelului
s se utilizeze urmtoarea procedur. S se aranjeze elementele
tabelului a1, , an astfel, ca la nceputul tabelului s fie grupa de
elemente valorile crora snt mai mari ca elementul de pe primul
loc, urmeaz valoarea primul element al consecutivitii date i
apoi vor urma elementele cu valori mai mici sau egale ca primul
element. Astfel, pas cu pas efectund procedura descris, s se
obin tabelul sortat. Numrul de comparri fiecare etap nu
trebuie s ntreac n 1.
14. Fie a i b snt fiiere, k este un numr natural. Vom spune c
fiierele i b snt corelate k-sortate, dac:
a) n fiecare din fiierele a i b primele k componente, urmtoarele
dup ele k componente etc. formeaz grupe sortate; ultima grup
a componentelor din fiier (tot sortat) poate conine mai puin
de k elemente, dar numai un singur fiier poate avea o grup
necomplet;
b) numrul grupelor sortate a fiierului a se deosebesc de numrul
grupelor sortate a fiierului b nu mai mult dect cu o unitate;
c) dac ntr-un fiier numrul grupelor sortate snt mai puin cu o
unitate dect n cellalt fiier, grupul incomplet de elemente (mai
139

puin de k elemente) poate fi numai n fiierul cu mai multe


componente.
d) componentele a dou fiiere i b corelate k-sortate pot fi
alocate n fiierele g i h astfel, nct g i h s fie corelate 2ksortate. Aceasta se efectueaz prin intermediul unirii grupelor
sortate. Rezultatele unirii se aranjeaz alternativ cnd n fiierul
g, cnd n fiierul h. Fig.2 ilustreaz acest proces la primele uniri
ale grupelor sortate. Fiierele se prezint n form de segmente,
componentele crora se prezint ca grupe sortate cu numrul
determinat de componente. S se finalizeze descrierea acestui
algoritm cercetnd etapa final. S se demonstreze c fiierele g
i h ntr-adevr vor fi corelate 2k- sortate.
S se realizeze acest algoritm n form de program.

Fig.2.
15. Fie dat tabelul a1, , an. Trebuie de permutat elementele a1, ,
an astfel, ca la nceput de tabel s fie grupa de elemente mai
mari dect elementul care se afl pe primul loc n tabelul iniial,
apoi nsi acest element, dup care urmeaz cele mai mici sau
egale cu el. Numrul de comparri i permutri nu trebuie s
ntreac n - 1. Algoritmul recursiv de sortate (algoritmul de
sortare rapid) care se bazeaz pe transformrile descrise mai
sus este urmtorul. Dac tabelul conine nu mai mult de un
element, tabelul se consider sortat. n caz contrar, efectum
transformarea descris n V..10 i determinm rezultatele de
utilizare a algoritmului de sortare rapid pentru tabelul a1, ,
an n felul urmtor: mai nti se formeaz prima grup sortat
cu ajutorul algoritmului de sortare rapid, apoi fr schimbare
acel element care mparte grupa nti i doi, dup care urmeaz
grupa doi de elemente, sortat cu ajutorul algoritmului de
140

sortare rapid. Acest algoritm nu utilizeaz tabelul suplimentar


i necesit aproximativ n log2 n comparri i tot attea
permutri de elemente. Acestea snt caracteristicele numerice
medii. Pentru cel mai ru caz, numrul de comparri poate
ajunge la n(n1)/2. n afar de aceasta, acest algoritm necesit
recursie. S se scrie un algoritm care realizeaz algoritmul de
sortare rapid.

141

Lucrarea de laborator nr. 7.


Tema: Prelucrarea excepiilor. Blocul try{} throw() catch()
Scopul lucrrii: familiarizarea studenilor cu
excepiilor, lucrul cu blocul try{} throw () catch()

prelucrarea

Consideraiile teoretice necesare:


Tratarea excepiilor
Excepiile snt situaiile neateptate aprute n cadrul
sistemului care ruleaz un program. Programele trebuie s conin
proceduri de tratare a acestor situaii excepionale.
In C++ s-a realizat un mecanism de tratare a excepiilor.
Astfel, o excepie este un obiect a crui adres este trimis dinspre
zona de cod, unde a aprut problema, ctre o zon de cod, care
trebuie s-o rezolve.
Paii care trebuie, n general, urmai n vederea tratrii
excepiilor n cadrul programelor C++ snt:
se identific acele zone din program, n care se efectueaz o
operaie despre care se cunoate c ar putea genera o excepie
i se marcheaz n cadrul unui bloc de tip try. In cadrul acestui
bloc, se tasteaz condiia de apariie a excepiei, i n caz
pozitiv se semnaleaz apariia excepiei prin intermediul
cuvntului- cheie throw;
se realizeaz blocuri de tip catch, pentru a capta excepiile
atunci cnd acestea snt ntlnite.
Blocurile catch urmeaz un bloc try, n cadrul crora snt tratate
excepiile.
Sintaxa pentru try:
try {
// cod
throw TipExcepie;
}
Sintaxa pentru throw:
throw TipExcepie;
Sintaxa pentru catch:
142

catch(TipExcepie)
{
// cod tratare excepie
}
Dac TipExcepie este "...", este captat orice excepie aprut.
Dup un bloc try, pot urma unul sau mai multe blocuri
catch. Dac excepia corespunde cu una din declaraiile de tratare a
excepiilor, aceasta este apelat. Dac nu este definit nici o funcie
de tratare a excepiei, sistemul apeleaz funcia predefinit, care
ncheie execuia programului n curs. Dup ce funcia este
executat, programul continu cu instruciunea imediat urmtoare
blocului try.
TipExcepie nu este altceva dect instanierea unei clase vide
(care determin tipul excepiei), care poate fi declarat ca:
class TipExcepie {};
n continuare vom prezenta un exemplu de program care utilizeaz
tratarea excepiilor.
#include <iostream.h>
#define MAXX
80
#define MAXY
25
class Point
{ public:
class xZero {};
class xOutOfScreenBounds {};
Point(unsigned x1, unsigned y1)
{ x =x1; y =y1; }
unsigned GetX() { return x; }
unsigned GetY() { return y; }
void SetX(unsigned x1)
{ if(x1 > 0)
if(x1 < = MAXX) x =x1;
else
throw xOutOfScreenBounds();
else
throw xZero();
}
143

void SetY(unsigned y1)


{ if( y1 > 0)
if( y1 < = MAXY) y =y1;
else throw xOutOfScreenBounds();
else throw xZero();
}
protected:
int x, y;
};
void main()
{ Point p(1, 1);
try
{ p.SetX(5);
cout<<"p.x successfully set to "<<p.GetX()<<"."<<
endl;
p.SetX(100);
}
catch(Point::xZero)
{ cout << "Zero value!\n"; }
catch(Point::xOutOfScreenBounds)
{ cout << "Out of screen bounds!\n"; }
catch(...)
{ cout << Unknown exception!\n"; }
}
Rezultatul ndeplinirii programului:
p.x successfuly set to 5.
Datorit faptului c excepia este instanierea unei clase, prin
derivare pot fi realizate adevrate ierarhii de tratare a excepiilor.
Trebuie de avut ns n vedere posibilitatea de apariie a unor
excepii chiar n cadrul codului de tratare a unei excepii, situaii
care trebuie evitate.
ntrebrile pentru verificarea cunotinelor:
1. Cum snt realizate excepiile n cadrul programelor C++ ? Dai
exemple.
144

Temele pentru acas:


1. Ce rezultate vor fi obinute la rularea urmtorului program:
void main()
{ cout<<nceput;
try{ // nceputul blocului try
cout<<interiorul blocului try \n;
throw 10; // generarea erorii
cout<<Aceasta nu se va executa;
}
catch (int i) {
cout<<Este prelucrat eroarea: ;
cout<<I<<\n;}
cout << Sfrit; }
Teme pentru lucrri de laborator:
1. Scriei un program care calculeaz numrul de elemente ale unui
fiier care snt mai mici ca valoarea medie aritmetic a tuturor
elementelor acestui fiier.
2. Scriei un program care compar dou fiiere date.
3. Scriei un program care determin numrul maximal i cel
minimal dintr-un ir de numere aleatoare dintr-un fiier.
Subconsecutivitatea de elemente dintre numrul maximal i cel
minimal determinat s se nregistreze ntr-un nou fiier.
4. Scriei un program care tiprete toate cuvintele diferite de
ultimul cuvnt dintr-un fiier. Cuvintele din fiier snt separate
prin virgul, iar.dup ultimul cuvnt se pune punct.
5. Scriei un program care formeaz un fiier nou selectndu-se din
trei fiiere date mai nti numerele negative, zerourile, apoi
numerele pozitive.
6. Scriei un program care ordoneaz lexicografic o consecutivitate
de nregistrri (dintr-un fiier) de tipul
struct { char nume [30];
int ani} nregistrare;
7. Scriei un program care formeaz un fiier nou din trei fiiere
date dup urmtoarea legitate: se selecteaz mai nti numerele
145

divizibile la 3, la 5 i la 7, apoi numerele pozitive pare de pe


locuri impare.
8. Scriei un program care sorteaz lexicografic cuvintele dintr-un
text. Pentru fiecare element sortat s se indice numrul de
repetri ale cuvntului n textul dat.
9. Scriei un program care din dou fiiere ordonate descresctor se
vor uni n unul nou n care se va pstra ordinea descresctoare
de sortare.
10. Scriei un program care va tipri n ordine invers
subconsecutivitatea de numere dintre valoarea minim i
maxim ale unei consecutiviti de numere citit dintr-un fiier.
11. Scriei un program care calculeaz suma nmulirii numerelor
vecine pe locuri pare dintr-un fiier dat.
12. Scriei un program care determin frecvena cu care a fost
generat fiecare element n fiierului creat. Valorile elementelor
snt cuprinse ntre 1 i 100.
13. Scriei un program care determin numrul maximal i cel
minimal din numerele unui fiier dat. S se determine
elementele mai mari ca cel minimal i mai mici ca numrul
maximal.
14. Scriei un program care formeaz un fiier nou din cel dat dup
urmtoarea legitate: elementele fiierului nou se obine din
inversul numerelor din fiierul dat.
15. Scriei un program care s formeze un fiier nou care conine
elementele a dou fiiere ordonate cresctor.Elementele
fiierului format va pstra ordinea cresctoare de sortare.
16. Scriei un program care efectueaz reformatarea unui fiier
textual n felul urmtor. Lungimea rndului de caractere n
fiierul nou are lungimea de 60 de caractere. Dac n rndul dat
se depisteaz punctul, restul rndului din fiierul dat se scrie
din rnd nou.

Bibliografia
1.

D. Somnea, D. Turturea. Introducere n C++. Programarea


obiect orientata. Bucureti, ed. Teora, 1993.
146

2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.

O. Catrina, L. Cojocaru. Turbo C++. Bucureti, ed. Teora,


1994.
D. Costea. Iniiere n limbajul C. Bucureti, ed. Teora, 1996.
D. M. Popovici, I. M. Popovici, I. Tnase. C++. Tehnologia
orientat pe obiecte. Aplicaii. Bucureti, ed. Teora, 1996.
L. Negrescu. Iniiere n limbajul C, C++. Cluj, 1996.
. . ++ . . ,
c, 1996
. . ++. . .,
, BHV, 1997.
. . ++.
, c, 1997.
G. D. Mateescu. C++ limbaj de programare. Bucureti, ed.
Petrion, 1998.
L. Negrescu. Limbajele C, C++ pentru nceptori. Cluj
Napoca, ed. Albastra, 2000, v.II.
. ++. .BINOM, 2000.
D. M. Popovici, I. M. Popovici, I. Tnase. C++. Tehnologia
orientat pe obiecte. Aplicaii. Bucureti, ed. Teora, 2002.

147

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