lab

47
Programare 2 Indrumar Laborator Nota laborator = Prezenta + Activitate laborator + Partial + Examen Prezenta Fiecare prezenta duce la obtinerea unui punct ( 1p). Se pot obtine maximum 12 puncte. In ultima saptamana se va desfasura examenul de laborator, la care se adauga partialul. Partial Prezenta este obligatorie. Acesta are loc in saptamana a 7-a sau a 8-a. Daca partialul nu este promovat aceasta se poate repeta in ultima saptamana. Partialul consta din rezolvarea (pe calculator) a unei probleme asemanatoare cu cele propuse si rezolvate in prima parte a semestrului. Notarea se face cu punctaj intre 0 si 45. Trebuie sa se obtina minum 23 puncte pentru a considera ca partialul a fost promovat. Examen Este obligatoriu. Neprezentarea la examenul de laborator echivaleaza cu nepromovarea laboratorului si implicit a materiei. Examenul consta din rezolvarea (pe calculator) a unei probleme asemanatoare cu cele propuse si rezolvate in timpul semestrului. Notarea se face cu punctaj intre 0 si 50. Trebuie sa se obtina minum 25 de puncte pentru a considera ca examenul a fost promovat. Punctaj laborator = (Numar prezente) * 1 + (Punctaj partial) + (Punctaj examen laborator) Asadar, punctajul maxim poate fi: Punctaj laborator max = 12 + 45 + 50 = 107 Nota laborator = Punctaj laborator / 10. Pentru promovarea laboratorului este necesara obtinerea unei punctaj mai mare de 50 de puncte (corespunzatoare notei 5). Atentie! 45 de puncte nu inseamna nota 5 ! Situatia la laborator este disponibila la adresa http://upm.adrianroman.ro/prog2/note.xls

Upload: 123alex99

Post on 01-Jul-2015

26 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: lab

Programare 2

Indrumar Laborator

Nota laborator = Prezenta + Activitate laborator + Partial + Examen

Prezenta

Fiecare prezenta duce la obtinerea unui punct (1p). Se pot obtine maximum 12 puncte. In ultima

saptamana se va desfasura examenul de laborator, la care se adauga partialul.

Partial

Prezenta este obligatorie. Acesta are loc in saptamana a 7-a sau a 8-a. Daca partialul nu este

promovat aceasta se poate repeta in ultima saptamana.

Partialul consta din rezolvarea (pe calculator) a unei probleme asemanatoare cu cele propuse si

rezolvate in prima parte a semestrului. Notarea se face cu punctaj intre 0 si 45. Trebuie sa se

obtina minum 23 puncte pentru a considera ca partialul a fost promovat.

Examen

Este obligatoriu. Neprezentarea la examenul de laborator echivaleaza cu nepromovarea

laboratorului si implicit a materiei.

Examenul consta din rezolvarea (pe calculator) a unei probleme asemanatoare cu cele propuse si

rezolvate in timpul semestrului. Notarea se face cu punctaj intre 0 si 50. Trebuie sa se obtina

minum 25 de puncte pentru a considera ca examenul a fost promovat.

Punctaj laborator = (Numar prezente) * 1 + (Punctaj partial) + (Punctaj examen laborator)

Asadar, punctajul maxim poate fi:

Punctaj laborator max = 12 + 45 + 50 = 107

Nota laborator = Punctaj laborator / 10.

Pentru promovarea laboratorului este necesara obtinerea unei punctaj mai mare de 50 de

puncte (corespunzatoare notei 5). Atentie! 45 de puncte nu inseamna nota 5 !

Situatia la laborator este disponibila la adresa http://upm.adrianroman.ro/prog2/note.xls

Page 2: lab

Laborator 1

Recapitulare Programare 1

Exemplul 1

/********************************

Program: Hello World

Obiectiv: studirea structurii unui program C

********************************/

#include <iostream> //directiva preprocesor

using namespace std; //spune compilatorului ca anumite obiecte se

gasesc in namespace-ul standard

int main () //functia principala

{

cout << "Primul meu program in C! Bravo!\n";

getchar(); //asteapta apararea unei taste. De testat programul si fara

aceasta linie

return 0;

}

Exemplul 2

/********************************

Program: Calcularea mediei

Obiectiv: studirea instructiunii if

********************************

#include <iostream>

using namespace std;

int main ()

{

int n1, n2, n3;

double medie;

cout << "Introduceti 3 note : ";

cin >> n1 >> n2 >> n3;

medie = (n1 + n2 + n3)/3.0;

cout << "Media este : " <<medie <<endl;

if (medie >= 5.0) cout << "Studentul a promovat!";

else cout << "Studentul a picat!";

cin.ignore();

getchar();

return 0;

}

Exemplul 3

/******************************************

Program: Afisarea numerele de la 1 la 100 pe ecran

Obiectiv - instructiunea for

*****************************************/

#include <iostream>

using namespace std;

int main()

Page 3: lab

{

int number;

for (number =1; number <= 100; number++)

{

cout << number << " "; //afiseaza numarul si un spatiu

}

getchar();

return 0;

}

Exemplul 4

/********************************

Program: Apelare prin referinta

********************************/

#include <iostream>

using namespace std;

void citiredim (int &, int &);

float calc (int, int);

int main()

{

int lungime, latime;

float mp;

citiredim(lungime, latime);

mp = calc (lungime, latime);

cout << "Aria in metrii patrati " << mp;

getchar();

getchar();

return 0;

}

void citiredim (int &lun, int &lat)

{

cout << "Introduceti lungimea: ";

cin >> lun;

cout << "Introduceti latimea: ";

cin >> lat;

}

float calc (int lungime, int latime)

{

float aria;

aria = lungime * latime;

return aria;

}

Exercitiu

Sa se scrie si sa se apeleze o functie care calculeaza divizorii unui numar citit de la

tastatura.

Page 4: lab

Laborator 2

Spatii de nume

C++ foloseste spatii de nume (namespaces) pentru a organiza functii/clase cu

functionalitati inrudite, folosite in cadrul programelor.

Uneori, o variabilă dintr-un domeniu se suprapune peste o variabilă cu acelaşi nume din

alt domeniu. Suprapunerea numelor poate, uneori, să pună probleme, mai ales atunci când

se folosesc în acelaşi program mai multe biblioteci care utilizează la nivel global

identificatori cu aceleaşi nume. O astfel de situaţie conduce, de regulă, la erori

de compilare.

Limbajul C++ rezolvă această problemă prin spaţiile de nume (namespaces).

Fiecare namespace defineşte un domeniu în care sunt plasaţi identificatorii. Pentru a

folosi un membru al unui namespace, acesta trebuie să fie precedat de numele

namespace-ului:

nume_namespace::membru

Alternativ, se poate folosi declaraţia using înaintea identificatorului care este folosit.

În mod obişnuit, declaraţiile using sunt plasate la începutul fişierului în care sunt folosiţi

membrii namespace-ului. De exemplu, instrucţiunea

using namespace nume_namespace;

la începutul unui fişier sursă specifică faptul că membrii lui nume_namespace

pot fi folosiţi în fişier fără a preceda fiecare identificator cu numele namespace-ului şi

operatorul domeniu ::.

Instructiunea using namespace std; este un spatiu de nume.

Daca nu am fi folosit spatiul de nume

using namespace std; , instructiunile din corpul functiei main

ar fi trebuit scrise:

std::cout <<" Primul program CLR console application \n\nFelicitari!!";

std::cin.get();

return 0;

Instrucţiunea

using namespace std;

