Sunteți pe pagina 1din 117

UNIVERSITATEA TITU MAIORESCU DIN BUCURETI

FACULTATEA DE INFORMATIC

Programare orientat pe obiecte n limbajul C++

-suport de curs pentru forma de nvtmnt la distan -

Confereniar univ. dr. Dsclescu Ana Cristina

- 2016 -

1
Introducere

Acest curs se adreseaz studenilor anului II, specializarea Informatic, forma de invatamant la
distan. Modul de prezentare ine cont de particularitile nvmntului la distan, la care studiul
individual este determinant.

Disciplina Programarea orientat pe obiecte utilizeaz noiunile predate la disciplinele Bazele


Informaticii, Programare procedural, discipline studiate n anul I.

Competenele dobndite de ctre studeni prin nsuirea coninutului cursului sunt folosite la
disciplinele de specialitate precum Programarea n Java, Tehnici avansate de programare,
Proiectarea interfeelor grafice etc. O nenelegere a noiunilor fundamentale prezentate n acest
curs poate genera dificulti n asimilarea conceptelor mai complexe ce vor fi introduse n aceste
cursuri de specialitate.

Principalele obiective ale disciplinei Programarea orientat pe obiecte sunt:


Programarea n limbaje de nivel nalt
Utilizarea instrumentelor informatice in context interdisciplinary
Utilizarea bazelor teoretice ale informaticii si a modelelor formale

Structura cursului este urmtoarea:

Unitatea de nvare 1. Introducere n programarea orientat pe obiecte


Unitatea de nvare 2. Clase i obiecte
Unitatea de nvare 3. Tablouri de obiecte. Date i membre statice
Unitatea de nvare 4. Clase derivate. Motenirea
Unitatea de nvare 5. Suprancarcarea operatorilor
Unitatea de nvare 6. Operaii de intrare/ieire
Unitatea de nvare 7. Facilitaii ale limbajului C++

2
Pachet software recomandat:

Orice IDE (Integrated Development Environment) pentru limbajul C++ poate fi folosit, dar pentru
a face o alegere, mai puin costisitoare, de altfel gratuit, v sugerm IDE-ul numit CodeBlocks
care se poate descrca de pe site-ul
https://sourceforge.net/projects/codeblocks/files/Binaries/16.01/Windows/codeblocks-16.01mingw-
setup.exe/download

Nota final care se va acorda fiecrui student, va conine urmtoarele


componente n procentele menionate:
- examen final 60%
- lucrari practice/ proiect 40%

Coordonator de disciplin
Conf. univ. dr. Ana Cristina Dsclescu

3
Unitatea de nvare Nr. 1

INTRODUCERE N PROGRAMAREA ORIENTAT PE OBIECTE

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui s:


intelegei conceptele progrmarii orientate pe obiecte;
realzai o paralel ntre programarea procedural i cea orientat
pe obiecte;
cunoatei elemnte specifice limbajului C++

Cuvinte cheie: abstractizarea datelor, tip abstract de date, ncapsulare, referine, pointer.

Timpul minim pe care trebuie s-l acordati acestui modul este de 4 ore.

Evoluia tehnicilor de programare a fost susinut de evoluia aplicaiilor informatice a cror


dimensiune este din ce n ce mai mare. A aparut necesitatea divizrii unei aplicaii n mai multe
module care s fie gestionate independent unul de cellalt. Astfel, din punct de vedere al
descompunerii programelor, s-au dezvoltat mai mute pradigme de programare:
Pradigma programrii structurate: un program este privit ca o mulime de blocuri i
proceduri (Fortran, Pascal, C, C++).

Algoritm + Structura de date = Program (Nikluas Wirth)

Paradigma programrii orientate pe obiecte: un program este construit dintr-o mulime de


obiecte care interacioneaz (C++, Java, C#)

Paradigma programrii concurente i distribuite: excecuia unui program este constituit


din aciuni multiple executate n mod paralel pe una sau mai multe maini (Java, Ada, Linda
etc.).

4
Paradigma programrii funcionale si logice: programul este descris prin funcii matematice
(LISP, Scheme, Pyton, Scala)
1.1 Abstractizarea datelor. Tipuri de date abstracte
Un tip de date predefinit poate fi privit ca o reprezentare a unui concept. De exemplu,tipul
predefinit float, mpreun cu operaiile definite asupra acestuia (+, -, *, etc.) reprezint o versiune
a conceptului matematic de numere cu virgul. Pentru alte concepte, care nu au o reprezentare
direct prin tipurile predefinite cunoscute de ctre limbajul de programare, se pot defini noi tipuri
de date care s specifice aceste concepte. De asemenea, aceste tipuri de date nu au ntotdeauna o
reprezentare unitar. Spre exemplu, o aplicatie pentru realizarea recensmntului persoanelor ar
putea necesita un tip de date Persoana, care s includ numele persoanei, vrsta, localitatea etc. O
alt aplicaie poate necesita tipul de date Persoana pentru calculul ntreinerii, caz n care se vor
lua n calcul pentru acest concept alte caracteristici, cum ar fi suprafaa locuit, numrul prsoanelor
aflate n ntreinere etc. Acest proces de grupare a datelor i metodelor de prelucrare specifice
rezolvarii unei probleme se numete abstractizare.

n cazul dezvoltrii unui aplicaii software, abstractizarea se poate defini ca fiind o structurare a
unei probleme n entitti bine precizate prin definirea datelor i a operaiilor asociate. Se definesc
astfel, tipurile de date abstracte, care pe lnga cele predefinite de limbaj, pot modela obiecte din
lumea real.

Un tip de date abstract (TDA) const dintr-o structur de date i o multime de operatii/funcii ce
prelucreaz/manevreaz structura de date. Mulimea de operaii reprezint interfaa unui TDA,
fiind acea poriune vizibil din exterior, n timp ce structura de date reperezint implementarea unui
TDA, fiind cu un cacater privat.

Un tip de date abstract (TDA) este caracterizat de urmtoarele proprietti:


1. definete un tip de date;
2. export o multime de operatii (furniznd interfaa TDA);
3. singurul mecanism de acces la structura de date a tipului este furnizat de operatiile definite
n interfat;

1.2 Concepte ale programrii orientate pe obiecte

Cele sase concepte de baz ce caracterizeaz programarea orientat pe obiecte sunt :


Obiectele;
Clasele;
Mesajele
Incapsularea;
Mostenirea
Polimorfismul.

5
Obiectele

Un obiect poate fi considerat ca fiind o entitate care ncapsuleaz att structuri de date, ct si
operaii care prelucreaz structura de date. Comportamentul unui obiect este dat de ctre operaiile
care definesc interfaa public. Cu ajutorul acestora se gestioneaz structura de date. Obiectele pot
fi de tipuri diferite: entitti fizice, algoritmi, relaii sau subsisteme.

Pentru tipul de date abstract Persoana, definit mai sus, un exemplu de obiect poate fi definit astfel:
Popescu Ion, 34, 56 m2 .

Clasele

Clasele reprezint implementarea concret a unui tip abstract de date. Ele desemneaz o colecie
de obiecte care au n comun faptul c pot fi caracterizate similar din punct de vedere informaional
i comportamental.

O clas reprezint o implemntare a tipului abstract de date. O declarare a unei clase definete un
tip nou care reunete date i funcii ce manevreaz structura de date.

Mesajele

Mesajul reprezint o aciune efectuat asupra unui obiect prin apelarea unei metode ncapsulate n
clas. Trimiterea unui mesaj care cere unui obiect s aplice o anumit actiune este similar cu apelul
unei proceduri din limbajele de programare procedural.

Un mesaj este o cerere adresat unui obiect pentru a invoca una din metodele sale. Astfel, un mesaj
conine numele metodei i argumentele metodei.

Exemplul : calculul intreinerii pentru obiectul Popescu Ion.

ncapsularea

ncapsularea se refer la capacitatea de a separa aspectele externe ale unui obiect (interfaa),
accesibile altor obiecte, de aspectele de implementare, interne obiectului, care sunt ascunse fa de
celelalte obiecte. Utilizatorul unui obiect poate accesa doar anumite metode ale acestuia, aflate ntr-
o seciune public, n timp ce atributele i celelalte metode rmn inaccesibile, aceste aflndu-se
ntr-o zon privat. Astfel, ncapsularea va mpiedica modificarea caracteristicilor unui obiect,
aplicaiile care utilizeaz obiectul folosindu-se doar de interfaa public a clasei.

6
Motenirea

Mecanismul derivarii permite crearea facila de noi clase, care preiau caracteristicile unor clase de
baza, deja definite. Derivarea are ca obiectiv reutilizarea soft-ului, prin folosirea unor funcii deja
scrise pentru clasele existente i eliminarea redundanei descrierilor, n cazul claselor care au
elemente comune, funcii sau date. Acest concept este prezentat n detaliu n moulul 3.

Polimorfismul

Termenul polimorfism se refer la comportamente diferite ale unor metode din clase care se afl
ntr-o ierarhie. n cazul n care mai multe clase mostenesc atributele i comportamentele unei clase
de baz, pot apare situaii n care comportamentul unei clase derivate este diferit de cel al clasei de
baz sau de cel al clasei derivate de tip frate (de pe acelasi nivel). n consecin, un mesaj poate
avea efecte diferite n funcie de tipul obiectului care primeste mesajul.

Spre exemplu s considerm trei clase: clasa de baz Student si clasele derivate
Student_Informatica i Student_Medicina care mostenesc toate atributele i comportamentele
clasei Student. Un mesaj care va activa comportamentul Medie al unui obiect al clasei
Student_Informatica conduce la o formul de calcul n care nota obinut la o prob practic are o
pondere de 30%, n timp ce comportamentul Medie al unui obiect al clasei Student_Medicina
conduce la o formul de calcul n care nota obinut la o prob practic are o pondere de 70%.

1.3 Elemente ntroductive ale programrii orientate pe obiecte n limbajul


C++
Limbajul C++ este unul dintre cele mai utilizate limbaje de programare orientate pe obiecte.
Elaborat de ctre B . Stroustrup n anul 1980 n laboratoarele Bell din Murray Hill, New Jersey,
limbajul C++ este o versiune extins a limbajului C. Extensiile dezvoltate de Stroustrup pentru
limbajul C++ permit programarea orientat pe obiecte, pstrnd eficiena, flexibilitatea i concepia
de baz a limbajului C. Numele iniial a fost C cu clase, numele de C++ fiindu-i atribuit n anul
1983.

De la apariia sa, C++ a trecut prin trei revizii, n 1985, 1989 i ultima, prilejuit de definirea
standardului ANSI pentru acest limbaj. O prim versiune a standardului a fost publicat n anul
1994, iar urmtoarea versiune este nc n lucru.

n acest capitol sunt prezentate concis conceptele de baz n programarea C++, att cele care sunt
preluate din limbajul C ct i cele nou introduse.

7
Operatii de intrare/iesire. Fluxuri (stream-uri)

Sistemul de intrri/ieiri al limbajului C++ are la baz noiunea de flux (stream).


Un stream este un concept abstract care reprezint un flux de date unidirecional de la o surs la o
destinaie.
Limbajul C++ pune la dispoziie o ierarhie de clase pentru gestiunea unui flux de intrare/ieire.
La nceperea execuiei unui program C++, n mod automat se deschid trei streamuri standard
ncorporate:
cin - Intrare standard Tastatur
cout - Ieire standard Ecran
cerr -Ieire standard pentru eroare Ecran

Operaiile de scriere/citire a unei valori const n inserarea/extragerea sa ntr-un/dintr-un flux,


folosind operatorii << / >>. De exemplu, urmtorul program va scrie pe ecran mesajul Primul
program n C++!, urmat de o linie nou:

#include <iostream.h>
int main(){
cout << Primul program in C++!<< endl;}

Operaia de citire de la tastatur poate fi realizat n limbajul C++ printr-o instruciune care
folosete operatorul >>. De exemplu, n instruciunea urmtoare se citete de la tastatur un numr
ntreg:

int i;
cin >> i;

Exemplul P1_1 prezint un exemplu de utilizare a operatiilor de intrare/iesire n limbajul C++.

// fisierul sursa P1_1.cpp


#include <iostream.h>
int main()
{
int a, b;
float m;
cout << "\n Introduceti un numar intreg a = ";
cin >> a;
cout << "\n Introduceti un numar intreg b = ";
cin >> b;
m = (float) (a+b)/2;

8
cout << "\n Media aritmetica este " << m;
}

Programul P1_1 citeste dou numere ntregi, a si b si calculeaz media lor aritmetic, m, pe care
o afiseaz pe ecran. Citirea celor dou numere se poate realiza si cu o singur operatie de citire,
aa cum se observ n programul P1_2

Exemplul P1_2
// fisierul sursa P1_1_v2.cpp
#include <iostream.h>
int main()
{
int a, b;
float m;
cout << "\n Introduceti doua numere intregi: ";
cin >> a >> b;
m = (float) (a+b)/2;
cout << "\n Media aritmetica este " << m;
}

Sintaxa operatiei de intrare (citire):


cin >> var_1 >> var_2 >> >> var_n;

Se citesc de la dispozitivul de intrare valorile variabilelor var_1, var_2, , var_n.

Sintaxa operaiei de ieire (scriere, afiare):

cout << expr_1 << expr_2 << << expr_p;

Se afiseaz pe ecran valorile expresiilor expr_1, expr_2, , expr_p. Expresiile pot fi expresii
aritmetice, variabile sau pot conine text, ce este marcat ntre ghilimele (). Textul poate contine
secvente de tipul \n (trecere la linie nou), \t (afisarea se face la dreapta n pozitia dat de tab), \a
(avertizare sonor) etc.

1.4 Tipuri de date

n C++ sunt definite urmtoarele tipuri fundamentale:


1. Tipuri de date aritmetice:
a) tipul ntreg, utilizat pentru definirea numerelor ntregi
short int 2 octei

9
int 2 sau 4 octei
long 4 sau 8 octei

b) tipul pentru numere flotante, pentru definirea numerelor reprezentate cu cu virgul flotant:
float 4 octei
double 8 octei
long double 12 sau 16 octei

2. Tipul caracter, pentru definirea caracterelor


char 1 octet

3. Tipul void specific o mulime vid de valori. Acest tip poate fi utilizat pentru conversii de
pointeri sau ca tip de returnare al unei funcii, ns nu se poate declara o variabil de tip void.

Pe langa tipurile de date fundamentale enumerate, se pot defini conceptual un numr infinit de
tipuri derivate pornind de la tipurile fundamentale. Tipurile derivate sunt:
tablouri de obiecte
pointeri la obiecte
referine
funcii
constante simbolice
clase, structuri, uniuni
pointeri la membrii claselor.

n continuare se vor prezenta primele cinci tipuri derivate, iar celelate vor fi introduse pe parcursul
seciuniunilor urmtoare.

Tablouri de obiecte

Un tablou este o structur omogen, format dint-o mulime finit de elemente de aceelai tip,
numit tip de baz. Fiecare element, cu excepia ultimului, are un suucesor unic.
Elementele unui tablou de obiecte pot fi: obiecte dintr-un tip fundamental (cu excepia tipului void),
pointeri, enumerri sau alte tablouri.
Fiecare element, cu excepia ultimului, are un suucesor unic, iar localizarea sa se realizeaz printr-
un sistem de indici.
Din punct de vedere fizic, tabloului i se aloc o zon continu de memorie, de dimiensiune fix,
care este mprit n locaii de aceeai dimensiune.

Declararea unui tablou unidimensional tab format din dim obiecte de tipul T (dim trebuie s fie o
constant de tip ntreg) se realizeaz prin:
T tab[dim];

10
Tabloul tab va avea cele dim elemente numerotate de la 0 la 1, respectiv:
[0], [1], , [ 2], [ 1].

ntr-un mod asemntor se poate declara un tablou bidimensional de obiecte de tipul T:


T tab[dim_1][dim_2];
n acest caz, tabloul bidimensional tab va fi considerat ca fiind un tablou unidimensional de
dimensiune dim_1, fiecare element al su fiind un tablou unidimensional de dimensiune dim_2.
Elementele unui astfel de tablou bidimensional se memoreaz astfel:

A[0][0], A[0][1], ..., A[0][dim_2-1],


A[1][0], A[1][1], ..., A[1][dim_2-1],
..................................................
A[dim_1-1][0], A[dim_1-1][1], A[dim_1-1][dim_2-1]

Tipul de date pointer

Pentru un tip de date T, T* este un tip denumit pointer la T, adic o variabil de tipul T*
memoreaz adresa unui obiect de tipul T.
Operaia fundamental asupra unui pointer este operaia de derefereniere (dereferencing), adic
accesarea obiectului a crui adres o reprezint pointerul respectiv. Operatorul de derefereniere
este operatorul unar *.
Exemplu:
char c = a; // variabila c1
char* p = &c; // p memoreaz adresa lui c1
char x= *p; // dereferentiere, x = a;
Operatorul & este operatorul adres, care se utilizeaz pentru a obine adresa unei variabile.

Observaie: Tipul void* poate fi folosit pentru a indica adresa unui obiect de tip necunoscut.

Asupra pointerilor sunt admise anumite operaii aritmetice:


1. adunarea/scderea unui numr natural
int x, *p;
p=&x;
n acest caz p+n reprezint adresa octetului aflat peste n*sizeof(int) octei fa de adresa memorat
n p.
2. Incrementarea/decrementarea
int x, *p;
p=&x;
p++;// adresa octetului aflat peste sizeof(int) octei fa de adresa memorat n p.

11
De exemplu, se consider un vector de caractere dintre care ultimul este caracterul 0. Pentru
calculul numrului de caractere se pot folosi operaii cu pointeri astfel:
int strlen(char* p){
int i = 0;
while (*p++) i++;
return i;
}

Funcia strlen() returneaz numrul de caractere ale irului, fr caracterul terminal 0, folosind
operaia de incrementare a pointerului i operaia de derefereniere pentru a testa valoarea
caracterului. O alt implementare posibil a funciei este urmtoarea:
int strlen(char* p){
char* q = p;
while (*q++);
return q-p-1;
}

n C++, ca i n limbajul C, numele al unui tablou reprezint adresa primului element:

int sir[] = {1,2,3,4,5};


int* p =sir;
int* q = &sir[0]; // p = q

De exemplu, + 1 va indica urmtorul element al tabloului, iar 1 va indica elementul


precedent al tabloului.

3. Diferena a doi pointeri

Diferena a doi pointeri reprezint numrul de octei aflat ntre cele dou zone de memorie referite.
int x, y;
int *p=&x;
int *q=&y;
Valoarea p-q este un numr egal cu numrul de valori ntregi cuprinse ntre cele dou adrese
memorate de cei doi pointeri.

Referine

O referin (reference) este un nume alternativ al unui obiect , numit i alias. Utilizarea principal
a referinelor se face pentru transmiterea argumentelor unei funcii, precum i a valorilor returnate
de funcii. O alt aplicabilitate a lor este i pentru procesul de suprancrcarea a operatorilor.
Notaia T& nseamn referin la un obiect de tipul T.

12
De exemplu:
int a = 1;
int& b = a; // b i a se refer la aceeai entitate
int x = a; // x = 1
b++; // a = 2;

Aa cum se poate observa, pentru definirea unei referine se folosete operatorul adres &, dar
difer tipul construciei n care este folosit. De exemplu:

int a = 5;
int* pi = &a; // & calculeaz adresa;
// pi este adresa lui a
int& r = a; // & introduce o referinta;
// r este o referin (alt nume) pt. a

O referin este utilizat ca argument pentru o funcie care poate s modifice permanent valoarea
acestui argument. De exemplu:

