In C++ au fost introdusi 4 operatori noi folositi pentru alocare, respectiv pentru eliberarea dinamica de memorie.
Pentru alocarea unei casute de memorie se foloseste operatorul new
.
tip_date *p = new tip_date;
Eliberarea se face cu ajutorul operatorului delete
.
delete p;
Pentru alocarea unui vector de casute se foloseste operatorul new[]
.
p = new tip_date[n];
Eliberarea se face cu operatorul delete[]
.
delete[] p;
Introducerea operatorilor new
si delete
fac posibila alocarea dinamica a memoriei intr-o maniera moderna, simplifica scrierea codului fata de folosirea functiilor din C, castigul, insa nu este consistent deoarece pentru alocari complexe (matrici), alocarile ramand a se face in mai multi pasi, ca in C.
Gestionarea memoriei alocate dinamic stil C difera fata de stilul C++, de aceea nu trebuie combinate alocarii C cu eliberarea C++ sau invers. Daca se face acest lucru este posibil sa avem erori la executie.
Combinarea unui apel new[]
cu un delete
, de regula nu afecteaza executia programului (depinde de compilator). Este bine sa folosim delete[]
cand avem new[]
.
In C++ au fost introduse o multime de elemente noi atunci cand se scriu functii. Acestea ajuta la o redactare mai eleganta a codului. In C, semnatura functieie este data de numele ei, ceea ce inseamna ca la compilare, cand se intalneste un apel de functie, este identificata pe baza numelui, in consecinta, nu pot exista mai multe functii cu acelasi nume si care sa difere prim parametri in acelasi proiect. In C++, semnatura este data de: nume, numar de parametri, tipurile de date ale parametrilor, consecinta imediata este ca in C++ putem avea functii cu acelasi nume, dar care sa difere prim parametri. Aceasta proprietate poarta denumirea de supraincarcarea (overloading) functiilor.
int maxim(int x, int y);
float maxim(float x, float y);
int maxim(int x, int y, int z);
Tipul de date returnat nu poate face parte din semnatura.
In anumite situatii poate fi o alternativa mai moderna si mai simpla la pointeri.
O variabila v1
de tip referinta se declara tip_date& v1=v2
. Declaratia variabile e tip referinta se termina intotdeauna cu =
dupa care urmeaza o variabila de acelasi tip referit de v1
. v1
este un alias al lui v2
, ambele variabile referind aceeasi casuta de memorie.
Variabila referinta poate ajuta la simplificarea scrierii codului atunci cand ne referim la un camp al unui structuri
struct pereche
{
float x,y;
};
struct cerc
{
pereche centru;
float raza;
};
cerc c;
float& x = c.centru.x;
float& y = c.centru.y;
float& r = c.raza
x = 7;
y = 1.4;
r = 10;
Scrierea de mai sus, in care coordonata si raza sunt referinte, prin cele trei variabile este simplificata si optimizata ca viteza de executare.
O data cu introducerea tipului referinta, s-a simplificat si folosirea parametrilor de iesire a functiilor.
//f1
void inc(int* x)
{
(*x)++;
}
inc(&a);
vs
//f2
void inc(int &x)
{
x++;
}
inc(a);
La apelul f2
, inc
apare o noua variabila x
care refera variabila transmisa (a
si x
referind aceeasi casuta de memorie); x++
modifica casuta, deci efectul se va vedea si in variabila a
. Dupa cum se poate observa, apelul celei de-a doua functie inc
este simplificat, la fel si implementarea.
Unul sau mai multi parametri pot capata valori implicite la implementarea unei functii.
int inc(int&x, int v=1)
{
x+=v;
}
In antetul functiei, valoarea implicita este data pentru un parametru dupa =
. La apelul unei functii care are parametri cu valori implicite este posibil sa nu transmitem valori pentru o parte dintre acestia. Pentru cei care lipsesc din apel se vor considera valorii implicite 1
.
void main()
{
int a = 7;
inc(a); //a = 8
inc(a, -2); //a = 5
}
La compilare, al intalnirea unui astfel de functie, se creeaza mai multe functii cu acelasi nume, diferind pin numarul de parametri, lucru posibil dat mecanismului de supraincarcarea a functiilor.
In cazul implementarii cu un parametru, variabila v
devine variabila locala initializata cu 1
.
Reguli ce trebuie respectate:
- parametrul care capata valoarea implicita trebuie sa fie obligatoriu ultimul
- la apelul unei astfel de functii, valoarile transmise initializeaza parametri de la stanga la dreapta, iar pentru valorile lipsa (ultimele) se considera valori implicite.
void f(int x, int y = 1, float z = 2);
//--
f(1,4.7);
/* x ia valoarea 1,
4.7 initializeaza pe y (y devie 4),
z se ia valoarea implicita 2.
*/
De regula, valorile implicite pentru parametri se specifica in antetul functiei si nu se dau din nou cand functia este implementata.
void f(int x=1); //antet
void f(int x){...} //cpp