informează compilatorul că va fi folosit namespace-ul std. Întreg conţinutul fişierului

header iostream este definit ca parte a lui std. Această declaraţie presupune că

unii membri ai lui std vor fi folosiţi în mod frecvent în program. Programatorul are,

astfel, posibilitatea, să acceseze toţi membrii acestui namespace şi să scrie

Page 5: lab

instrucţiuni într-o variantă mai concisă:

cout << "d= " << d;

decât scriind

std::cout << "d= " << d;

Fără instrucţiunea de declarare a lui std, fiecare cout şi endl ar trebui să fie

precedat de std::.

Exemplul 2.1

//Namespace0

#include <iostream>

using namespace std;

int i = 10;

int main()

{ double i = 3.4;

cout<<"local i "<<i<<'\n';

cout<<"global i "<<::i<<'\n';

cin.get();

return 0;

}

Exemplul 2.2

//Namespace 1

#include <iostream>

using namespace std;

namespace first

{ int var =5;}

namespace second

{ double var =3.1415; }

int main()

{ cout<< first::var<<'\n';

cout << second::var << '\n';

cin.get();

return 0;

}

Exemplul 2.3

//Namespace 2

#include <iostream>

using namespace std;

namespace first

{ int x =5;

Page 6: lab

int y = 10;

}

namespace second

{ double x = 3.1415;

double y = 2.7183;

}

int main()

{ using first::x;

using first::y;

cout <<x<<'\n';

cout << y<<'\n';

cout<< second::x <<'\n';

cout<< second::y<<'\n';

cin.get();

return 0;

}

Exemplul 2.4

//Namespace 3

#include <iostream>

using namespace std;

namespace first

{ int x =5;

int y = 10;

}

namespace second

{ double x = 3.1415;

double y = 2.7183;

}

int main()

{ using namespace first;

cout <<x<<'\n';

cout << y<<'\n';

cout<< second::x <<'\n';

cout<< second::y<<'\n';

cin.get();

return 0;

}

Exercitiu

Page 7: lab
Page 8: lab

Laborator 3

Exceptii C++

Exceptiile sunt erori produse la executia programului cind controlul este preluat de codul

de tratarea acestor exceptii, daca exista. In acest fel se poate preveni opriri bruste ale

programelor la aparitia acestor erori, putindu-se lua masuri de genul eliberat resursele

afisate, atentionat utilizatorul, scris detalii despre eroare in fisiere de log, etc.

Pentru a trata erorile se folosesc blocurile try .. catch.

Exemplul 3.1

#include <iostream>

using namespace std;

int main () {

try

{

throw 20;

}

catch (int e)

{

cout << "Exceptie aparuta cu nr. " << e << endl;

}

return 0;

}

Tot codul de executat in care este posibil sa apara exceptiile e inclus in try {}. In acest

exemplu este generata o exceptie cu numarul 20, care va fi tratata mai jos. Dupa codul

din try{} urmeaza una sau mai multe instructiuni catch() pentru diverse tipuri de erori. In

acest caz este prinsa doar eroarea de tip intreg.

De exemplu puteti avea asa:

try {

// codul e aici

}

catch (int param) { cout << "Exceptie intreaga"; }

catch (char param) { cout << "Exceptie de tip caracter"; }

catch (...) { cout << "Orice alte exceptii"; }

Dupa cum se vede se poate specifica prin '...' orice tip de exceptii netratata anterior.

La aparitia unei erori sint analizate toate instructiunile catch() iar daca una se potriveste

tipului de eroare este executata, dupa care programul continua cu instructiilile de dupa

catch().

Page 9: lab

Exemplul 3.2

#include <iostream>

using namespace std;

void Ehandler(int);

int main()

{ cout<<"start\n";

Ehandler(1);

Ehandler(2);

Ehandler(0);

Ehandler(3);

cout<<"sfarsit\n";

cin.get();

return 0;

}

void Ehandler(int test)

{ try

{ if(test)

throw test;

}

catch(int i)

{ cout<<"am prins exceptia cu valoarea "<<i<<'\n';

}

}

Exemplul 3.3

#include <iostream>

using namespace std;

void Xhandler(int) throw(int,char,double);

int main()

{ cout<<"start\n";

for(int k =0;k<3;k++)

{ try

{ Xhandler(k);

}

catch( int i)

{ cout <<"am prins int\n";

}

catch( char i)

{ cout <<"am prins char\n";

}

catch( double i)

{ cout <<"am prins double\n";

}

Page 10: lab

}

cout<<"sfarsit\n";

cin.get();

return 0;

}

void Xhandler(int test) throw (int,char,double)

{

if(test == 0) throw test;

if(test == 1) throw 'a';

if(test == 2) throw 3.14;

}

Exercitii

1. Sa se scrie un program care sa citeasca 10 valori de tip intreg de la tastatura. Daca

se introduce un numar negativ sa se arunce o exceptie.

2. Sa se scrie un program care sa citeasca 10 valori de la tastatura. Daca se introduce

o valoare care nu reprezinta un numar sa se arunce o exceptie.

Page 11: lab

Laborator 4

Alocare dinamica

Se pune problema utilizării, într-un program, a unui număr foarte mare de date de tip double, de

exemplu, care trebuie prelucrate rapid şi care, în consecinţă, trebuie să se afle în memorie în

momentul rulării, chiar dacă iniţial se află într-un fişier pe disc. Este evident că în acest caz vom

folosi tablouri cu dimensiuni adecvate volumului de date.

Utilizarea tablourilor este foarte simplă dar, dacă volumul de date prelucrat este cu adevărat

mare, ne vom lovi de un neajuns major: nu pot fi declarate tablouri de dimensiuni variabile:

alocarea unui tablou are un caracter static, este făcută la compilarea programului, prin urmare

numărul de elemente trebuie desemnat printr-o constantă. Programatorul trebuie să estimeze o

dimensiune maximă, acoperitoare pentru toate situaţiile în care va fi folosit respectivul tablou, şi

să-l declare în consecinţă. Apare astfel o risipă inerentă de spaţiu de memorie.

De exemplu, dacă declarăm tabloul: double mat[100][100];

şi la rulare îl încărcăm cu o matrice de 10 x 10 elemente, folosim numai 1% din spaţiul

rezervat prin program! Risipa este evidentă, iar remediul constă în alocarea dinamică a

memoriei, adică alocarea în momentul rulării programului.

In locul lor tablourilor declarare static vom folosi variabile de tip pointer pentru a reţine adresele

locaţiilor de memorie obţinute de la sistemul de calcul prin operaţii de alocare. In cazul alocării

tablourilor se garantează că elementele succesive au locaţii succesive şi, în consecinţă,

parcurgerea tablourilor alocate dinamic poate fi facută cu operatorul de indexare, ca în cazul

alocării statice, utilizând identitatea dintre expresia p[i] şi *(p+i).

Important !

Diferenţa esenţială dintre pointeri şi tablouri: instrucţiunea double* p

declară o variabilă de tip pointer către double, în timp ce double tab[10];

declară un tablou al cărui nume, tab, este o constantă de tip pointer către double, cu valoarea:

adresa primului element al tabloului, atribuirea p=tab;

este corectă, în locaţia de memorie numită p se scrie adresa primului element din tabloul

tab, în timp ce atribuirea tab=p;

nu este permisă: nu există o locaţie de memorie numită tab care să conţină o adresă care

să fie modificată. Este clar că, la compilare, apare undeva într-un tabel numele tab urmat

de valoarea sa, adresa primului element al tabloului, şi această informaţie este utilizată la

