Documente Academic
Documente Profesional
Documente Cultură
LABORATOR 2
Elemente specifice limbajului C++
using namespace std; // se pot accesa toate elementele din spațiul de nume std
int main(void)
{
int num = 7;
double r = sqrt(num);
r = round(r * 1000) / 1000; // 3 zecimale
cout << "Radical din " << num << " este " << r;
return 0;
}
Exemplul 2 – utilizarea directivei using pentru obiectul cout din spațiul de nume std
#include <iostream>
#include<cmath>
int main(void)
{
int num = 7;
double r = sqrt(num);
r = round(r * 1000) / 1000; // 3 zecimale
POO
cout << "Radical din " << num << " este " << r;
return 0;
}
În Exemplul 2, declarațiile folosesc operatorul de rezoluție :: pentru a crea un nume complet. Un nume complet
constă din spațiul de nume, operatorul de rezoluție și membrul spațiului de nume. De exemplu, numele
complet pentru obiectul cout este std :: cout.
Dacă nu folosim o directivă using, putem utiliza numele complet, ca în Exemplul 3.
Exemplul 3 – utilizarea numelui complet pentru obiectul cout
#include <iostream>
#include<cmath>
int main(void) {
int num = 7;
double root = std::sqrt(num);
root = std::round(root * 1000) / 1000; // round to 3 decimal places
std:: cout << "The square root of " << num << " is " << root;
return 0;
}
namespace unu {
int a;
void afisare() {
cout << " spațiul unu: a = " << a << endl;
}
}
namespace doi {
double a;
void afisare() {
cout << " spațiul doi: a = " << a << endl;
}
}
int main(void) {
unu::a = 10;
unu::afisare();
doi::a = 3.7;
doi::afisare();
return 0;
}
Operatorul de rezoluție :: permite:
- accesul la o dată globală redefinită local.
- accesul la o entitate aparţinând unui spaţiu de nume, calificând-o cu numele spaţiului urmat de
operatorul de rezoluţie.
- accesul la o dată/funcţie membru ascunsă, calificând-o cu numele clasei urmat de operatorul de
rezoluţie.
Operatorul :: are prioritate maximă.
POO
Exemplul 4
#include<iostream>
using namespace std;
int main()
{
int x = 10; // variabila locala
cout << "Valoarea globala x: " << ::x;
cout << "\nValoarea locala x: " << x;
return 0;
}
Exemplul 5
#include<iostream>
using namespace std;
class A
{
public:
void mesaj();
};
int main()
{
A a;
a.mesaj();
return 0;
}
2. SupraÎncărcarea funcțiilor
Supraîncărcarea funcţiilor presupune existenţa mai multor funcţii diferite, dar cu acelaşi nume, în acelaşi
proiect. Restricţia care se impune la supraîncărcarea funcţiilor şi care este şi criteriul după care compilatorul
deosebeşte între ele funcţiile cu acelaşi nume, este ca tipul şi/sau numărul de parametri al funcţiilor
supraîncărcate să difere. Atenţie: tipul returnat de funcţii nu asigură de regulă suficiente informaţii pentru ca un
compilator să poată decide ce funcţie să folosească la apelare. Aşadar, funcţiile supraîncărcate pot să difere şi
prin tipul returnat, dar trebuie neapărat să difere prin numărul sau tipul parametrilor.
Exemplul 1
#include <iostream>
#include <math.h>
if (a != 0 && b != 0 && c != 0)
{
Med = 3 / (1 / a + 1 / b + 1 / c);
cout << "Media armonica testata Ma=";
cout << Med << endl;
}
else
{
cout << "Media armonica nu se poate";
cout << " calcula!" << endl;
}
}
int main()
{
double x, z;
float y;
y = 1.7;
3. Argumente implicite
Argumentele implicite sunt o altă caracteristică a limbajului C++. Dacă supraîncărcarea funcţiilor permite
programatorului să utilizeze aceleaşi nume pentru mai multe funcţii, argumentele implicite permit unei funcţii să
fie utilizată ca şi cum ar fi mai multe funcţii.
La declararea funcţiei se pot atribui valori pentru o parte sau toţi parametrii funcţiei. Respectivii parametri
se vor numi în continuare impliciţi şi pot lipsi la apelul funcţiei, valorile lor fiind date de cele implicite. Şi în acest
caz însă există o restricţie: parametrii impliciţi sunt întotdeauna plasaţi la sfârşitul listei de parametri formali ai
funcţiei. De asemenea, nu sunt admise situaţii de genul: ultimul parametru implicit să fie prezent în apelul
funcţiei, iar penultimul să lipsească.
Exemplul 1
#include <iostream>
using namespace std;
int main() {
cout << fun1(4, 5, 6) << endl; // Nu se folosesc valorile implicite
cout << fun1(4, 5) << endl; // 4, 5, 3(implicit)
cout << fun1(4) << endl; // 4, 2(implicit), 3(implicit)
cout << fun1() << endl; // 1(implicit), 2(implicit), 3(implicit)
Exemplul 2
/*****************************
Parametri Impliciti
salut.cpp
*****************************/
#include <iostream>
#include <stdio.h>
using namespace std;
void main()
{
char Nume[20];
//Apeluri incorecte:
//Afis("4-> ",);
//Afis("5-> ","Iti place C++, ", ,"?");
}
POO
void Afis(const char* Sir0, const char* Sir1, const char* Sir2, const char* Sir3)
{
cout << Sir0 << Sir1 << Sir2 << Sir3 << endl;
}
4. Referințe
O referință este un alt nume sau un alias pentru o variabilă care deja există. Definirea unei referințe nu ocupă
memorie suplimentară. Orice operație facută cu referința este efectuată asupra variabilei la care se referă.
Sintaxa definirei unei referințe:
int i = 5;
int& j = i;
Variabila j este o referință la variabila i. Modificarea lui j va modifica și valoarea lui i și invers, i și j vor avea
întotdeauna aceeași valoare.
Exemplul 1 – exemplificarea referințelor
#include <iostream>
using namespace std;
int main() {
int numar = 88;
int& refNumar = numar; // Declararea unei referinte (alias) la variabila numar
refNumar = 99;
cout << refNumar << endl;
cout << numar << endl;
numar = 55;
cout << numar << endl;
cout << refNumar << endl;
}
int main() {
int var1 = 88, var2 = 22;
int y = 2;
cout << "x=" << x << " y=" << y << endl;
Interschimbare(x, y);
cout << "x=" << x << " y=" << y << endl;
return 0;
}
Pentru a putea schimba valori ale unor variabile din funcţia apelantă prin modificări ale parametrilor efectivi de
apel, trebuie folosit mecanismul de transmitere al parametrilor prin referinţă. În acest caz, se transmit funcţiei
apelate, transparent faţă de utilizator, adresele parametrilor efectivi de apel. De aceea acest transfer se
numeşte prin referinţă sau prin adresă.
Transferul prin referință al parametrilor, folosind pointerii
Exemplul 4
#include <iostream>
int main()
{
int x = 1;
int y = 2;
cout << "x=" << x << " y=" << y << endl;
Interschimbare(&x, &y);
cout << "x=" << x << " y=" << y << endl;
return 0;
}
#include <iostream>
int main()
{
int x = 1;
int y = 2;
POO
cout << "x=" << x << " y=" << y << endl;
Interschimba(x, y);
cout << "x=" << x << " y=" << y << endl;
return 0;
}
Tipul referinţă poate funcţiona şi ca tip returnat de o funcţie, caz în care apelul de funcţie poate figura şi în
stânga operatorului de atribuire.
Observaţie: în astfel de situaţii este important ca locaţia de memorie spre care se referă să nu fie eliberată la
încheierea execuţiei funcţiei (de exemplu referinţa către o variabilă locală!).
Exemplul 6
#include <iostream>
using namespace std;
int& fctRef(int&);
int* fctPointer(int*);
int main() {
int var1 = 8;
cout << "In main() &var1: " << &var1 << endl;
int& valRet = fctRef(var1);
cout << "In main() &valRet: " << &valRet << endl;
cout << valRet << endl; // 64
cout << var1 << endl; // 64
int var2 = 9;
cout << "In main() &var2: " << &var2 << endl;
int* pvalRet = fctPointer(&var2);
cout << "In main() pvalRet: " << pvalRet << endl;
cout << *pvalRet << endl; // 81
cout << var2 << endl; // 81
}
Următorul program are o eroare logică gravă, deoarece funcția returnează o referință la o variabilă locală.
Variabila locală are domeniul de existență local în cadrul funcției, iar valoarea ei este distrusă după ieșirea din
funcție.
Exemplul 7
#include <iostream>
using namespace std;
int* fctPointer(int);
int& fctRef(int);
POO
int main() {
int var = 8;
cout << var << endl; // 8
cout << *fctPointer(var) << endl; // ??
cout << fctRef(var) << endl; // ??
}
int main() {
int numere[] = { 11, 22, 33, 44, 55 };
6. Struturi de date
Spre deosebire de tablou, o structură stochează elemente (câmpuri) de tipuri diferite, dar tot în locații
consecutive de memorie. După cum se va vedea, structurile de date reprezintă trecerea către clasele din C++.
struct nume_structura
{
// membrii structurii
}
POO
Exemplul 1
#include <iostream>
using namespace std;
struct Data
{
ZilePeSapt NumeZi;
int Zi;
LuniPeAn Luna;
int An;
};
int main()
{
LuniPeAn OLuna, AltaLuna;
Data DataNasterii, DataOarecare;
OLuna = Ian;
AltaLuna = Oct;
DataNasterii.NumeZi = Luni;
DataNasterii.Zi = 25;
DataNasterii.Luna = AltaLuna;
DataNasterii.An = 1982;
DataOarecare = DataNasterii;
Exemplul 2
În continuare se prezintă o aplicaţie a structurilor de date, în care este disponibil un pachet de cărţi, care
urmează a se amesteca. Rulaţi programul pas cu pas şi urmăriţi structura pachetului de cărţi şi felul în care se
modifică acesta.
/*****************************
Structuri de date:
Declaratii si incluziuni
carti.hpp
*****************************/
#include <iostream>
enum Culori { Inima, Frunza, Romb, Trefla };
struct Carte
{
int Numar;
Culori Culoare;
};
/*****************************
Structuri de date
Functia principala
carti.cpp
*****************************/
#include "Carti.hpp"
using namespace std;
void main()
{
Carte Pachet[52]; //Pachet este un sir de 52 de carti
Init(Pachet);
cout << "Pachetul de carti ordonat:" << endl;
AfisarePachet(Pachet);
Amestec(Pachet);
cout << endl << "Pachetul de carti amestecat:";
cout << endl;
AfisarePachet(Pachet);
}
/*****************************
Structuri de date
functii.cpp
*****************************/
#include "carti.hpp"
using namespace std;
void AfisareCarte(Carte c)
//Afiseaza o carte din pachet
{
if (c.Numar >= 2 && c.Numar <= 10) cout << c.Numar;
else switch (c.Numar)
{
case Jack: cout << "J"; break;
case Dama: cout << "Q"; break;
case Rege: cout << "K"; break;
case As: cout << "A"; break;
}
switch (c.Culoare)
{
case Inima: cout << "i"; break;
case Frunza: cout << "f"; break;
case Romb: cout << "r"; break;
case Trefla: cout << "t"; break;
}
};
Exerciții propuse
1. Explicați rezultatul execuției codului de mai jos:
int* ptr = nullptr;
int a[] = { 12,32, 45,67,89, 90 };
ptr = a + 1;
cout << " *(ptr + 1) = " << *(ptr + 1) << endl;
cout << " *ptr + 1 = " << *ptr + 1 << endl;
2. Scrieți o funcție care returnează o referință la valoarea minimă a două numere întregi date ca
parametri. Folosind această funcție, afișați minimul dintre două numere întregi citite de la consolă.
3. Scrieți o funcție care convertește caracterele unui șir în majuscule. Funcția are prototipul după cum
urmează: void strToMajuscula (string &). Apelați această funcție într-un program de test.