void incr(int& x) {x++;}


void f(){
int i = 1;
incr(i); // i = 2;
}

O alt utilizare important a referinelor este pentru definirea funciilor care pot fi folosite att ca
membru drept ct i ca membru stng al unei expresii de asignare. De exemplu:

#include <iostream.h>
int& fr(int v[], int i){
return v[i];
}
int main(){
int x[] = {1,2,3,4};
fr(x,2) = 7;
cout <<fr(x,0)<<fr(x,1)<<fr(x,2)<< fr(x,3)<<endl;
}

La execuia acestui program se obine mesajul:


1 2 7 4
Deoarece valoarea returnat de funcie este referina (numele) unui element al vectorului, acesta
poate fi modificat prin folosirea funciei fr() ca membru stng al egalitii.

13
Funcii

Una dintre cele mai importante caracteristici ale limbajelor C i C++ o reprezint funciile. O
funcie este un bloc independent de instruciuni, identificat printr-un nume, care are rolul de a
realiza o anumit prelucrare a datelor de intrare. Orice program C/C++ const din mai multe funcii,
dintre care una este obligatoriu funcia predefinit main. n momentul rulrii unui program, prima
dat va fi executat funcia main. Restul funciilor definite n cadrul programului se vor executa
doar n momentul n care ele vor fi apelate. O funcie se definete astfel:

tip_returnat nume_func(lista_parametrilor_formali) {
corpul funciei
}

n limbajul C, o funcie pot returna fie o singur valoare, folosind instruciunea return, fie poate s
nu returneze nimic, caz n care tipul returnat va fi considerat void. Numele unei funcii nume_func
trebuie s o identifice n mod unic n cadrul unui program i va fi folosit pentru apelul su. n
lista_parametrilor_formali sunt specificai parametrii funciei, separai prin virgule, pentru fiecare
dintre ei fiind specificat tipul de date corespunztor. Dac o funcie nu are nici un argument, atunci
lista parametrilor si formali va fi vid.

Corpul unei funciei este definit ntr-un bloc de instruciuni, delimitat de acolade, i conine
declarri de variabile i instruciuni. Variabilele declarate ntr-o funcie sunt locale i se memoreaz
n segmentul de stiv asociat programului. Parametrii formali ai unei funcii sunt considerai, la
rndul lor, ca fiind variabile locale ale funciei.

Apelul unei funcii se realizeaz prin numele su i prin lista parametrilor efectivi. Parametrii
efectivi pot fi constante, variabile sau expresii.

int exemplu(int a, double f){


int v = a+f;
return v;
}
int main{
int x = exemplu(7, 11);

n momentul apelului unei funcii, parametrii efectivi iniializeaz parametrii formali din declaraia
funciei, n ordinea din declaraie. Parametrii unei funcii se pot transfera n dou moduri: prin
valoare sau prin referin.

14
n cazul apelului prin valoare se copiaz valoarea parametrului efectiv n parametrul formal
corespunztor. Astfel, modificrile efectuate asupra parametrului formal nu se reflect i asupra
parametrului efectiv.

n cazul apelului prin referin este accesat direct variabila din parametrul efectiv transmis
funciei, care va fi, deci, modificat. De exemplu, definim o funcie swap() care interschimb
valorile a dou variabile. Dac nu se folosesc referine, argumentele de apel ale funciei trebuie s
fie pointeri la variabilele respective. Pointerii, ca parametrii de apel, nu vor fi modificai, dar
variabilele indicate de acetia pot fi modificate. Funcia swap() cu parametrii de tip pointer este
urmtoarea:
void swap(int* x, int* y){
int t;
t = *x; // dereferentiere
*x = *y;
*y = t;
}
Aceeai funcie swap(), folosind parametrii de tip referin, se definete astfel:
void swap(int& x, int& y){
int t;
t = x;
x = y;
y = t;
}

Se poate observa perfecta simetrie ntre cele dou implementri i c, n mod evident, referina
folosete adresa variabilei pentru a o putea modifica (deci un pointer). Dar, n cazul referinelor,
pointerul i defererenierea sunt ascunse, programatorul nu trebuie s le prevad explicit, programul
rezultat este mai concis i mai clar.

Referinele sunt deosebit de utile n apelul funciilor ale cror argumente sunt obiecte de dimensiuni
mari i copierea lor n argumentele formale (plasate n segmentul de stiv al programului) ar fi
foarte ineficient.

1.4 Operatori specifici C++

Majoritatea operatorilor C++ sunt preluai din limbajul C, cu aceeai sintax i reguli de operare.
n plus fa de operatorii C, n C++ mai sunt introdui urmtorii operatori:
operatorul de rezoluie (::)
operatorii de alocare-eliberare dinamic a memoriei new i delete.

15
Operatorul de rezoluie

Operatorul de rezoluie (::) este folosit pentru modificarea domeniului de vizibilitate al unui nume.
Acesta permite folosirea unui identificator ntr-un bloc n care el nu este vizibil.
Exemplu:

int var_globala=1;
int main()
{
int var_globala=2;
cout<<var_globala; //se afiseaz 2
cout<<::var_globala; //se afiseaz 1
}

n acest exemplu operatorul de rezoluie a fost folosit pentru a accesa variabila global ascuns de
variabila local cu acelai nume din funcie. Deoarece utilizarea cea mai extins a operatorului de
rezoluie este legat de utilizarea claselor, el va fi reluat pe parcursul seciunilor urmtoare.

Operatorii new i delete

n limbajul C se pot aloca dinamic zone n memoria liber (heap) folosind funcii de bibliotec (de
exemplu, malloc(), calloc(), realloc()) i se pot elibera folosind funcia free(). n limbajul C++ se
adaug operatorii de alocare i eliberare dinamic a memoriei, new i delete.

Pentru alocarea unei singure variabile, operatorul new are urmtoarea form general:

tip_data* p = new tip_data(initializare);

unde tip_data este un tip de date predefinit sau definit de utilizator (clas), p este pointerul
(adresa de nceput) a zonei alocate n memoria liber, returnat la execuia operatorului new, iar
initializare este o expresie care depinde de tipul datei i permite iniializarea zonei de memorie
alocate. Dac alocarea nu este posibil, pointerul returnat este NULL.

Forma de utilizare a operatorului new pentru alocarea unui vector de date (tablou unidimensional)
de dimensiune dim, este urmtoarea:
tip_data* p = new tip_data[dim];
La alocarea unui vector nu se poate transmite o expresie de iniializare a zonei de memorie alocat.
Operatorul delete elibereaz o zon din memoria heap. El poate avea una din urmtoarele forme:

16
delete p; delete []p;

Exemple:
int *pi = new int(3); // alocare int i iniializare
double *pd = new double; // alocare double neinitializat
char *pc1 = new char[12]; // vector de 12 caractere
char *pc2 = new char[20]; // vector de 20 caractere
delete pi;
delete pc1; //corect, char e tip predefinit
delete []pc2; // corect, elibereaza vector

17
Teste de autoevaluare

1.1 Care din afirmatiile urmtoare sunt adevrate si care sunt false? Justificati rspunsul n cazul
afirmatiilor care sunt false.
(a) Toate variabilele trebuie declarate nainte de a fi utilizate.
(b) Un program C++ care afiseaz trei linii pe ecran trebuie s contin 3
instructiuni de afisare cout.
(c) Comentariile dintr-un program C++ determin afisarea textului aflat dup // pe
ecran la executia programului.
(d) n limbajul C++ toate variabilele locale trebuie declarate la nceputul funciei
de care aparin.
1.2 Definii tipul de date abstract STIVA
Se vor specifica: structura de date, operatorii de baz.

1.3 Care din urmtoarele concepte sunt concepte de baz ale programrii orientate pe obiecte?
(a) obiect
(b) mostenire
(c) metod
(d) ncapsulare
(e) modul
(f) procedur
(g) polimorfism
(h) stream
(i) cout

18
Rspunsuri - teste de autoevaluare

1.1
(a) adevrat
(b) fals: o singur instructiune cout cu secvene \n multiple poate afisa mai multe linii.
(c) fals: comentariile au doar rolul de a documenta un program.
(d) fals: n limbajul C++ declaraiile de variabile locale pot s apara la prima utilizare
a acestora si eliminandu-se, obligativitatea declarrii lor la nceputul funciei de care
apartin.

1.2
Stuctura de date:
stiva
dim_max
Operatii de baza:
stiva_noua( )
pune_element(stiva, r)
scoate_element(stiva)
stiva_vida(stiva)
stiva_plina(stiva)
varful_stivei(stiva)
numar_elemente(stiva)

1.3
(a), (b), (d), (g)

Aplicaii practice:
1. Se consider definite dou subprograme:
- Subprogramul s1, cu 3 parametri, care primete prin intermediul parametrului a un tablou
unidimensional cu numere ntregi de cel mult 4 cifre fiecare, prin intermediul parametrului n
numrul de elemente ale tabloului, iar prin intermediul parametrilor p i q (0p<q<100)
poziiile a dou elemente ale tabloului. Subprogramul furnizeaz prin intermediul
parametrului p poziia primului element par (dac exist), i prin intermediul parametrului q
poziia ultimului element impar (dac exist), din secvena , +1 , , . Dac aceast
secven nu conine niciun element par subprogramul va furniza prin intermediul lui p

19
valoarea -1, iar dac nu conine niciun element impar, va furniza prin intermediul lui q
valoarea -1.
- Subprogramul s2, cu doi parametri, a i b, dou numere ntregi cu cel mult 4 cifre fiecare;
subprogramul interschimb valorile a dou variabile transmise prin intermediul parametrilor
a i b.
a) Scriei definiia complet a subprogramelor s1 i s2.
b) Scriei un program C++ care:
- citete de la tastatur un numr natural nenul n, apoi cele n elemente ale unui ir a.
- determin rearanjarea elementelor irului astfel nct toate valorile pare s fie plasate la
sfritul irului a, folosind apeluri utile ale subprogramelor s1 i s2;

Exemplu: pentru n=5 i a=(2,3,4,7,5) se va afia 7 5 3 4 2.

2. Se citete un vector cu numere ntregi ( 2). S se aloce dinamic doi vectori care s conin
elementele pozitive din vector, respectiv pe cele negative.

3. Scriei un program C++ care citete de la tastatur un numr natural format din cel mult patru
cifre, construiete n memorie un tablou bidimensional neregulat cu elemente ntregi de forma
indicat mai jos i apoi afieaz pe ecran tabloul obinut.

4. Scriei un program C++ care citete de la tastatur un numr natural format din cel mult patru
cifre, construiete n memorie un tablou bidimensional neregulat cu elemente ntregi de forma
indicat mai jos i apoi afieaz pe ecran tabloul obinut.

1
12
123
1234
.........
1 2 3 4 5 .........n

5. La departamentul de training se primete o list de cursuri, mpreun cu intervalul desfurare


corespunztor. Directorul dorete s printeze o list cu aceste cursuri sortate cresctor dup ora
de nceput. Scriei un program care s il ajute pe directorul departamentului de training.

Lista cursuri Lista cursuri ordonate


7
10:00-11:20 Java 08:20 - 09:50 Linux
09:30-12:10 Baze de date 09:30 - 12:10 Baze de date
08:20-09:50 Linux 10:00 - 11:20 Java
11:30-14:00 Structuri de date 11:30 - 14:00 Structuri de date
12:10-13:10 Algoritmi 12:10 - 13:10 Algoritmi
14:00-16:00 Javascript 14:00 - 16:00 Javascript
15:00-15:30 PHP 15:00 - 15:30 PHP

20
Unitatea de nvare Nr. 2

CLASE I OBIECTE

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui:


s construii noi tipuri de date;
s ingelegei care este structura unei clase;
s instaniati o clas;
s aplelai metodele unui obiect;
s manageriai accesul la datele membre.

Cuvinte cheie: clase, obiecte, constructori, destructor, funcii inline, funcii friend.

Timpul minim pe care trebuie s-l acordati acestui modul este de 4 ore.

Un tip de date predefinit poate fi privit ca o reprezentare a unui concept. De exemplu, tipul primitiv
float, mpreun cu operaiile definite asupra acestuia (+, -, *, etc.) reprezint o versiune a conceptului
matematic de numere cu virgul. Pentru alte concepte, care nu au o reprezentare direct prin tipurile
predefinite, se pot defini noi tipuri de date care s specifice aceste concepte. De asemenea, aceste
tipuri de date nu au ntotdeauna o reprezentare unitar. Spre exemplu, o aplicatie pentru realizarea
recensmntului persoanelor ar putea necesita un tip de date Persoana, care s includ numele
persoanei, vrsta, localitatea etc. O alt aplicaie poate necesita tipul de date Persoana pentru calculul
ntreinerii, caz n care se vor lua n calcul pentru acest concept alte caracteristici, cum ar fi suprafaa
locuit, numrul persoanelor aflate n ntreinere etc.

Definirea un nou tip de dat care s modeleze un anumit concept se poate realiza prin definirea unui
tip de dat compus, distinct, care s fie cunoscut limbajului de programare. Astfel de tipuri de date
compuse apar prin alaturarea de variabile cu tipuri de date deja existente; spre exemplu, pentru a
reprezenta o dat calendaristica, ar putea fi suficient s cream un tip de date care ncapsuleaz 3
variabile de tip int - pentru zi, luna si an. n schimb, pentru tipul de date Persoana, este nevoie de o
variabila de tip String pentru numele persoanei, una de tip int pentru vrst etc. Desigur, nu este
suficient doar s definim tipul de date abstract prin compunerea mai multor date de tip predefinit, ci

21
este necesar s se stabileasc i care setul de operaii ce se va excuta aspura datelor componente,
precum i care sunt restrictiile pentru fiecare n parte.

O clasa reprezinta structura unui nou tip de date definit de ctre programator, spre deosebire de
predefinit a cror structura este deja cunoscuta compilatorului. Pe baza clasei putem construi
obiecte, care sunt date de acel nou tip; crearea de obiecte ale unei clase poarta numele de instaniere
a clasei n cauza. Fiecare obiect este o instan a clasei, aa cum mai multe aparate de acelasi fel pot
fi construite pornind de la aceeasi schema electronica. La clase diferite vor corespunde tipuri de
obiecte diferite, aa cum din doua scheme electronice distincte obinem doua tipuri de aparate
distincte.

Definiie. O clas este implementarea unui tip abstract de date (TDA).


Ea definete atribute i metode care implementeaz structuri de date i operaii ale unui TDA.

Definiie. Un obiect este o instant a unei clase.


El este unic identificat de numele lui i definete o stare care este reprezentat de valorile atributelor,
la un moment dat. Starea unui obiect se poate schimba prin metodele publice care i sunt aplicate.

Definiie. Comportamentul unui obiect este definit de mulimea metodelor care i pot fi aplicate.

Definiie. O metod este o funcie asociat unei clase. Un obiect apeleaz (invoc) o metod drept
reactie la primirea unui mesaj.

Primul pas pentru gruparea datelor i metodelor de prelucrare, l-au reprezentat stucturile; ele
permiteau declararea unor ansambluri eterogene de date ce erau manipulate unitar.

Exemplu: Se definete un nou tip de dat Angajat care curinde urmatoarele date: nume, varsta,
salariul.

struct Angajat
{
char nume[20];
int varsta;
float salariul;
}

Declaratii de variabile:

Angajat a1; // o structura de tip angajat p1


Angajat tablouangajat[10]; // un tablou cu zece elemente de tip angajat
Angajat *a2; // un pointer catre o structura de tip angajat a2

22
Angajat &a3=a1; // o referinta catre o structura de tip angajat a3

Membrii unei structuri sau ai unei clase sunt accesai cu ajutorul operatorilor de acces: operatorul
., respectiv, operatorul ->.
Operatorul . acceseaz o structur sau un membru al unei clase prin numele variabilei pentru
obiect sau printr-o referint la obiect.
Operatorul -> acceseaz un membru al unei structuri sau clase printr-un pointer la obiect.

In aplicatia P2_1 se implementeaz tipul de date Angajat cu ajutorul unei unei structuri C. Functia
afisare( ) are rolul de a afia datele unui angajat. Programul realizeaz constructia tipului de data
abstract Angajat prin definirea unei structuri, setarea valorilor pentru cmpurile structurilor (membrii
structurilor) i afisarea acestora.

// fisierul sursa P2_1.c


#include <stdio.h>
#include <conio.h>
#include <string.h>
// definitia structurii angajat
struct angajat {
char num[20];
int varsta;
float salariul;
} a1 = {"Pop", 28,1530};
// definitia funciei de afisare a datelor unei angajat
void afisare(struct angajat a)
{
printf("\n Nume \t Varsta \t Salariul");
printf("%s\t%i\t%d",a.nume,a.varsta,a.salariul);
}
int main()
{
struct angajat a2;
strcpy(a2.nume, "Ion");
a2.varsta = a1.varsta; a2.salariul = 1600;
printf("\n Angajat nr 1 \n");
afisare(a1);
printf("\n Angajat nr 2 \n");
afisare(a2);
getch();
}

23
2.1 Definirea unei clase
Clasele permit programatorului s modeleze obiectele care au atribute (reprezentate de datele
membre) si comportament (reprezentat de funciile membre, numite si metode). Practic, o clas
ncapsuleaz o multime de valori si o multime de operatii.

Sintaxa definirii unei clase:

class <nume_clas>
{
private:
// membrii privati
public:
// membrii publici
protected:
// membrii protejati};

Cuvntul-cheie class introduce declaraia clasei (a tipului de date) cu numele nume_clasa. Clasa se
consider i definit dac declaraia ei este urmat de corpul clasei cuprins n blocul definit de
perchea de acolade.

Observaie: Dac declaraia conine numai cuvntul-cheie class i numele clasei, atunci aceasta
este doar o declaraie de nume de clas.

Corpul unei clase conine definiii de date membre ale clasei i definiii sau declaraii de funcii
membre ale clasei, desprite printr-unul sau mai muli specificatori de acces. Un specificator_acces
poate fi unul din cuvintele-cheie din C++:

public private protected

Specificatorul public asigur un acces din afara clasei la datele i la metodele membre. Astfel,
seciunea public a clasei mai este denumit i interfaa clasei. n acest seciune, se ncapsuleaz,
de regul, metodele membre ale clasei. Acestea vor oferi un comportament la un moment dat al unui
obiect de tipul clasei.

Specificatorul private asigur o protecie de acces a datelor/metodelor membre, accesul la acestea


fiin limitat doar la interiorul clasei. Acesat seciune este denumit implementarea clasei i cuprinde,
de regul, stuctura de date a clasei.

24
Specificatorul protected asigur o protecie de acces la datele sau funciile membre ale clasei
respective, acestea fiind accesibile din interiorul clasei sau din interiorul claselor care se afl ntr-o
ierarhie definit prin mecanismul de derivare al claselor.

Observaie: Implicit, dac nu se declar nici un specificator de acces, datele sau funciile membre
sunt de tip private.

Astfel, toate datele sau funciile declarate de la nceputul blocului clasei pn la primul specificator
de acces sunt de tip private. n interiorul clasei, un specificator de acces se poate schimba ori de cte
ori se dorete: unele declaraii sunt trecute public, dup care se poate reveni la declaraii private, etc.

2.2 Definirea obiectelor


Dup definirea unei clase C, denumirea aceasteia poate fi utilizat ca tip de data pentru definirea
obiectelor, tablourilor de obiecte si a pointerilor, astfel:

C o1, // obiect de tip C


C Tablou[20], // tablou de obiecte de tip C
C *ptrC, // pointer la un obiect de tip C
C &tC = o1; // referinta la un obiect de tip C

Numele unei clase devine specificator de tip si se pot defini, teoretic, o infinitate de obiecte ale clasei.

Accesarea membrilor publici ai unei clase

Membrii publici ai unei clase pot fi accesai cu ajutorul operatorilor . , dac obiectul este alocat
static, sau cu operatorul ->, dac obiectul este alocat dinamic.

Observaie: Variabilele membru private nu pot fi accesate dect n cadrul metodelor clasei
respective.

In aplicatia2.2 se implementeaz tipul de date angajat sub forma unei clase C++. Clasa Angajat
cuprinde datele membre: varsta, salariul, nume si funcii membre: init() pentru initializarea datelor
membre, funciia membra de acces spune_varsta(), functia afisare() pentru afisarea datelor membre.

class Angajat
{
private:
int varsta;
protected

25
float salariul;
public:
char nume[20];
void init ( char n[]=Anonim, int v=0, float s=0)
{strcpy(nume,n);
varsta=v;
salariul=s;}
int spune_varsta() { return varsta};
void afisare()
{cout<<nume: <<nume<<endl;
cout<<varsta: <<varsta<<endl;
cout<<salariul: <<salariul;
}};

int main()
{ Angajat a;
a.init(); // apelul funciei membre init() pentru obiectul a
cout<<a.spune_varsta();//apelul funciei membre soune_varsta()
} pentru obiectul a

Dupa rolul pe care l joaca n cadrul clasei, funciile membre ale unei clase se mpart n patru
categorii:
constructori, responsabili cu crearea obiectelor;
destructor, reponsabil cu distrugere obiectelor i eliberarea memoriei ocupate de acesta;
funcii de acces, care mediaz legatura obiectului cu exteriorul;
metode, funcii care introduc operaiile i prelucraile specifice obiectului.

2.3 Constructori si destructor


Utilizarea unor funcii membre ale unei clase, aa cum este metoda init() din clasa angajat, pentru
iniializarea obiectelor nu este o metod elegant. D asemenea poate induce i anumite erori de
programare, deoarece nu exist nici o constrngere din partea limbajului ca un obiect s fie iniializat
(de exemplu, nu apare nici o eroare de compilare dac nu este apelat funcia init() pentru un obiect
din clasa Angajat), programatorul poate s uite s apeleze funcia de iniializare sau s o apeleze de
mai multe ori. n cazul simplu al clasei prezentate ca mai sus, acest lucru poate produce doar erori
care se evideniaz uor. n schimb, pentru alte clase, erorile de iniializare pot fi dezastruoase sau
mai greu de identificat.
Din aceast cauz, limbajul C++ prevede o modalitate elegant i unitar pentru iniializarea
obiectelor de tipuri definite de utilizator, prin intermediul unor metode speciale numite metode
constructor.

26
Constructorul este o metod membr special care este apelat automat atunci cnd este creat un
obiect. El poarta numele clasei i nu are nici un tip, deoarece este apelat automat.
Avantajele utilizrii metodelor constructor sunt:
complexitatea structurii obiectelor date de de existena variabilelor i a funciilor, de existena
seciunilor privat, public i protejat, face dificil initializarea directa a obictelor;
exist situaii n care doar unele date membre trebuie inializate, altele sunt ncarcate n urma
apelarii unor metode;
datele de obicei sunt declarate n seciunea privat i deci nu pot fi accesate din exteriorul unei
clase, ci prin intermediul metodelor publice.

O clas poate meniona mai multi construcori, prin suprancarcare, folosirea unuia dintre ei la
declararea unei variabile de clas, fiind dedus n funcie de numarul i tipul parametrilor de apel.

Vom definii clasa Angajat pentru care vom defini doi constructori astfel:

class Angajat
{int varsta;
float salariul;
char nume[20];
public:
Angajat() { strcpy(nume,Noname); varsta=0;salariul=0}
Angajat(char *n, int v, float s)
{strcpy(nume,n);varsta=v;salariul=s;}
char *spune_nume(){return nume;}
int spune_varsta(){return varsta;}
}

n clasa Angajat s-au definit doi constructori:


- un constructor fara parametru care inializeaz datele membre cu valori constante
(implicite); constructorul fara parametrii se numeste constructor impicit;
- al doilea constructor primeste trei parametri si are ca scop iniializarea datelor membre
din variabile elemntare; un asfel de constructor se numeste constructor cu argumente.

Constructorii definii mai sus se pot apela asfel:


Angajat a1 // aplelul constructorului implicit
Angajat a2(Pop,28,1200) //apelul constructorului cu argumente.
Dac clasa nu menioneaz nici un constructor n interiorul unei clase, atunci compilatorul definete
unul automat care nitializeaz toate datele membre cu valori reziduale, selectate n mod aleator.

Astfel, este recomandat ca o clas s menioneze mai multi constructori deoarece modurile de
inializare a datelor membre sun diverse:

27
iniializarea membrilor cu constante;
inializarea din datele elementare;
iniializarea prin citire de la tastatura;
iniializarea prin citire din fisier;
iniializarea din datele unui obiect existent.

Observaie. La crearea unui obiect este selectat un singur constructor care este apleat o singur
dat.

Aplicaia 2.3 impementeaz clasa Complex care descrie conceptul matematic de numar complex.
Clasa conine datele membre: partea real a numarului complex re, partea imaginar a numarului
complex im. Vor fi definii trei constructori Complex(), Complex (double v), Complex ( double x,
double y) precum i o funcie membr care permite afiarea datelor unui numar complex.

#include <iostream.h>
class Complex{
double re;
double im;
public:
Complex(){cout<< "Constructor fara argumente"<<endl;
re = 0;
im = 0;
}
Complex(double v){cout<<"Constructor pentru
initializarea a partii reale")<<endl;
re = v;
im = 0;
}
Complex(int x, int y)
{
cout << "Constructor cu 2 arg intregi"<<endl;
re = x;
im = y;
}
Complex(double x, double y){
cout << "Constructor cu 2 arg"<<endl;
re = x;
im = y;
}
void afisare()
{ cout<<re<<+<<im<<i<<endl;
};

28
int main (){
Complex c1;
Complex c2(2);
Complex c3(3.3,5.2);
Complex c3(2,4);
}

La execuia funciei main(), sunt afisate urmtoarele mesaje:

Constructor fara argumente


Constructor pentru initializarea cu o valoare a partii reale
Constructor cu 2 arg
Constructor cu 2 arg intregi

n sursa de mai sus s-au creat patru obiecte de tip Complex. Pentru fiecare declarare a unei variabile
de clas, adic a unui obiect s-a apelat cte un constructor. Astfel, declararea primului obiect
Complex c1 implic i niializarea datelor sale membre, re i im, cu valori nule, deoarece s-a apeleat
automat contructorul far argumente. Declararea celorlate trei obiecte de tip Complex, c2, c3 c4 a
condus la apelul celor trei contructori cu argumente, definii n interiorul clasei.

Constructorul de copiere

Dintre modurile de intializare amintite mai sus, un rol important o are intializarea unui obiect prin
copierea datelor unui alt obiect de acelai tip. Aceast operaie este posibil prin intermediul unui
constructor mai special al clasei, numit constructor de copiere. Forma general a constructorului de
copiere al unei clase Exemplu este:

Exemplu(Exemplu& r){ } // initializare obiect folosind referina r

Constructorul de copiere primete ca parametru formal o referin r la un obiect din clasa Exemplu
(obiectul surs) i iniializeaz obiectul nou creat cu datele membre coninute n obiectul referin r.

Observaie: Pentru crearea unui obiect printr-un constructor de copiere, argumentul transmis
trebuie s fie o referin la un obiect din aceeai clas.

De exemplu, pentru obiecte de tip Complex:

int main(){
Complex c1(2,3); // Constructor initializare
Complex c2(c1); // Constructor copiere
Complex c3 = c2; // Constructor copiere

29
c3.afisare(); // afiseaza 2 3
}

La declararea primului obiect c1 este apelat constructorul de iniializare cu dou argumente al clasei
Complex. Cel de-al doilea obiect c2 este creat prin apelul constructorului de copiere al clasei
Complex, avnd ca argument referina la obiectul c1. La declaraia de forma Complex c3 = c2; se
apleaz pentru iniializarea obiectului c3, constructorul de copiere, care realizeaz o copie membru
cu mebru a obiectului c3.

n cazul n care nu este definit explicit de ctre programator un constructor de copiere, compilatorul
apelez unul implicit atunci cnd este declarat un nou obiect i iniializat cu datele mebre ale unui
obiect creat anterior. Aceast modalitate de copiere mai este denumit copie la nivel de bii (bitwise
copy) sau copie membru cu membru.

Pentru clasa Complex, constructorul de copiere definit explicit are urmtoarea structur:

Complex(Complex &r)
{
cout << Constructor copiere\n;
re = r.re;
im = r.im;
}

Constructorul de copiere trebuie definit explicit de ctre programator dac clasa conine date membre
alocate dinamic. Constructorul de copiere generat implicit de compilator copiaz doar datele membre
declarate n clas (membru cu membru) i poate s aloce date dinamice pentru obiectul nou creat.
Folosind un astfel de constructor, se ajunge la situaia n care dou obiecte, cel nou creat i cel de
referin, s conin pointeri cu aceeai valoare, care indic spre aceeai zon din memorie. O astfel
se situaie este o surs puternic de erori de execuie subtile i greu de depistat.
Exemplificam acest caz definind clasa angajat asfel:

Aplicatia 2.4

class Angajat
{ float salariul;
public:
char *nume;
Angajat(char *n,int s)
{int nr=strlen(n);
nume=new char[nr];// alocare dinamica pentru sirul nume
strcpy(nume,n);
salariul=s;}

30
int spune_salariul(){return salariul;}}
int main()
{ Angajat a1(Popescu,35);
Angajat a2=a1;
strcpy(a2.nume,Ion);
cout<<a1.nume<< <<a1.salariul<<endl;
cout<<a2.nume<< <<a2.salariul;
}

Dupa rularea programului se va afia: Ion 35


Ion 35

La construirea obiectului a2 s-a aplelat constructorul de copiere implicit care a copiat membrul nume
al obiectului a1, dar nu a realizat alocarea dinamic. Asfel, obiectele a1 i a2 folosesc aceeai zon
de memorie alocat pentru campul nume.
Se poate observa asfel, necesiatea de a introduce n clasa angajat un constructor de copiere care s
aloce explicit memorie , dup care s fac copierea continuului zonei de memorie a obiectului surs
la destinaie:

class Angajat
{float salariul;
public:
char *nume;
Angajat(char *n,int s)
{int nr=strlen(n);
nume=new char[nr];
strcpy(nume,n);
salariul=s;
}
Angajat(angajat &a)
{
int nr= strlen(a.nume)
strcpy(nume,p.nume);
varsra=a.varsta;
}
int spune_salariul(){return salariul;}}
int main()
{ angajat a1(Popescu,35);
angajat a2=a1;
strcpy(a2.nume,Ion);
cout<<a1.nume<< <<a1.salariul<<endl;
cout<<a2.nume<< <<a2.salariul;}

31
Rezultatul afiat prin rularea aceeluiai program este: Popescu 35
Ion 35

n concluzie, pentru un obiect cu un membru pointer spre o zon alocat dinamic progrmatorul va
furniza un contructor de copiere care sa aloce memorie pentru noul obiect.

Destructor

Multe clase definite ntr-un program necesit o operaie care efectueza tergerea complet a
obiectelor. O astfel de operaie este efectuat de o funcie membr a clasei, numit funcie
destructor.
Dac este declarat explicit in cadrul clasei, destructorul porta numele clasei, precedat de semnul ~
(de ex. ~angajat()).
Destructorul, spre deosebire de constructor, este unic i nu are parametrii de apel.

Dac programatorul nu definete un destructor explicit, compilatorul C++ va genera unul implicit.
Destructorul generat de compilator apeleaz destructorii pentru variabilele membru ale clasei.
Membrii unei clase sunt ntotdeauna distrui n ordinea invers celei n care au fost creai.

Aplicaia 2.5

#include <iostream.h>
class Complex
{
double re;
double im;
public:
Complex(double x, double y){
cout << "Constructor cu 2 arg\n";
re = x;
im = y;
}
~Complex(){cout << "Destructor";
}
int main()
{
Complex z(3,4);
}

Rezultatul afiat dup rularea programului este:

32
Constructor cu 2 arg
Destructor
Se observ n programul anterior c nu s-a realizat un apel explicit al destructorului. Acesta a fost
apelat automat la sfaritul programului.
Destructorii sunt apelai implicit i n alte situaii, cum ar fi:
atunci cnd un obiect local sau temporar iese din domeniul de definiie;
la apelul operatorului delete, pentru obiectele alocate dinamic.

2.4 Pointerul this


Fiecare obiect al unei clase are acces la propria adres prin intermediul unui pointer numit
this. Acest pointer este utilizat n mod implicit pentru referirea att la membrii date ct i la
funciile membru ale unui obiect.
ntr-o clas X pointerul constant this este declarat implicit astfel:
X* const this;

Deoarece this este cuvnt cheie, el nu poate fi declarat explicit. De asemenea, fiind declarat
implicit pointer constant, el nu poate fi modificat, dar poate fi folosit explicit.
Ca expemplul vom defini, in aplicaia 2.6, o clas care va conine o metod ce utilizez
pointerul this.

class C
{ int x;
public:
C(int a){
x=a;}
void afisare(){
cout<<this->x;}
}
int main()
{C ob(7);
ob.afisare();
}

2.5 Funcii inline


Aa cum am prezentat mai sus, pentru un obiect al unei clase se pot apela metode publice
ncapusulate n clas. Apelul acestor funcii poate produce un cost ridicat de execuie, din cauza
operaiilor necesare pentru rezervarea spaiului n stiva, pentru transferul argumentelor i returnarea
unei valori. ns, metodele ncapsulate n clasa de cele mai multe ori au dimensiuni reduse, astfel
acest cost de execuie nu se justifica. n acest sens, pentru a reduce timpul de executii C++ pune la
dispozitie funcii inline.

33
n general, o funcie declarat inline se schimb la compilare cu corpul ei, adic apelul funciei se
realizeaz prin expandare. n felul acesta se elimin operaiile suplimentare de apel i revenire din
funcie. Dezavantajul funciilor inline este acela c produc creterea dimensiunilor programului
compilat, de aceea se recomand a fi utilizate pentru funcii de dimensiuni mici (maximum 3-4
instruciuni). n plus, mai exist i unele restricii privind funciile inline: ele nu pot fi declarate
funcii externe, deci nu pot fi utilizate dect n modulul de program n care au fost definite i nu pot
conine instruciuni ciclice (while, for, do-while).

n cazul claselor, funciile membru care sunt definite n interiorul clasei devin n mod implicit inline.
n cazul n care le definim n afara clasei si vrem s fie inline trebuie s utilizm sintaxa declarrii
unei funcii inline.

Sintaxa declarrii unei funcii inline:

inline <tip> <nume_funcie>([<lp>])

unde <tip> reprezint tipul ntors de funcie, iar <lp> lista de parametri.

n aplicaia P2.7 se prezint un exemplu de definire i utilizare a unei funcii inline pentru calculul
ariei unui patrat cu latura data, arie_patrat() .

// fisierul sursa P2_6.cpp


#include <iostream.h>
inline double arie_patrat(double a)
{
return a*a;
}

int main()
{
double x;
cout<<"\n Latura patratului:";
cin>>x;
cout<<"\n Aria patratului este "<<arie_patrat(x);
}

34
2.6 Funcii i clase friend

Aceesul la mebrii unei clase declarati n seciunile private i protected este restrictionat. Acestea pot
fi utilizate doar de funciile membre ale clasei.
Accesul la membrii unei clase poate fi ngdiut, totui i unor funcii externe clasei sau apartinnd
altor clase. Astfel de funcii se numesc funcii prietene clasei respective (funcii friend) si sunt
declarate astfel cu ajutorul specificatorului friend.

Funciile friend raman externe, nefiind legate de clasa i cu att mai puin de un obiect anume. Pentru
a avea acces la datele unui obiect, functia friend trebuie sa primeasca drept parametru de intrare
referinta la obiectul respectiv.

Declararea unei funcii f() de tip friend se realizeaza in interiorul clasei iar funcia nsi se definete
n alt parte n program astfel:

class C{
//..
friend tip_returnat f(lista_argumente);
};
..
tip_returnat f(lista_argumente){
// corpul funciei
}
Programul P2.8 prezint un exemplu de declarare i utilizare a unei funcii friend a clasei
Nr_Complex, modulul(), care calculeaz modulul unui numar complex.

// fisierul sursa P2_5.cpp


#include <iostream.h>
#include <math.h>
class Complex {
double re, im;
public:
Complex(double x, double y)
{ real = x;
imag = y;
}
friend double modul(Complex &);};

double abs(Nr_Complex& z)
{
return sqrt(z.real*z.real+z.imag*z.imag);
}

35
int main()
{
Complex Z=Complex(3,4);
cout<<"\n Modulul lui numarului complex z este "<<
modul(Z);
}

Trebuie subliniat faptul ca utilizarea funciilor friend trebuie fcut cu mare grij ntruct acestea
ncalc principiul ncapsulrii, respectiv, ascunderea informatiei, principiu fundamental n POO.
Avantajul principal al declarrii unei funcii friend este accesul rapid pe care aceasta l are direct la
membrii privati ai clasei cu care este prieten.

36
Teste de autoevaluare

2.1 Care este valoarea de adevr a afirmaiilor urmtoare:

(a) O clas C++ i o structur C definesc acelai concept, de TDA.


(b) O clas C++ ncorporeaz att date ct si operatii asociate datelor, n timp ce o structur
C defineste doar datele, operatiile nefiind legate direct de datele structurii.
(c) O clas C++ ascunde datele n zona privat, n timp ce structura C permite accesul direct
la datele sale neasigurnd consistenta acestora.
(d) Structurile C nu pot fi afisate ca o singur entitate si nu pot fi comparate dect membru
cu membru.

2.2 Care este numrul maxim de constructori si destructori care se pot defini ntr-o clas? Selectati
rspunsul corect.

(a) un constructor i un destructor


(b) un constructor i mai multi destructori
(c) 10 constructori i un destructor
(d) o infinitate de constructori (teoretic) i un singur destructor

2.3 Considerm clasa Carte definit astfel:

class Carte {
char* titlu;
int an_aparitie;
char* editura;
char* ISBN;
public:
Carte();
Carte(char* T, int A, char* Ed, char* Nr);
Carte(char* T, char* Ed);
Carte(char* T, int A);
~Carte();
void afisare_date();
};
si obiectele ob1, ob2, ob3, ob4 definite astfel:
Carte ob1=Carte(Compilatoare, 2000, Teora, 052-1432);

37
Carte ob2=Carte(Limbajul Java, Editura Tehnica);
Carte ob3=Carte(Programare logica, 2000);
Carte ob4;
(a) Explicati cum va diferentia compilatorul cei trei constructori cu parametri, lund drept
exemplu obiectele ob1, ob2 si ob3.
(b) Ce constructor va aplica compilatorul pentru crearea obiectului ob4?

2.4 Fie secventa:


class cls{public:
cls( ){ cout<<constructor;}
cls(cls &c){cout<<constructor de copiere ;}};
int f(cls c){ return 1;}
int main()
{cls c; f(c);}
La executia programului de mai sus:
a). constructorul de clasa se apeleaz o data, iar cel de copiere nu se apleleaz;
b). constructorii de clasa i de copiere se apeleaz fiecare cte o data;
c). constructorul de copiere se apeleaz o data, iar cel de clas nu se apeleaz;
d). constructorul de clasa se apeleaz de doua ori, iar cel de copiere nicio dat.
e). constructorul de clasa si de copiere se apeleaza fiecare de cate doua ori.