proiectarea codului, dar programatorul nu are acces la acel tabel. Putem spune, aşadar, că

tab este un pointer static, un pointer utilizat numai de compilator, cu o valoare constantă,

Page 12: lab

în timp ce p este un pointer dinamic, a cărui valoare poate fi modificată de către programator şi

care, în consecinţă, trebuie iniţializată tot de către programator.

Un pointer poate fi iniţializat corect doar în următoarele trei moduri:

1) cu adresa unei variabile alocate deja de compilator: int i=7;

int* p;

p=&i;

cout<<*p<<endl; //7

sau, 2) printr-o atribuire cu o expresie corectă din aritmetica pointerilor, de exemplu int tab[10]={0,1,2,3,4,5,6,7,8,9};

int* p;

p=tab+5;

cout<<tab[5]<<"=="<<*p<<endl; //5==5

sau, 3) prin alocare dinamică, după cum urmează mai jos.

In limbajul C alocarea dinamică a memoriei poate fi facută numai cu funcţii din biblioteci

specializate în gestionarea memoriei, cele mai utilizate fiind funcţiile malloc(), calloc(), free(),

realloc(), toate din <malloc.h>.

In C++ se utilizeaza operatorii new şi delete care fac parte din integrantă din limbaj. Operatorul

new poate fi utilizat în două moduri: pentru a rezerva spaţiu de memorie pentru un singur obiect,

caz în care new întoarce adresa obiectului alocat, sau pentru a rezerva spaţiu pentru un tablou cu

un numar variabil de obiecte (dar bine precizat, la rulare, în momentul evaluării expresiei), caz în

care new întoarce adresa primului element din tablou.

Spaţiul alocat cu operatorul new (şi numai acesta) poate fi eliberat cu ajutorul operatorului

delete. Pentru a reuşi eliberarea spaţiului, operatorul delete trebuie să primească adresa primului

octet al locaţiei, adică exact valoarea iniţială a pointerului încărcat de new la alocare. La

dealocarea unui tablou se utilizează forma delete [ ].

Exemplul 1, alocarea şi dealocarea unor variabile simple: #include<iostream.h>

int main(void)

{

int *q,*p;

p=new int;

q=new int;

*p=10;

*q=*p+23;

cout<<"p="<<p<<endl;

cout<<"q="<<q<<endl;

cout<<"*q="<<*q<<endl;

delete q;

delete p;

cout<<"q="<<q<<endl;

cout<<"*q="<<*q<<endl;

q=new int;

*q=12;

cout<<"q="<<q<<endl;

cout<<"*q="<<*q<<endl;

return 0;

}

Page 13: lab

/* REZULTAT

p=0x00430030

q=0x00431740

*q=33

q=0x00431740

*q=-572662307 //GUNOI

q=0x00430030

*q=12

Press any key to continue

Exemplul 2, alocarea şi dealocarea unui tablou de variabile simple: #include<iostream.h>

int* aloca1D(int n)

{

int* p = new int[n];

for(int i=0;i<n;i++){

p[i]=100*(i+1);

}

cout<<endl;

return p;

}

void dealoca1D(int *p){

delete [] p;

}

int main(void)

{

int i,dim=5;

int* vector;

vector=aloca1D(dim);

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

cout<<vector[i]<<endl;

dealoca1D(vector);

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

cout<<vector[i]<<endl;

return 0;

}

/* REZULTAT

100

200

300

400

500

-572662307

-572662307

-572662307

-572662307

-572662307

Press any key to continue

*/

Page 14: lab

Exercitiu

Sa se scrie un program care stocheaza intr-un tablou alocat dinamic divizorii unui intreg citit de

la tastatura si ii afiseaza.

Page 15: lab

Laborator 5

Alocare unui tablou de tablouri

In programul următor declarăm, cu instrucţiunea:

int (*p)[5];

un pointer catre tipul int[5], adică pointer către tablouri de 5 întregi, pe care îl încărcăm cu

operatorul new cu adresa unui astfel de tablou, primul dintr-o serie de n tablouri succesive,

fiecare cu câte 5 elemente. Definim astfel un tablou 2D cu un număr variabil de linii şi cu un

număr constant, 5, de coloane. Declaraţia funcţiei aloca() este mai complicată: lista parametrilor

formali este formată numai de variabila int n iar rezultatul este de tip int(*)[5], adică pointer

către int[5].

Exemplul 1 #include<iostream>

#include<iomanip>

using namespace std;

int (*aloca(int n))[5]{

int (*p)[5];

p = new int[n][5];

for(int i=0;i<n;i++)

{

for(int j=0;j<5;j++){

p[i][j]=10*i +j;

}

}

return p;

}

void dealoca(int (*p)[5]){

delete [] p;

return;

}

int main(void){

int dim=3;

int (*p)[5];

p=aloca (dim);

for(int i=0;i<3;i++){

for(int j=0;j<5;j++)

cout<<setw(5)<<p[i][j];

cout<<endl;

}

dealoca(p);

getchar();

return 0;

}

/*

REZULTAT:

0 1 2 3 4

10 11 12 13 14

20 21 22 23 24

Page 16: lab

Press any key to continue

*/

Avem deci un exemplu de alocare a unui tablou 2D de tipul n x 5. Alocarea unui tablou

de tipul 5 x n este mult mai simplă, vezi secvenţa următoare: int i,j, n=7;

int* tab[5];

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

tab[i]= new int[n];

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

for(j=0;j<n;j++)

tab[i][j]=i*j;

Declarăm un tablou, tab, format din 5 pointeri către int şi încărcăm fiecare pointer cu

adresa unui vector de n elemente întregi, alocat dinamic.

Exemplul 2

//CitesteVector

#include <iomanip>

#include <iostream>

using namespace std;

int main()

{ int max = 2;

int *a = new int[max];

int n=0;

cout<<"\n\nDimensiune initiala a tabloului = "<<max<<'\n';

cout<<"\n\nIntroduceti numere intregi,terminati cu ctrl Z\n";

while(cin>>a[n])

{ n++;

if(n >= max)

{ max += 2;

int *temp = new int[max];

for(int i =0;i<n;i++)

temp[i] = a[i];

delete [] a;

a = temp;

}

}

cin.clear();

cout<<"\n\nDimensiune finala a tabloului"<<max<<'\n';

cout<<"\n\nNumerele introduse sunt:\n\n";

for(int i= 0;i<n;i++)

cout<<setw(5)<<a[i];

cout<<"\n\nApasati tasta Enter";

cin.get();

getchar();

return 0;

}

Exercitiu

Sa se scrie un program care stocheaza intr-un tablou alocat dinamic divizorii unui intreg citit de

la tastatura si ii afiseaza.

Page 17: lab

Laborator 6

Alocare unui tablou 2D cu ambele dimensiuni variabile

#include <iostream>

using namespace std;

double** aloca2D(int nrLin, int nrCol){

// double** double* double

//

// mat -> mat[0] -> mat[0][0]

// mat[0][1]

// mat[0][2]

//

// mat[1] -> mat[1][0]

// mat[1][1]

// mat[1][2]

int i;

double** mat;

mat= new double*[nrLin];

for(i=0;i<nrLin;i++){

mat[i]=new double[nrCol];

}

return mat;

}

void dealoca2D(double** mat,int nrLin, int nrCol){

for(int i=0;i<nrLin;i++)

delete mat[i];

delete mat;

}

void afiseaza(double** mat,int nrLin, int nrCol){

int i,j;

for(i=0;i<nrLin;i++){

for(j=0;j<nrCol;j++) cout<<mat[i][j]<<" ";

cout<<endl;

}

}

