Documente Academic
Documente Profesional
Documente Cultură
FACULTATEA DE INFORMATIC
- 2010 -
Cuprins
Cap. 1 Introducere in programarea orientata pe obiecte ..................................................................3
1.2 Concepte ale programrii orientate pe obiecte.......................................................................5
1.3 Elemente introductive ale programrii orientate pe obiecte n limbajul C++ ......................7
1.4 Tipuri de date .........................................................................................................................9
1.5 Operatori specifici C++........................................................................................................17
Cap.2 Clase si Obiecte .................................................................................................................21
2.1 Definirea unei clase..............................................................................................................23
2.2 Constructori si destructor .....................................................................................................25
2.3 Tablouri de obiecte...............................................................................................................31
2.4 Funcii i clase friend ...........................................................................................................32
2.5 Funcii inline .......................................................................................................................33
2.6 Date si functii statice ............................................................................................................34
Capitolul 3 .Mostenire....................................................................................................................41
3.1 Relatia de mostenire. Clase de baz si clase derivate ..........................................................41
3.2 Constructori i destructori n clasele derivate ......................................................................44
3.3 Controlul accesului la membrii clasei de baz .....................................................................45
3.4 Mostenirea multipla..............................................................................................................47
3.4 Clase de baz virtuale...........................................................................................................50
3.6 Funcii virtuale i polimorfism.............................................................................................51
3.7 Clase abstracte......................................................................................................................54
3.8 Polimorfism..........................................................................................................................56
Cap. 4 Facilitti ale limbajului C++...............................................................................................64
4.1 Supraincarcarea operatorilor ................................................................................................64
4.2 Funcii operator membre ale claselor ...................................................................................64
4. 3 Template-uri ........................................................................................................................68
4.4 Stream-uri de I/E ..................................................................................................................69
4.5 Funcii de I/O pentru tipurile predefinite .............................................................................69
Funcii de I/O pentru tipuri definite de utilizator .......................................................................71
4. 6 Procesarea fisierelor ............................................................................................................72
Teste recapitulative: .......................................................................................................................76
Obiective:
Conceptul programre orientata pe obiecte;
Paralela ntre programarea procedural si cea orientat pe obiecte;
Tipuri de date abstracte. Abstractizare;
Concepte de baz ale programrii orientate pe obiecte;
Scurta incursiuni n programarea orientat pe obiecte prin intermediul limbajului C++.
Modalitile (tehnicile, paradigmele) de programare au evoluat de-a lungul anilor, reflectnd
trecerea de la programe de dimensiuni reduse, la programe i aplicaii de dimensiuni foarte mari,
pentru coordonarea crora sunt necesare tehnici evoluate.
Software-ul de dimensiuni mari, care nu poate fi realizat de o singur persoan, intr n categoria
sistemelor complexe, cu o mare diversitate de aplicaii.
Situaiile reale i experiene ale psihologilor au relevat limitele capacitii umane n perceperea
sistemelor complexe, adic imposibilitatea unei persoane de a percepe i controla simultan un
numr mare de entiti de informaie. De aceea, este esenial descompunerea i organizarea
sistemelor complexe, pentru a fi percepute, proiectate sau conduse.
Modul n care este abordat programarea, din punct de vedere al descompunerii programelor,
definete mai multe tehnici de programare , care s-au dezvoltat i au evoluat odat cu evoluia
sistemelor de calcul.
Programarea procedural este prima modalitate de programare care a fost i este nc frecvent
folosit. n programarea procedural accentul se pune pe descompunerea programului n
proceduri (funcii) care sunt apelate n ordinea de desfurare a algoritmului. Limbajele care
suport aceast tehnic de programare prevd posibiliti de transfer a argumentelor ctre funcii
i de returnare a valorilor rezultate. Limbajul Fortran a fost primul limbaj de programare
procedural. Au urmat Algol60, Algol68, Pascal, iar C este unul din ultimele invenii n acest
domeniu.
Programarea modular. n cursul evoluiei programrii procedurale, accentul n proiectarea
programelor s-a deplasat de la proiectarea procedurilor ctre organizarea datelor, aceast
deplasare reflectnd creterea dimensiunilor programelor. O mulime de proceduri corelate,
mpreun cu datele pe care le manevreaz, sunt organizate ca un modul. Tehnica de programare
modular decide descompunerea unui program n module, care ncorporeaz o parte din datele
programului i funciile care le manevreaz. Aceast tehnic este cunoscut ca tehnic de
ascundere a datelor (data-hiding). n programarea modular stilul de programare este n
3
continuare procedural, iar datele i procedurile sunt grupate n module, existnd posibilitatea de
ascundere a unor informaii definite ntr-un modul, fa de celelalte module. Gruparea de date i
proceduri n module nu implic i o asociere strict ntre acestea.
Programarea orientat pe obiecte apeleaza la o modalitate nou de gndire a unei probleme.
Spre deosebire de programarea procedural care se concentreaz pe structuri de date si algoritmi,
programarea orientat pe obiecte se concentreaz pe definirea de obiecte care modeleaz
problema ce trebuie rezolvat.
n programarea orientat pe obiecte (POO) un program are rolul de a simula strile si activittile
obiectelor lumii reale. Pe lng structuri de date (care descriu strile obiectelor, atributele
acestora) trebuie incluse si metodele asociate obiectelor, adic acele functii care modific
atributele obiectelor si care descriu comportamentul lor.
structura de date
Mesajele
Obiectele pot comunica ntre ele prin intermediul mesajelor. Trimiterea unui mesaj care cere unui
obiect s aplice o anumit actiune numit metod este similar apelului de procedur din
limbajele de programare procedural. n programarea orientat pe obiecte se consider c
obiectele sunt autonome si pot comunica ntre ele prin interschimb de mesaje. Obiectele
reactioneaz atunci cnd primesc mesaje, aplicnd o anumit metod, de exemplu. Ele pot refuza
executarea metodei respective dac, de exemplu, obiectului care este apelat nu i se permite s
execute metoda cerut.
Un mesaj este o cerere adresat unui obiect pentru a invoca una din metodele sale. Astfel, un
mesaj contine numele metodei si argumentele metodei.
Exemplul : calculul intretinerii pentru obiectul Popescu Ion.
Incapsularea
nelegerea acestui principiu presupune dou nivele de abordare.
@ Ca metod de concepie, ncapsularea se refer la capacitatea de a separa aspectele externe ale
unui obiect (interfaa), accesibile altor obiecte, de aspectele implementaionale, interne
obiectului, care sunt ascunse fa de celelalte obiecte. Utilizatorul unui obiect poate accesa doar
anumite metode ale acestuia, numite publice, n timp ce atributele i celelalte metode i rmn
inaccesibile (acestea se numesc private).
ncapsularea este foarte important atunci cnd dorim s schimbm implementarea anumitor
metode (cu scopul de a optimiza un algoritm sau de a elimina posibile erori).
ncapsularea ne va mpiedica s modificm toate caracteristicile obiectului iar aplicaiile care
utilizeaz obiectul nu vor avea de suferit deoarece protocolul de comunicaie al obiectului
motenit de la interfaa clasei (rezultatul ncapsulrii ca metod de concepie) nu s-a schimbat.
1.3
Limbajul C++ este unul dintre cele mai utilizate limbaje de programare orientate pe obiecte;
compilatoare, biblioteci i instrumente de dezvoltare a programelor C++ sunt disponibile att
pentru calculatoare personale ct i pentru cele mai dezvoltate sisteme i staii de lucru.
Limbajul C++ este o versiune extins a limbajului C elaborata de ctre B. Stroustrup n anul 1980
n laboratoarele Bell din Murray Hill, New Jersey. 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.
Scopul pentru care a fost creat C++ este acelai cu scopul pentru care este abordat n general
programarea orientat pe obiecte: dezvoltarea i administrarea programelor foarte mari. Chiar
dac superioritatea limbajului C++ este evident n cazul dezvoltrii programelor foarte mari, nu
exist limitri n a fi folosit n orice fel de aplicaie, deoarece C++ este un limbaj tot att de
eficient ca i limbajul C.
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 general, limbajul C++ prevede mai multe faciliti i mai puine restricii dect limbajul C,
astfel nct majoritatea construciilor din C sunt legale i au aceeai semnificaie i n C++.
n acest capitol sunt prezentate unitar i concis conceptele de baz n programarea C++, att cele
care sunt preluate din limbajul C ct i cele nou introduse. Multe dintre ele sunt reluate i
dezvoltate pe parcursul seciunilor urmtoare.
Operatii de intrare/iesire. Stream-uri
Cel mai scurt program C++ este:
main(){ }
Acesta definete o funcie numit main (), care nu primete nici un argument, nu execut nimic i
nu returneaz nici o valoare.
Dac se dorete ca programul s scrie un mesaj la consol (de tipul Primul program in C++!), pe
lng utilizarea funciei obinuite din limbajul C (funcia printf()), n C++ se poate utiliza i o
funcie de scriere la ieirea standard (cout). Aceast funcie este funcia operator de scriere <<
care este definit n fiierul antet iostream.h. Un astfel de program este urmtorul:
#include <iostream.h>
void main(){
cout << Primul program in C++!<< endl;
}
Prima operaie de scriere afieaz la consol irul, Primul program in C++!, iar urmtoarea (endl)
introduce caracterul de linie nou. Operaia de citire de la tastatur poate fi realizat n C++
printr-o instruciune care folosete funcia operator de citire >>. De exemplu, n instruciunile
care urmeaz se citete de la tastatur un numr ntreg:
int i;
cin >> i;
Desigur, funcia scanf() de citire de la tastatur din limbajul C poate fi n continuare folosit, dar
pe parcursul exemplificrilor se vor folosi mai mult aceste funcii C++ de citire i de scriere la
consol.
Programul P1.1 prezint un exemplu de utilizare a operatiilor de intrare/iesire n limbajul C++.
// fisierul sursa P1_1.cpp
#include <iostream.h>
void main()
{
int a, b;
float m;
cout << "\n
cin >> a;
cout << "\n
cin >> b;
m = (float)
cout << "\n
}
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 asa
cum se observ n programul P1.1_v2
// fisierul sursa P1_1_v2.cpp
#include <iostream.h>
void 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;
}
10
T D[dim1][dim2];
i reprezint dim1 tablouri unidimensionale, fiecare de dimensiune dim2. Elementele tabloului
bidimensional se memoreaz cu valori succesive pentru indicele din dreapta astfel:
D[0][0], D[0][1], D[0][dim2-1],
D[1][0], D[1][1], D[1][dim2-1],.
D[dim1-1][0], D[dim1-1][1], D[dim1-1][dim2-1].
11
char* p = alpha;
char* q = &alpha[0]; // p = q
O referin este utilizat ca argument pentru o funcie care poate s modifice 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];
}
void main(){
12
Numele argumentelor formale sunt opionale n prototipul unei funcii. Prototipurile permit
compilatorului s verifice tipurile argumentelor de apel i s semnaleze eroare la conversii
13
ilegale. Spre deosebire de limbajul C, unde este admis i simpla declaraie a numelui funciei
(fr tipurile argumentelor de apel), utilizarea prototipurilor este obligatorie n C++. De exemplu:
double f2(int, double); // prototip functie f2
double f3(int a, double f){ // definitie functie f3
/*..*/
double t = f/a;
return t;
}
void fp(){
double r1 = f1(7, 8.9); // eroare,
// identificator nedeclarat
double r2 = f2(7, 8.9); // corect, fol. prototipul
char str[] = "abcde";
double r3 = f3(7, str); // eroare de tip argument
}
double f1(int a, double f) {
/*..*/
double t = a + f;
return t;
}
double f2(int a, double f) { // definiie funcie f2()
/*...*/
double t = a*f;
return t;
}
La compilare apare o eroare datorit apelului funciei f1(), care nu este definit, nici declarat
prin prototip n domeniul funciei apelante fp() i o eroare datorat apelului funciei f3() cu un
argument (argumentul al doilea) care nu poate fi convertit la tipul argumentului formal.
Transferul argumentelor funciilor. La apelul unei funcii, argumentele de apel (se mai numesc i
argumente
reale
sau
efective)
iniializeaz
argumentele
formale
din declaraia funciei, n ordinea din declaraie. Argumentele unei funcii se pot transfera n dou
moduri: apelul prin valoare i apelul prin referin.
n apelul prin valoare se copiaz valoarea argumentului real n argumentul formal corespunztor
al funciei. n acest caz, modificrile efectuate asupra argumentului funciei nu modific
argumentul real.
n apelul prin referin este accesat direct variabila din argumentul real transmis funciei, care
poate fi deci modificat. Ca exemplificare, se definete o funcie swap() care realizeaz
intershimbul ntre valorile a dou variabile. Dac nu se folosesc referine, argumentele de apel ale
funciei trebuie s fie pointeri la variabilele respective. Pointerii, ca argumente de apel, nu vor fi
modificai, dar variabilele indicate de acetia pot fi modificate. Funcia swap() cu argumente
pointeri arat astfel:
void swap(int* x, int* y){
int t;
14
t = *x; // dereferentiere
*x = *y;
*y = t;
}
Aceeai funcie swap(), folosind argumente de tip referin, arat 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.
Argumente implicite ale funciilor. Se ntmpl frecvent ca o funcie s aib un numr mai mare
de argumente dect sunt necesare n cazurile simple dar frecvente de apel. Dac nu este necesar
s fie transmis ntotdeauna valoarea real a unui argument i acesta poate lua, de cele mai multe
ori, o valoare implicit, atunci n declaraia funciei se prevede o expresie de iniializare a acestui
argument, iar din apel poate s lipseasc valoarea argumentului corespunztor.
De exemplu, o funcie pentru stabilirea datei calendaristice, care prevede valori implicite pentru
argumentelelunaian:
struct data{
int zi;
int luna;
int an;
} g_data;
void setdata(int zi, int luna=9, int an =1999){
g_data.zi = zi;
g_data.luna = luna;
g_data.an = an;
}
void main(){
setdata(15); // 15 9 1999
setdata(21,7); // 21 7 1999
setdata(20,1,2000); // 21 1 2000
}
Numai argumentele de la sfritul listei pot fi argumente implicite. De exemplu, este eronat
urmtoarea declaraie:
15
Constante simbolice
O constant simbolic (sau constant cu nume) este un nume a crui valoare nu poate fi
modificat n cursul programului. n C++ exist trei modaliti de a defini constante simbolice:
Orice valoare, de orice tip care poate primi un nume, poate fi folosit ca o constant
simbolic prin adugarea cuvntului-cheie const n declaraia acesteia.
Orice nume de funcie sau de tablou este o constant simbolic.
O enumeraie definete o mulime de constante ntregi.
De exemplu, urmtoarele declaraii introduc constante simbolice prin folosirea cuvntului-cheie
const:
const int val = 100;
const double d[] = {1.2, 2.8, 9.5};
Deoarece constantele nu pot fi modificate, ele trebuie s fie iniializate n declaraie. ncercarea
de modificare ulterioar este detectat ca eroare n timpul compilrii:
val++; // eroare
d = 200; // eroare
Cuvntul-cheie const modific tipul obiectului, restricionnd modul n care acesta poate fi
folosit.
Un aspect interesant i intens folosit n programare, este acela de a declara pointeri la constante.
Atunci cnd se folosete un pointer, sunt implicate dou obiecte: pointerul nsui i obiectul ctre
care indic pointerul.
Prin prefixarea declaraiei unui pointer cu cuvntul const, obiectul indicat este fcut constant, nu
pointerul nsui. De exemplu:
const char* pc = abcd;// pc este pointer la o constant
pc[2] = m; // eroare, nu se poate modifica
// obiectul constant
pc = ghij; // corect, este modificat
// valoarea pointerului
pc++; // corect
Pentru ca pointerul nsui s fie constant, se folosete operatorul *const:
char *const cp = abcd;// cp este pointer constant;
cp[2] = m; // corect, modifica valoarea
cp++; // eroare, pointer constant
16
Pentru alocarea unei singure date (obiect), 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];
Prima form se utilizeaz pentru eliberarea unei zone de memorie ocupat de o singur dat
(obiect), nu de un vector. Pointerul p trebuie s fie un pointer la o zon de memorie alocat
anterior printr-un operator new. Operatorul delete trebuie s fie folosit doar cu un pointer valid,
alocat numai cu new i care nu a fost modificat sau nu a mai fost eliberat zona de memorie mai
nainte (cu un alt operator delete sau prin apelul unei funcii free()). Folosirea operatorului delete
cu un pointer invalid este o operaie cu rezultat nedefinit, cel mai adesea producnd erori de
execuie grave.
Cea de-a doua form a operatorului delete[] se folosete pentru eliberarea unei zone de memorie
ocupat de un vector de date. Pentru tipurile de date predefinite ale limbajului, se poate folosi i
prima form pentru eliberarea unui vector, dar, n cazul obiectelor de tipuri definite de utilizator,
acest lucru nu mai este valabil. Aceast situaie va fi detaliat n seciunea urmtoare.
Cteva exemple de utilizare a operatorilor new i delete:
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;
deletepd
delete pc1; //corect, char e tip predefinit
delete []pc2; // corect, elibereaza vector
n legtur cu cele dou metode de alocare dinamic, prin operatorii new-delete i prin funciile
de bibliotec malloc-free, fr s fie o regul precis, se recomand evitarea combinrii lor,
deoarece nu exist garania compatibilitii ntre ele.
18
Teste de autocontrol
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 functiei de care apartin.
1.2 Descriei pe scurt diferena dintre funciile care returneaz valoare i cele care returneaz
referin.
(d) ncapsulare
(e) modul
(f) procedur
(g) polimorfism
(h) stream
(i) cout
1.12 Definiti tipul de date abstract (TDA).
1.13 Definiti urmtoarele tipuri de date abstracte:
(a) LISTA
(b) COADA
Se vor specifica: structura de date, operatorii de baz si cei suplimentari si axiomele n mod
similar cu definitia TDA STIVA.
1.14 S se scrie declaraiile pentru urmtoarele tipuri de variabile: pointer la un caracter, un
vector de 10 valori ntregi, pointer la un vector de 10 valori ntregi, un pointer la un pointer la un
caracter.
1. 15 S se scrie un program care tiprete dimensiunea tipurilor fundamentale de date. Se va
folosi operatorul sizeof.
20
Obiective
Definirea notiunilor de clas, obiect, atribut, metod;
ntelegerea notiunilor de instant, instantiere, constructor, destructor;
nsusirea modului n care se realizeaz accesarea membrilor unei clase;
Definirea constructorilor unei clase (implicit, cu parametri, de copiere, de convertire si
atribuire);
Definirea destructorului unei clase;
Definirea si utilizarea claselor compuse si a obiectelor compuse;
Pointerului this;
Particularitti ale limbajului C++ (functii friend, functii inline, membrii statici, tablouri
de obiecte, pointeri la metode)
Un tip de date ntr-un limbaj de programare este o reprezentare a unui concept. De exemplu, tipul
float din C++, mpreun cu operaiile definite asupra acestuia (+, -, *, etc.) reprezint o versiune a
conceptului matematic de numere reale. Pentru alte concepte, care nu au o reprezentare direct
prin tipurile predefinite ale limbajului, se pot defini noi tipuri de date care s specifice aceste
concepte.
O clas este un tip de date definit de utilizator. O declarare a unei clase definete un tip nou care
reunete date i funcii. Acest tip nou poate fi folosit pentru a declara obiecte de acest tip, deci un
obiect este un exemplar (o instan) a unei clase.
Definitie. O clas este implementarea unui TDA. Ea defineste atribute si metode care
implementeaz structuri de date si operatii ale TDA-ului.
Definitie. Un obiect este o instant a unei clase. El este unic identificat de numele lui si defineste
o stare care este reprezentat de valorile atributelor, la un moment dat. Starea unui obiect se
schimb n raport cu metodele care i sunt aplicate.
Definitie. Comportamentul unui obiect este definit de multimea metodelor care i pot fi
aplicate.
Definitie. O metod este o functie asociat unei clase. Un obiect apeleaz (invoc) o metod
drept reactie la primirea unui mesaj.
21
Primul pas pentru gruparea datelor si metodelor de prelucrare, l-au reprezentat stucturile; ele
permiteau declararea unor ansambluri eterogene de date ce erau manipulate unitar.
Consideram structura 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
angajat &a3=a1; // o referinta catre o structura de tip angajat a3
Membrii unei structuri sau ai unei clase sunt accesati cu ajutorul operatorilor de acces: operatorul
., respectiv, operatorul ->.
9 Operatorul . acceseaz o structur sau un membru al unei clase prin numele variabilei
pentru obiect sau printr-o referint la obiect.
9 Operatorul -> acceseaz un membru al unei structuri sau clase printr-un pointer la
obiect (a2 = &a1)
Programul P2.1 implementeaz tipul de date angajat cu ajutorul unei unei structuri C. Functia
afisare( ) are rolul de a afisa datele unui angajat. Programul realizeaz constructia tipului de data
abstract angajat prinn definirea unei structuri , setarea valorilor pentru cmpurile structurilor
(membrii structurilor) si 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 functiei 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);
}
void main()
22
{
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();
}
Cuvntul-cheie class introduce declaraia clasei (a tipului de date) cu numele nume_clasa. Dac
este urmat de corpul clasei (cuprins ntre acolade), aceast declaraie este totodat o definiie.
Dac declaraia conine numai cuvntul-cheie class i numele clasei, atunci aceasta este doar o
declaraie de nume de clas.
Corpul clasei 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
Specificatorii private i protected asigur o protecie de acces la datele sau funciile membre ale
clasei respective, iar specificatorul public permite accesul la acestea i din afara clasei. Efectul
unui specificator de acces dureaz pn la urmtorul specificator de acces. Implicit, dac nu se
declar nici un specificator de acces, datele sau funciile membre sunt de tip private. De aceea,
toate datele sau funciile declarate de la nceputul blocului clasei pn la primul specificator de
acces sunt de tip private. ntr-o declaraie de clas se poate schimba specificatorul de acces ori de
cte ori se dorete: unele declaraii sunt trecute public, dup care se poate reveni la declaraii
private, etc. Diferena ntre tipurile de acces private i protected const n modul n care sunt
motenite drepturile de acces n clase derivate.
23
Definirea obiectelor
Dup definirea unei clase C, aceasta poate fi utilizat ca tip n definirea obiectelor, tablourilor de
obiecte si a pointerilor, astfel:
C
C
C
C
Numele unei clase devine specificator de tip si se pot defini, teoretic, o infinitate de obiecte ale
clasei.
Accesarea membrilor unei clase
Membrii publici ai unei clase pot fi accesati cu ajutorul operatorilor . si ->, dup cum
obiectul de care apartin este desemnat prin nume sau printr-un pointer. Variabilele membru
private nu pot fi accesate dect n cadrul metodelor clasei respective.
Programul 2.2 implementeaz tipul de date angajat sub forma unei clase C++. Clasa angajat
cuprinde datele membre: varsta, salariul, nume si functii membre: init() pentru initializarea
datelor membre, functiia membra de acces spune_varsta(), functia afisare() pentru afisarea
datelor membre.
class angajat
{
private:
int varsta;
protected
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;
}
}
void main()
{ angajat a;
a.init(); // apelul functiei membre init() pentru obiectul a
24
Dupa rolul pe care il joaca in cadrul clasei, functiile membre ale unei clase se impart in patru
categorii:
9 constructori, responsabili cu crearea obiectelor;
9 destructor, reponsabil cu distrugere obiectelor si eliberarea memoriei ocupate de acesta;
9 functii de acces, care mediaza legatura obiectului cu exteriorul;
9 metode, functii care introduc operatiile si prelucraile specifice obiectului.
25
26
n fiecare dintre aceste situaii a fost creat un obiect de tip Complex, c1, c2, c3 i de fiecare dat
a fost apelat constructorul care are acelai numr i tip de argumente cu cele de apel.
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 X este:
X::X(X& r){ } // initializare obiect folosind referina r
La crearea 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. Este posibil i declaraia de forma Complex
c3 = c2; a unui obiect prin care se apeleaz, de asemenea, constructorul de copiere.
27
Importanta constructorului de copiere este subliniata de situatia in care datele membre ale unei
clase sunt alocate dinamic. Constructorul de copiere generat implicit de compilator copiaz doar
datele membre declarate n clas (membru cu membru) i nu tie s aloce date dinamice pentru
obiectul nou creat. Folosind un astfel de constructor, se ajunge la situaia c dou obiecte, cel nou
creat i obiectul 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:
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;
}
int spune_salariul(){return salariul;}
}
void main()
{ angajat a1(Popescu,35);
angajat a2=a1;
strcpy(a2.nume,Ion);
cout<<a1.nume<< <<a1.salariul<<endl;
cout<<a2.nume<< <<a2.salariul;
}
Ion
Ion
35
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 dinamica. Asfel, obiectele a1 si a2 folosesc
aceeasi zona de memorie alocata pentru campul nume.
28
35
35
In concluzie, pentru un obiect cu un membru pointer spre o zona alocata dinamic progrmatorul va
furniza un contructor de copiere care sa aloce memorie pentru noul obiect.
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.
Cand este declarat explicit in cadrul calsei, destructorul porta numele clasei, precedat de semnul
~ (de ex. ~angajat()).
Destructorul, spre deosebire de constructor, este unic si nu are parametrii de apel.
Dac programatorul nu defineste 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 distrusi n ordinea invers celei n care au fost creati.
29
#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";
}
Void main()
{
Complex z(3,4);
}
Constructor cu 2 arg
Destructor
Se observa in programul anterior ca nu s-a realizat un apel explicit al destructorului. Acesta a fost
apelat automat la sfarsitul programului.
Destructorii sunt apelai implicit si in 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.
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 si la functiile
membru ale unui obiect. El poate fi utilizat si explicit cand se doreste folosirea adresei obiectului.
Adresa obiectului, desi este transparenta pentru utilizator, exista memorata intr-un pointer numit
this.
Ca expemplul vom defini, in programul 2.3, o clasa care va contine o metoda ce utilizeza
pointerul this.
class C
{ int x;
public:
C(int a){
x=a;}
void afisare(){
cout<<this->x;}
}
void main()
{C ob(7);
ob.afisare;
}
30
31
tab[i].seteaza_valori();
// afiseaza cele n obiecte
for (i=0;i<n;i++)
tab[i].afisare();
}
32
void main()
{
Complex Z=Complex(3,4);
cout<<"\n Modulul lui numarului complex z este "<< modul(Z);
}
Trebuie subliniat faptul ca utilizarea functiilor friend trebuie fcut cu mare grij ntruct acestea
ncalc principiul ncapsulrii, respectiv, ascunderea informatiei, principiu fundamental n POO.
Avantajul principal al declarrii unei functii friend este accesul rapid pe care aceasta l are direct
la membrii privati ai clasei cu care este prieten.
unde <tip> reprezint tipul ntors de functie, iar <lp> lista de parametri.
Programul P2.6 prezint un exemplu de definire si utilizare a unei functii inline pentru calculul
ariei unui patrat cu latura data, arie_patrat() .
33
void main()
{
double x;
cout<<"\n Latura patratului:";
cin>>x;
cout<<"\n Aria patratului este "<<arie_patrat(x);
}
Variabila total_ang va fi unica pentru toti angajatii. Se poate observa ca o data cu definirea
varbilei statice s-a realizat si intializarea acesteia.
Functiile membre statice efectueaza prelucrari care nu sunt individualizate pe obiecte, ci
prelucrari care au loc la nivelul clasei. Functiile 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.
Programul 2.7 redefineste clasa angajat, prin adaugarea datelor membre statice total_ang si
total_b care vor retine numarul total de angajati si numarul total de barbati. Clasa va contine si
trei functii membre statice care vor returna valorile retinute in cele doua date statice.
34
35
In programul de mai sus se remarca faptul ca intretinerea variabilei total_ang cade in sarcina
constructorilor si a destructorului, care incrementeaza sau decrementreaza acesta variabila.
De asemenea, functia membra statica numara_total_b() primeste ca parametru referinta la un
obiect de tip angajat pentru ca utilizeaza data membra gen care nu este statica.
ntruct variabilele membru statice nu apartin unui obiect anume, ele pot fi accesate si prin
prefixarea numelui clasei de operatorul ::.
36
Teste de autocontrol
2.1 Care este valoarea de adevr a afirmatiilor urmtoare:
(a) O clas C++ si o structur C definesc acelasi 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 si un destructor
(b) un constructor si mai multi destructori
(c) 10 constructori si un destructor
(d) o infinitate de constructori (teoretic) si 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();
};
2.6 Explicati de ce este necesar definirea unui constructor implicit n cazul utilizrii tablourilor
de obiecte n limbajul C++?
2.7 Care este valoarea de adevr a afirmatiilor urmtoare:
(a) Membrii statici ai unei clase pot fi att variabile (date membru) ct si metode (functii
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.
2.8 S se defineasc o clas Date pentru memorarea datei sub forma (zi, lun, an). Clasa va
conine atia constructori ct sunt necesari pentru urmtoarele definiii de obiecte:
Date
Date
Date
Date
2.9 Construiti clasa student care contine datele membre: nume, prenume, nr_matricol, an, grupa.
a). Introduceti in clasa cel putin doi constructori.
b). Realizati un tablou de obiecte de tipul clasei student;
c). Afisati numarul studentilor din grupa 201, utilizand date si functii membre statice;
2.10 Se consider urmtorul program n care o variabil global numbers memoreaz numrul
obiectelor n via la un moment dat:
#include <iostream.h>
int numbers = 0;
class Item {
public:
Item(){ // constructorul creste cu 1 nr obiectelor
numbers++;
cout << "Nr. obiecte " << numbers << endl;
}
~Item() { // destructorul descreste cu 1 nr ob.
numbers--;
cout << "Nr. obiecte " << numbers << endl;
}
};
void main() {
Item ob1, ob2, ob3;
{ // se deschide un nou bloc
Item ob4, ob5;
}
Item *pob6 = new Item[3];
delete [] pob6;
}
Care sunt mesajele care apar la consol la execuia acestui program? S se explice evoluia
numrului de obiecte n via n cursul execuiei.
38
2.11 Construiti clasa credite care contine datele membre private val_credit, nr_cont, si date
membre publice nume, tip_credit.
a). Introduceti in clasa cel putin doi constructori pentru intializarea obectelor din clasa credite.
b). Realizati un tablou cu 20 obiecte din clasa credite.
c). Realizati functii de acces la datele membre private.
d). Afisati numarul creditelor de tip ipotecar, utilizand date si functii membre.
2. 12 Definii clasa pacient care contine datele private: vrsta, profesie, salariul i data membra
public nume.
Realizai:
a). un tablou de 10 obiecte de tipul clasei definit anterior;
b). funcii membre de acces la datele private ale clasei;
c). numarul pacientilor care au varsta peste media vrstelor utiliznd o funcie membr static;
d). realizai o funcie operator pentru a calcula suma veniturilor pentru pacienii cu acelai nume
2. 13 Realizai clasa fractie care cuprinde datele membre private :numitor, numarator.
1. realizai funcii de acces la datele membre ale clasei definit anterior;
2. realizai funcii membre pentru a calcula suma si inmultirea a doua fractii, utlizand functii
operator;
3. construii un tablou cu 10 obiecte de tipul definit anterior;
4. realizai ordonarea fraciilor in ordine crescatoare dupa numitor.
2.14 Spunei de cte ori se execut fiecare constructor n programul de mai jos i n ce ordine.
#include <iostream.h>
class cls1
{ protected: int x;
public: cls1(){ x=13; } };
class cls2: public cls1
{ int y;
public: cls2(){ y=15; }
int f(cls2 ob) { return (ob.x+ob.y); } };
int main()
{ cls2 ob; cout<<ob.f(ob);
return 0;
}
2.15 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, altfel,
spunei de ce nu este corect. #include <iostream.h>
class cls1
{ int x;
public: cls1(){ x=13; }
int g(){ static int i; i++; return (i+x); } };
class cls2
{ int x;
public: cls2(){ x=27; }
cls1& f(){ static cls1 ob; return ob; } };
39
int main()
{ cls2 ob;
cout<<ob.f().g();
return 0;
}
2.16 Spunei dac programul de mai jos este corect. n caz afirmativ, spunei ce afieaz, altfel,
spunei de ce nu este corect. #include <iostream.h>
class cls1
{ protected: int x;
public: cls1(int i=10) { x=i; }
int get_x() { return x;} };
class cls2: cls1
{ public: cls2(int i):cls1(i) {} };
int main()
{ cls d(37);
cout<<d.get_x();
return 0;
}
40
Capitolul 3 .Mostenire
Obiective
Definirea notiunilor de clas de baz, clas derivat, ierarhie de clase, mostenire
nsusirea modalittii de creare de noi clase pornind de la clase existente
ntelegerea rolului membrilor protejati ai unei clase
nsusirea mecanismului de redefinire a membrilor unei clase ntr-o clas derivat
Mostenirea sau relatia 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 functiile
membru din sectiunea respectiv.
41
Observatii
O clas derivat nu poate accesa direct membrii privati ai clasei sale de baz. Dac s-ar
permite asa ceva s-ar nclca unul din principiile fundamentale ale POO (ncapsularea).
O clas derivat poate accesa membrii privati doar prin intermediul functiilor publice si
protejate ale clasei de baz.
O clas derivat poate accesa membrii publici si protejati ai clasei de baz
Relatia de mostenire este tranzitiv.
Functiile friend nu se mostenesc.
Se consider un program P3.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 display();
};
Angajat::display(){
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
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 display();
}
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:
42
Redefinirea funciei display() 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().
Din clasa derivat (n funcii membre ale acesteia sau pentru obiecte din clasa derivat) este
accesat membrul redefinit n clasa derivat. Se spune c membrul din clasa de baz este ascuns
(hidden) de membrul redefinit n clasa derivat. 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
}
43
<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.
44
45
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
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
setb
setb
setc
setc
din
din
din
din
din
baza
baza
derivata
baza
derivata
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
46
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. ntradevr, 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.
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
private,
o nou clas derivat (care motenete indirect clasa de baz) nu va mai putea accesa nici unul
din membrii clasei de baz.
Student
Elev
Angajat
Medic
Profesor
47
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 clas de baz pentru clasele
Medic si Profesor.
Programul P3.3 prezint un exemplu de implementare a claselor Persoana, Salariat, Arhitect,
Inginer si Medic.
// fisierul sursa p3_5.cpp
#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)
{
nume = new char[strlen(N)+1];
strcpy(nume, N);
pren = new char[strlen(P)+1];
strcpy(pren, P);
}
Persoana::~Persoana()
{
delete nume;
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=0);
void seteazaSalariu(float s);
void afisare();
};
48
49
Functia afisare() din clasele Inginer si Profesor apeleaz functia afisare() din clasa Salariat:
Salariat::afisare();
L
A
B
D
{
:
:
:
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.
50
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
- 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
class
class
class
L
A
B
D
{
:
:
:
public: int x; };
virtual public L { /* */ };
virtual public L { /* */ };
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:
51
clasa de baz. Funcia declarat virtual n clasa de baz acioneaz ca o descriere generic prin
care se definete interfaa comun, iar funciile redefinite n clasele derivate precizeaz aciunile
specifice fiecrei clase derivate.
Mecanismul de virtualitate asigur selecia funciei redefinite n clasa derivat numai la apelul
funciei pentru un obiect cunoscut printr-un pointer. n apelul ca funcie membr a unui obiect dat
cu numele lui, funciile virtuale se comport normal, ca funcii redefinite.
n limbajele de programare, un obiect polimorfic este o entitate, ca de exemplu, o variabil sau
argumentul unei functii, creia i se permite s pstreze valori de tipuri diferite n timpul executiei
programului. Functiile polimorfice sunt acele functii care au argumente polimorfice. n limbajele
de programare orientate pe obiecte, polimorfismul mpreun cu legarea dinamic reprezint una
din caracteristicile extrem de utile care conduc la cresterea calittii programelor.
Implementarea obiectelor polimorfice se realizeaz prin intermediul functiilor virtuale.
Sintaxa declarrii unei functii virtuale:
virtual <tip_functie> <nume_functie> ([<lp>]);
<tip_functie> reprezint tipul ntors de functie, <lp> este
Cnd un pointer al clasei de baz puncteaz la o functie virtual din clasa derivat si aceasta este
apelat prin intermediul acestui pointer, compilatorul determin care versiune a functiei trebuie
apelat, tinnd cont de tipul obiectului la care puncteaz acel pointer. Astfel, tipul obiectului la
care puncteaz determin versiunea functiei virtuale care va fi executat.
In programul P3.4 se consider o clas de baz B i dou clase derivate D1 i D2. n clasa de
baz sunt definite dou funcii: funcia normal f()i funcia virtual g(). n fiecare din clasele
derivate se redefinesc cele dou funcii f() i g(). n funcia main() se creeaz trei obiecte: un
obiect din clasa de baz B indicat prin pointerul B* pb i dou obiecte din clasele derivate D1 i
D2. Fiecare dintre obiectele derivate poate fi indicat printr-un pointer la clasa derivat respectiv
(D1* pd1, respectiv D2* pd2), precum i printr-un pointer la baz corespunztor (B* pb1 = pd1,
respectiv B* pb2 = pd2).
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"; }
};
class D2:public B {
public:
void f() { cout << "f() din D2\n"; }
52
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.
Polimorfismul, adic apelul unei funcii dintr-o clas derivat prin pointer de tip clas de baz,
este posibil numai prin utilizarea pointerilor la obiecte. Obiectele nsele determin varianta
funciei apelate, deci nu se pot selecta alte funcii dect cele ale obiectului de tipul respectiv. De
exemplu, pentru aceleai clase definite ca mai sus, se consider funcia fv2():
void fv2(){
B obB;
D1 obD1;
D2 obD2;
obB.f(); // f() din B
obB.g(); // g() din B
obD1.f(); // f() din D1
obD1.g(); // g() din D1
53
Observati
Constructorii nu pot fi functii virtuale. n schimb, destructorii pot fi functii virtuale.
Functiile inline nu pot fi virtuale.
Functiile virtuale sunt ntotdeauna functii membru nestatice ale unei clase.
3.7
Clase abstracte
De cele mai multe ori, o funcie declarat de tip virtual n clasa de baz nu definete o aciune
semnificativ i este neaprat necesar ca ea s fie redefinit n fiecare din clasele derivate. Pentru
ca programatorul s fie obligat s redefineasc o funcie virtual n toate clasele derivate n care
este folosit aceast funcie, se declar funcia respectiv virtual pur. O funcie virtual pur
este o funcie care nu are definiie n clasa de baz, iar declaraia ei arat n felul urmtor:
virtual tip_returnat nume_functie(lista_argumente) = 0;
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 claselor ei de baz, devine clas normal i pot fi
create instane ale acesteia.
Exemplul urmtor (5.6) evideniaz caracteristicile claselor abstracte i ale funciilor virtuale
pure.
Programul P3.5 se realizeaza conversia unor date dintr-o valoare de intrare ntr-o valoare de
ieire; de exemplu, din grade Farenheit n grade Celsius, din inch n centimetri, etc.
class Convert{
protected:
double x; // valoare intrare
double y; // valoare iesire
public:
Convert(double i){x = i;}
double getx(){return x;}
double gety(){return y;}
virtual void conv() = 0;
};
// clasa FC de conversie grade Farenheit in grade Celsius
class FC: public Convert{
public:
FC(double i):Convert(i){}
void conv(){y = (x-32)/1.8;}
54
};
// clasa IC de conversie inch in centimetri
class IC: public Convert{
public:
IC(double i):Convert(i){}
void conv(){y = 2.54*x;}
}
Clasa de baz abstract Convert este folosit pentru crearea prin derivare a unei clase specifice
fiecrui tip de conversie de date dorit. Aceast clas definete datele comune, necesare oricrui
tip de conversie preconizat, de la o valoare de intrare x la o valoare de ieire y. Funcia de
conversie conv() nu se poate defini n clasa de baz, ea fiind specific fiecrui tip de conversie n
parte; de aceea funcia conv() se declar funcie virtual pur i trebuie s fie redefinit n fiecare
clas derivat.
n funcia main() se execut o conversie a unei valori introduse de la consol, folosind un tip de
conversie (o clas derivat) care se selecteaz pe baza unui caracter introdus la consol.
Acesta este un exemplu n care este destul de pregnant necesitatea funciilor virtuale: deoarece
nu se cunoate n momentul compilrii tipul de conversie care se va efectua, se folosete un
pointer la clasa de baz pentru orice operaie (crearea unui obiect de conversie nou, apelul
funciei conv(), afiarea rezultatelor, distrugerea obiectului la terminarea programului). Singura
difereniere care permite selecia corect a funciilor, este tipul obiectului creat, care depinde de
tipul conversiei cerute de la consol.
55
3.8
Polimorfism
Polimorfismul permite unei entitti (de exemplu, variabil, functie, obiect) s aib o varietate de
reprezentri. El este furnizat att la momentul compilrii (legare timpurie), prin folosirea
operatorilor si a functiilor redefinite, ct si la momentul executiei (legare trzie), prin utilizarea
functiilor virtuale.
Conceptul de legare dinamic permite unei variabile s aib tipuri diferite n functie de continutul
ei la un moment dat. Aceast abilitate a variabilei se numeste polimorfism, iar variabila se
numeste variabil polimorfic.
n limbajul C++ variabilele polimorfice apar doar prin utilizarea pointerilor sau referintelor. n
cazul n care un pointer al clasei de baz puncteaz ctre o functie virtual, programul va
determina la momentul executiei la care tip de obiect puncteaza pointerul si apoi va selecta
versiunea corespunztoare functiei redefinite.
Programul P4.4 defineste clasa de baz Persoana si dou clase derivate, Student si Salariat. Clasa
de baz Persoana este o clas abstract avnd declarat o functie virtual pur, venit(), definit n
clasele derivate. De asemenea, clasa Persoana mai contine o alt functie 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
functii afisare() si venit(), corespunztoare obiectului referit prin nume; ultimele dou instructiuni
ilustreaz legarea dinamic apelnd cele dou functii afisare() si venit() prin intermediul a dou
functii, 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.
// fisierul sursa p4_4.cpp
#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();
// functie virtuala pura
virtual double venit() = 0;
virtual void afisare();
};
Persoana::Persoana(char* P, char* N)
{
prenume = new char[strlen(P)+1];
56
strcpy(prenume, P);
nume = new char[strlen(N)+1];
strcpy(nume, N);
}
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()
{
return bursa;
57
}
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()
{
return salariu + nr_ore*venit_ora;
}
void Salariat::afisare()
{
cout << "\n Salariat:";
Persoana::afisare();
}
// functie care apeleaza functiile virtuale prin legare
58
59
Teste de autocontrol
3.1 Definiti relatia de derivare.
3.2 Definiti mostenirea.
3.3 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
3.4 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) Functiile friend ale clasei de baz se mostenesc de ctre clasa derivat.
(d) Constructorul si destructorul clasei de baz se mostenesc n clasa derivat.
3.5 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
3.6 Care este avantajul principal oferit de mecanismul mostenirii?
3.7 Utilizarea mostenirii si a polimorfismului permite eliminarea unei anumite instructiuni. Care
este aceast instructiune n limbajul C++?
3.8 Cum este specificat o functie virtual pur?
3.9 Cum se numeste o clas care contine una sau mai multe functii virtuale pure?
3.10 Dac apelul unei functii este rezolvat la momentul executiei legarea este
(a) static
(b) timpurie
(c) nul
(d) dinamic
60
class cls1
{ public: int x;
cls1(int i=13) { x=i; } };
class cls2: virtual public
{ public: cls2(int i=15) {
class cls3: virtual public
{ public: cls3(int i=17) {
cls1
x=i; } };
cls1
x=i; } };
62
63
Obiective
Redefinirea operatorilor
Definirea template-urilor
nsusirea modului de lucru cu fisiere n limbajul C++
Programul P 4.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
64
extremitate al vectorului. Pentru aceast clas se pot defini mai multe operaii cu vectori, ca de
exemplu:
65
Point& Point::operator*(double
x *=v;
y *=v;
return *this;
}
void f1(){
Punct pct1(10,20);
Punct pct2(30,40);
Punct pct3;
pct1.Display();
pct2.Display();
pct3 = pct1 + pct2;
pct3.Display();
pct3 = pct2 pct1;
pct3.Display();
}
v){
// afiseaza 10 20
// afiseaza 30 40
// afiseaza 40 60
// 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.
n general, un operator binar poate fi suprancrcat fie printr-o funcie membr nestatic cu un
argument, fie printr-o funcie nemembr cu dou argumente.
Un operator unar poate fi suprancrcat fie printr-o funcie membr nestatic fr nici un
argument, fie printr-o funcie nemembr cu un argument. 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.
class Point{
//
public:
Point operator!();
Point operator++();
Point operator();
Point operator++(int x);
Point operator(int x);
};
66
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;
}
67
// afiseaza 10 20
// afiseaza 30 40
// afiseaza 40 60
Observatii
Dac functia operator este implementat ca o functie 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 functie 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 functie operator ne-membru trebuie declarat functie friend dac functia respectiv
trebuie s acceseze direct membrii privati sau protejati ai clasei respective.
4. 2 Template-uri
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
functii prin utilizarea unui tip n acelasi mod n care parametrii unei functii 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>
68
{
// definitia clasei sablon
};
Programul P4.3 prezint un exemplu de definire a unei functii template, afisare_vector(.).
Aplicarea functiei template celor trei variabile T1, T2 si respectiv T3 va determina afisarea unui
vector de numere ntregi, a unui vector de numere reale, respectiv a unui vector de caractere.
69
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.
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:
void main(){
int size = 10;
int array[10];
for(int i=0;i<size;i++){
if (cin >> array[i])
cout << array[i] << " ";
else {
cout << "eroare 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 eroare 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(){
char c;
while(cin.get(c)) cout << c;
70
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.
In programul P 4.4 se defineste clasa Complex care cuprinde functiile operator << si >>.
class Complex {
double x, y;
public:
Complex(){x = 0; y = 0}
Complex(double r, double i){
x = r;
y = i;
}
..
friend ostrem& operator << (ostrem& os,Complex z);
71
4. 4 Procesarea fisierelor
Procesarea fisierelor n limbajul C++ necesit includerea fisierelor antet <iostream.h> si
<fstream.h>. Fisierul antet <fstream.h> cuprinde definitiile claselor streamului: 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 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)
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 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.
72
La citirea dintr-un fiier de tip text de pe disk folosind operatorul >> apar, la fel ca la citirea
de la consol, anumite modificri de caractere. Pentru a evita astfel de modificri se folosesc
funciile de I/O binare care vor fi prezentate n seciunea urmtoare.
73
Teste de autocontrol
4.1 Care este rolul redefinirii operatorilor n limbajul C++?
4.2 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.
4.3 Care sunt clasele predefinite, dedicate procesrii fisierelor C++?
4.4 S se citeasc un fiier care conine numere flotante, s se construiasc numere complexe din
perechi de cte dou numere flotante i s se afieze la consol numerele complexe.
4.4 Pentru clasa String s se defineasc urmtoarele operaii de comparaie folosind funcii
operator friend:
int operator ==( const String& s1, const String& s2 );
int operator ==( const String& s1, const char* s2 );
int operator ==( const char* s1, const String& s2 );
int operator !=( const String& s1, const String& s2 );
4.5 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;} };
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;
}
74
4.6 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;
}
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
{ 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);
*p2=p2->aduna(*p1);
*p1=p2->minus();
p1->afisare();
return 0;
}
75
Teste recapitulative:
Specificai varianta corect :
1. Clasa
class c { float a;
void afisisare();
}
are membrii:
a). publici;
c). protected;
b). privai
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;
public:
float c (int, int)
int det_a {return a;}
c (); }
d). virtual.
7. In secvena urmatoare:
class cls { public:static int s;};
int cls::s=0;
int main(){int i=7;cls::s=i;cout<<cls::s;}
Afiseaz:
a). afiseaz 1 0;
b). afiseaz 0 0
77
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. Secventa 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
11. Secvena urmatoare afiseaz:
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 ;}
Afiseaza :
a).20 20;
b).20 21 ;
c).21 22;
d).20 22.
78
12 . Fie secvena :
class c { int a;
public: c();
c(const c&);
void operator=(c&);}
int main()
{ c a;
//instructiuni;
c b=a;}
80
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;
}
..............
}
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;
18. Se da secventa 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];
}
81
void fct()
{
int k;
...........
k++;
...........
}
void gct()
{
int k=2;
...........
::k++; // (?)
...........
}
82
23. 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.
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 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;
}
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 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);
83
x[5]=7;
cout<<x;
return 0;
}
28. 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()
{ const cls d(-15);
cout<<d.f();
}
29. Spunei dac o variabil constant poate fi transmis ca parametru al unei funcii i dac da, n ce
situaii. Justificai.
30. 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;
84
31. Spuneti dac programul de mai jos este corect. n caz afirmativ, spunei ce afiseaz, n caz
negativ spuneti de ce nu este corect.
#include<iostream.h>
class B
{ int x;
public: B(int i=2):x(i){}
int get_x() const { return x; } };
class D: public B
{ int *y;
public: D(int i=2):B(i){ y=new int[i];
for(int j=0; j<i; j++) y[j]=1; }
D(D& a){ y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i]; }
int& operator[](int i) { return y[i]; } };
ostream& operator<<(ostream& o, const D& a)
{ for(int i=0;i<a.get_x();i++) o<<a[i];
return o;
}
int main()
{ D ob(5);
cout<<ob;
return 0;
}
32. Descrieti trei metode de proiectare diferite prin care elementele unei clase se pot regsi n
dublu exemplar, sub diverse forme, n definitia altei clase.
33. 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;
}
34. 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
{ public: int x;
B(int i=16) { x=i; }
85
35. Spuneti ce este obiectul implicit al unei metode si descrieti pe scurt propriettile pe care le
cunoasteti despre acesta.
36. 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) { nr=i; v=new int[i];
for (int j=1; j<nr; j++) v[j]=0; }
int size() { return nr; }
int& operator[](int i) { return *(v+i); } };
int main()
{ cls x(10);
x[4]=-15;
for (int i=0; i<x.size(); i++) cout<<x[i];
return 0;
}
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
{ 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;
}
86
40. 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;
}
87
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>
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;
}
46. 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;
88
a;
} };
b;
b=i; }
{ b=x.a; } };
89
Bibliografie
1. Oprea M., Programare orientat pe obiecte - Exemple n limbajul C++, Editura Matrix Rom.
2. Dr. Kris Jamasa, Totul despre C si C++, Editura Teora.
3. Ion Smeureanu , Programare orientat pe obiecte in Limbajul C++, Editura CISON,
Bucuresti 2005.
4.Liviu Negrescu, Limbajul C++, Editura ALBASTRA , Cluj 2000.
5.Luminita Duta, Programarea calculatoarelor in limbajul C++ , Editura Cetatea de Scaun
2006.
90