2.5 Fie secventa:


class cls{
public: cls( ){ cout<<constructor;}
cls(cls &c){cout<<constructor de copiere ;}};
int f(cls &c){ return 1;}
int main()
{cls c; f(c);}
La execuia programului de mai sus:
a). constructorul clasei se apeleaz o data, iar cel de copiere nu se apeleaz nici o data;
b). constructorii de clas i de copiere se apeleaz fiecare cte o data;
c). constructorul de copiere se apeleaz o data, iar cel de clasa nu se apeleaz;
d). constructorul clasei se apeleaz de doua ori, iar cel de copiere nicio dat.
e). constructorul de clasa si de copiere se apeleaza fiecare de cate doua ori.

2.6. Avnd declaraia:


class persoana{
char nume[20];
int varsta;
public:
persoana();
int spune_varsta(){returnvarsta;}};

38
int main()
{persoana p;
cout<<p.nume<<p.varsta;
}
n acest caz:
a). secvena afiseaz numele i vrsta unei persoane;
b). secvena afiseaz doar vrsta unei persoane;
c). descriere eronat pentru ca funcia membr nu este utlizat;
d). nu este permis afisarea datelor unei persoane.

Rspunsuri - teste de autoevaluare

2.1

(a) fals
(b) adevrat
(c) adevrat
(d) adevrat

2.2

(d)

2.3

(a) compilatorul va diferenia cei trei constructori cu parametri, prin numarul


i tipul parametrilor;
(b) constructorul far argumente;
2.4

(c) la declararea obiectului c se execut constructorul de clasa (implicit) iar la


transmiterea obiectului , prin valoare, ca parametru al funciei f() se execut
constructorul de copiere pentru a se copia obiectul(parameru) pe stiva.

2.5
(d) nu este permis afisarea datelor unei persoane, deoarece datele sunt n seciunea
privat.

39
Aplicaii practice

1. Definii clasa Data pentru memorarea datei sub forma zi lun an. Clasa va
conine metode de tip constructor necesare pentru urmtoarele definiii de obiecte:

Data d1(15, 3, 99); // zi, lun, an


Data d2(20, 4); // zi, lun, an curent
Data d3(18); // zi, lun curent, an curent
Data d4; // zi curent,lun curent, an current

Implementare:

#include<iostream>
#include<ctime>
using namespace std;

class Data
{
int zi, luna, an;
public:
Data(int zi, int luna, int an);
Data(int zi, int luna);
Data(int zi);
Data();

void afisare();
~Data();
};

Data::Data(int zi, int luna, int an)


{
this->an=an;
this->luna=luna;
this->an=an;
}

Data::Data(int zi, int luna)


{
time_t d = time(0);
tm *ptm = localtime(&d);

40
an=1900 + ptm->tm_year;
this->zi=zi;
this->luna=luna;
}

Data::Data()
{
time_t d=time(0);
tm *pmt=localtime(&d);
an=1900+pmt->tm_year;
luna=1+pmt->tm_mon;
zi=pmt->tm_mday;
}
void Data::afisare()
{
cout<<zi<<" "<<luna<<" "<<an<<endl;
}

Data::~Data()
{
cout<<"Des"<<endl;
}

int main()
{
Data ob1(2,3);
ob1.afisare();
Data ob2;

ob2.afisare();

return 0;
}

41
2. Definii clasa Carte cu urmtoarea structur:

class Carte {
char* titlu;
int an_aparitie;
char* editura;
public:
Carte();
Carte(char* T, int A, char* Ed);
Carte(char* T, char* Ed);
Carte(char* T, int A);
~Carte();
void afisare_date();
char* get_titlu();
int get_an_aparitie();
char get_editura();
void set_titlu(char *T);
void set_an_aparitie(int A);
void set_editura(char *Ed);
};

Definii dou obiecte de tip Carte i iniializai datele membre ale obiectelor.

3. Definii clasa Stiva cu urmtoarea structur:


class Stiva
{
int *elem;
int size;
int dim;
public:
Stiva();
Stiva(int n);
Stiva(Stiva &s);
void afisare();
void push(int v);
void pop();
int top();
int isEmpty();
}
Definii un obiect de tip Stiva cu n elemente ntregi i realizai operaii de actualizare.
Definii un nou obiect de tip Stiva realiznd o copie a obiectului creat anterior.

42
Unitatea de nvare Nr. 3

TABLOURI DE OBIECTE. DATE I MEMBRE STATICE

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui s:


construii tablouri de obiecte;
inelegei utilitatea datelor membre statice;
aplelai date si metode membre statice;

Cuvinte cheie: tablou de obiecte, date statice, metode statice.

Timpul minim pe care trebuie s-l acordati acestui modul este de 4 ore.

3.1 Tablouri de obiecte

Definirea unei clase induce definiia unui nou tip de dat. Astfel, se pot declara obiecte de tipul
clasei. La declararea unui obiect se apeleaz automat un constructor al clasei.
Declarea unui tablou de obiecte se poate realiza n limajul C++, ns cu o restricie: clasa care include
obiectul trebuie s contin un constructor implicit.
Aceast restricie este cauzat de imposibilitatea de a furniza argumentele necesare constructorilor.

Aplicatia P3.1 definete un tablou de obiecte de tip angajat.

// fisierul sursa P31.cpp