void citeste(double** mat,int nrLin, int nrCol){

int i,j;

for(i=0;i<nrLin;i++){

for(j=0;j<nrCol;j++) {

cout<<"m["<<i<<"]["<<j<<"]=";

cin>>mat[i][j];

}

cout<<endl;

}

}

int main(void)

{

int m,n;

double **qmat;

cout<<"dati nr. de linii, m=";cin>>m;

Page 18: lab

cout<<"dati nr. de coloane, n=";cin>>n;

qmat=aloca2D(m,n);

citeste(qmat,m,n);

afiseaza(qmat,m,n);

dealoca2D(qmat,m,n);

return 0;

}

Observăm că, în funcţia aloca2D(), alocarea se efectuează în două etape: mai întâi alocam un

tablou de pointeri (fiecare va ţinti către o linie a matricii) şi apoi încărcăm fiecare astfel de

pointer cu adresa primului element al unei linii nou alocate. Dacă dorim să lucrăm cu o matrice

de tip n x m de elemente de tip double, avem nevoie de un pointer mat de tip double** care să

reţină adresa primului pointer dintre cei n pointeri de tip

double* (anume pointerii mat[0], mat[1], ... , mat[n-1]),

care la rândul lor trebuie să reţină adresele primelor elemente de pe fiecare linie. Dealocarea se

face în ordine inversă: întâi dealocam liniile, rând pe rând, şi apoi dealocăm coloana de pointeri.

Exercitii

1. Sa se citeasca de la tastatura valorile unei matrici de n * m, unde n si m se citesc de la

tastatura si sa se adune cu matricea unitate. Sa se afiseze rezultatul.

2. Sa se citeasca de la tastatura valorile a 2 matrice si sa se calculeze suma lor.

3. Sa se citeasca de la tastatura valorile a 2 matrice si sa se calculeze produsul lor.

4. Sa se implementeze un program de calcul a sumei elementelor de pe fiecare rând

împartita la valoarea elementului de pe diagonala a unei matrice.

5. Sa se implementeze un program de calcul a rangului unei matrice.

6. Pentru o matrice de m linii si n coloane (dreptunghiulara) sa se afiseze coloanele ce

reprezinta siruri ordonate crescator, si liniile care reprezinta siruri ordonate descrescator.

7. Pentru o matrice An,n, se cauta în toate submatricele formate din liniile si coloanele i…n,

cu i=1,.., n, elementele maxime în valoare absoluta. Acestea vor fi aduse pe pozitiile ai,i.

Determinati apoi daca matricea este dominant-diagonala, adica daca elementul de pe

diagonala principala, în valoare absoluta - |ai,i| - este mai mare decât suma modulelor

vecinilor sai de pe linia i.

8. Sa se calculeze media aritmetica si produsul elementelor cuprinse în zonele superioara si

inferioara, situate între diagonala principala si secundara ale matricei.

Page 19: lab

Laborator 7

Tipuri Utilizator

Exemplul 1 – Union

//Union

#include <iostream>

int main()

{ union conversie

{ int numar;

char litere[2];

};

conversie data;

data.numar = 65 + 66*256;

cout<<"\nData ca numar zecimal "<<data.numar<<endl;

cout<<"\nData ca numar hexa "<<hex<<data.numar<<endl;

cout<<"\nData ca sir de caractere "<<data.litere[1]

<<" "<<data.litere[0]<<endl;

cout<<"\nApasati tasta ENTER";

cin.get();

return 0;

}

Exemplul 2 - Stiva

//Stiva

#include <iostream>

#include <iomanip>

#include <conio.h>

struct nod

{ int data;

nod *prec,*urm;

};

nod *varf;

void afisez();

void adaug(int);

void sterg();

int main()

{ char optiune;

int n;

varf = NULL;

do

{ clrscr();

cout<<"1 = Pun in stiva\n2 = Scot din stiva\nS = Sfarsit\n";

cout<<"\n\nOptiune : ";

cin>>optiune;

cin.ignore();

cout<<'\n';

Page 20: lab

switch(optiune)

{case '1':

cout<<"\n\nPun in stiva";

cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

adaug(n);

afisez();

break;

case '2':

cout<<"\n\nScot din stiva";

sterg();

afisez();

break;

case 'S':

break;

case 's':

optiune &= 0x5f;

break;

default:

cout<<"\n\nOptiune incorecta";

}

cout<<"\n\nApasati tasta ENTER";

cin.get();

}

while ( optiune != 'S');

return 0;

}

void afisez()

{ nod *p;

cout<<"\nStiva este: ";

if (!varf)

cout<<"vida";

else

for(p=varf;p;p=p->prec)

cout<<setw(4)<<p->data;

}

void adaug(int n)

{ nod *p = new nod;

p->data = n;

p->urm = 0;

p->prec = varf;

if(varf)

varf->urm = p;

varf=p;

}

void sterg ()

{ nod *p;

if (!varf)

return;

else

Page 21: lab

{ p = varf;

varf = varf->prec;

delete p;

}

}

Exercitiu

Sa se scrie un program care sa testeze daca o expresie ce contine paranteze este valida. Se

va folosi stiva.

