Documente Academic
Documente Profesional
Documente Cultură
Indrumarr
Indrumarr
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
CUPRINS
Introducere ..........................................................................
................................................
................................................
61
................................................
81
................................................ 107
................................................ 114
................................................ 133
................................................
Bibliografie .........................................................................
148
153
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
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
char *cp;
void *vp;
vp=cp;
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
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
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
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;
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:
{ 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:
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:
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
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
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
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
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
55
iniializarea listei;
57
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
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
...
};
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
{ 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
-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
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.
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
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
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.
101
virtual
class B2
class C
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
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
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
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
{ 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
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.
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
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
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
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
141
prelucrarea
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
Bibliografia
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
147