class Angajat
{
char *nume;
int varsta;
float salariul;
public:

43
Angajat()
{strcpy(nume,Anonim);
varsta=0;
salariul=0;
}
Angajat( char *nume, int varsta, float salariu)
{strcpy(thid->nume,nume);
this->varsta=varsta;
this->salariul=salariu;}
void setNume(char *nume)
{
this->nume=new char[strlen(nume)];
}
void setVarsta(int varsta)
{
this->varsta=varsta;
}
void afisare()
{cout<<nume: <<nume<<endl;
cout<<varsta: <<varsta<<endl;
cout<<salariul: <<salariul;
}};
int main()
{
Angajat tab[20]; // tablou static
int i, n;
cout<<"\n Cate obiecte doriti sa creati?";
cin>>n;
char nume[30];
int v;
flout salariu;
// initializeaza n obiecte
for (i=0;i<n;i++)
{
cout<<Nume: ;
cin>>nume;
tab[i].setNume(nume);
cout<<Varsta: ;
cin>>varsta;
tab[i].setVarsta(varsta);
cout<<Salariu: ;

44
cin>>salariu;
tab[i].setSalariu(salariu);
}

// afiseaza cele n obiecte


for (i=0;i<n;i++)
`tab[i].afisare();
}

3.2 Date i funcii membre statice

Implicit membrii de date sunt alocati pe obiecte. De exemplul fiecare angajat al unei firme are propiul
sau nume, cnp etc. Exist, ns unele propietai care sunt mpartite de ctre toate obiectele unei clase,
cum ar fi de exemplul, pentru clasa angajat, numarul total de angajai ai unei firme, salariul mediu
al firmei etc.

O varinat posibil ar fi stocarea acestor informaii ntr-o variabil global uzual. De exemplu, am
putea utiliza o variabila de tip ntreg pentru a pastra numarul de obiecte angajat. Problema acestei
soluii este c variabilele globale sunt declarate n afara clasei; pentru putea fi aduse n interiorul
clasei aceste variabile trebuie s fie declarate de tip static.

Datele statice nu se regasesc n fiecare set de valori ale clasei, ci ntr-un singur exemplar, pentru
toate obiectele clasei. Datele ce apar n toate obiectele se aloc de ctre un constructor , dar cum un
membru static nu face parte din nici un obiect, nu se aloc prin constructor. Astfel, la definirea clasei,
o data static nu se considera definit, ci doar declarat, urmnd a avea o definiie extern clasei.
Legatura cu declaraia din interiorul clasei se face prin operatorul de rezolutie :: precedat de numele
clasei din care face parte precum si de tipul variabilei statice, asfel:

class Angajat
{
//...
Static int total_ang;
//...
}
int angajat::total_ang=0;;

Variabila total_ang va fi unic pentru toi angajaii. Se poate observ c o data cu definirea varbilei
statice s-a realizat i intializarea acesteia.

45
Funciile membre statice efectueaz prelucrari care nu sunt individualizate pe obiecte, ci
prelucrari care au loc la nivelul clasei. Funciile statice nu apartin unui obiect anume si deci nu
beneficiaza de referinta implicita a obiectului asociat (pointerul this).
Daca functia membra statica opereaza pe o data nestatica a clasei, obiectul trebuie transmis explicit
ca parametru , in timp ce cu datele membre statice , lucreaza in mod direct.

Aplicaia 3.2 Se definete clasa Student cu datele membre: nume, nrMatricol, an. S se afieze
numrul total de studeni, precum i numrul studenilor din anul 2.

Se poate observa din cerin faptul ca date precum numrul total de studeni sau numarul total de
studeni din anul 2 nu pot fi considerate date membre nestatice ale unui obiect de tip Student,
deoarece aceste se afl ntr-o singur copie pentru toate obiectele de tip Student. Astfel, n definiia
clasei se pot introduce dou date membre statice care s memoreze valorile dorite. Mai mult, pentru
a manageria aceste date, n definiia clasei se pot introduce metode membre statice.

#include<iostream>

using namespace std;

class Student
{
char *nume;
int an;
int nrMatricol;
static int nrStud;
static int intStud2;
public:
Student();
Student(char *nume, int an, int nrMatricol);
Student(Student &s);
void setNume(char *nume);
void setNrMatricol(int nrMatricol);
void setAn(int an);
static int getNrStud();
static int Student:: getNrStud2()
static void numara(Student *s);
}

int Student::nrStud=0;
int Student::nrStud2=0;

46
Student::Student()
{
nume=NULL;
nrMatricol=0;
an=0;
nrStud++
}
Student::Student(char *nume, int an, int nrMatricol)
{
this->nume=new char[strlen(nume)+1];
strcpy(this->nume, nume);
this->nrMatricol=nrMatricol;
this->an=an;
nrStud++
}
Student::Student(Student &s)
{
this->nume=new char[s.strlen(nume)+1];
strcpy(this->nume, s.nume);
this->nrMatricol=s.nrMatricol;
this->an=s.an;
nrStud++;
}
void Student::setNume(char *nume)
{
this->nume=new char[strlen(nume)+1];
strcpy(this->nume, nume);
}
void Student::setNrMatricol(int nrMatricol)
{
this->nrMatricol=nrMatricol;
}
void Student::setAn(int an)
{
this->an=an;
}
int Student:: getNrStud()
{
return nrStud;
}

47
int Student:: getNrStud2()
{
return nrStud;
}
void Student::numara(Student *s)
{
if(s.an==2)
nrStud2++;
}

int main()
{
Student ts[20];
int n, i, nrMatricol, an;
char nume[30];
cout<<"Nr de obiecte: ";
cin>>n;

for(i=0;i<n;i++)
{
cout<<"Nume: ";
cin>>nume;
ts[i].setNume(nume);
cout<<"An: ";
cin>>an;
ts[i].setAn(an);
cout<<"Nr Matricol: ";
cin>>nrMatricol;
ts[i].setNrMatricol(nrMatricol);
}

for(i=0;i<n;i++)
Student::numara(ts[i]);
cout<<"Nr total de studenti: "<<Student::getNrStud()<<endl;
cout<<"Nr total de studenti din anul 2 <<Student::getNrStud2();

return 0;
}

48
Teste de autoevaluare

3.1 Care este valoarea de adevr a afirmatiilor urmtoare:


(a) Membrii statici ai unei clase pot fi att variabile (date membru) ct si metode (funcii
membru).
(b) Cuvntul cheie static desemneaz o proprietate a clasei si nu a unui obiect specific
clasei.
(c) Domeniul de valabilitate al membrilor statici este tot programul n care este definit
clasa din care fac parte.
(d) n limbajul C++ datele statice trebuie initializate o singur dat.

3.2 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz,
n caz negativ spunei de ce nu este corect.

#include<iostream.h>
class cls
{ static int i;
int j;
public: cls(int x=7) { j=x; }
static int imp(int k){ cls a(3); return i+k+a.j; } };

int cls::i=0;
int main()
{ int k=5;
cout<<cls::imp(k);
return 0;
}
3.4 In secventa de program:
# include <iostream.h>
class C {public: static int s;};
int C::s=0;
int main()
{ int a=7; C::s=a; cout<<C::a;}
Utilizarea lui s este:
a). ilegala, deoarece nu exista niciun obiect creat;
b). ilegala, deoarece s este initializat in afara clasei;
c). ilegala, deoarece s este dublu definit , in clasa si in afara ei;
d). ilegala, deoarece datele statice pot fi doar private;
e). corecta, deoarece membri statici exista inainte de a se crea obiecte din clasa;

49
Rspunsuri teste de autoevaluare

3.1
(a), (b), (d)
3.2
programul este corect si va afisa pe ecran valoarea 8.
3.3
(e) pentru ca membrii statici nu se aloc odata cu instanele clasei

Aplicaii practice

I. Definii clasa Carte cu urmtoarea structur:

class Carte {
char* titlu;
int an_aparitie;
char* editura;
public:
Carte();
Carte(char* T, int A, char* Ed);
Carte(Carte &c);
~Carte();
void afisare_date();
char* get_titlu();
int get_an_aparitie();
char get_editura();
void set_titlu(char *T);
void set_an_aparitie(int A);
void set_editura(char *Ed);
};

1. Definii un tablou cu obiecte de tip Carte i iniializai datele membre ale obiectelor cu
date citite de la tastatur.

2. Folosind date i metode membre statice, afiai cte cri au fost publicate dup anul 2010.

50
II. Definii clasa Produs cu urmtoarea structur:

class Produs {
char* denumire;
double pret;
int cantitate;
public:
Produs();
Produs(char* denumire, double pret, int cantitate);
void afisare_date();
void set_denumire(char *T);
void set_cantitate(int A);
void set_pret(double P);
};

1. Definii un tablou cu obiecte de tip Produs i iniializai datele membre ale obiectelor. Afiai
numrul obiectelor care au preul mai mare dect o valoare data.

51
Unitatea de nvare Nr. 4

CLASE DERIVATE. MOTENIREA

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui s:


construii tipuri noi de date utiliznd cele create anterior ;;
tii cum s instaniai obiecte derivate;
nelegei noiunea de ierarhie;
tii cum s construii clase noi prin derivarea mai multor clase
existente;
nelegei noiunea de polimorfism.

Cuvinte cheie: clase derivate, ierarhii de clase, funcii virtuale, polimorfism.

Timpul minim pe care trebuie s-l acordati acestui modul este de 8 ore.

4.1 Relaia de motenire. Clase de baz i clase derivate


Derivarea unei clase este un concept specific paradigmei programrii orientate pe obiecte. Acest
mecanism permite definirea ntr-un mod simplu, eficient i flexibil a unor clase noi prin adugarea
unor funcionaliti claselor deja existente, fr s fie necesar reprogramarea sau recompilarea
acestora. Clasele derivate exprim relaii ierarhice ntre conceptele pe care acestea le reprezint i
asigur o interfa comun pentru mai multe clase diferite. De exemplu, entitile cerc, triunghi,
dreptunghi, sunt corelate ntre ele prin aceea c toate sunt forme geometrice, deci ele au n comun
conceptul de form geometric.

Mostenirea reprezint o form de implementare a reutilizrii codului. Ea apare n urma crerii de noi
clase prin operatia de derivare.

Derivarea reprezint definirea unei noi clase prin extinderea uneia sau a mai multor clase existente.
Noua clas se numeste clas derivat, iar clasele existente din care a fost derivat se numesc clase
de baz. n cazul n care exist o singur clas de baz, mostenirea se numeste mostenire singular.
Limbajul C++ accept existenta mai multor clase de baz, concept denumit motenire multipl.

52
O clas derivat mosteneste toti membrii tuturor claselor sale de baz. O clas derivat poate fi la
rndul ei clas de baz pentru noi clase. Astfel se poate genera o ierarhie de clase (graf de mostenire).

Sintaxa declarrii unei clase derivate dintr-o clas de baz :

class <clasa_derivat> : public <clasa_de_baz>


{ // membrii clasei derivate
};

Motenirea sau relaia de derivare este indicat n antetul clasei derivate prin cuvntul cheie public
prefixat de caracterul : si urmat de numele clasei de baz.
n cadrul relatiei de mostenire poate apare n clasa de baz o sectiune protejat, marcat prin cuvntul
cheie protected, care permite accesul claselor derivate din ea la datele si funciile membru din
sectiunea respectiv.

Observatii
O clas derivat nu poate accesa direct membrii privati ai clasei sale de baz. Dac s-ar
permite aceesul, atunci s-ar nclca unul din principiile fundamentale ale POO (ncapsularea).
O clas derivat poate accesa membrii privati doar prin intermediul funciilor publice i
protejate ale clasei de baz.
Relatia de mostenire este tranzitiv.
Funciile friend nu se mostenesc.

Aplicatia P4_1 care descrie organizarea personalului unei instituii fr folosirea claselor derivate.
O clas numit Angajat deine date i funcii referitoare la un angajat al instituiei:

class Angajat{
char *nume;
float salariu;
public:
Angajat();
Angajat(char *n, float sal);
Angajat(Angajat& r);
void aisare();
};
Angajat::afisare(){
cout << nume << << salariu << endl;
}

Diferite categorii de angajai necesit date suplimentare fa de cele definite n clasa Angajat,
corespunztoare postului pe care l dein. De exemplu, un aministrator este un angajat (deci sunt
necesare toate datele care descriu aceast calitate) dar mai sunt necesare i alte informaii, de

53
exemplu precizare seciei pe care o conduce. De aceea, clasa Administator trebuie s includ un
obiect de tipul Angajat, la care adaug alte date:

class Administrator{
Angajat ang;
int sectie;
public:
void afisare();}

Posibilitatea de a include ntr-o clas date descrise ntr-o alt clas are n limbajele orientate pe
obiecte un suport mai eficient i mai simplu de utilizat dect includerea unui obiect din tipul dorit:
derivarea claselor, care motenesc (date i funcii membre) de la clasa de baz.
Un administrator este un angajat, de aceea clasa Administrator se poate construi prin derivare din
clasa Angajat astfel:

class Administrator : public Angajat {


int sectie;
public:
void afisare();}

In clasa Administrtrator nu se pot aceesa datele private din clasa Angajat, chiar data tipul mostenerii
este public. O metod pentru a accesa membrii private ai clasei de baz din clasa derivat este dat
de utilizarea funciilor membre publice ale clasei de baz. De exemplu, nu se poate implementa
funcia afisare() din clasa Administrator prin accesarea membrilor private ai clasei Angajat:

void Administrator::afisare(){
cout << nume << << salariu << endl; // eroare
cout << sectie << endl;
}
n schimb, se poate folosi funcia membr public display() a clasei Angajat:

void Administrator::display(){
Angajat::display();
cout << sectie << endl;
}

Redefinirea funciei afisare() n clasa derivat ascunde funcia cu acelai nume din clasa de baz, de
aceea este necesar calificarea funciei cu numele clasei de baz folosind operatorul de rezoluie:
Angajat::display().

54
Din clasa derivat este accesat membrul redefinit n clasa derivat. Se spune c membrul redefinit n
clasa derivat domin membrul definit n clasa de baz. Un membru ascuns din clasa de baz poate
fi totui accesat dac se folosete operatorul de rezoluie (::) pentru clasa de baz. De exemplu:

class Base {
public:
int a, b;
}
class Derived {
public:
int b, c; // b este redefinit
};
void fb() {
Derived d;
d.a = 1; // a din Base
d.Base::b = 2; // b din Base
d.b = 3; // b din Derived
d.c = 4; // c din Derived
}

4.2 Constructori i destructori n clasele derivate


Constructorii i destructorii sunt funcii membre care nu se motenesc. La crearea unei instane a
unei clase derivate se apeleaz implicit mai nti constructorii claselor de baz i apoi constructorul
clasei derivate. Ordinea n care sunt apelai constructorii claselor de baz este cea din lista claselor
de baz din declaraia clasei derivate. Constructorii nu se pot redefini pentru c ei, n mod obligatoriu,
au nume diferite (numele clasei respective).

La distrugerea unui obiect al unei clase derivate se apeleaz implicit destructorii n ordine invers:
mai nti destructorul clasei derivate, apoi destructorii claselor de baz, n ordinea invers celei din
lista din declaraie.

La instanierea unui obiect al unei clase derivate, dintre argumentele care se transmit constructorului
acesteia o parte sunt utilizate pentru iniializarea datelor membre ale clasei derivate, iar alt parte
sunt transmise constructorilor claselor de baz. Argumentele necesare pentru iniializarea claselor de
baz sunt plasate n definiia (nu n declaraia) constructorului clasei derivate.

Un exemplu simplu, n care constructorul clasei derivate D transfer constructorului clasei de baz
B un numr de k argumente arat astfel:

class B{

55
//.
public:
B(tip1 arg1,,tipk argk);
};
class D:public B {
//.
public:
D(tip1 arg1, ,tipk argk,,tipn argn);
};
D::D(tip1 arg1, ,tipk argk, .,tipn argn)
:B(arg1, arg2, ,argk);
{
// initialzare date membre clasa derivata
}
Sintaxa general pentru transmiterea de argumente din clasa derivat ctre clasa de baz:

<construct_cls_derivata>(<L1>) : <construct_cls_baza>(<L2>)
{
// corpul constructorului clasei derivate
}

<L1> reprezint lista de argumente ale constructorului clasei derivate, iar <L2> lista de argumente
ale constructorului clasei de baz. Lista <L1> include lista <L2>.

Observatii:
Constructorii si destructorul clasei de baz nu se mostenesc.
Constructorul clasei de baz se va executa naintea constructorului clasei derivate, iar
destructorul clasei derivate se va executa naintea destructorului clasei de baz.

4.3 Controlul accesului la membrii clasei de baz

Accesul la membrii clasei de baz motenii n clasa derivat este controlat de specificatorul de acces
(public, protected, private) din declaraia clasei derivate.

O regul general este c, indiferent de specificatorul de acces declarat la derivare, datele de tip
private n clasa de baz nu pot fi accesate dintr-o clas derivat. O alt regul general este c, prin
derivare, nu se modific tipul datelor n clasa de baz.

Un membru protected ntr-o clas se comport ca un membru private, adic poate fi accesat numai
de membrii acelei clase i de funciile de tip friend ale clasei. Diferena ntre tipul private i tipul

56
protected apare n mecanismul de derivare: un membru protected al unei clase motenit ca public
ntr-o clas derivat devine tot protected n clasa derivat, adic poate fi accesat numai de funciile
membre i friend ale clasei derivate i poate fi transmis mai departe, la o nou derivare, ca tip
protected.

Motenirea de tip public a clasei de baz

Dac specificatorul de acces din declaraia unei clase derivate este public, atunci:
Datele de tip public ale clasei de baz sunt motenite ca date de tip public n clasa derivat i
deci pot fi accesate din orice punct al domeniului de definiie al clasei derivate.
Datele de tip protected n clasa de baz sunt motenite protected n clasa derivat, deci pot fi
accesate numai de funciile membre i friend ale clasei derivate.

n aplicaia P4_2 sunt prezentate i comentate cteva din situaiile de acces la membrii clasei de
baz din clasa derivat atunci cnd specificatorul de acces este public.

class Base {
int a;
protected:
int b;
public:
int c;
void seta(int x){a = x; cout << "seta din baza\n";}
void setb(int y){b = y; cout << "setb din baza\n";}
void setc(int z){c = z; cout << "setc din baza\n";}
};
class Derived : public Base {
int d;
public:
void seta(int x) {
a = x; // eroare, a este private }
void setb(int y) {
b = y;
cout << "setb din derivata\n";}
void setc(int z) {
c = z;
cout << "setc din derivata\n";}};
void fb(){
Derived obd;
obd.a = 1; // eroare, a este private in baza
obd.seta(2); // corect, se apeleaz baza::seta
obd.b = 3; // eroare, b este protected

57
obd.Base::setb(5);// corect, Base::setb este public
obd.setb(4); // corect, Derived::setb este public
obd.c = 6; // corect, c este public
obd.Base::setc(7);// corect, Base::setc este public
obd.setc(8); // corect, Derived::setc este public
}

Dac se comenteaz liniile de program care provoac erori i se execut funcia fb(), se obin
urmtoarele mesaje la consol:

seta din baza


setb din baza
setb din derivata
setc din baza
setc din derivata

Motenirea de tip protected a clasei de baz

Dac specificatorul de acces din declaraia clasei derivate este protected, atunci toi membrii de tip
public i protected din clasa de baz devin membri protected n clasa derivat. Bineneles, membrii
de tip private n clasa de baz nu pot fi accesai din clasa derivat.
Se reiau clasele din exemplul precedent cu motenire protected:

58
class Derived : protected Base {
// acelasi corp al clasei };

n aceast situaie, n funcia fb() sunt anunate ca erori de compilare toate apelurile de funcii ale
clasei de baz pentru un obiect derivat, precum i accesul la variabila c a clasei de baz:

void fb(){
Derived obd;
obd.a = 1; // eroare, a este private in baza
obd.seta(2); // eroare, Base::seta()este protected
obd.b = 3; // eroare, b este protected
obd.Base::setb(5); // eroare, Base::setb este prot.
obd.setb(4); // corect, Derived::setb este public
obd.c = 6; // eroare, c este protected
obd.Base::setc(7); // eroare, Base::setc este prot.
obd.setc(8); // corect, Derived::setc este public
}

Dac se comenteaz toate liniile din funcia fb() care produc erori, la execuia acesteia se afieaz
urmtoarele rezultate:
setb din derivata
setc din derivata
Din acest exemplu reiese pregnant faptul c n motenirea protected a unei clase de baz nu mai
pot fi accesai din afara clasei derivate nici unul dintre membrii clasei de baz.

Motenirea de tip private a clasei de baz

Dac specificatorul de acces din declaraia clasei derivate este private, atunci toi membrii de tip
public i protected din clasa de baz devin membri de tip private n clasa derivat i pot fi accesai
numai din funciile membre i friend ale clasei derivate. Din nou trebuie reamintit c membrii de
tip private n clasa de baz nu pot fi accesai din clasa derivat. Din punct de vedere al clasei
derivate, motenirea de tip private este echivalent cu motenirea de tip protected. ntr-adevr,
dac modificm clasa derivata din Exemplul 5.2 astfel:

class Derived : private Base {


// acelasi corp al clasei
};

mesajele de erori de compilare i de execuie ale funciei fb() sunt aceleai ca i n motenirea
protected.

59
Ceea ce difereniaz motenirea de tip private fa de motenirea de tip protected este modul cum
vor fi trasmii mai departe, ntr-o nou derivare, membrii clasei de baz.Toi membrii clasei de
baz fiind motenii de tip privateo nou clas derivat (care motenete indirect clasa de baz) nu
va mai putea accesa nici unul din membrii clasei de baz.

4.4 Mostenirea multipla


Motenirea multipl reprezint proprietatea unei clase de a prelua caracteristici (date membre) i
comportamente (metode membre) din mai multe clase de baz.
Un exemplu de ierarhie de clase definit prin conceptul de motenire multipl este reprezentat in
figura 4.1

Persoana

Student Angajat Elev

Medic Profesor

Fig. 4.1 Ierarhie de clase

Clasa de baz a ierarhiei de clase este clasa Persoana. Din aceast clas sunt derivate direct
clasele Elev, Student si Salariat. La rndul ei clasa Salariat este o clas de baz pentru clasele
Medic si Profesor.

Aplicaia P4_3 prezint un exemplu de implementare a claselor Persoana, Salariat, Arhitect,


Inginer si Medic.

#include <iostream.h>
#include <string.h>
#include <assert.h>
// definitia clasei de baza Persoana
class Persoana {
char* nume;
char* pren;
public:
Persoana(char*, char*);
~Persoana();
void afisare();};
Persoana::Persoana(char* N, char* P)
{

60
nume = new char[strlen(N)+1];
strcpy(nume, N);
pren = new char[strlen(P)+1];
strcpy(pren, P);
}
Persoana::~Persoana()
{
if(nume)
delete []nume;
if(pren)
delete []pren;
}
void Persoana::afisare()
{
cout << "\n Nume: "<< nume << " Prenume: " << pren;
}
// definitia clasei Salariat derivata din clasa Persoana
class Salariat : public Persoana {
float salariu;
public:
Salariat(char *n, char *p, float s);
void seteazaSalariu(float s);
void afisare();};
Salariat::Salariat(char* n, char* p, float s)
:Persoana(n, p)
{
seteazaSalariu(s);
}
void Salariat::seteazaSalariu(float S)
{
salariu = s;
}
void Salariat::afisare()
{
cout << "\n Salariat:";
Persoana::afisare();
cout << "\n Salariu:" << salariu;
}
// definitia clasei Inginer derivata din clasa Salariat
class Inginer : public Salariat {
char* domeniu;
public:
Inginer(char* n, char* p, float s, char* d);

61
void seteazaDomeniu(char *d);
void afisare();
};
Inginer::Inginer(char* n, char* p, float s, char * d)
:Salariat(n, p, s)
{
domeniu = new char[strlen(d)+1];
strcpy(domeniu, d);
}
void Inginer::seteazaDomeniu(char* d)
{
if(domeniu)
delete []domeniu;
domeniu = new char[strlen(d)+1];
strcpy(domeniu, d);
}
void Inginer::afisare()
{
cout << "\n Inginer ";
Salariat::afisare();
cout << "\n\t Domeniu de lucru este " << domeniu;
}
class Profesor : public Salariat {
char* tip;
public:
Profesor(char* n, char* p, float s, char* t);
void seteazaTip(char *t);
void afisare();};
Profesor::Profesor(char* n, char* p, float s, char* t)
:Salariat(n, p, s)
{
tip = new char[strlen(t)+1];
strcpy(tip_inginer, t);
}
void Profesor::seteazaTip(char* t)
{
if(tip)
delete []tip;
tip = new char[strlen(t)+1];
strcpy(tip_inginer, t);
}
void Profesor::afisare()
{

62
cout << "\n Profesor ";
Salariat::afisare();
cout << "\n\t Tip profesor " << tip;
}
int main()
{
Persoana P1=Persoana("Popescu", "Ana");
Salariat S1=Salariat("Ion", "Alexandru", 2300);
Inginer I1=Inginer("Syan", "Maria", 3400,
"inginer civile");
Profesor PR1=Inginer("Pop", "Cristi", 2200,
"informatica");
P1.afisare();
S1.afisare();
I1.afisare();
PR1.afisare();
}

Motenirea utilizat este cea public. Functia afisare() a fost redefinit n toate clasele derivate,
ea apelnd varianta din clasa imediat urmtoare pe nivelul superior din ierarhia de clase.
De exemplu, functia afisare() din clasa Salariat apeleaz functia afisare() din clasa Persoana
astfel,

Persoana::afisare();

Functia afisare() din clasele Inginer si Profesor apeleaz functia afisare() din clasa Salariat:
Salariat::afisare();

4.5 Clase de baz virtuale


ntr-o motenire multipl este posibil ca o clas s fie motenit indirect de mai multe ori, prin
intermediul unor clase care motenesc, fiecare n parte, clasa de baz. De exemplu:

class L { public: int x;};


class A : public L { /* */};
class B : public L { /* */};
class D : public A, public B { /* */};

Acest motenire se poate reprezenta printr-un graf aciclic direcionat care indic relaiile dintre
subobiectele unui obiect din clasa D. Din graful de reprezentare a motenirilor, se poate observa
faptul c baza L este replicat n clasa D.

63
Un obiect din clasa D va conine membrii clasei L de dou ori, o dat prin clasa A (A::L) i o dat
prin clasa B (B::L). In acest caz ser creaza o ambiguitate in situatia urmatoare :

D ob;
ob.x = 2; // eroare D::x este ambiguu; poate fi n baza L a clasei A sau n baza L a
clasei B
Aceste ambiguiti se pot elimina prin urmatoarele doua metode:
prin calificarea variabilei cu domeniul clasei creia i aparine:

ob.A::x = 2; // corect, x din A


ob.B::x = 3; // corect, x din B

crearea unei singure copii a clasei de baz n clasa derivat. Pentru aceasta este necesar ca
acea clas care ar putea produce copii multiple prin motenire indirect (clasa L, n
exemplul de mai sus) s fie declarat clas de baz de tip virtual n clasele care o introduc
n clasa cu motenire multip. De exemplu:

class L { public: int x; };


class A : virtual public L { /* */ };
class B : virtual public L { /* */ };
class D : public A, public B { /* */ };

O clas de baz virtual este motenit o singur dat i creeaz o singur copie n clasa derivat.
Graful de reprezentare a motenirilor din aceste declaraile de mai sus poate fi ilustrat asfel:

64
4.6 Funcii virtuale i polimorfism

Atunci cnd o clas motenete metodele unei alte clase, se poate ntmpla ca numele membrilor
sa fie n conflict. Dac obiectul derivat este de tipul clasei derivate, atunci se va apela metoda
definit n clasa derivat. ns, dac obiectul derivat este referit printr-un pointer al clasei de baz
(conversie implicit), atunci se va apela metoda definit n baz. Acest efect are loc, deoarece se
o metod se apeleaz dupa tipul pointer-lui, ci nu dup tipul obiectului. Totui, n practic este
necesar ca metoda redefinit n clasa derivat s domine metoda definit n clasa de baz.

Pentru a atinge acest deziderat, se definete metoda respectiv n clasa de baz ca fiind una virtual.

Sintaxa declarrii unei funcii virtuale:

virtual <tip_funcie> <nume_funcie> ([<lp>]);

In Aplicaia P4_4 se consider o clas de baz B i o clas derivat D1. n clasa de baz sunt
definite dou funcii: funcia f() i funcia virtual g(). Clasa derivat se redefinesc cele
dou funcii f() i g(). n funcia main() se creeaz dou obiecte: un obiect din clasa de baz
B indicat prin pointerul B* pb i un obiect al clasei derivate D1. Obiectul derivat poate fi
indicat printr-un pointer la clasa derivat respectiv (D1* pd1), precum i printr-un pointer
la baz corespunztor (B* pb1 = pd1)

class B {
public:
void f() { cout << "f() din B\n"; }
virtual void g(){ cout << "g() din B\n"; }};
class D1:public B {
public:
void f() { cout << "f() din D1\n"; }
void g() { cout << "g() din D1\n"; }
};
int main(){
B* pb = new B;
D1* pd1 = new D1;
B* pb1 = pd1;
//f() este funcie normala,g() este funcie virtuala
// Obiect B, pointer B*
pb->f(); // f() din B
pb->g(); // g() din B

65
//Obiectul D1 prin pointerul D1*
pd1->f(); // f() din D1
pd1->g(); // g() din D1
//Obiectul D1 prin pointerul B*
pb1->f(); // f() din B
pb2->f(); // f() din B
pb1->g(); // g() din D1
pb2->g(); // g() din D2
delete pb;
delete pd1; };

n primele situaii, cnd pointerul este pointer la tipul obiectului, nu se manifest nici o deosebire
ntre comportarea unei funcii virtuale fa de comportarea unei funcii normale: se selecteaz
funcia corespunztoare tipului pointerului i obiectului.
Diferena de comportare se manifest n ultima situaie, atunci cnd este apelat o funcie pentru
un obiect de tip clas derivat printr-un pointer la o clas de baz a acesteia. Pentru funcia normal
f() se selecteaz varianta depinznd de tipul pointerului. Pentru funcia virtual g() se selecteaz
varianta n funcie de tipul obiectului, chiar dac este accesat prin pointer de tip baz.

Funciile virtuale conduc la implementarea polimorfismului.


}

Observati
Constructorii nu pot fi funcii virtuale. n schimb, destructorii pot fi funcii virtuale.
Funciile inline nu pot fi virtuale.
Funciile virtuale sunt ntotdeauna funcii membru nestatice ale unei clase.

4.7 Clase abstracte

n multe situaii, o funcie declarat de tip virtual n clasa de baz nu definete o aciune
semnificativ, ns este necesar ca acesta s fie redefinit n clasele derivate. n aceste caz, se poate
defini o funcie virtual pur.

Definiie: O funcie virtual pur este o funcie declarat n clasa de baz i redefinit n clasele
derivate.
Sintaxa unei funcii virtuale pure:
virtual tip_returnat nume_funcie(lista_argumente) = 0;
Efectul declarrii unei funcii viruale pure ntr-o clas conduce la un nou concept, cel de clas
abstract.

66
Definiie: O clas care conine cel puin o funcie virtual pur se numete clas abstract.

Deoarece o clas abstract conine una sau mai multe funcii pentru care nu exist definiii, nu pot
fi create instane din acea clas, dar pot fi creai pointeri i referine la astfel de clase abstracte. O
clas abstract este folosit n general ca o clas fundamental, din care se construiesc alte clase
prin derivare.

Orice clas derivat dintr-o clas abstract este, la rndul ei clas abstract (i deci nu se pot crea
instane ale acesteia) dac nu se redefinesc toate funciile virtuale pure motenite. Dac o clas
redefinete toate funciile virtuale pure ale claseor ei de baz, devine clas normal i pot fi create
instane ale acesteia.

Aplicatia P4_5 Se definete o ierarhie de clase pentru a modela mai multe figuri geometrice din
plan. Clasa abstract FiguraGeometrica cuprinde un comportament comun specific unei
figuri n plan, cum ar fi calculul ariei, setarea dimensiunilor etc. Se definesc dou clase
derivate, Dreptunghi i Triunghi. n fiecare din clasele derivate se refefinete funcia
arie().

class FiguraGeometrica
{
double dim1, dim2;
public:
virtual double arie()=0;
void setDim1(double v)
{
dim1=v;
}
void setDim2(double v)
{
dim2=v;
}
};

class Dreptunghi:public FiguraGeometrica


{
public:
double arie()
{
return dim1*dim2;
}
}
class Triunghi:public FiguraGeometrica

67
{
public:
double arie()
{
return (dim1*dim2)/2;
}
}

int main()
{
FiguraGeometrica *ob;

double a, b;
cout<<"Dati dimensiuni: ";
cin>>a>>b;
char op;
cout<<"Tipul obiectului";
cin>>op;
switch(op)
{
'D': pb=new Dreptunghi;
pb->setDim1(a);
pb->setDim2(b);
break;
'T': pb=new Triunghi;
pb->setDim1(a);
pb->setDim2(b);
break;
}

cout<<"Arie: "<<pb->arie();

return 0;
}

Observatii
Principiul care st la baza polimorfismului este o singur interfat, metode
multiple. Practic, polimorfismul reprezint abilitatea obiectelor din clase diferite
ale unei ierarhii de clase de a rspunde diferit la acelasi mesaj (adic,la apelul unei
funcii membru).
Implementarea polimorfismului este realizat prin intermediul funciilor virtuale.

68
n cazul n care o funcie membru ne-virtual este definit ntr-o clas de baz si
redefinit ntr-o clas derivat, comportamentul este ne-polimorfic. Astfel, dac
functia membru este apelat printr-un pointer al clasei de baz la obiectul clasei
derivate, se utilizeaz versiunea clasei de baz. Dac functia membru este apelat
printr-un pointer al clasei derivate, se utilizeaz versiunea clasei derivate.

Teste de autoevaluare

4.1 Dac din clasa X se genereaz o clas Z cum se numesc cele dou clase?
(a) X clas derivat, Z clas de baz
(b) X superclas, Z subclas
(c) X clas copil, Z clas printe
(d) X clas de baz, Z clas derivat

4.2 Care dintre afirmatiile urmtoare sunt adevrate si care sunt false?
(a) Obiectele unei clase derivate au acces la membrii privati ai clasei sale de baz.
(b) Relatia de mostenire este tranzitiv.
(c) Constructorul si destructorul clasei de baz se mostenesc n clasa derivat.

4.3 Selectati rspunsul corect referitor la ordinea de apelare a constructorilor si a destructorilor


n cazul claselor derivate dintr-o clas de baz.
Ordinea de apelare este urmtoarea:
(a) constructorul clasei derivate constructorul clasei de baz destructorul clasei derivate
destructorul clasei de baz
(b) constructorul clasei de baz constructorul clasei derivate destructorul clasei derivate
destructorul clasei de baz
(c) constructorul clasei derivate constructorul clasei de baz destructorul clasei de baz
destructorul clasei derivate
(d) constructorul clasei de baz constructorul clasei derivate destructorul clasei de baz

69
4.4 Care dintre afirmatiile urmtoare sunt adevrate?
(a) Constructorii pot fi funcii virtuale.
(b) Destructorul poate fi funcie virtual.
(c) Orice funcie membru static este funcie virtual.

4.5 Spunei care dintre declaraiile funciei main()sunt corecte n programul de mai jos. Justificai.

#include <iostream.h>
class B1 { public: int x; };
class B2 { int y; };
class B3 { public: int z; };
class B4 { public: int t; };
class D: private B1, protected B2, public B3, B4
{ int u; };
int main()
{ D d;
cout<<d.u; (1)
cout<<d.x; (2)
cout<<d.y; (3)
cout<<d.z; (4)
cout<<d.t; (5)
return 0;
}
4.6 Spunei dac programul de mai jos este corect. n caz afirmativ, precizai exact constructorii care
se execut i n ce ordine. n caz negativ spunei de ce nu este corect.

#include<iostream.h>
class cls1
{ public: int x;
cls1(int i=13) { x=i; } };
class cls2: virtual public cls1
{ public: cls2(int i=15) { x=i; } };
class cls3: virtual public cls1
{ public: cls3(int i=17) { x=i; } };
class cls4: public cls1
{ public: cls4(int i=19) { x=i; } };
class cls5: public cls2, public cls3, public cls4
{ public: int y;
cls5(int i,int j):cls4(i),cls2(j){ y=i+j; }
cls5(cls5& ob) { y=-ob.y; }};
int main()
{ cls5 ob1(-9,3), ob2=ob1;
cout<<ob2.y;
return 0;}
4.7 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n caz
negativ spunei de ce nu este corect. #include <iostream.h>
class B 70
{ int a;
public: B(int i=0) { a=i; }
Rspunsuri - teste de autoevaluare

4.1
(d)
4.2
(a) fals
(b) adevarat
(c) fals
4.3
(a) fals
(b) adevarat
(c) adevarat
(d)
4.4
(a)
(b)
4.5
(4) si (5) pentru ca motenirea este de tip public, iar datele membre z si t sunt
publice n clasele de baza.
4.6
programul va afia pe ecran valoarea 6; clasele cls2 si cls 3 sunt motenite virtuale, astfel
n cls5 se realizeaz o singur copie a clasei cls1.
4.7
programul este corect pentru ca funcia membra int get_a()este public n clasa de
baz, astfel ea poate fi apelat n clasa derivat; se va afia pe ecran -89
4.8
(d) pentru ca se apeleaza mai inti constructorul clasei de baz derivat virtual dupa care
se apeleaz n ordine constructorii claselor de baz. Ultimul constructor care se apleleaz
este cel al clasei derivate.
4.9.
(a)

71
Aplicaii practice
1. Se definesc clasa de baz Persoana i dou clase derivate, Student si Salariat. Clasa de
baz Persoana este o clas abstract avnd declarat o funcie virtual pur, venit(), definit
n clasele derivate. De asemenea, clasa Persoana mai contine o alt funcie virtual,
afisare(), care este redefinit n clasele derivate. n programul principal sunt create dou
obiecte S1 si T1 din clasele Student si respectiv Salariat. Pentru fiecare din cele dou
obiecte se execut o secvent de patru instructiuni: primele dou instructiuni ilustreaz
legarea static, prin apelul celor dou funcii afisare() si venit(), corespunztoare obiectului
referit prin nume; ultimele dou instructiuni ilustreaz legarea dinamic apelnd cele dou
funcii afisare() si venit() prin intermediul a dou funcii, Ref_Pointer(.), Ref_Referinta(.),
care utilizeaz un pointer, respectiv o referint ctre clasa de baz Persoana.
Aceste ultime dou instructiuni genereaz un comportament polimorfic, la momentul
executiei programului.

#include <iostream.h>
#include <string.h>
#include <assert.h>
// clasa de baza Persoana, clasa abstracta
class Persoana {
char* prenume;
char* nume;
public:
Persoana(char*, char*);
~Persoana();
char* preiaPrenume();
char* preiaNume();
// funcie virtuala pura
virtual double venit() = 0;
virtual void afisare();
};
Persoana::Persoana(char* P, char* N)
{
prenume = new char[strlen(P)+1];
strcpy(prenume, P);
nume = new char[strlen(N)+1];
strcpy(nume, N);

72
}
Persoana::~Persoana()
{
delete prenume;
delete nume;
}
char* Persoana::preiaPrenume()
{
return prenume;
}
char* Persoana::preiaNume()
{
return nume;
}
void Persoana::afisare()
{
cout << prenume << " " << nume << "\n";
}
// definim clasa Student derivata din clasa Persoana
class Student : public Persoana {
double bursa;
double media;
public:
Student(char*, char*, double = 0.0, double = 0.0);
void seteazaBursa(double);
void seteazaMedia(double);
virtual double venit();
virtual void afisare();};
Student::Student(char* P, char* N, double B, double M)
:Persoana(P,N)
{
M>=8.50?seteazaBursa(B):seteazaBursa(0.0);
seteazaMedia(M);
}
void Student::seteazaBursa(double B)
{
bursa = B>0?B:0;
}
void Student::seteazaMedia(double M)
{
media = M>0?M:0.0;
}
double Student::venit()

73
{
return bursa;
}
void Student::afisare()
{
cout << "\n Student:";
Persoana::afisare();
cout << "\t Media = " << media << "\n";
}
// definim clasa Salariat derivata din clasa Persoana
class Salariat:public Persoana {
double salariu;
double venit_ora;
int nr_ore;
public:
Salariat(char*, char*, double = 0.0, double = 0.0, int
= 0);
void seteazaSalariu(double);
void seteazaVenitOra(double);
void seteazaNrOre(int);
virtual double venit();
virtual void afisare();
};
Salariat::Salariat(char* P,char* N,double S,double
V,int nr):Persoana(P, N)
{
seteazaSalariu(S);
seteazaVenitOra(V);
seteazaNrOre(nr);
}
void Salariat::seteazaSalariu(double S)
{
salariu = S>0 ? S : 0;
}
void Salariat::seteazaVenitOra(double V)
{
venit_ora = V>0.0 ? V : 0.0;
}
void Salariat::seteazaNrOre(int nr)
{
nr_ore = nr>0 ? nr : 0;
}
double Salariat::venit()

74
{
return salariu + nr_ore*venit_ora;
}
void Salariat::afisare()
{
cout << "\n Salariat:";
Persoana::afisare();
}
// funcie care apeleaza funciile virtuale prin legare
// dinamica, in cazul unui pointer al clasei de baza
// referire prin pointer
void Ref_Pointer(Persoana *Ptr)
{
Ptr->afisare();
cout << " venit (lei) " << Ptr->venit();
}
// funcie care apeleaza funciile virtuale prin legare
// dinamica, in cazul unei referinte la clasa de baza
// referire prin referinta
void Ref_Referinta(Persoana &Ptr)
{
Ptr.afisare();
cout << " venit (lei) " << Ptr.venit();
}
int main()
{
Student S1("Alexandra", "Stoica", 1500000, 10);
cout << "\n Legare statica:\n";
S1.afisare();
cout << " venit (lei) "<<S1.venit();
cout << "\n Legare dinamica:\n";
Ref_Pointer(&S1);
Ref_Referinta(S1);
Salariat T1("Silvan", "Manole", 50000000, 100000,
30);
cout << "\n Legare statica:\n";
T1.afisare();
cout<<" venit (lei) "<<T1.venit();
cout << "\n Legare dinamica: \n";
Ref_Pointer(&T1);
Ref_Referinta(T1);
}

75
2. Datele despre un produs comercializat de ctre un supermarket sunt stocate n fiierul
produse.txt. In supermarket se comercializeaz att produse electronice, ct i produse
alimentare. Realizai o ierarhie de clase care s descrie un produs electronic cu datele
membre denumire, pre, consum i un produs alimentar cu datele membre denumire,
pre, valabilitate.

Fiecare produs are un cod unic care arat categoria produsului, astfel: dac produsul este
electronic, codul ncepe cu cifra 1, iar produsul este alimentar, codul ncepe cu cifra 2.

Realizai o aplicaie care permite urmtoarle operaii:


- ncarcarea datelor din fisier n obiecte specifice tipului produsului.
- definii o metod pentru calculTVA (pentru produse electronice taxa TVA este 24% din
valoare produsului, iar pentru produse alimentare 19%), precum i o metod pentru
calculDiscount (pentru produse electronice se acorda un discount de 10% din pretul
produsului, daca consumul este mai mare dect 80 W/h, iar pentru produse alimentare se
acord un discount de 5%, daca termenul de valabilitate expira peste 10 zile).
- afiai produsele care au stocul mai mic dect 100, utiliznd date i funcii membre statice

76
Unitatea de nvare Nr. 5

SUPRANCARCAREA OPERATORILOR

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui s:


redefinii operatori pentru TDA ;
nvai s redefinii operatori prin metode membre;
nvai s redefinii operatori prin funcii independente de tip friend;

Cuvinte cheie: redefinire operatori, funcii operator, asignare.

Timpul minim pe care trebuie s-l acordati acestui modul este de 4 ore.

5.1 Introducere
Limbajul C++ permite programatorului s defineasc diverse operatii cu obiecte ale claselor,
utiliznd simbolurile operatorilor standard. Pentru tipurile fundamentale ale limbajului sunt
definite seturi de operatori care permit operaii de baz executate ntr-un mod convenabil. Dar,
dup cum este cunoscut, n limbaj sunt definite prea puine tipuri de date ca date fundamentale, iar
pentru reprezentarea altor tipuri care sunt necesare n diferite domenii (cum ar fi aritmetica
numerelor complexe, algebra matricilor, etc.), se definesc clase care conin funcii ce pot opera
asupra acestor tipuri.

Limbajul C++ nu permite crearea de noi operatori, n schimb permite redefinirea majorittii
operatorilor existenti astfel nct atunci cnd acesti operatori sunt aplicati obiectelor unor clase s
aib semnificatia corespunztoare noilor tipuri de date.

77
Principalele avantaje ale redefinirii operatorilor sunt claritatea i usurinta cu care se exprim
anumite operatii specifice unei clase. Solutia alternativ ar fi definirea unor funcii si apelul
funciilor n cadrul unor expresii.

Funciile operator pentru o anumit clas pot s fie sau nu funcii membre ale clasei. Dac nu sunt
funcii membre ele sunt, totui, funcii friend ale clasei i trebuie s aib ca argument cel puin un
obiect din clasa respectiv sau o referin la aceasta.

Se pot suprancrca majoritatea operatorilor din limbaj:

+ - * / % ^ & |
~ ! = < > += -= *=
/= %= ^= &= |= << >> >>=
<<= == != <= >= && || ++
-- ->* , -> [] () new delete
new[] delete[]

Nu se pot suprancrca operatorii:

. .* :: ?: sizeof

5.2 Funcii operator membre ale claselor


Forma general pentru funciile operator membre ale clasei este urmtoarea:

tip_returnat operator # (lista_argumente){


// operaii}
Semnul # reprezint oricare dintre operanzii care pot fi suprancrcai.
Funcia operator fiind o funcie membr clasei, primete ca argument implicit pointer-ul obiectului
referit (pointerul this). Astfel, numrul argumentelor depinde de aritatea operatorului:
- Dac opeartorul este unar, atunci funcia operator membr nu primete niciun argument.
Operaia se realizeaz asupra obiectului referit.
- Dac operatorul este binar, atunci funcia operator membr primete ca argument
operandul din partea dreapt, operandul din partea stng fiind cel referit prin pointer-ul
this.

Aplicatia P 5.1 prezinta clasa Point care descrie un vector ntr-un plan bidimensional prin dou
numere de tip float, x i y. Valorile x i y reprezint coordonatele punctului de

78
extremitate al vectorului. Pentru aceast clas se pot defini mai multe operaii cu vectori,
ca de exemplu:

Suma a doi vectori


Diferena a doi vectori
Produsul scalar a doi vectori
Multiplicarea unui vector cu o constant (scalare)

Aceste operaii se pot implementa prin suprancrcarea corespunztoare a operatorilor. Pentru


nceput se vor defini funciile operator+() i operator() pentru calculul sumei, respectiv
a diferenei a doi vectori.

class Point{
float x;
float y;
public:
Point(){
x = 0;
y = 0;
}
Point(double a, double b){
x = a;
y = b;
}
void Display() {
cout << x << " " << y << endl;
}
Point operator+(Point op2); // suma a doi vectori
Point operator-(Point op2); // diferena a doi vect
double operator*(Point op2);// produs scalar
Point& operator*(double v); // multipl. cu o const.

};
Point Point::operator+(Point op2){
point temp;
temp.x = x + op2.x;
temp.y = y + op2.y;
return temp;
}
Point Point::operator-(Point op2){
point temp;
temp.x = x + op2.x;

79
temp.y = y + op2.y;
return temp;
}
double Point::operator*(Point op2){
return x*op2.y + y*op2.x;
}
Point& Point::operator*(double v){
x *=v;
y *=v;
return *this;
}
void f1(){
Punct pct1(10,20);
Punct pct2(30,40);
Punct pct3;
pct1.Display(); // afiseaza 10 20
pct2.Display(); // afiseaza 30 40
pct3 = pct1 + pct2;
pct3.Display(); // afiseaza 40 60
pct3 = pct2 pct1;
pct3.Display(); // afiseaza 20 20
}

Funcia operator+() are un singur argument, chiar dac ea suprancarc un operator binar
pentru ca argumentul transmis funciei este operandul din dreapta operaiei, iar operandul din
stnga este chiar obiectul pentru care se apeleaz funcia operator.
Pentru acelai operator se pot defini mai multe funcii suprancrcate, cu condiia ca selecia uneia
dintre ele n funcie de numrul i tipul argumentelor s nu fie ambigu. n clasa Point s-a
suprancrcat operatorul * cu dou funcii: prima pentru calculul produsului scalar a doi vectori,
cealalt pentru multiplicarea vectorului cu o constant.

n implementarea prezentat, funcia operator+() creaz un obiect temporar, care este distrus
dup returnare. n acest fel, ea nu modific nici unul dintre operanzi, aa cum nici operatorul +
pentru tipurile predefinite nu modific operanzii.

La suprancrcarea operatorilor de incrementare sau decrementare (++, --) se poate diferenia un


operator prefix de un operator postfix folosind dou versiuni ale funciei operator. n continuare
sunt prezentate cteva funcii operator ale clasei Point pentru operatori unari.

80
Aplicatia P5.2
class Point{
//
public:
Point operator!();
Point operator++();
Point operator();
Point operator++(int x);
Point operator(int x);
};
Point operator!(){
x = -x;
y = -y;
return *this;
}
Point Point::operator++(){
x++;
y++;
return *this;
}
Point Point::operator--(){
x--;
y--;
return *this;
}
Point Point::operator ++(int x){
++x;
++y;
return *this;
}
Point Point::operator --(int x){
--x;
--y;
return *this;
}

Dac ++ precede operandul, este apelat funcia operator++(); dac ++ urmeaz


operandului, atunci este apelat funcia operator++(int x), iar x are valoarea 0.

5.3 Funcii operator membre ale claselor

81
La suprancrcarea unui operator folosind o funcie care nu este membr a clasei este necesar s
fie transmii toi operanzii necesari, deoarece nu mai exist un obiect al crui pointer (this) s
fie transferat implicit funciei. Din aceast cauz, funciile operator binar necesit dou argumente
de tip clas sau referin la clas, iar funciile operator unar necesit un argument de tip clas sau
referin la clas. n cazul operatorilor binari, primul argument transmis este operandul stnga, iar
al doilea argument este operandul dreapta

In Aplicatia P5.3 o parte din funciile operator ale clasei Point sunt implementate ca funcii
friend ale clasei.

class Point
{
int x;
int y;
public:
//.
friend Point operator+(Point op1, Point op2);
friend Point operator-(Point op1, Point op2);

Point operator+(Point op1, Point op2){


Point temp;
temp.x = op1.x + op2.x;
temp.y = op1.y + op2.y;
return temp;
}
Point operator-(Point op1, Point op2){
Point temp;
temp.x = op1.x - op2.x;
temp.y = op1.y - op2.y;
return temp;
}

void f2(){
Punct pct1(10,20);
Punct pct2(30,40);
Punct pct3;
pct1.Display(); // afiseaza 10 20
pct2.Display(); // afiseaza 30 40
pct3 = pct1 + pct2;
pct3.Display(); // afiseaza 40 60
pct3 = pct2 pct1;

82
}

Observatii

Dac functia operator este implementat ca o funcie membru, operandul cel mai
din stnga (eventual, unicul operand) trebuie s fie un obiect al clasei sau o referint
ctre un obiect al clasei. Implementarea sub form de funcie nemembru este
indicat n cazul n care cel mai din stnga operand este un obiect al unei clase
diferite sau al unui tip predefinit.
O funcie operator ne-membru trebuie declarat funcie friend dac functia
respectiv trebuie s acceseze direct membrii privati sau protejati ai clasei
respective.

Teste de autoevaluare

5.1 Care dintre afirmatiile urmtoare sunt adevrate?


(a) Precedenta unui operator poate fi modificat prin redefinire.
(b) Aritatea unui operator nu poate fi modificat prin redefinire.
(c) Asociativitatea unui operator poate fi modificata prin redefinire.
(d) Semnificatia modului n care lucreaz un operator asupra obiectelor
de tipuri predefinite nu poate fi schimbat prin redefinire.

5.2 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce
afieaz, n caz
negativ spunei de ce nu este corect.
#include<iostream.h>
class B
{ protected: int x;
B(int i=10) { x=i; }
public: virtual B operator+(B ob) { B y(x+ob.x);
return y;} };

83
class D: public B
{ public: D(int i=10) { x=i; }
void operator=(B p) { x=p.x; }
B operator+(B ob) { B y(x+ob.x+1);
return y; }
void afisare(){ cout<<x; } };
int main()
{ D p1(-59),p2(32),*p3=new D;
*p3=p1+p2;
p3->afisare();
return 0;
}

5.3 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce
afieaz, n caz negativ spunei de ce nu este corect. #include<iostream.h>
class cls
{ public: int sa;
cls(int s=0) { sa=s; }
operator int() { return sa; }
int f(int c) { return (sa*(1+c/100)); } };
int main()
{ cls p(37);
cout<<p.f(p);
return 0;
}

5.4 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce
afieaz, n caz negativ spunei de ce nu este corect. #include<iostream.h>
class B
{ public: int x;
B(int i=0) { x=i; }
virtual B aduna(B ob) { return(x+ob.x); }
B minus() { return(1-x); }
void afisare(){ cout<<x; } };
class D: public B
{ public: D(int i=0) { x=i; }
B aduna(B ob) { return(x+ob.x+1); } };
int main()
{ B *p1, *p2;
p1=new D(138);
p2=new B(-37);

84
*p2=p2->aduna(*p1);
*p1=p2->minus();
p1->afisare();
return 0;
}
5.5 Secvena urmatoare afiseaz:
class persoana
{int varsta;
public:
persoana(int v=18){varsta=v;}
persoana& operator++(int)
{varsta++;
return *this;}
int get_varsta(){return varsta;}};
int main(){
persoana p(20);
cout<<p++. get_varsta() ;}
Afiseaz :
a). 21 ;
b). 20 ;
c). 18;
d). 19;

5.6 Programul afiseaza


#include<iostream.h>
class salariat
{ int varsta;
public:
salariat (int v=20) {varsta =v;}
operator int() { return varsta;}
salariat& operator++( )
{varsta++; return *this;}
salariat operator++ (int)
{ varsta++; return *this;}};
int main()
{ salariat s(21);
int a =s++, b=++s;
cout<<a<< <<b<<endl;
}
Afiseaza:
a) 20 21;

85
b) 21 22;
c) 22 23;
d) 20 22;
e) 21 23;

Raspunsuri - teste de autoevaluare

5.1
(b), (d).
5.2
programul nu este corect pentru c data membra x din clasa B este protejat,
astfel aplelul sau n funcia operator adun nu este permis.
5.3
programul este corect i va afia pe ecran valoarea 37.
5.4
programul este corect i va afia pe ecran valoarea -100
5.5
(a)
5.6
(c)

Tema de autoinstruire

5.1 Diferenta dintre constructorul de copiere si metoda care supraincarca


operatorului de asignare.
5.2 Comparatie intre modalitatile supraincarca operatorii prin funcii membre si
funcii independente.

86
Aplicaii practice

1. Implementai clasa Fracie cu datele membre nr (numrtor) i num (numitor). Definii


urmtoarele operaii:
2. suma a dou fracii, folosind o metod membr;
3. nmulirea a dou fracii, folosind o funcie independent de tip friend;
4. simplificarea unei fracii, folosind o metod membr;

2. Sa se implementeze clasa String care modeleaz noiunea de ir de caractere, mpreun cu


operaii specifice:

class String{
char *p;
int len;
public:
String(char* mp);
String(String& s);
~String();
String& operator= (String& s);
String& operator=(char *p);
String operator+ (String& s);
String operator- (String& s); //elimina toate aparitiile sirului s.
}

3. Pentru clasa Complex, cu datele membre re (partea real) i im (partea imaginar), definii
urmtoarele funcii operator:

suma a dou numere complexe, folosind o metod membr;


conjugatul unui numr complex, folosind o metod membr;
nmulirea unui numr complex cu un scalar, folosind o funcie independent de tip friend;

87
Unitatea de nvare Nr. 6

OPERAII DE INTRARE/IEIRE

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui s:


nelegei funcii de I/O pentru tipuri predefinite;
nelegei funcii de I/O pentru TDA:
procesai fiiere de intrare si ieire;

Cuvinte cheie: stream, ostream, istream, fiier de intrare, fisier de ieire.

Timpul minim pe care trebuie s-l acordati acestui modul este de


2 ore.

6.1 Funcii de I/O pentru tipurile predefinite

Limbajul C++ introduce o ierarhie de clase pentru a realiza operaiile de intrare/ieire (I/O).
Aceast ierarhie are la baz conceptul de stream (flux).

Stream-ul este un concept abstract care nglobeaz orice flux de date de la o surs (canal de
intrare) la o destinatie (canal de ieiere)

Biblioteca standard ce nglobeaz ierarhia de clase pentru opretaii de I/O este iostream.h.

Operaiile de I/O din C++ se efectueaz folosind funciile operator de inserie << i operator de
extragere >>.

Funciile de operare asupra streamurilor specific modul n care se execut conversia ntre un ir
de caractere din stream i o variabil de un anumit tip. Aceste funcii operator sunt definite n clasa
ostream, respectiv istream, pentru toate tipurile predefinite ale limbajului, iar pentru tipurile
definite de utilizator ele pot fi suprancrcate.

88
Funcia de citire de la consol a unei secvene de numere ntregi separate prin spaii albe
(whitespace adic unul din caracterele blanc, tab, newline, carriage return, formfeed) poate arta
asfel:
int main(){
int size = 10;
int array[10];
for(int i=0;i<size;i++){
if (cin >> array[i])
cout << array[i] << " ";

else {
cout << "non int";
break;
}
}
}

O intrare diferit de ntreg va cauza eroare n operaia de citire i deci oprirea buclei for. De
exemplu, din intrarea:
1 2 3 4.7 5 6 7 8 9 0 11
se va citi primele patru numere, dup care apare eroare n operaia de intrare, citirea numerelor
ntregi se ntrerupe i pe ecran apare mesajul:
1 2 3 4 non-int
Caracterul punct este lsat n streamul de intrare, ca urmtor caracter de citit.

O alt soluie pentru citirea unei secvene de intrare este prin folosirea uneia din funciile get()
definite n clasa iostream astfel:

class iostream : public virtual ios {


//
istream& get(char& c);
istream& get(char* p, int n, char ch=\n);
};

Aceste funcii treateaz spaiile albe la fel ca pe toate celelalte caractere.


Funcia get(char& c) citete un singur caracter n argumentul c. De exemplu, o funcie fg()
de copiere caracter cu caracter de la intrare (streamul cin) la ieire (streamul cout) poate arta
astfel:

void stream(){

89
char c;
while(cin.get(c)) cout << c;
}

Funcia operator >> () are un echivalent ca funcie de scriere la consol fr


suprancrcarea operatorului >>, numit funcia put(), astfel nct funcia fg() se
poate rescrie astfel:

void stream(){
char c;
while(cin.get(c)) cout.put(c);
}

6.2 Funcii de I/O pentru tipuri definite de utilizator

Funciile de I/O pentru tipuri definite de utilizator se obin prin suprancrcarea operatorilor de
inserie i de extragere, care au urmtoarea form general:

ostream& operator<<(ostream& os,tip_clasa nume){


// corpul funciei
return os;
}
istream& operator<<(istream& is,tip_clasa& nume){
// corpul funciei
return is;
}

Primul argument al funciei este o referin la streamul de ieire, respectiv de intrare. Pentru funcia
operator de extragere << al doilea argument este dat printr-o referin la obiectul care trebuie s
fie extras din stream; n aceast referin sunt nscrise datele extrase din streamul de intrare. Pentru
funcia operator de inserie >> al doilea argument este dat prin tipul i numele obiectului care
trebuie s fie inserat, sau printr-o referin la acesta. Funciile operator de inserie i extracie
returneaz o referin la streamul pentru care au fost apelate, astfel nct o alt operaie de I/O
poate fi adugat acestuia.

Funciile operator << sau >> nu sunt membre ale clasei pentru care au fost definite, dar pot (i
este recomandabil) s fie declarate funcii friend n clasa respectiv.

Aplicatia P 6.1 se defineste clasa Complex care cuprinde funciile operator << si >>.

class Complex {
double x, y;

90
public:
Complex(){x = 0; y = 0}
Complex(double r, double i){
x = r;
y = i;
}
..
friend ostrem& operator << (ostrem& os,Complex z);
friend istream& operator >>(istream& is,Complex& z);
};
ostream& operator<<(ostream& os, Complex& z){
os << ( << z.x << ,<< z.y << );
return os;
}
istream& operator>>(istream& is, Complex z){
is >> z.x >> z.y;
return is;
}

int main(){
Complex z;
cout << "Introduceti x, y :";
cin >> z;
cout << "z = " << z << '\n';
cin.get();
int size = 10;

Execuia acestei funcii produce urmtoarele mesaje la consol:

Introduceti x, y: 1.3 4.5


z = (1.3,4.5)
Introduceti un sir:123456
123456

6. 3 Procesarea fisierelor

Fisierul antet <fstream.h> cuprinde definitiile claselor speficice streamului de tip fiier: ifstream
(pentru intrrile dintr-un fisier operatii de citire din fisier), ofstream (pentru iesirile ctre un fisier
operatii de scriere n fisier) si fstream (pentru intrrile/iesirile de la/ctre un fisier).

Pentru utilizarea unui fiier pe disc acesta trebuie s fie asociat unui stream. Pentru aceasta se
creaz mai nti un stream, iar apelul funciei open() a streamului execut asocierea acestuia cu un

91
fiier ale crui caracteristici se transmit ca argumente ale funciei open(). Funcia open() este
funcie membr a fiecreia dintre cele trei clase stream (ifstream, ofstream i fstream)
class ios{
public:
// ..
enum open_mode {
in=1, // desch. pt. citire
out=2, // desch. pt. scriere
ate=4, // desch. pt cutare
app=010, // adaugare (append)
trunc=020, // trunchiere
nocreate=040, // er. daca nu exista fis.
noreplace=0100 // er. daca fis. exista
};
//
};
Argumentul mode este opional pentru streamuri de intrare ifstream, pentru care valoarea implicit
este ios::in, i pentru streamuri de ieire ofstream, pentru care valoarea implicit este ios::out.
Pentru streamuri de intrare/ieire fstream, argumentul mode trebuie s aib una din valorile definite n
clasa ios. n argumentul mode se pot combina prin operatorul OR (SAU) dou sau mai multe din aceste
valori definite.

Exemple de apeluri ale funciei open() pentru deschidere de fiiere:

ifstream in;
input.open("date_intrare.txt");
ofstream out;
output.open("date_iesire.txt");
fstream inout;
inout.open("fisier", ios::in|ios::out);

Deschiderea unui fiier se poate realiza prin declaraii care apelaza un constructor de iniializare al
streamului. De exemplu, se pot rescrie definirile de streamuri i fiiere asociate de mai sus astfel:
ifstream input("intrare.txt");
ofstream output("iesire.txt");
fstream inout("fisier", ios::in|ios::out);
Implicit, fiierele se deschid n mod text. Valoarea ios::binary determin deschiderea n mod binar
a fiierului.

Pentru nchiderea unui fiier se apeleaz funcia close(), care funcie membr a claselor stream
(ifstream, ofstream i fstream).
Pentru scrierea i citirea dintr-un fiier de tip text se folosesc funciile operator << i >> ale
streamului asociat acelui fiier. Aceste funcii operator suprancrcate pentru un anumit tip de date

92
pot fi folosite fr nici o modificare att pentru a scrie sau citi de la consol ct i pentru a scrie
sau citi dintr-un fiier pe disc.

Aplicatia P6.2 creaz un fiier de inventariere inventar.txt care conine numele


articolului, preul unitar, numrul de buci i valoarea total.
void finv(){
ofstream output("inventar.txt");
if (!output)
cout << "Nu se poate deschide
fisierul inventar.txt\n";

char buffer[80];
double pret,total;
int buc;
while(1){
cout << "\nArticol: ";
cin.get(buffer,80);
if (buffer[0] == 0)
break;
cout << "Pret unitar: ";
cin >> pret;
cout << "Nr. bucati: ";
cin >> buc; cin.get();
total = buc*pret;
output << buffer << endl;
output << pret<< endl;
output << buc << endl;
output << total << endl;
}
output.close();
}

Aplicatia P6.3 definete clasa Produs cu datele membre deumire, pret stoc. Datele
produselor se afl n fierul Produs.txt, pe cte o linie. Se definete un tablou de obiecte de tip
Produs cu datele membre ncrcate din fiier i se afieaza n fiierul Stoc.txt vlaorea stocului
pentru fiecare produs (pret*stoc).

93
class Produs
{
char* denumire;
double pret;
int cantitate;
public:
Produs();
Produs(char* denumire, double pret, int cantitate);
void afisare_date();
void set_denumire(char *T);
void set_cantitate(int A);
void set_pret(double P);
char* get_denumire();
double get_pret();
int get_cantitate();
};
Produs::Produs()
{
denumire=new char[4];
strcpy(denumire,"###");
pret=0.0;
cantitate=0;
}
Produs::Produs(char* denumire, double pret, int cantitate)
{
this->denumire=new char[strlen(denumire)+1];
strcpy(this->denumire,denumire);

this->pret=pret;
this->cantitate=cantitate;
}
void Produs::afisare_date()
{
cout<<denumire<<" "<<pret<<" "<<cantitate<<endl;
}
void Produs::set_denumire(char *T)
{
if(denumire)
delete []denumire;
this->denumire=new char[strlen(T)+1];
strcpy(this->denumire,T);
}

94
void Produs::set_cantitate(int A)
{
cantitate=A;
}
void Produs::set_pret(double P)
{
pret=P;
}

int main()
{
ifstream fin("Produs.txt");
char linie[100];

int k=0;//nr de linii;


//se numra cate produse sunt in fisier
while(fin.getline(linie,100)!=NULL)
k++;
Produs tab[k];
//pozitionare la inceputul fisierului
fin.clear();
fin.seekg(0);
int i=0,c;
double a;
//se parcurge fisierul
while(fin.getline(linie,100)!=NULL)
{
char *p=strtok(linie," ");
tab[i].set_denumire(p);

p=strtok(NULL," ");
a=atof(p);
tab[i].set_pret(a);

p=strtok(NULL," ");
c=atoi(p);
tab[i].set_cantitate(c);

i++;
}

ofstream fout("ValoareStoc.txt");
for(i=0;i<k;i++)

95
{
tab[i].afisare_date();
//fout<<tab[i].denumire

return 0;
}

6.4 Accesul aleator la fiiere


Accesul aleator la datele dintr-un fiier se realizeaza utilizand doi pointeri: pointerul de citire (get) care
specific poziia de unde va avea loc urmtoarea citire din fiier i pointerul de scriere (put), care specific
poziia unde va avea loc urmtoarea scriere n fiier. Dup fiecare operaie de citire sau de scriere, pointerul
corespunztor este avansat secvenial n fiier. Pentru poziionarea ntr-o anumit poziie a celor pointeri se
folosesc funcii membre publice ale claselor de baz istream, ostream.

Pentru accesul aleator n operaiile de ieire se pot folosi urmtoarele funcii membre publice ale clasei
ostream:
class ostream: public virtual ios {
// .
public:
ostream& seekp(streampos pos);
ostream& seekp(streamoff offset, seek_dir orig);
streampos tellp();
//
};

ipurile de date streamoff i streampos sunt definite n fiierul antet iostream.h,


Funcia seekp() cu un argument poziioneaz pointerul de inserie a fiierului la valoarea pos, dat ca
argument, iar funcia seekp() cu dou argumente deplaseaz pointerul de inserie al fiierului asociat
streamului cu un numr de caractere egal cu valoarea offset fa de originea orig specificat ca
argument.
Funcia tellp() returneaz poziia curent de scriere n fiier, deci valoarea pointerului de scriere.

96
Tema de autoinstruire

6.1 Clasele predefinite, dedicate procesrii fisierelor;


6.2 Funcii de I/O pentru tipuri predefinite de date.

Aplicaii practice

1. S se realizeze un program care s asigure gestiunea unei biblioteci universitare cu cri n


diferite domenii (literatur, informatic, fizic, matematic, mecanic etc.). La fiecare carte se
cunoate: autor, titlu, cota, editura, anul_apariiei, nr_ediie, mprumutat (cmp care poate
lua urmtoarele valori: 0 dac nu este mprumutat i data pn cnd este mprumutat).
La pornirea aplicaiei va fi afiat urmtorul meniu:
ncrcare bibliotec dintr-un fiier.
Creare domeniu nou.
Adugare carte la un anumit domeniu.
Cutare carte n bibliotec.
tergere carte din bibliotec.
mprumutare / Returnare carte (dup cot).
Verificare cri cu termen depit de mprumut.
Salvare n fiier a bibliotecii.
Ieire

2. S se realizeze un program care s asigure gestionarea angajailor unei firme. Pentru un angajat
se cunosc urmtoarele cmpuri: nume, prenume, vrst, adres, departament, funcie, salariu,
zile_concediu. La pornirea aplicaiei se vor ncrca din fiier datele despre angajai, iar la fiecare
angajat n parte luna, salarul i zilele de concediu rmase.
Se va afia urmtorul meniu:
Adugare angajat nou.
tergere angajat cu toate informaiile corespunztoare acestuia.
Adugare salariu i zile de concediu rmase ntr-o anumit lun citit de la tastatur, la un
angajat citit.
Afiare angajai ordonai:
o dup nume
o dup media salariului de pe toate lunile
Afiare angajai cu zile de concediu rmase din cadrul unui departament.
Ieire

97
Unitatea de nvare Nr. 7

FACILITAII ALE LIMBAJULUI C++

Obiective:

Dup ce vei parcurge aceast unitate de nvare, vei reui s:


construii clase ablon;
instaniai clase ablon;

Cuvinte cheie: clase template, funcii template, exceptii.

Timpul minim pe care trebuie s-l acordati acestui modul este de 2 ore.

7. 1 Funcii i clase template

O alt facilitate important a limbajului C++ este dat de posibilitatea definirii unor sabloane
numite template-uri. Un template reprezint o modalitate de parametrizare a unei clase sau a unei
funcii prin utilizarea unui tip n acelasi mod n care parametrii unei funcii furnizeaz o modalitate
de a defini un algoritm abstract fr identificarea valorilor specifice.

O clas template specific modul n care pot fi construite clase individuale, difereniate prin tipul
sau tipurile de date asupra crore se opereaz.

Sintaxa definirii unui template:


template <class <parametru> > class <nume_clas>
{
// definitia clasei sablon
};

Aplicatia P7.1 prezint un exemplu de definire a unei funcii template, afisare_vector(.).


Aplicarea funciei template celor trei variabile T1, T2 si respectiv T3 va determina afisarea

98
unui vector de numere ntregi, a unui vector de numere reale, respectiv a unui vector de
caractere.

#include <iostream.h>
template <class T>
void afisare_vector(const T *t, const int nr)
{
for (int i=0;i<nr;i++)
cout<<t[i]<<" ";
}
void main()
{
const int nr1 = 5, nr2 = 7, nr3 = 4;
int T1[nr1] = {1,2,3,4,5};
double T2[nr2] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7};
char T3[nr3] = "Ana";
cout<<"\n Vectorul contine: ";
// functia template pentru vector de numere intregi
afisare_vector(T1, nr1);
cout<<"\n Vectorul contine: ";
// functia template pentru vector de numere reale
afisare_vector(T2, nr2);
cout<<"\n Vectorul contine: ";
// functia template pentru vector de caractere
afisare_vector(T3, nr3);
}

Clasele template sunt descrieri parametrizate de clasa, care vor fi adaptate ulterior diferitelor
tipuri de date recunoscute de limbaj.

Aplicatia 7. 2 defineste o clasa template pentru un obiect de tip vector in memorie dinamica,
continad adresa ade inceput si dimensiunea lui, ceruta la alocare. Initial, tipul elementelor
stocate in vector este generic, iar in functia principala main() se solocita particularizari ale
clasei template pentru tipul int si double.

template<class T> class vector


{
T * vec;
int size;
public:
vector(int n)
{

99
dim=n;
vec=new T[n];
for(int i=0;i<size;i++)
cin>>vect[i];
}
void afisare()
{
for(int i=0;i<size;i++)
cout<<vect[i];
}
int get_size()
{ return size;}
}
void main( )
{
vector<int> vi(3);
vi.afisare();
vector<double>vd(4);
vd.afisare();
}
Observaii:
vi este un vector cu trei elemente intregi;
vd este un vector cu patru elemente reale;
metodele se apleaza in mod obisnuit, fara a necesita o sintaxa speciala;
template-urile furnizeaz o alt form de polimorfism.

7.2 Instantierea sabloanelor

Un sablon de clas poate fi instaniat devenind o clas concret prin substituirea tipurilor generice
cu tipuri concrete. La definirea sabloanelor de clasa atat datele , ct i funciile membre se definesc
in legatura cu unul sau mai multe tipuri generice. Funciile membre pot avea aceeasi denumire prin
tehnica de supraincarcare, in schimb doua clase nu pot avea aceelasi nume deoarece o clasa
corespunde de fapt unui tip de data. Utilizand clasele template se poate construi un singur tip care
sa aiba mai multe denumiri. Adica, programatorul poate referi clasele construite din template dupa
n nume compus din numele dat de el in sablon, urmat de diverse nume de tip pentru care se cere
instantierea modelului.

Putem avea n consecin clasele vector<int>, vector<douable> etc. care sunt particularizri ale
modelului de clasa vector. Numele de instan a clasei template poate fi folosit nu numai pentru
pentru generari de obiecte ale clasei, ci i pentru a descrie funcii care nu sunt template.

100
In Aplicatia 7.3 se definete o funcie care verific dac doi vectori au aceealai numar de
componente. Funcia va returna -1, 0, 1 daca primul vector este mai scurt, egal sau mai
lung decat cel de al doilea.

int masoara(vector<int> &v1,vector<double>&v2)


{
int size1=v1. get_size(), size2=v2.get_size();
if(size1==size2) return 0;
else
if(size1<size2) return -1;
else
return +1;
}

Tema de autoinstruire

7.1 Utilitatea funciilor template;


7.2. Instantierea claselor template;

Aplicaii practice

7.1 S se defineasc o clas template pentru reprezentarea unui liste simplu inlantuite de date de un tip
oarecare T, Tvector. Definiti o lista de numere intregi, lista de obiecte de tip Student definit in
aplicatia 3.1

7.2 S se definesc un vector de iruri de caractere (obiecte de clas String) folosind clasa template
TArray<String> i s se verifice funcionarea acestuia ca stiv i coad de iruri de caractere.

7.3 S se defineasc o clas template pentru reprezentarea unui stive de date de un tip oarecare T, Tvector.
Definiti o stiva de numere intregi, o stiva de obiecte de tip Fractie definit n aplicatia 2.3.

101
Teste de evaluare:
Specificai varianta corect :

1. Clasa
class c { float a;
void afisisare();
}
are membrii:
a) publici; b) privai
c) protected; d) date private i metode pubice.
2. Fie secvena:
class c {....};
void main()
{ c e
/* instructiuni */
}
n acest caz:
a) c este un obiect i e este clas;
b) c este o instana a clasei i e este un obiect;
c) c este o clasa i e este un obiect;
d) descrierea este eronat deoarece se folosete acelai identificator pentru clas i obiect.

3. Avnd declaraia:
class persoana {
char nume[20];
int varsta;
public:
persoana();
int spune_varsta() { return varsta;}
};
void main()
{persoana p;
cout<<p.nume<<p.varsta;
}
n acest caz :
a) programul afiseaz numele i vrsta unei persoane;
b) nu este permis afisarea datelor unei persoane;
c) descriere eronat pentru c funcia membra nu este utilizat;
d) afiseaz doar vrsta unei persoane.

4. Fie clasa :
class c { int a,b;

102
public:
float c (int, int)
int det_a {return a;}
c (); }
Declaraia float c(int, int) ar putea corespunde unui constructor al clasei?
a) da, fiind o suprancarcare a celui existent;
b) nu, deoarece creaz ambiguitate;
c) nu, deoarece constructorul nu are tip returnat;
d) nu, deoarece nu este de tip friend.

5. Fie declaraia :
class c1 {int a ;}
class c2 :public c1
{ public :
int b ;
void scrie_a() {cout<<a ;}
}
void main ()
{ c2 ob ;
ob.scie_a () ;
}
Selectai afirmaia corect :
a) funcia scrie_a() nu are drept de acces asupra unui membru privat;
b) programul afiseaz valoare lui a;
c) derivarea public este incorect relaizat;
d) prin derivare public, accesul la membrii moteniti devine public.

6. Fie declaraia
class c1{/* instructiuni */}
class c2:public c1 {/* .*/}
Atunci clasa c2 faa de clasa c1 este:
a). derivat; b). de baz; c). friend d). virtual.

7. n secvena urmtoare:
class cls { public:static int s;};
int cls::s=0;
int main(){int i=7;cls::s=i;cout<<cls::s;}
Utilizarea lui s este:
a) ilegal, deoarece nu exist nici un obiect creat;
b) ilegal, deoarece variabilele statice pot fi doar private;
c) ilegal, deoarece s este dublu definit, n clas i n afara ei;
d) corect, deoarece membrii statici exist nainte de a se crea obiecte din clasa.

8. Secvena urmatoare:

103
class persoana
{ int varsta, salariul;
friend ostream & operator<<(ostream &out,persoana p)
{out<<p.varsta<< <<p.salariul; return out;}
public:
persoana(int v){varsta=v;salariul=0;}
persoana(){varsta=0;salariul=0;}
}
int main()
{persoana p(1);cout<<p;}
Afiseaz:
a). afiseaz 1 0; b). afiseaz 0 0
c). afiseaz 1 1; d). afiseaz 0 1.

9. Secvena urmatoare:

class vector{int*pe,nr_c;
public:
operator int(){return nr_c;}
vector(int n){
pe=new int[n];nr_c=n;
while(n--) pe[n]=n;}
void f(int i){cout<<i<<endl;}
int main()
{vector x(10); f(x)}
Afiseaz:
a). 10 b). 9
c). numerele de la 1 la 10
d). numerele de la 0 la

10. Secvena urmatoare:


class vector{int*pe,nr_c;
public:
operator int(){return nr_c;}
vector(int n){
pe=new int[n];nr_c=n;
while(n--) pe[n]=n;}
void f(int i){cout<<i<<endl;}
int main()
{vector x(10); f(x)}
Afiseaza:
a). 10
b). 9
c). numerele de la 1 la 10
d). numerele de la 0 la 9

104
11. Secvena urmatoare:
class persoana
{int varsta;
public:
persoana(int v=18){varsta=18;}
operator int(){return varsta;}
persoana& operator++()
{varsta++;return *this;}
persoana operator ++(int)
{persoana aux=*this;varsta++;return aux;}
int main(){
persoana p(20);
int x=p++,y=++p;
cout<< x<< y ;}
Afiseaz:
a).20 20;
b).20 21 ;
c).21 22;
d).20 22.

12 . Fie secvena :
class c { int a;
public: c();
c(const c&);
void operator=(c&);}
int main()
{ c a;
//instructiuni;
c b=a;}
Linia c b=a; determin:
a). execuia constructorului de copiere;
b). execuia metodei prin care se supraincarc operatorul =;
c). execuia att a constructorului de copiere, ct i a metodei operator =;
d). execuia contructorului implicit

13. Se consider urmatoarea secvena de program:

class complex
{
double real;
double imag;
public:
complex(double x=10.0, double y=10.0){real=x; imag=y;}
complex(const complex &u)
{

105
real=u.real;
imag=u.imag;
}
..............
}
Precizai n care situatie se realizeaza o copiere a unui obiect n alt obiect:
a) complex z1(3.42, -12.9);
b) complex z2=z1;
c) complex z3(1.0,-1.0);
d) complex z(10.7,0.8);
e) complex z(23.25);

14. Se consider urmatoarea secventa de program:


class complex
{
double re;
double im;
public:
complex(double x=-11.0, double y=-56.90){re=x; im=y;}
complex( const complex &u)
{
real=u.re;
imag=u.im;
}
............
}
Precizati n situatie se utilizeaza constructorul de copiere:
a) complex z1(3.4, -12.9);
b) complex z3(0.0,-10.9);
c) complex z2(0.0,1.0);
d) complex z3(z1);
e) complex z(2.25);

15. Se considera urmatoarea secventa de program:


class complex
{
double real;
double imag;
public:
complex(double x=-11.0, double y=-56.90){real=x; imag=y;}
complex( const complex &u)
{
real=u.real;
imag=u.imag;
}

106
..............
}
Precizati situatia n care nu era necesara folosirea unui constructor cu parametri care iau
valori n mod implicit:
a) complex z2(3.42,-12.9);
b) complex z3(z2);
c) complex z=z2;
d) complex z4(z);
e) complex z5=z4;

16. Se d secvena de program:


class A
{
int a[3];
public:
A(int i, int j, int k){a[0]=i; a[1]=j; a[2]=k;}
int &operator[](int i){return a[i];}
};
void main(void)
{
A ob(1,2,3);
cout << ob[1];
ob[1]=25;
cout<<ob[1];
}
Ce se poate afirma despre operator[]()?
a) produce suprancarcarea unei funcii;
b) produce suprancarcarea unui operator unar;
c) suprancarca operatorul [];
d) este o funcie membru oarecare a clasei A care nu produce suprancarcarea unui
operator;
e) reprezinta un operator ternar;

17. Suprancarcarea unor operatori se poate realiza prin funcii operator sau funcii friend.
Diferenta ntre aceste doua posibilitati consta n:
a) lista de parametri;
b) obiect returnat;
c) precedent a operatorilor;
d) n-aritatea operatorului;
e) alte situatii.

18. In secventa de program:


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

107
int k=100;
void fct()
{
int k;
...........
k++;
...........
}
void gct()
{
int k=2;
...........
::k++; // (?)
...........
}
In instructiunea marcata cu (?), k este o variabila:
a) externa;
b) statica;
c) registru;
d) globala;
e) automatica;

19. Se considera secvena de program:


class B1 { class D1:public B1,public B2 {
public: public:
B1(){cout<<"(1)\n";} D1(){cout<<"(7)\n";}
~B1(){cout<<"(2)\n";} ~D1(){cout<<"(8)\n";}
}; };
class B2 { class D2:public D1,public B3 {
public: public:
B2(){cout<<"(3)\n";} D2(){cout<<"(9)\n";}
~B2(){cout<<"(4)\n";} ~D2(){cout<<"(10)\n";}
}; };
class B3 {
public:
B3(){cout<<"(5)\n";}
~B3(){cout<<"(6)\n";}
};
void main(){
D1 ob1;
D2 ob2;
}
Care mesaj se va scrie?
a) (1),(3),(7),(3),(5),(7),(9),(10),(6),(8),(4),(2),(2),(3),(2),(2);
b) (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(9),(7),(2),(3),(2),(2);
c) (1),(3),(7),(1),(3),(7),(5),(9),(10),(6),(8),(4),(2),(8),(4),(2);
d) (1),(3),(5),(7),(9),(2),(4),(6),(6),(8),(8),(10),(2),(2),(4),(2);

108
e) (1),(3),(7),(1),(3),(7),(9),(5),(10),(6),(4),(8),(2),(8),(4),(2);

20. Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n
caz negativ spunei de ce nu este corect. #include <iostream.h>
template <class tip>
class cls
{ tip z;
public: cls(tip i) { z=i; }
tip operator-(cls); };
template <class tip>
tip cls<tip>::operator-(cls<tip> a)
{ return z-a.z;
}
template <class tip>
tip dif(tip x, tip y)
{ return x-y;
}
int dif(int x, int y)
{ return x>=y?x-y:y-x;
}
int main()
{ cls<int> i=3; cls<float> j=4;
cout<<dif(i,j);
return 0;
}

21. Descriei pe scurt cum putei prelua o dat prin incluziune i a doua oar prin motenire o
clas numar ntr-o clas lista care descrie liste nevide de dimensiune variabil de elemente
de tip numar.

22. Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n
caz negativ spunei de ce nu este corect.
#include<iostream.h>
class cls
{ static int x;
public: cls(int i=25) { x=i; }
friend int& f(cls); };

int cls::x=-13;
int& f(cls c) { return c.x; }
int main()
{ cls d(15);
cout<<f(d);
return 0;
}

109
23. Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n caz
negativ spunei de ce nu este corect.

#include<iostream.h>
class cls
{ int v,nr;
public: cls(int i) { nr=i; v=new int[i]; }
friend int& operator[](int);
friend ostream& operator<<(ostream&,cls); };
int& operator[](cls& x, int i)

{ return x.v[i]; }
ostream& operator<<(ostream& o, cls x)
{ for(int i=0;i<x.nr;i++) cout<<x.v[i]<< ; return o; }
int main()
{ cls x(10);
x[5]=7;
cout<<x;
return 0;
}

24. Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n
caz negativ spunei de ce nu este corect.
#include<iostream.h>
class cls
{ static int i;
int j;
public: cls(int x=7) { j=x; }
static int imp(int k){ cls a; return i+k+a.j; } };

int cls::i;
int main()
{ int k=5;
cout<<cls::imp(k);
return 0;
}

25. Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n
caz negativ spunei de ce nu este corect.
#include<iostream.h>
class cls
{ int x;
public: cls(int i=32) { x=i; }
int f() const; };

int cls::f() const { return x++; }


void main()

110
{ const cls d(-15);
cout<<d.f();
}

26. Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz pentru
o valoare ntreag citit egal cu 7, n caz negativ spunei de ce nu este corect.

#include <iostream.h>
float f(float f)
{ if (f) throw f;
return f/2;
}
int main()
{ int x;
try
{
cout<<Da-mi un numar intreg: ;
cin>>x;
if (x) f(x);
else throw x;
cout<<Numarul <<x<< e bun!<<endl;
}
catch (int i)
{ cout<<Numarul <<i<< nu e bun!<<endl;
}
return 0;
}
27. Descrieti trei metode de proiectare diferite prin care elementele unei clase se pot regsi n
dublu exemplar, sub diverse forme, n definitia altei clase.

28. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spunei de ce nu este corect.
#include<iostream.h>
class B
{ int x;
public: B(int i=10) { x=i; }
int get_x() { return x; } };
class D: public B
{ public: D(int i):B(i) {}
D operator+(const D& a) {return x+a.x; } };
int main()
{ D ob1(7), ob2(-12);
cout<<(ob1+ob2).get_x();
return 0;
}

111
29. Spunei dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.
#include<iostream.h>
class B
{ public: int x;
B(int i=16) { x=i; }
B f(B ob) { return x+ob.x; } };
class D: public B
{ public: D(int i=25) { x=i; }
B f(B ob) { return x+ob.x+1; }
void afisare(){ cout<<x; } };
int main()
{ B *p1=new D, *p2=new B, *p3=new B(p1->f(*p2));
cout<<p3->x;
return 0;
}
30. Spunei ce este obiectul implicit al unei metode si descrieti pe scurt propriettile pe care
le
cunoasteti despre acesta.

31. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

32. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

#include<iostream.h>
class cls
{ int x;
public: cls(int i=-20) { x=i; }
const int& f(){ return x; } };
int main()
{ cls a(14);
int b=a.f()++;
cout<<b;
return 0;
}
33. Descriei pe scurt mostenirea virtual si scopul n care este folosit.

34. Spunei dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

112
#include<iostream.h>
class B
{ static int x;
int i;
public: B() { x++; i=1; }
~B() { x--; }
static int get_x() { return x; }
int get_i() { return i; }
};
int B::x;
class D: public B
{ public: D() { x++; }
~D() { x--; }
};
int f(B *q)
{ return (q->get_i())+1;
}
int main()
{ B *p=new B;
cout<<f(p);
delete p;
p=new D;
cout<<f(p);
delete p;
cout<<D::get_x();
return 0;
}
35. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

#include<iostream.h>
class B
{ int x;
public: B(int i=17) { x=i; }
int get_x() { return x; }
operator int() { return x; } };
class D: public B
{ public: D(int i=-16):B(i) {} };
int main()
{ D a;
cout<<27+a;
return 0;
}

36. Enumerai 3 metode de implementare a polimorfismului de compilare.

113
37. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

#include<iostream.h>
class cls
{ static int x;
public: cls (int i=1) { x=i; }
cls f(cls a) { return x+a.x; }
static int g() { return f()/2; } };
int cls::x=7;
int main()
{ cls ob;
cout<<cls::g();
return 0;
}

38. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

#include<iostream.h>
class cls
{ int *v,nr;
public: cls(int i=0) { nr=i; v=new int[i];
for (int j=0; j<size(); j++) v[j]=3*j; }
~cls() { delete[] v; }
int size() { return nr; }
int& operator[](int i) { return v[i]; }
cls operator+(cls); };
cls cls::operator+(cls y)
{ cls x(size());
for (int i=0; i<size(); i++) x[i]=v[i]+y[i];
return x; }
int main()
{ cls x(10), y=x, z;
x[3]=y[6]=-15;
z=x+y;
for (int i=0; i<x.size(); i++) cout<<z[i];
return 0;
}

39. Descrieti pe scurt mecanismul de tratare a exceptiilor.

40. Spunei dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

114
#include<iostream.h>
class B
{ int i;
public: B() { i=1; }
int get_i() { return i; }
};
class D: public B
{ int j;
public: D() { j=2; }
int get_j() {return j; }
};
int main()
{ B *p;
int x=0;
if (x) p=new B;
else p=new D;
if (typeid(p).name()=="D*") cout<<((D*)p)->get_j();
return 0;
}

41. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

#include <iostream.h>
class cls
{ int x;
public: cls(int i) { x=i; }
int set_x(int i) { int y=x; x=i; return y; }
int get_x(){ return x; } };
int main()
{ cls *p=new cls[10];
int i=0;
for(;i<10;i++) p[i].set_x(i);
for(i=0;i<10;i++) cout<<p[i].get_x(i);
return 0;
}
42. Descriei pe scurt diferenta dintre un pointer si o referint.

43. Spuneti dac programul de mai jos este corect. n caz afirmativ, spuneti ce afiseaz, n
caz
negativ spuneti de ce nu este corect.

#include <iostream.h>
template<class T>
int f(T x, T y)
{ return x+y;

115
}
int f(int x, int y)
{ return x-y;
}
int main()
{ int a=5;
float b=8.6;
cout<<f(a,b);
return 0;
}

44. Spunei pe scurt prin ce se caracterizeaz un cmp static al unei clase.


45 . Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, n caz
negativ spunei de ce nu este corect. #include<iostream.h>
class cls1
{ public: int a;
cls1() { a=7; } };
class cls2
{ public: int b;
cls2(int i) { b=i; }
cls2(cls1& x) { b=x.a; } };
int main()
{ cls1 x;
cout<<x.a;
cls2 y(x);
cout<<y.b;
return 0; }

116
BIBLIOGRAFIE

1. Bjarne Strostroup- The C++ Programming Language, 4th Edition, Addison Wesley, 2013

2. Dr. K. Jamsa, L. Klander ,Totul despre C si C++ - Manualul fundamental de C i C++,


Editura Teora, 2010

3. Smeureanu, M. Dardila - Programare orientat pe obiecte n limbajul C++, Editura CISON,


Bucureti 2005;

4. Oprea M - Programare orientat pe obiecte - Exemple n limbajul C++, Editura Matrix Rom.

5. Liviu Negrescu - Limbajul C++, Editura ALBASTRA , Cluj 2000.

6. Luminita Duta - Programarea calculatoarelor in limbajul C++ , Editura Cetatea de Scaun


2006.

117

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