Exemplu de expresie invalida: (a+b*c

Exemplu de expresie valida: (a+b)*c sau (a+b*c)

Page 22: lab

Laborator 8

Tipuri Utilizator - Coada

Exemplul 1 – Coada statica

//Coada

#include <iomanip>

#include <conio.h>

const int N=5;

int coada[N],primul=0,nrelem=0;

void adaug(int);

void extrag();

void afisez();

int main()

{ char optiune;

int n;

do

{ clrscr();

cout<<"1 = Adaugare elememt\n2 = Extragere element"

"\n3 = Afisare\nS = Sfarsit\n";

cout<<"\n\nOptiune : ";

cin >> optiune;

cin.ignore();

switch(optiune)

{ case '1':

cout<<"\n\nAdaugare element";

if (nrelem == N)

{cout<<"\n\nCoada este plina";

afisez();

}

else

{ cout<<"\nValoare element: ";

cin>>n;

cin.ignore();

adaug(n);

afisez();

}

break;

case '2':

cout<<"\n\nExtragere element";

extrag();

break;

case '3':

cout<<"\n\nAfisare coada";

afisez();

break;

case 'S':

break;

case 's':

optiune &= 0x5f;

break;

Page 23: lab

default:

cout<<"\n\nOptiune incorecta";

break;

}

cout<<"\n\nApasati tasta Enter";

cin.get();

}

while ( optiune != 'S');

return 0;

}

void adaug(int n)

{ coada[(primul+nrelem)%N]=n;

nrelem++;

}

void extrag()

{ if(!nrelem)

cout<<"\n\nCoada este vida";

else

{primul = (primul+1)%N;

nrelem--;

afisez();

}

}

void afisez()

{ if(!nrelem)

cout<<"\n\nCoada este vida";

else

{ cout<<"\n\nCoada este:";

for(int i=0;i<nrelem;i++)

cout<<setw(4)<<coada[(primul+i)%N];

}

}

Exemplul 2 – Coada dinamica

//CoadaD

#include <conio.h>

#include <iomanip>

struct nod

{int data;

nod *next;

};

nod *primul,*ultimul;

void afisez();

void adaug(int);

void extrag();

int main()

{ primul = ultimul= 0;

char optiune;

Page 24: lab

int n;

do

{ clrscr();

cout<<"1 = Adaugare elememt\n2 = Extragere element"

"\n3 = Afisare\nS = Sfarsit\n";

cout<<"\nOptiune : ";

cin>>optiune;

cin.ignore();

cout<<'\n';

switch(optiune)

{ case '1':

cout<<"\n\nAdaugare element";

cout<<"\nValoare element: ";

cin>>n;

cin.ignore();

adaug(n);

afisez();

break;

case '2':

cout<<"\n\nExtragere element";

extrag();

break;

case '3':

cout<<"\n\nAfisare coada";

afisez();

break;

case 'S':

break;

case 's':

optiune &= 0x5f;

break;

default:

cout<<"\n\nOptiune incorecta";

}

cout<<"\n\nApasati tasta ENTER";

cin.get();

}

while ( optiune != 'S');

}

void adaug(int n)

{ nod *p = new nod;

p->data = n;

p->next = 0;

if (! primul)

primul = ultimul = p;

else

{ ultimul->next = p;

ultimul = p;

}

}

void extrag()

{ nod *p;

if(!primul)

Page 25: lab

cout<<"\n\nCoada este vida";

else

{ p = primul;

primul = primul->next;

delete p;

afisez();

}

}

void afisez()

{ nod *p;

if (!primul)

cout<<"\n\nCoada este vida";

else

{ cout<<"\n\nCoada este:";

for(p=primul;p;p=p->next)

cout<<setw(4)<<p->data;

}

}

Exercitiu

Sa se scrie un program care sa citeasca de la tastatura un set de comenzi care apoi sa fie

introduse intr-o coada si apoi sa fie afisate una cate una.

Exemplu:

Intrare: comanda1 comanda2 comanda3 comanda4 comanda5

Iesire:

comanda1

comanda2

comanda3

comanda4

comanda5

Page 26: lab

Laborator 9

Tipuri Utilizator - Lista

Exemplul 1

//ListaS

#include <iomanip>

#include <conio>

#include <new>

struct nod

{ int data;

nod *next;

};

nod *primul;

void afisez();

void creare();

void adaugst(int);

void adaugdupa(int);

void sterg(int);

void main()

{ char optiune;

int n;

primul =new nod;

primul->next = 0;

set_new_handler(0);

do

{ clrscr();

cout<<"1 = Creare lista\n2 = Adaugare nod stanga\n3 = Adaugare dupa

nodul n"

"\n4 = Stergere nodul n\n5 = Afisare lista\nS = sfarsit\n";

cout<<"\nOptiune : ";

cin>>optiune;

cin.ignore();

cout<<'\n';

switch(optiune)

{ case '1':

cout<<"Creare lista";

creare();

break;

case '2':

afisez();

cout<<"\n\nAdaugare nod stanga";

cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

adaugst(n);

break;

case '3':

afisez();

cout<<"\n\nAdaugare dupa nodul";

Page 27: lab

cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

adaugdupa(n);

break;

case '4':

afisez();

cout<<"\n\nStergere nod";

cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

sterg(n);

break;

case '5':

cout<<"Afisare lista";

afisez();

break;

case 'S':

break;

case 's':

optiune &=0x5f;

break;

default:

cout<<"\n\nOptiune incorecta";

}

cout<<"\n\nApasati o tasta\n";

cin.get();

}

while ( optiune != 'S');

}

void creare()

{ int n;

nod *p;

if (primul->next)

{ cout<<"Lista exista";

afisez();

}

else

{ cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

p = new nod;

p->data = n;

p->next = 0;

primul->next = p;

afisez();

}

}

void afisez()

{ nod *p;

cout<<"\nLista este:";

if (!(primul->next))

cout<<" vida";

Page 28: lab

else

for(p=primul->next;p;p=p->next)

cout<<setw(5)<<p->data;

}

void adaugst(int n)

{ nod *p;

if (!(primul->next))

{ cout<<"\nLista este vida";

cout<<"Lista trebuie creata";

return;

}

else

{ for(p=primul;p->next && p->next->data != n;p=p->next);

if ( p->next)

cout<<"\nNodul "<<n<<" exista in lista\n";

else

{ p = new nod;

p->data = n;

p->next = primul->next;

primul->next = p;

afisez();

}

}

}

void adaugdupa(int n)

{ nod *p,*q;

int m;

if (!(primul->next))

{ cout<<"\nLista este vida";

cout<<"Lista trebuie creata";

return;

}

else

{ for(p=primul;p->next && p->next->data != n;p=p->next);

if (!( p->next))

{ cout<<"\nNodul "<<n<<" nu exista in lista\n";

return;

}

else

{ cout<<"\nValoare nod care se adauga: ";

cin>>m;

cin.ignore();

for(q=primul;q->next && q->next->data != m;q=q->next);

if ( q->next)

cout<<"\nNodul "<<m<<" exista in lista\n";

else

{ p=p->next;

q = new nod;

q->data = m;

q->next = p->next;

p->next = q;

afisez();

}

}

Page 29: lab

}

}

void sterg (int n)

{ nod *p,*q;

if (!(primul->next))

{ cout<<"\nLista este vida";

cout<<"Lista trebuie creata";

}

else

{ for(p=primul;p->next && p->next->data != n;p=p->next);

if (!( p->next))

{ cout<<"\nNodul "<<n<<" nu exista in lista\n";

return;

}

else

{ q = p->next;

p->next = p->next->next;

delete q;

afisez();

}

}

}

Exemplul 2

//ListaD

#include <iomanip>

#include <conio.h>

#include <new.h>

struct nod

{int data;

nod *prec,*urm;

};

nod *cap=0,*coada=0,*poz=0;

bool esteGoala()

{ return cap == 0;

}

bool maiSuntElemente()

{ return poz != 0;

}

int urmatorulElement()

{ nod *temp = poz;

poz = poz->urm;

return temp->data;

}

Page 30: lab

nod* gaseste(int n)

{ if(esteGoala())

return 0;

nod *temp = cap;

while(temp != 0)

{ if(temp->data == n)

return temp;

temp = temp->urm;

}

return 0;

}

void adauga(int n)

{ nod *temp = new nod;

temp->data = n;

temp->prec = 0;

temp->urm =0;

if( cap == 0)

{ cap = temp;

coada = temp;

}

else

{ coada->urm = temp;

temp->prec = coada;

coada = temp;

}

}

void insereaza(int n, int poz)

{ nod *pozNod = gaseste(poz);

if(pozNod == 0)

{ cout<<"\n\nNodul " << poz <<" nu este in lista\n";

return;

}

nod* temp = new nod;

temp->data = n;

temp->urm = pozNod;

temp->prec = pozNod->prec;

if(pozNod == cap)

cap = temp;

else

pozNod->prec->urm = temp;

pozNod->prec = temp;

}

void sterge(int n)

{ nod *stergNod = gaseste(n);

if(stergNod == 0)

{ cout<<"\n\nNodul " <<n<<" nu este in lista\n";

return;

}

if(stergNod == cap)

cap = stergNod->urm;

else

stergNod->prec->urm = stergNod->urm;

if(stergNod == coada)

coada = stergNod->prec;

Page 31: lab

else

stergNod->urm->prec = stergNod->prec;

delete stergNod;

}

void afiseaza()

{ poz = cap;

while(maiSuntElemente())

cout<<setw(4)<<urmatorulElement();

}

int main()

{char optiune;

int n,m;

do

{clrscr();

cout<<"1 = Adauga nod\n2 = Insereaza nod in fata altui nod"

"\n3 = Stergere nodul n\n4 = Afisare lista\nS = Sfarsit\n";

cout<<"\n\\nOptiune : ";

cin>>optiune;

cin.ignore();

cout<<'\n';

switch(optiune)

{ case '1':

cout<<"\n\nAdauga nod";

cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

adauga(n);

break;

case '2':

cout<<"\n\nInsereaza nod in fata altui nod";

cout<<"\nValoare nod care s insereaza: ";

cin>>n;

cin.ignore();

cout<<"\nValoare nod in fata caruia se insereaza: ";

cin>>m;

cin.ignore();

insereaza(n,m);

break;

case '3':

cout<<"\n\nStergere nod";

cout<<"\nValoare nod: ";

cin>>n;

cin.ignore();

sterge(n);

break;

case '4':

cout<<"\n\nAfisare lista\n";

afiseaza();

break;

case 'S':

break;

case 's':

optiune &= 0x5f;

break;

Page 32: lab

default:

cout<<"\n\nOptiune incorecta";

}

cout<<"\n\nApasati tasta ENTER";

cin.get();

}

while ( optiune != 'S');

return 0;

}

Exercitiu

Sa se scrie un program care sa introduca intr-o lista 20 de numere prime mai mari decat

un numar citit de la tastatura si sa se afiseze descrescator.

Exemplu:

Intrare: 6

Iesire: 83, 79, 73, 71, 67, 61, 59, 53, 47, 43, 41, 37, 31, 29, 23, 19, 17, 13, 11, 7

Page 33: lab

Laborator 10

Programare Orientata Obiect in C++

Tipul class

Sintaxa generală de declarare a unui tip de date class este:

class <nume_clasa> <: lista_clase_baza> {<lista_membri>}

<lista_variabile>;

unde:

nume_clasa este un identificator care desemnează numele tipului clasă

declarat, care trebuie să fie unic în domeniul în care este valabilă declaraţia;

lista_clase_baza este lista claselor din care este derivată clasa declarată (dacă

este cazul);

lista_membri reprezintă secvenţa cu declaraţii de datele membre şi declaraţii

sau definiţii de funcţii membre; datele membre pot fi de orice tip, mai puţin

tipul clasă declarat, dar se admit pointeri către acesta

lista_variabile este lista variabilelor de tip nume_clasa.

Important! Membrii unei clase au implicit atributul de acces private.

#include<iostream.h>

class Punct{

private: // se specifică accesul private la membrii clasei

int x, y; // date membre ale clasei

public: // se specifică acces public la membrii clasei

void init(int initx=0, int inity=0)

// funcţie de iniţializare, funcţie membră cu parametri impliciţi

{x = initx; y = inity; }

int getx(){ return x; } // funcţie care returnează valoarea membrului x

int gety(){ return y; } // funcţie care returnează valoarea membrului y

void move(int dx, int dy);

// funcţie membră cu parametri, definită în afara

// declaraţiei clasei

void afisare() // funcţie de afişare a valorilor membrilor

{ cout<<”\nx=<<x<<”\tz=”<<y”;}

};

void Punct::move(int dx, int dy)

// definirea funcţiei move(), membră a clasei Punct

{

x+=dx;

y+=dy;

}

void main()

{

Punct Punct1; // se declară un obiect de tip Punct, Punct1

int x1, y1;

cout<<"\n Introduceti coordonata x= ";

Page 34: lab

cin>>x1;

cout<<" Introduceti coordonata y= ";

cin>>y1;

Punct1.init(x1, y1); // iniţializarea obiectului Punct1 cu

valorile x1,

// respectiv y1

cout<<"\n x este = "<<Punct1.getx(); // afişarea coordonatei x

cout<<"\n y este = "<< Punct1.gety(); // afişarea coordonatei y

Punct1.move(10, 20); // modificarea coordonatelor obiectului

Punct1

cout<<"\n x este = "<<Punct1.getx(); // afişarea coordonatei x

cout<<"\n y este = "<< Punct1.gety(); // afişarea coordonatei y

Punct Punct2; // se declară un obiect de tip Punct, Punct2

Punct2.init(); // membrii x şi y preiau valorile implicite ale

// parametrilor, deci x=y=0

Punct2.afisare(); // afişarea caracteristicilor obiectului Punct2

Punct *p_Punct3; // se declară un obiect pointer la Punct

p_Punct3 = &Punct2;

p_Punct3 -> move ( 5, 12);

// apelul funcţiilor membre se face folosind

// operatorul de selecţie “->”

p_Punct3 -> afisare();

}

}

