Documente Academic
Documente Profesional
Documente Cultură
Destructori virtuali
Conversii la atribuirea de obiecte
C++ 11, C++14
Auto-typing
Smart_ptr, dynamic_cast, static_cast
Lambda functions
Referintele, ca si pointerii, sunt variabile care contin adresa unei zone de memorie. Semantic,
ele reprezinta aliasuri ale unor variabile existente. Referintele sunt legate de variabile la declaratie si
nu pot fi modificate pentru a referi alte zone de memorie.
Sintaxa folosita pentru declararea unei referinte este:
Tip & referinta = valoare;
Proprietatile cele mai importante ale referintelor sunt:
referintele trebuie sa fie initializate la declaratie (spre deosebire de pointeri care pot fi
initializati in orice moment);
dupa initializare, referinta nu poate fi modificata pentru a referi o alta zona de memorie
(pointerii pot fi modificati pentru a referi alta zona) ;
intr-un program C++ valid nu exista referinte nule Referintele utilizate in principal pentru
transmiterea parametrilor in functii.
Trimiterea parametrilor in functii
prin valoare: valorile parametrilor sunt copiate pe stiva; modificarile efectuate de functie
asupra parametrilor nu se vor reflecta in apelant
prin adresa: se copiaza pe stiva adresele de memorie unde se afla datele corespunzatoare
parametrilor; modificarile efectuate de functie vor fi vizibile si in apelant.
Exemple de transmitere parametri:
Functie
Prin valoare:
void Inc(int i)
{
i++;
}
Prin referinta:
void IncReferinta(int &i)
{
i++;
}
Apel
int i = 10;
Inc(i);
cout << i;
Rezultat: 10
int i = 10;
IncReferinta(i);
cout << i;
Rezultat: 11
Prin pointeri:
void IncPointer(int *pi)
{
(*pi)++;
}
int i = 10;
IncPointer(&i);
cout << i;
Rezultat: 11
Pointerii la zone de momorie constante sunt pointeri prin intermediul carora nu se poate modifica
continutul zonei referite.
Sintaxa de declarare este:
tip const * pointer_zona_ct;
Exemplu:
// declarare pointer la zona constanta
int const * pZonaCt;
// modificarea adresei referite
// este permisa
pZonaCt = &i;
pZonaCt = &j;
// modificarea continutului nu este permisa
(*pZonaCt) = 7; // => eroare de compilare
Cele doua forme pot fi folosite simultan pentru a declara pointeri constanti la zone de memorie
constanta:
tip const * const pointer_ct_zona_ct;
In acest caz nu poate fi modificata nici adresa referita, nici constinutul acesteia.
Supraincarcarea functiilor
C++ permite sa avem mai multe functii cu acelasi nume. Cand rulam programul, compilatorul
C++ determina care functie trebuie apelata in functie de numarul si tipul parametrilor pe care
intructiunea de apelare ii transmite functiei.
Exemplu:
#include "stdafx.h"
using namespace std;
int suma(int *matrice, int nr_element)
{
int rezultat=0;
int nr;
for (nr=0; nr<nr_element; nr++)
rezultat+=matrice[nr];
return rezultat;
}
double suma(double *matrice, int nr_element)
{
double rezultat=0;
int nr;
for (nr=0; nr<nr_element; nr++)
rezultat+=matrice[nr];
return rezultat;
}
void main()
{
int a[5]={1,2,3,4,5};
double b[4]={1.11,2.22,3.33,4.44};
cout<<"suma valorilor int este "<<suma(a,5)<<endl;
cout<<"suma valorilor double este "<<suma(b,4)<<endl;
}
Functiile pot avea acelasi tip, dar atunci trebuie sa difere numarul de parametrii, iar daca au acelasi
numar de parametrii trebuie neaparat sa fie de alt tip.
Supraincarcarea unui operator
Prin supradefinirea operatorilor se pot realiza operatii specifice unui nou tip de date la fel de
usor ca in cazul tipurilor de date standard.
Cand supraincarcati un operator trebuie sa continuati sa utilizati operatorul in formatul sau
standard, adica daca supraincarcati operatorul (+) acesta trebuie sa utilizeze operatorul sub forma
operand+operand. Puteti sa supraincarcati doar operatorii existenti. C++ nu va permite definirea unor
operatori proprii. Operatorul supraincarcat se aplica numai instantelor clasei specificate. De exemplu,
daca avem o clasa Sir si am incarcat operatorul plus astfel incat operatorul sa concateneze doua siruri
de caractere sir_nou=sir1+sir2; daca utilizati operatorul plus supraincarcat, cu doua valori intregi,
supraincarcarea nu se va aplica. Operatori care NU pot fii supraincarcati sunt . .* :: ?:
NU puteti utiliza o functie friend pentru supraincarcarea urmatorilor operatori = [ ] ( ) ->
Adesea functiile operator returneaza un obiect al clasei asupra caruia opereaza. Atunci cand
supraincarcati un operator unar lista de argumente trebuie sa fie goala, iar cand supraincarcati un
operator binar lista de argumente trebuie sa contina un singur parametru.
Sintaxa:
tip_return nume_clasa operator #(lista_argumente){
//operatii
}
Supradefinirea se poate face folosind:
functii membre nestatice
functii prietene
Incapsularea se refera la protectia datelor unui obiect. Utilizatorul ( tot programator ) al unui
obiect sa nu aibe acces direct la datele clasei;
cand folosesti class{ }; tot ce e inauntru acestei clase este default privat, adica doar
functiile din interiorul clasei pot accesa datele;
class Student
{
string mNume;
public:
float medie;
private:
int x;
}
mNume si x sunt variabile private, iar medie e public ( nu e recomandat sa faci public o variabila )
Membrii public ai unei clase de baz pot fi accesai de orice funcie din program
Membrii private al unei clase de baz sunt accesibili doar funciilor membre sau prietenilor clasei
Membrii protected ai unei clase de baz pot fi accesai doar de
Datele protected depesc ideea de ncapsulare pentru c o schimbare a membrilor protected din
clasa de baz poate influena toate clasele derivate
Atributul din
clasa de baza
Modificator
de acces
Accesul mostenit
de clasa derivata
Accesul din
exterior
private
protected
public
private
private
private
inaccesibil
private
private
inaccesibil
inaccesibil
inaccesibil
private
protected
public
public
public
public
inaccesibil
protected
public
inaccesibil
inaccesibil
accesibil
Tipuri de constructori
- constructor implicit (default constructor);
- constructor de copiere (copy constructor);
O clas poate conine, de asemenea, constructori de copiere.
Constructorul de
copiere generat implicit copiaz membru cu membru toate variabilele
argumentului n cele ale
obiectului care apelaz metoda. Compilatorul genereaz implicit un
constructor de copiere n
fiecare clas n care programatorul nu a declarat unul n mod explicit.
Constructori de copiere - Utilizare
Exemplu:
class X {
X (X&); // constructor de copiere
X (void); // constructor implicit
};
Destructorii
Destructorul este complementar constructorului. Este o metod care are
acelai nume
ca i clasa creia i aparine, dar este precedat de ~. Dac constructorii
sunt folosii n
special pentru a aloca memorie i pentru a efectua anumite operaii (de
exemplu:
incrementarea unui contor al numrului de obiecte), destructorii se
utilizeaz pentru eliberarea
memoriei alocate de constructori i pentru efectuarea unor operaii
inverse (de exemplu:
decrementarea contorului).
Exemplu:
class exemplu
{
public :
return 0;
}
Mostenirea claselor
Mecanismul prin care o clas preia structura (datele membru) i comportamentul (metodele)
unei alte clase la care adaug elemente specifice.
Avantaje:
Tipuri de Motenire
class A
{
int m;
void f() const
{
// attempt to modify this object
m = 1; // Error
}
};
Alfel spus, specificatorul const face ca poiterul this din corpul functiei sa fie de tip pointer to const.
In exemplul echivalent [2], functia A::f foloseste pointerul this pentru a ilustra acest lucru.
class A
{
int m;
void f() const
{
(*this).m = 1; // Error (l-value specifies const object)
}
};
Overload (supraincarcare)
- utilizarea aceluiasi nume de metoda impreuna cu liste diferite de argumente
ex: void f(string nume, int pid){} i
void f(int pid, string nume){}
Override (suprascriere)
- se foloseste pentru a modifica o metoda sau o proprietate si furnizeaza o noua
implementare a unui membru mostenit dintr-o clasa de baza
- metoda suprascrisa si metoda de suprascriere trebuie sa aiba aceeasi signatura (tip si
numar de parametrii)
ex: public virtual void Display(); - in clasa de baza
public override void Display(); - in clasa derivata
!!! O functie virtuala nu poate fi declarata private deoarece nu ar mai putea fi supraincarcata in clasa
derivata
OVERLOADING se rezolva la compile time iar OVERRIDING la runtime!!!!
Virtual
- folosit in declararea unei metode sau a unei proprietati ==> membrii virtuali
- implementarea unui membru virtual poate fi schimbata prin suprascrierea membrului intr-o clasa
derivata.
ex:
class Baza
{
public virtual void Afiseaza()
{
Console.WriteLine("Apelul functiei Afiseaza din clasa de
baza\n");
}
}
class Derivata : Baza
{
public override void Afiseaza()
{
Console.WriteLine("Apelul functiei Afiseaza din clasa
derivata");
}
}
Namespace
Fiecare obiect de tip clasa are propriile lui copii ale tuturor membrilor acelei clase. Este posibila
definirea de membrii care sa fie folositi n comun de catre toate obiectele clasei.
Datele statice exista ntr-o singura copie, comuna tuturor obiectelor. Crearea, initializarea si
accesul la aceste date statice sunt total independente de obiectele clasei.
Funcii membre statice
Name mangling
C++ diferentiaza functiile dupa nume si parametrii acesteia. Acesta genereaza un nume nou pentru
fiecare functie. Noul nume depinde de numele original al functiei si de parametrii acesteia si este
UNIC. Daca parametrii sau numarul lor se schimba atunci compilatorul va genera un alt nume, chiar
daca numele propriu-zis al functiei este acelasi. Acest proces de codificare al numelor functiilor se
numeste NAME MANGLING si este compiler dependent.
Funciile friend sunt funcii asociate unor clase care au acces la datele i metodele protejate ale
acelor clase dei nu sunt funcii membre ale acelei clase.
Funciile friend membre ale altor clase:
Sunt funcii membre ale unei clase ce au acces la datele membru protejate ale unei alte clase.
Declararea unei funcii friend se face incluznd prototipul ei, precedat de cuvntul cheie
friend, n clasa n care se dorete accesul
Clase friend
Dac dorim ca toate metodele dintr-o clas IdClasaB s aibe acces asupra tuturor datelor
membre protejate ale unei alte clase IdClasaA atunci declarm clasa IdClasaB ca fiind clas
friend (prieten) pentru clasa IdClasaA
Relaia de prietenie dintre dou clase nu este reflexiv: Dac clasa IdClasaA este clas prieten
a clasei IdClasaB, atunci nu i reciproca este valabil
Relaia de prietenie nu este tranzitiv: dac clasa IdClasaA este clas prieten clasei IdClasaB,
iar IdClasaB este clas prieten clasei IdClasaC, asta nu implic faptul c IdClasaA este clas
prieten a clasei IdClasaC.
Relaia de prietenie nu se motenete n clasele derivate.
Funcii virtuale
O funcie virtual este o funcie membr a unei clase care poate fi nlocuit, n momentul execu iei
programului, cu o funcie membru din clasa derivat.
Funciile virtuale pure sunt funcii virtuale ce sunt doar declarate n clasa de baz, urmnd ca acestea
sa fie definite n clasele derivate.
Functii template
O funcie template (ablon, generic) este un tipar utilizat de compilator pentru a construi
automat diverse funcii. n Se utilizeaz pentru implementarea de funcii care difer doar prin tipul
parametrilor
Clase Template
O clas template (generic) este un model (un ablon) utilizat pentru generarea unor clase
concrete, clase ce difer prin tipul anumitor date membre.
Prin supradefinirea operatorilor se pot realiza operatii specifice unui nou tip de date la fel de
usor ca in cazul tipurilor de date standard.
Cand supraincarcati un operator trebuie sa continuati sa utilizati operatorul in formatul sau
standard, adica daca supraincarcati operatorul (+) acesta trebuie sa utilizeze operatorul sub
forma operand+operand.
Puteti sa supraincarcati doar operatorii existenti. C++ nu va permite definirea unor operatori
proprii.
Operatorul supraincarcat se aplica numai instantelor clasei specificate. De exemplu, daca
avem o clasa Sir si am supraincarcat operatorul plus astfel incat operatorul sa concateneze
doua siruri de caractere sir_nou=sir1+sir2; daca utilizati operatorul plus supraincarcat, cu doua
valori intregi, supraincarcarea nu se va aplica. Operatorii care NU pot fii supraincarcati
sunt . .* :: ?:
NU puteti utiliza o functie friend pentru supraincarcarea urmatorilor operatori = [ ] ( ) ->
Adesea functiile operator returneaza un obiect al clasei asupra caruia opereaza.
Atunci cand supraincarcati un operator unar lista de argumente trebuie sa fie goala, iar cand
supraincarcati un operator binar lista de argumente trebuie sa contina un singur parametru.
Sintaxa:
tip_returnat nume_clasa operator #(lista_argumente)
{ //operatii }
Supradefinirea se poate face folosind:
Tratarea exceptiilor
Suportul sintactic C++ pentru tratarea excepiilor se rezum la trei cuvinte
cheie, a cror semantic preliminar este prezentata n tabelul urmtor:
Cuvntul
cheie
try
throw
catch
Semnificaie
Delimiteaz o poriune de cod n care se instituie controlul
sistemului asupra excepiilor n timpul rulrii.
Lanseaz o excepie de un anumit tip
Capteaz o excepie lansat
Pasii care trebuiesc in general urmati in vederea tratarii exceptiilor in cadrul programelor C++ sunt:
1. se identifica acele zone din program in care se efectueaza o operatie despre care se cunoaste ca
ar putea genera o exceptie, si se marcheaza in cadrul unui bloc de tip try. In cadrul acestui
bloc, se testeaza conditia de aparitie a exceptiei, si in caz pozitiv se semnaleaza aparitia
exceptiei prin intermediul cuvantului cheie throw;
2. se realizeaza blocuri de tip catch pentru a capta exceptiile atunci cand acestea sunt intalnite.
Blocurile catch urmeaza un bloc try, in cadrul carora sunt tratate exceptiile.
Late binding
Clase abstracte
Dorim sa stabilim interfata comuna pentru a putea crea functionalitate diferita pentru fiecare
subtip si pentru a sti ce anume au clasele derivate in comun.
O clasa cu caracteristicile enumerate mai sus se numeste abstracta. Cream o clasa abstracta atunci
cand dorim sa:
Metodele suprascrise in clasele derivate vor fi apelate folosind dynamic binding (late binding).
Nu exista instante ale unei clase abstracte, aceasta exprimand doar un punct de pornire pentru
definirea unor instrumente reale. De aceea, crearea unui obiect al unei clase abstracte este o eroare,
compilatorul Java semnaland eroare in acest caz.
abstracte:
Clase abstracte in contextul mostenirii
O clasa care mosteneste o clasa abstracta este
ea insasi abstracta daca nu
implementeaza toate metodele abstracte ale
clasei de baza. Putem defini clase abstracte
care mostenesc alte clase abstracte si tot asa. O
clasa care poate fi instantiata (nu este
abstracta) si care mosteneste o clasa abstracta
trebuie sa implementeze (defineasca) toate
metodele abstracte pe lantul mostenirii (ale
tuturor claselor abstracte care ii sunt "parinti").
Este posibil sa declaram o clasa abstracta
fara ca ea sa aiba metode abstracte. Acest lucru
este folositor cand declaram o clasa pentru care
nu dorim instante (nu este corect conceptual sa
avem obiecte de tipul acelei clase, chiar daca
definita ei este co mpleta). Iata cum putem sa
modificam exemplul instrument cu metode
Interfata reprezinta un mecanism prin care o clasa C utilizeaza date si servicii oferite de instante ale
unor clase A1, A2,. . ., An, in mod independent de acestea, accesand clasele Ai prin intermediul unei
interfete.
Clase vs structuri
O structura permite punerea la un loc a mai multor tipuri de date pentru a forma un nou tip de data.
Clasa=structura in care membrii nu mai sunt accesibili by default ( asa cum sunt cei dintr-o
structura ) , acestia primind cate un calificativ precum private,public sau protected. De asemenea,
clasele pot contine si functii.
STL se bazeaza pe trei concepte centrale: containeri, iteratori si algoritmi deja implemantati;
o
Agregarea
Numita si compunere, agregarea reprezinta pur si simplu prezenta unei referinte la un obiect intr-o alta
clasa. Acea clasa practic va refolosi codul din clasa corespunzatoare obiectului. Exemplu:
class Page {
private String content;
public int no;
public Page(String c, int no) {
this.content = c;
this.no
= no;
}
}
class Book {
private Page[] pages;
public Book(int dim, String title) {
pages = new Page[dim];
for (int i=0; i < dim; i++)
pages[i] = new Page("Pagina " + i, i);
}
}