Exercitiu

Sa se modifice clasa de mai sus astfel incat Punct sa aiba 3 coordonate.

Page 35: lab

Laborator 10

Programare Orientata Obiect in C++

Constructori şi destructori

Unele obiecte necesită alocarea unor variabile dinamice la creare, eventual

atribuirea de valori adecvate datelor înainte de utilizare. Pe de altă parte, eliminarea unui

obiect de acest tip impune eliberarea zonei de memorie alocată dinamic.

Pentru crearea, iniţializarea, copierea şi distrugerea obiectelor, în C++ se folosesc

funcţii membre speciale, numite constructori şi destructori.

Constructorul se apelează automat la crearea fiecărui obiect al clasei, indiferent

dacă este static, automatic sau dinamic (creat cu operatorul new), inclusiv pentru obiecte

temporare.

Destructorul se apelează automat la eliminarea unui obiect, la încheierea timpului

de viaţă sau, în cazul obiectelor dinamice, cu operatorul delete.

Aceste funcţii efectuează operaţiile prealabile utilizării obiectelor create, respectiv

eliminării lor. Alocarea şi eliberarea memoriei necesare datelor membre rămâne în

sarcina compilatorului.

Constructorul este apelat după alocarea memoriei necesare datelor membre ale

obiectului (în faza finală creării obiectului).

Destructorul este apelat înaintea eliberării memoriei asociate datelor

membre ale obiectului (în faza iniţială a eliminării obiectului).

Constructorii şi destructorii se deosebesc de celelalte funcţii membre prin câteva

caracteristici specifice:

numele funcţiilor constructor sau destructor este identic cu numele clasei căreia îi

aparţin; numele destructorului este precedat de caracterul tilde (~);

la declararea şi definirea funcţiilor constructor sau destructor nu se specifică nici

un tip de rezultat (nici tipul void);

nu pot fi moşteniţi, dar pot fi apelaţi de clasele derivate;

nu se pot utiliza pointeri către funcţiile constructor sau destructor;

constructorii pot avea parametri, inclusiv parametri impliciţi şi se pot supradefini;

destructorul nu poate avea parametri şi este unic pentru o clasă.

Constructorul fără parametri se numeşte constructor implicit.

Dacă o clasă nu are constructor şi destructori definiţi, compilatorul generează automat

un constructor implicit, respectiv un destructor implicit, care sunt funcţii publice.

Constructorii pot fi publici sau privaţi, dar, de regulă, se declară cu acces public. Dacă

se declară constructorul private, nu se pot crea obiecte de acel tip.

Acest lucru poate avea sens dacă respectiva clasă este destinată a folosi exclusive ca

şi clasă de bază pentru o ierarhie de clase derivate.

Exemplu

#include <iostream.h>

#include <conio.h>

Page 36: lab

class punct

{ double x,y;

public:

punct()

{ x = y = 0;

cout<<"\nConstructor implicit punct ("<<x<<','<<y<<')';

}

punct(double a,double b)

{ x = a;

y = b;

cout<<"\nConstructor explicit punct ("<<x<<','<<y<<')';

}

punct(punct& p)

{ x = p.x;

y = p.y;

cout<<"\nConstructor copiere punct ("<<x<<','<<y<<')';

}

~punct()

{ cout<<"\nDestructor punct ("<<x<<','<<y<<')';

cin.get();

}

void afisare()

{ cout<<"\nPunct("<<x<<','<<y<<')';

}

void deplasare(double dx,double dy)

{ x += dx;

y += dy;

}

};

class segment

{ punct A,B;

public:

segment(punct& X, punct & Y)

{ A = X;

B = Y;

cout<<"\nConstructor segment de extremitati";

A.afisare();

B.afisare();

}

segment(segment& CD)

{ A = CD.A;

B = CD.B;

cout<<"\nConstructor copiere segment.Noul segment";

A.afisare();

B.afisare();

}

~segment()

{ cout<<"\nDestructor segment de extremitati";

Page 37: lab

A.afisare();

B.afisare();

}

void afisare()

{ cout<<"\nSegment de extremitati";

A.afisare();

B.afisare();

}

void translatie(double dx,double dy)

{ cout<<"\nTranslatie segment.Noul segment";

A.deplasare(dx,dy);

B.deplasare(dx,dy);

A.afisare();

B.afisare();

}

};

void main()

{ cout<<"\nConstruiesc punctele P,Q,A,B";

punct P(7,8),Q(-4,5),A,B;

cout<<"\nApasati o tasta";

cin.get();

clrscr();

cout<<"\nConstruiesc segmentul S = PQ";

segment S(P,Q);

S.afisare();

cout<<"\nApasati o tasta";

cin.get();

clrscr();

cout<<"\nD = P";

punct D = P;

cout<<"\nD este";

D.afisare();

cout<<"\nDeplasez D cu dx=5, dy = 7";

D.deplasare(5,7);

D.afisare();

cout<<"\nSegment S1 = S";

segment S1 = S;

cout<<"\nTranslatez segmentul S cu 10,10";

S.translatie(10,10);

cout<<"\nmain s-a terminat! Apasati o tasta";

cin.get();

clrscr();

}

Exercitiu

Să se definească tipul de date: class ceas

{ private :

long int secunde;

public :

ceas();

ceas(int o, int m, int s=0);

Page 38: lab

ceas( ceas &);

~ceas();

afisare(); };

care reprezintă timpul scurs de la ora 0:0:0 a unei zile, exprimat în secunde.

Funcţia main() va conţine declaraţii de obiecte de tip ceas cu apel al diferiţilor

constructori şi atribuiri între obiecte de tip ceas şi afişarea proprietăţilor obiectelor ceas

prin apelul funcţiei afisare().

Page 39: lab

Laborator 11

Programare Orientata Obiect in C++

Mostenirea multipla

Conceptul de moştenire permite crearea de clase noi care moştenesc proprietăţile

mai multor clase de bază. Moştenirea multiplă aduce mai multă flexibilitate în construirea

claselor, rezultatul fiind obţinerea unor structuri de clase complexe.

Sintaxa folosită pentru declararea unei clase derivate D este:

class D: specif_acces clasa_baza1, specif_acces clasa_baza2,… {…}

În lista claselor de bază, pentru fiecare clasă de bază, se include specificatorul de

acces.

Principiile prezentate la derivarea simplă şi la crearea ierarhiilor simple de clase

sunt valabile şi în cazul derivării multiple. Prin clasa strpoz se vor crea obiecte ce conţin

un şir de caractere împreună cu poziţia de afişare. Această clasă se obţine prin derivarea

din clasele pozitie şi string, accesul către acestea fiind public.

#include <iostream.h>

#include <string.h>

#include <conio.h>

class pozitie // declarare clasă pozitie

{

protected :

int x, y;

public:

pozitie(int=0, int=0);

pozitie(pozitie&);

~pozitie();

void afisare();

void deplasare(int,int);

};

pozitie::pozitie(int abs, int ord)

{

x=abs; y=ord;

cout<<"\nConstructor - pozitie";

afisare();

}

pozitie::pozitie(pozitie &p)

{

x=p.x; y=p.y;

cout<<"\nConstructor copiere-pozitie";

afisare();

}

pozitie::~pozitie()

{

cout<<"\nDestructor - pozitie";

afisare();

}

void pozitie::afisare()

{

Page 40: lab

cout<<"\npozitie: x="<<x<<" y="<<y;

}

void pozitie::deplasare(int dx, int dy)

{

x+=dx; y+=dy;

}

class string // declarare clasă string

{

protected:

int ncar; // lungimea sirului

char *str;

public:

string(int n=0)

{

ncar=n;str=new char[ncar+1];

str[0]='\0';

cout<<"Constructor 1- string" ;

afisare();

}

string(char * s)

{

ncar=strlen(s); str=new char[ncar+1];

strcpy(str,s);

cout<<"\nConstructor 2 - string";

afisare();

}

string(string & s)

{

ncar=s.ncar;

str=new char[ncar+1];

strcpy(str, s.str);

cout<<"\nConstructor de copiere-string";

afisare();

}

~string()

{ cout<<"\nDestructor- string";

afisare();

delete str;

}

void afisare()

{

cout<<"\nstring:"<<str<<"\n";

}

string operator+(string &s)

{

string temp(ncar+s.ncar);

strcat(temp.str, str);

strcat(temp.str, s.str);

return temp;

}

};

class strpoz : public pozitie, public string

// declararea clasei strpoz, derivată din

// pozitie şi string cu acces public către

{ // acestea

char culoare;

Page 41: lab

public:

// în antetul constructorului se specifică parametrii preluaţi de

// constructorii claselor de bază

strpoz(int abs, int ord, int n=0, char c='A') : pozitie(abs,

ord), string(n)

{

culoare=c;

cout<<"\nConstructor 1 - strpoz";

afisare();

}

strpoz(int abs, int ord, char *s, char c='A'):pozitie(abs, ord),

string(s)

{

culoare=c;

cout<<"\nConstructor 2 - strpoz";

afisare();

}

strpoz(strpoz &sp) : pozitie(sp), string(sp) // parametrul

preluat de // constructorii

// claselor de bază este chiar sp pentru

// care se face conversia implicită către

// clasa de bază respectivă

{ culoare=sp.culoare;

cout<<"\nConstructor copiere - strpoz";

afisare();

}

~strpoz()

{

cout<<"\nDestructor -strpoz";

afisare();

}

void coloreaza(char c)

{ culoare=c; }

void afisare()

{

cout<<"\nstrpoz:"<<str;

cout<<"\nx="<<x<<" y="<<y;

cout<<"\nculoare:"<<culoare<<"\n";

}

strpoz operator+(strpoz &sp)

{

strpoz temp(x+sp.x, y+sp.y, ncar+sp.ncar);

strcat(temp.str, str);

strcat(temp.str, sp.str);

return temp;

}

};

void main()

{

strpoz sp1(5, 5, "TEXT");

strpoz sp2(sp1);

string s1("aaa"), s2("bbb");

string s3=s1+s2;

s3.afisare();

strpoz sp3=sp1+sp2;

sp3.afisare();

Page 42: lab

}

În declaraţia clasei strpoz se specifică derivarea cu acces public din clasele pozitie

şi string. Definiţia fiecărui constructor al clasei strpoz specifică transferul datelor către

constructorii claselor de bază.

Constructorii şi destructorii claselor de bază sunt apelaţi automat la crearea,

respectiv distrugerea obiectelor derivate. Ordinea apelării constructorilor este dată de

ordinea din lista claselor de bază din definiţia clasei derivate, constructorul clasei derivate

fiind apelat ultimul. Destructorii sunt apelaţi în ordine inversă.

Clasa derivată conţine toţi membrii claselor de bază, dar îi poate accesa doar pe

cei declaraţi cu acces public sau protected. Clasele derivate pot supradefini funcţii

existente în clasele de bază. Membrii şi funcţiile omonime pot fi accesate folosind

operatorul de rezoluţie.

De exemplu, pentru clasa strpoz se poate defini funcţia membră de afişare astfel: void strpoz::afisare()

{

cout<<”\nStrpoz:”

pozitie::afisare();

string::afisare();

cout<<”\culoare:”<<c<<endl;

}

iar în funcţia main() se poate include linia de program: sp3.pozitie::afisare();

Exerciţiu:

Să se definească o clasă derivată “produs” care descrie un produs prin denumire, cod,

preţ. Se vor folosi o clasă de bază string pentru membrul denumire şi o clasă care

defineşte codul prin trei grupe de caractere. Se vor realiza cele două variante de derivare,

şi anume o ierarhie simplă de clase şi, respectiv, derivarea multiplă.

Page 43: lab

Laborator 12

Programare Orientata Obiect in C++

Funcţii şi clase prietene unei clase

Accesul la membrii private ai unei clase se poate acorda, în afara funcţiilor

membre şi unor funcţii nemembre, dacă sunt declarate cu specificatorul friend.

Funcţiile declarate prietene unei clase pot fi funcţii independente sau funcţii

membre ale altei clase. Funcţiile prietene sunt externe clasei, deci apelul lor nu se face

asociat unui obiect al clasei.

class cls

{

friend void func();

}

void main()

{

cls obj;

obj.func(); // eroare, funcţia func() este externă clasei

func(); // apel corect al funcţiei func()

}

Funcţiile prietene au acces la toţi membrii clasei, ele operând asupra obiectelor care se

transferă ca parametrii ai funcţiei. Referirea unui membru se face prin numele obiectului,

operatorul de selecţie şi numele membrului, dată sau funcţie.

Se pot întâlni următoarele situaţii:

1. o funcţie independentă este prietenă unei clase;

2. o funcţie membră a unei clase este prietenă altei clase;

3. o funcţie este prietenă mai multor clase ;

4. o clasă este prietenă altei clase (toate funcţiile membre ale unei clase sunt

prietene celeilalte clase).

// Situaţia 1. class pozitie

{

int x, y;

public:

pozitie(int abs, int ord)

{ x=abs; y=ord; }

void deplasare(int dx, int dy)

{ x+=dx; y+=dy; }

friend void compar(pozitie &, pozitie &);

// funcţia compar() se declară prietenă

// clasei pozitie

};

void compar(pozitie &p1, pozitie &p2)

Page 44: lab

// funcţia compar() este externă clasei

// poziţie, deci nu poate fi definită decât

// în afara clasei pozitie

{

if ((p1.x= =p2.x)&&(p1.y= =p2.y))

// funcţia prietenă compar() are acces la

// membrii private ai clasei pozitie

cout<<”\n Pozitii identice”;

else

cout<<”\n Pozitii diferite”;

}

void main()

{

pozitie p1(1, 1); p2(3, 3);

compar(p1, p2); // apel al funcţiei compar()

p1.deplasare(2, 2);

compar(p1, p2); // apel al funcţiei compar()

}

// Situaţia 2

#include <iostream.h>

class A; // declaraţie incompletă a clasei A

class B // declaraţia clasei B

{

int b;

public:

B(int n)

{b=n;}

void func(A &);

// declararea funcţiei membre a lui B, având

// parametru de tip A

};

class A

{

int a;

public:

A(int n)

{a=n;}

friend void B::func(A &);

// se declară funcţia membră clasei B func()

} ; // prietenă clasei A

void B::func( A &ob_a) // definirea funcţiei func() membră a clasei B

{

cout<<'\n'<<ob_a.a;

// funcţia fiind prietenă clasei A are acces la

// membrul private “a” al clasei A

cout<<'\n'<<b;

}

void main()

{

A ob1(10);

B ob2(20);

ob2.func(ob1); // apelul funcţiei membre clasei B

}

Page 45: lab

Declaraţia friend din clasa A trebuie să găsească clasa B căreia îi aparţine funcţia func()

declarată. În declaraţie trebuie să se specifice şi numele clasei căreia îi aparţine funcţia

prietenă.

// Situaţia 3

#include <iostream.h>

class A; // declaraţie incompletă a clasei

class B; // declaraţie incompletă a clasei

class A

{

int a;

public:

A(int n)

{a=n;}

friend void func(A &, B &);

// funcţia func() este declarată prietenă clasei A

} ;

class B

{

int b;

public:

B(int n)

{b=n;}

friend void func(A &, B &);

// funcţia func() este declarată prietenă clasei B

};

void func( A &ob_a, B &ob_b)

//definirea funcţiei func(), externă claselor A şi B

{

cout<<'\n'<<ob_a.a;

cout<<'\n'<<ob_b.b;

}

void main()

{

A ob1(10);

B ob2(20);

func(ob1, ob2);

// apelul funcţiei func() cu parametri de tip A şi

// respectiv B

}

Funcţia func() se defineşte în afara claselor A şi B, ea fiind o funcţie independentă.

// Situaţia 4

#include <iostream.h>

class A; // declaraţie incompletă a clasei A

class B // declaraţia clasei B

{

int b;

public:

B(int n)

{b=n;}

void func(A &);

Page 46: lab

};

class A

{

int a;

public:

A(int n)

{a=n;}

friend class B; // clasa B se declară prietenă clasei A

} ;

void B::func( A &ob_a)

{

cout<<'\n'<<ob_a.a;

cout<<'\n'<<b;

}

void main()

{

A ob1(10);

B ob2(20);

ob2.func(ob1);

}

Declaraţia friend din clasa A trebuie să găsească clasa B declarată. Declaraţia

incompletă a clasei A este necesară pentru a se putea specifica parametrii de tip A în

funcţiile membre ale clasei B.

Utilizarea funcţiilor prietene încalcă principiul încapsulării, dându-se acces şi

altor funcţii decât celor membre la membrii private ai unei clase. Pot apare probleme şi

atunci când compilarea funcţiei prietene se face independent de compilarea funcţiilor

membre, prin omiterea accidentală a acesteia. De asemenea, dacă funcţia este membră

altei clase, apar interdependenţe între clase.

În ciuda acestor inconveniente, funcţiile prietene oferă anumite facilităţi, ele

oferind o altă soluţie de acces controlat către membrii unor clase.

Exerciţii:

Se defineşte clasa: class dreptunghi

{

int x1, y1, x2, y2;

static int cnt;

// membru static ce reprezintă un contor pentru obiectele

// clasei create

void normalizare();

// valorile coordonatelor sunt încadrate in intervalul

// [1, 80], cele orizontale şi [1, 25] cele verticale

public:

dreptunghi(int=1, int=1, int=80, int=25);

~dreptunghi();

void afisare();

// afişarea se face în mod text, prin marcarea laturilor

// dreptunghiului cu un caracter oarecare afişat în mod

// repetat

static int nr_dreptunghiuri();

// afişează numărul obiectelor dreptunghi existente la un

Page 47: lab

// moment

void deplasare(int, int);

// realizează translatarea dreptunghiului;

};

Să se definească o funcţie prietenă clasei dreptunghi, aria(), care să

returneze aria corespunzătoare dreptunghiului.

În funcţia main() se declară obiecte de tip dreptunghi. Se afişează

proprietăţile obiectelor, ariile corespunzătoare, numărul de instanţieri.