POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

25
11/28/2014 1 Funcții Forma generală de definire a unei funcţii este: tip_returnat nume_func(tip1 arg1,…,tipn argn) { //corpul functiei } Funcţia cu numele nume_func returnează o valoare de tip tip_returnat şi are un număr n de argumente formale declarate ca tip şi nume în lista de argumente formale. Argumentele formale din declaraţia unei funcţii se mai numesc şi parametrii funcţiei. Dacă o funcţie nu are argumente, atunci lista din parantezele rotunde este vidă. Funcții O funcţie este un nume global, dacă nu este declarată de tip static. O funcţie declarată static are domeniul de vizibilitate restrâns la fişierul în care a fost definită. Corpul funcţiei nu poate fi accesat din afara acesteia. Corpul unei funcţii este o instrucţiune compusă, adică o succesiune de instrucţiuni şi declaraţii incluse între acolade. În corpul funcţiei se pot defini variabile, care sunt locale şi se memorează în segmentul de stivă al programului. Dacă nu sunt declarate static, variabilele locale se creează la fiecare apel al funcţiei şi se distrug atunci când este părăsit blocul în care au fost definite. Funcții Nu se pot defini funcţii în interiorul unei funcţii. Argumentele formale ale unei funcţii sunt considerate variabile locale ale funcţiei, ca orice altă variabilă definită în funcţia respectivă. Dacă o funcţie nu are de returnat nici o valoare, atunci tip_returnat din declaraţia funcţiei este tipul void şi nu este necesară o instrucţiune de returnare (return) în funcţie. În toate celelalte cazuri, în corpul funcţiei trebuie să fie prevăzută returnarea unei variabile de tipul tip_returnat, folosind instrucţiunea return. Dacă în definiţie nu este prevăzut un tip_returnat, se consideră implicit returnarea unei valori de tip întreg. Funcții #include <iostream> using namespace std; int addition (int a, int b) { int r; r = a+b; return (r); } int main () { int z; z = addition (5,3); cout << "The result is " << z; return 0; } int addition (int a, int b) 8 z = addition ( 5 , 3 ); int addition (int a, int b) z = addition ( 5 , 3 );

description

functii si clase poo

Transcript of POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

Page 1: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

1

Funcții Forma generală de definire a unei funcţii este:

tip_returnat nume_func(tip1 arg1,…,tipn argn)

{

//corpul functiei

}

Funcţia cu numele nume_func returnează o valoare de tip tip_returnat şi are un număr n de argumente formale declarate ca tip şi nume în lista de argumente formale.

Argumentele formale din declaraţia unei funcţii se mai numesc şi parametrii funcţiei.

Dacă o funcţie nu are argumente, atunci lista din parantezele rotunde este vidă.

Funcții O funcţie este un nume global, dacă nu este declarată de tip

static.

O funcţie declarată static are domeniul de vizibilitate restrâns la fişierul în care a fost definită.

Corpul funcţiei nu poate fi accesat din afara acesteia.

Corpul unei funcţii este o instrucţiune compusă, adică o succesiune de instrucţiuni şi declaraţii incluse între acolade.

În corpul funcţiei se pot defini variabile, care sunt locale şi se memorează în segmentul de stivă al programului.

Dacă nu sunt declarate static, variabilele locale se creează la fiecare apel al funcţiei şi se distrug atunci când este părăsit blocul în care au fost definite.

Funcții Nu se pot defini funcţii în interiorul unei funcţii.

Argumentele formale ale unei funcţii sunt considerate variabile locale ale funcţiei, ca orice altă variabilă definită în funcţia respectivă.

Dacă o funcţie nu are de returnat nici o valoare, atunci tip_returnat din declaraţia funcţiei este tipul void şi nu este necesară o instrucţiune de returnare (return) în funcţie.

În toate celelalte cazuri, în corpul funcţiei trebuie să fie prevăzută returnarea unei variabile de tipul tip_returnat, folosind instrucţiunea return.

Dacă în definiţie nu este prevăzut un tip_returnat, se consideră implicit returnarea unei valori de tip întreg.

Funcții #include <iostream>

using namespace std;

int addition (int a, int b)

{

int r;

r = a+b;

return (r);

}

int main ()

{

int z;

z = addition (5,3);

cout << "The result is " << z;

return 0;

}

int addition (int a, int b)

8

z = addition ( 5 , 3 );

int addition (int a, int b)

z = addition ( 5 , 3 );

Page 2: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

2

Funcții #include <iostream>

using namespace std;

int addition (int a, int b)

{

int r;

r=a+b;

return (r);

}

int main ()

{

int x=5,y=3,z;

z = addition (x,y);

cout << "The result is " << z;

return 0;

}

Funcții Prototipurile funcţiilor. Pentru apelul unei funcţii este

necesară cunoaşterea definiţiei sau a prototipului acesteia. Prototipul unei funcţii este de forma: tip_returnat nume_func(tip1 arg1,……., tipn argn);

Numele argumentelor formale sunt opţionale în prototipul unei funcţii.

Prototipurile permit compilatorului să verifice tipurile argumentelor de apel şi să semnaleze eroare la conversii ilegale.

Spre deosebire de limbajul C, unde este admisă şi simpla declaraţie a numelui funcţiei (fără tipurile argumentelor de apel), utilizarea prototipurilor este obligatorie în C++.

Funcții

Prototipurile funcţiilor. double f2(int, double); // prototip functie f2

double f3(int a, double f) // definție functie f3

{

double t = f/a;

return t;

}

Argumentele funcțiilor

La apelul unei funcţii, argumentele de apel (argumente

reale sau efective) iniţializează argumentele formale

din declaraţia funcţiei, în ordinea din declaraţie.

Argumentele unei funcţii se pot transfera în două

moduri:

apelul prin valoare

apelul prin referinţă.

Page 3: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

3

Argumentele funcțiilor

Apelul prin valoare - se copiază valoarea

argumentului real în argumentul formal corespunzător

al funcţiei.

În acest caz, modificările efectuate asupra

argumentului formal (al funcţiei) nu modifică

argumentul real.

int x=5, y=3, z;

z = addition ( x , y );

int addition (int a, int b)

z = addition ( 5 , 3 );

Argumentele funcțiilor

Apelul prin referinţă - este accesată direct variabila

din argumentul real transmis funcţiei, care poate fi

deci modificată.

De exemplu - o funcţie swap() care realizează schimbul

între valorile a două variabile.

Dacă nu se folosesc referinţe, argumentele de apel ale

funcţiei trebuie să fie pointeri la variabilele respective.

Pointerii, ca argumente de apel, nu vor fi modificaţi, dar

variabilele indicate de aceştia pot fi modificate.

Argumentele funcțiilor

Funcţia swap() cu

argumente pointeri

void swap(int* x, int* y)

{

int t;

t = *x;// dereferentiere

*x = *y;

*y = t;

}

Funcţia swap() cu

argumente de tip referinţă

void swap(int& x, int& y)

{

int t;

t = x;

x = y;

y = t;

}

Argumentele funcțiilor Implementările sunt simetrice. Referinţa foloseşte adresa

variabilei pentru a o putea modifica.

În cazul referinţelor, pointerul şi defererenţierea sunt

ascunse, programatorul nu trebuie să le prevadă explicit,

programul rezultat este mai concis şi mai clar.

Referinţele sunt deosebit de utile în apelul funcţiilor ale

căror argumente sunt obiecte de dimensiuni mari şi

copierea lor în argumentele formale (plasate în segmentul

de stivă al programului) ar fi foarte ineficientă.

Page 4: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

4

Argumentele funcțiilor Argumente implicite ale funcţiilor.

Se întâmplă frecvent ca o funcţie să aibă un număr mai mare de argumente decât 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 declaraţia funcţiei se prevede o expresie de iniţializare a acestui argument, iar din apel poate să lipsească valoarea argumentului corespunzător.

De exemplu, o funcţie pentru stabilirea datei calendaristice, care prevede valori implicite pentru argumentele luna şi an:

Argumentele funcțiilor 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

}

Argumentele funcțiilor

Argumente implicite ale funcţiilor.

Numai argumentele de la sfârşitul listei pot fi

argumente implicite. De exemplu, este eronată

următoarea declaraţie: void setdata(int zi, int luna=9, int an); // eroare!

Pointeri la funcții

Dat fiind că o funcţie are o localizare în memorie,

această valoare poate fi atribuită unui pointer.

Adresa unei funcţiei este punctul de intrare în funcţie

şi, de aceea, funcţia poate fi apelată folosind un

pointer.

Tipul unui pointer la o funcţie se defineşte folosind

tipul valorii returnate şi tipurile argumentelor formale

ale funcţiei.

Înainte de apelul unei funcţii prin pointer, trebuie să fie

asignată valoarea pointerului folosind numele funcţiei.

Page 5: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

5

Pointeri la funcții float func1(int x, float y){

return x + y;

}

float func2(int x, float y){

return x * y;

}

void main(){

float (*pf)(int, float); // definire tip pointer

pf = func1; // asignare valoare pointer

float z = (*pf)(3, 1.2); // apel functie

cout << z << endl; // afiseaza 4.2

pf = func2; // asignare valoare pointer

z = (*pf)(3, 1.2); // apel functie

cout << z << endl; // afiseaza 3.6

}

Pointeri la funcții - exemplu int addition (int a, int b)

{ return (a+b); }

int subtraction (int a, int b)

{ return (a-b); }

int (*minus)(int,int) = subtraction;

int operation (int x, int y, int (*functocall)(int,int)){

int g;

g = (*functocall)(x,y);

return (g);

}

int main (){

int m,n;

m = operation (7, 5, addition);

n = operation (20, m, minus);

cout << n;

return 0;

}

Supraîncărcarea funcțiilor

În limbajul C, fiecare funcţie definită în program

trebuie să aibă un nume diferit.

În C++, mai multe funcţii pot avea acelaşi nume în

acelaşi domeniu de definiţie, dacă se pot diferenţia prin

numărul sau tipul argumentelor de apel.

Acest mecanism se numeşte supraîncărcarea funcţiilor

(function overloading).

În traducere, se mai întrebuinţează şi denumirile de

suprapunere, redefinire, supradefinire.

Supraîncărcarea funcțiilor

Dacă în acelaşi domeniu sunt definite mai multe

funcţii cu acelaşi nume, la fiecare apel se selectează

funcţia corectă prin compararea tipurilor argumentelor

reale de apel cu tipurile argumentelor formale ale

funcţiei.

double abs(double);

int abs(int);

abs(1); // apeleaza abs(int)

abs(1.0); // apeleaza abs(double)

Page 6: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

6

Supraîncărcarea funcțiilor Acceptarea mai multor versiuni ale unei funcţii cu

acelaşi nume este condiţionată de posibilitatea selectării fără ambiguitate a uneia dintre acestea după tipul sau numărul argumentelor.

Nu este admis ca funcţiile să difere doar prin tipul returnat.

Două funcţii declarate cu acelaşi nume se referă la aceeaşi funcţie dacă sunt în acelaşi domeniu şi au număr şi tipuri identice de argumente.

Supraîncărcarea funcțiilor

O funcţie declarată local nu este în acelaşi domeniu cu

o funcţie cu domeniul la nivel de fişier.

int f(char*);

void g()

{

extern f(int);

f(“abcd”); // eroare, f(int) ascunde f(char*)

//deci nu exista f(char*) în acest domeniu

}

Supraîncărcarea funcțiilor

Selecţia funcţiei la apel se bazează pe “cea mai bună

potrivire a argumentelor” (best argument matching).

Dacă printre funcţiile supraîncărcate există o funcţie

care are toate argumentele de tipuri identice cu

argumentele din apel, atunci această funcţie prezintă

cea mai bună potrivire a argumentelor şi este selectată.

Supraîncărcarea funcțiilor

Se consideră de exemplu funcţia supraîncărcată de calcul

a ridicării la o putere a unui număr, funcţia power():

int power(int, int);

long power(long, int);

double power(double, int);

double power(double, double);

power(7, 8); // selecteaza power(int, int)

power(5.6, 2); // selecteaza power(double, int)

power(6.7, 2.5);// selecteaza power(double, double)

Page 7: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

7

Supraîncărcarea funcțiilor

În aceste apeluri s-a selectat versiunea funcţiei power()

pe baza coincidenţei dintre argumentele de apel şi

argumentele formale.

În cazul în care nu există o astfel de coincidenţă, se fac

conversii ale argumentelor efective (de apel) către tipul

argumentelor formale.

Compilatorul încearcă cea mai bună potrivire pentru

fiecare argument în parte prin conversii pentru tipuri

predefinite care să nu conducă la trunchieri (pierderi de informaţie).

Supraîncărcarea funcțiilor De exemplu:

long a = 100;

int b = 10;

float c = 2.3f;

float d = 5.6f;

double e = 7.0;

double f = 2;

power(a,b); // selecteaza power(long, int)

power((int)a, b); // selecteaza power(int, int)

power(c,a); // selecteaza power(double, int)

power(c,d); // selecteaza power(double, double)

power(e,d); // selecteaza power(double, double)

Supraîncărcarea funcțiilor

Dacă prin astfel de conversii nu se poate stabili cea mai

bună potrivire a argumentelor, atunci sunt încercate şi

conversii pentru tipuri definite de utilizatori.

Apelul este acceptat numai dacă selecţia unei versiuni a

funcţiei (pe baza criteriului de cea mai bună potrivire a argumentelor) este unică.

Clase și obiecte

O clasă este un tip de date definit de utilizator.

O declarare a unei clase defineşte un tip nou care

reuneşte date şi funcţii.

Acest tip nou poate fi folosit pentru a declara obiecte

de acest tip, deci un obiect este un exemplar (o

instanţă) a unei clase.

Page 8: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

8

Clase și obiecte

Forma generală de declaraţie a unei clase care nu

moşteneşte nici o altă clasă este următoarea:

class nume_clasa {

date şi funcţii membre private

specificator_de_acces date şi funcţii membre

specificator_de_acces date şi funcţii membre

…………………………………………….

specificator_de_acces date şi funcţii membre

} lista_obiecte;

Clase și obiecte Cuvântul-cheie class introduce declaraţia clasei (a tipului

de date) cu numele nume_clasa.

Dacă este urmată de corpul clasei (cuprins între acolade), această declaraţie este totodată o definiţie.

Dacă declaraţia conţine numai cuvântul-cheie class şi numele clasei, atunci aceasta este doar o declaraţie de nume de clasă.

Corpul clasei conţine definiţii de date membre ale clasei şi definiţii sau declaraţii (prototipuri) de funcţii membre ale clasei, despărţite printr-unul sau mai mulţi specificatori de acces: public private protected

Ascunderea datelor: public, private C++ conţine posibilităţi speciale pentru ascunderea datelor

(de alte părţi ale programului), evitând adresări gresite sau coliziuni de nume.

Există doua cuvinte cheie speciale: private şi public.

Ele pot fi inserate în definitia unei structuri.

public defineşte toate câmpurile unei structuri accesibile de întreg codul program;

private defineşte toate câmpurile accesibile doar de codul ce face parte din structură (adică accesibile numai funcţiilor membru).

Într-o structură toate câmpurile sînt public dacă nu este specificat explicit altceva.

Ascunderea datelor: public, private

Deşi ascunderea datelor poate fi realizată prin

intermediul structurilor, cel mai adesea sunt folosite

clasele.

O clasă este în principiu echivalentă cu o structură cu

excepţia faptului că toate câmpurile sunt, dacă nu e

specificat altfel, private.

Page 9: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

9

Clase și obiecte Efectul unui specificator de acces durează până la următorul

specificator de acces.

Implicit, dacă nu se declară nici un specificator de acces, datele sau funcţiile membre sunt de tip private.

De aceea, toate datele sau funcţiile declarate de la începutul blocului clasei până la primul specificator de acces sunt de tip private.

Diferenţa între tipurile de acces private şi protected constă în modul în care sunt moştenite drepturile de acces în clase derivate şi va fi detaliat în secţiunea care se ocupă cu clasele derivate.

Clase și obiecte

Definirea unei clase introduce în program un tip nou de

date, definit de utilizator, care reuneşte date şi funcţii

membre într-un fel de “cutie neagră” (black-box).

Aceasta reprezintă abstractizarea, adică identificarea

caracteristicilor definitorii pentru entitatea pe care o

modelează clasa respectivă.

În limbajele de programare orientate pe obiecte, clasele

permit abstractizarea datelor, care este o caracteristică

fundamentală a modelului obiect.

Clase și obiecte

Datele declarate într-o clasă se numesc date membre

de obicei, ele sunt protejate (private sau protected),

dar există şi situaţii în care sunt declarate public.

nu se pot declara auto, extern sau register datele

membre ale unei clase.

Funcţiile definite într-o clasă se numesc funcţii membre

(sau metode ale clasei)

de obicei ele sunt de tip public, dar pot fi şi protejate.

Clase și obiecte

Clasa Complex conţine

2 date membre private: re şi im de

tip double

3 funcţii membre publice: init(),

set() şi display().

Page 10: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

10

Clase și obiecte Clase și obiecte

În funcţia main() a programului de mai sus s-a declarat un obiect cu numele c1 de tipul (clasa) Complex.

Pentru un obiect dintr-o clasă dată se poate apela oricare funcţie membră a clasei, folosind operatorul punct de acces la un membru;

dacă se scrie: c1.init(), acest lucru însemnă apelul funcţiei init() pentru obiectul c1 din clasa Complex.

Constructori și destructori Constructori și destructori

Page 11: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

11

Constructori și destructori Constructori și destructori class Vector{ double v[4]; public: Vector(); Vector( *pv); void set_element(int i, double e){ v[i] = e;} double get_element(int i) const { return v[i]; } }; Vector::Vector(){ for (int i = 0; i < 4; i++) v[i] = 0.0; } Vector::Vector(double *pv){ for (int i = 0; i < 4; i++) v[i] = pv[i]; }

int main() { double v1[]={1,2,3,4}; Vector vec(v1); return 0; }

Constructori și destructori

class Vector{ int n; double* pv; public: Vector(int); Vector(int, double*); ~Vector(); }; Vector::Vector(int dim){ n = dim; pv = new double[n]; for ( int i = 0; i < n; i++) pv[i] = 0.0; } Vector::Vector(int dim, double *pvi){ n = dim; pv = new double[n]; for ( int i = 0; i < n; i++) pv[i] = pvi[i]; }

Vector::~Vector(){ cout << "Destructor ! " << endl; delete pv; pv = NULL; } int main(){ int nr; cout<<"Nr elemente dorit:"<<endl; cin >> nr; Vector v2(nr); return 0; }

Constructori și destructori class Person{ char name[5]; public: Person(); Person(char *pv); void display(){ for(int i = 0; i<5; i++) cout << name[i]; cout << endl; } }; Person::Person(){ for (int i = 0; i < 5; i++) name[i] = 'x'; } Person::Person(char *pv){ for (int i = 0; i < 5; i++) name[i] = pv[i]; }

int main() { char v1[5]={}; cout<<"Dati numele (4 char):”<<endl; cin.get(v1,5); for(int i=0; i<strlen(v1); i++) { cout << v1[i]; } Person p1(v1), p2; cout << "p1 name" << endl; p1.display(); cout << "p2 name" << endl; p2.display(); return 0; }

Page 12: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

12

Constructori de copiere Forma generală a constructorului de copiere al unei clase X

este: X::X(X& r){

// initializare obiect folosind referinţa r

}

De exemplu, pentru obiecte de tip Complex:

class Complex {

...

public:

Complex(Complex &r); //Constructorul de copiere

};

Complex::Complex(Complex &r){

re = r.re;

im = r.im;

}

Constructori de copiere

Programul principal:

void main(){

Complex c1(4,5); // Constructor

initializare

Complex c2(c1); // Constructor copiere

c2.display(); // afiseaza 4 5

Complex c3 = c2; // Constructor copiere

c3.display(); // afiseaza 4 5

}

Constructori de copiere

class Vector{ int n; double* pv; public: Vector(int); Vector(int, double*); Vector(Vector &v); ~Vector(); }; Vector::Vector(Vector &v){ n = v.n; pv = new double[n]; for ( int i = 0; i < n; i++) pv[i] = v.pv[i]; }

Vector::~Vector(){ cout<<"Destructor!"<<endl; delete pv; pv = NULL; } int main(){ int nr=10; Vector v2(nr); Vector v3(v2); Vector v4 = v3; return 0; }

Date membre de tip static

O dată membră a unei clase poate fi declarată static în declaraţia clasei.

Va exista o singură copie a unei date de tip static, care nu aparţine nici unuia dintre obiectele (instanţele) clasei, dar este partajată de toate acestea.

Declaraţia unei date de tip static într-o clasă este doar o declaraţie, nu o definiţie şi este necesară definiţia acesteia în altă parte în program (în afara clasei).

Aceasta se face redeclarând variabila de tip static folosind operatorul de rezoluţie pentru clasa căreia îi aparţine, şi fără specificatorul static.

Page 13: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

13

Date membre de tip static

O variabilă membră de tip static a unei clase există

înainte de a fi creat un obiect din clasa respectivă

Dacă nu este iniţializată explicit, este iniţializată

implicit cu 0.

Cea mai frecventă utilizare a datelor membre statice

este de a asigura accesul la o variabilă comună mai

multor obiecte, deci pot înlocui variabilele globale.

Date membre de tip static

class S{ int v; static int s; // declaratia var. statice s public: S(){ v = 0; } int gets() { return s; } int getv() { return v; } void incs() { s++;} void incv() { v++;} }; int S::s; // definitia var. statice s

Date membre de tip static void main(){ S x, y; cout << "Inainte de incrementare:\n"; cout << "x.s: " << x.gets() << " y.s: " << y.gets() << endl; cout << "x.v: " << x.getv() << " y.v: " << y.getv() << endl; x.incs(); x.incv(); cout << "Dupa incrementare:\n"; cout << "x.s: " << x.gets() << " y.s: " << y.gets() << endl; cout << "x.v: " << x.getv() << " y.v: " << y.getv() << endl; }

Date membre static - exemplu: class Directory

{

public: // constructori, destructori, etc.

.

.

private: // data membru

static char path [];

};

Data membru path este o variabilă statică privată.

Ea există într-un singur exemplar, chiar dacă se creează mai multe obiecte din clasa Directory.

Această dată poate fi inspectată sau alterată de constructor, destructor sau orice altă funcţie membru al clasei Directory.

Page 14: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

14

Date membre de tip static Deoarece constructorii sunt apelaţi pentru fiecare nou

obiect al clasei, datele static nu sunt niciodată iniţializate de constructori, ci cel mult modificate.

De obicei, definiţia şi iniţializarea datelor static apar în fişierul sursă ce conţine şi definiţia clasei.

Data membru path poate fi definită şi iniţializată în fişierul sursă al constructorului:

// data membru static: definitie si initializare

char Directory::path [200] = "/usr/local";

// constructorul implicit

Directory::Directory ()

{

}

Date membre de tip static Trebuie reţinut că definiţia unei date statice poate apare în

orice fişier sursă (dar numai o singură dată).

În declaraţia clasei, membrii statici sunt doar declaraţi; numai la definiţia lor tipul şi numele clasei apare explicit.

Un alt exemplu de folosire al unei date private static:

class Graphics {

public: // constructorul, destructorul

Graphics ();

~Graphics ();

// alte functii de interfata

...

private:

static int nobjects; // numara obiectele

void setgraphicsmode ();

void settextmode ();

};

Date membre de tip static

// data membru statica

int Graphics::nobjects = 0;

// constructorul

Graphics::Graphics ()

{

if (! nobjects)

setgraphicsmode ();

nobjects++;

}

// destructorul

Graphics::~Graphics ()

{

nobjects--;

if (! nobjects)

settextmode ();

}

Clasa Graphics defineşte

comunicarea programului cu un device

grafic.

Pregătirea iniţială a device-ului, care ar

reprezenta o trecere din modul text în cel

grafic, este o acţiune a constructorului şi

depinde de o variabilă statică nobjects.

Variabila respectivă numără obiectele

de tip Graphics prezente la un moment

dat.

Când se creează primul obiect, este

iniţializat şi modul grafic (de către

constructor).

În mod similar, destructorul face

trecerea de la modul grafic la cel text

dacă nu mai există nici un obiect grafic.

Funcții membre de tip static

Funcţiile membre ale unei clase pot fi de asemenea declarate de tip static.

O funcţie membră de tip static se declară în interiorul clasei şi se defineşte în interiorul clasei sau în afara acesteia, folosind operatorul de rezoluţie.

O funcţie membră statică are vizibilitatea limitată la fişierul în care a fost definită şi este independentă de instanţele (obiectele) clasei.

Page 15: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

15

Funcții membre de tip static

class Directory

{

public: // constructori, destructori

...

// functii static publice

static void setpath (char const *newpath);

private:

static char path [];

};

// definitia variabilei static

char Directory::path [199] = "/usr/local";

// functia static

void Directory::setpath (char const *newpath)

{

strncpy (path, newpath, 199);

}

Funcții membre de tip static

int main ()

{

// Alternativa (1): apelul setpath() fara nici

un obiect din clasa Directory

Directory::setpath ("/etc");

// Alternativa (2): cu un object

Directory dir;

dir.setpath ("/etc");

return (0);

}

Obiecte membre ale claselor

Datele membre ale unei clase pot fi atât variabile de tipuri predefinite, cât şi obiecte de tipuri definite de utilizator.

Membrii care sunt de tip definit de utilizator (clasă) trebuie să fie obiecte de tipuri (clase) definite anterior, nu doar declarate ca nume.

Dacă o clasă conţine obiecte membre de tipuri definite de utilizator, argumentele necesare pentru construirea acestora sunt plasate în definiţia (nu în declaraţia) constructorului clasei care le conţine.

Obiecte membre ale claselor class X{ int *px; public: X(); X(int sx); ~X(); }; inline X::X(){ cout<<"Constructor X implicit"<<endl; px = NULL; } inline X::X(int sx){ cout<<"Constructor X cu 1 arg”<<endl; px = new int[sx]; } inline X::~X(){ cout<<"Destructor X”<<endl; if(px){ delete px; px = NULL; } }

class Y{ int *py; X x; // data membru = obiect x tip X public: Y(int sy); Y(int sx, int sy); ~Y(); }; inline Y::Y(int sy){ cout<<"Constructor Y cu 1 arg”<<endl; py = new int[sy]; } inline Y::Y(int sx, int sy):x(sx){ cout<<"Constructor Y cu 2 arg”<<endl; py = new int[sy]; } inline Y::~Y(){ cout << "Destructor Y”<<endl; if(py){ delete py; py = NULL; } }

Page 16: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

16

Obiecte membre ale claselor

Mesajele care se afișează la rularea acestui program sunt:

Se observă că se construiește întâi data membră x și apoi obiectul de clasă Y care o conține!

Obiecte membre ale claselor

Dacă sunt mai multe date membre care se iniţializează,

acestea se pot trece în orice ordine, separate prin virgulă în

definiţia constructorului obiectului care le conţine.

Constructorii obiectelor membre sunt apelaţi în ordinea în

care acestea sunt specificate în declaraţia clasei.

La distrugerea unui obiect, se execută mai întâi

destructorul obiectului şi apoi, în ordinea inversă

declaraţiei, destructorii datelor membre ale acestuia.

Ordinea de execuție a constructorilor

și destructorilor

Un constructor este apelat la definirea obiectului, iar destructorul este apelat atunci când obiectul este distrus. Dacă există mai multe declaraţii de obiecte, atunci ele sunt construite în ordinea declaraţiei şi sunt distruse în ordinea inversă a declaraţiei.

Obiectele membre ale unei clase se construiesc înaintea obiectului respectiv. Destructorii sunt apelaţi în ordine inversă: destructorul obiectului şi apoi destructorii membrilor.

Funcţiile constructor ale obiectelor globale sunt executate înaintea execuţiei funcţiei main(). Destructorii obiectelor globale sunt apelaţi în ordine inversă, după încheierea funcţiei main().

Clase locale. Clase imbricate. O clasă locală este o clasă definită în interiorul unei

funcţii. O astfel de clasă este cunoscută numai în interiorul acelei funcţii şi este supusă mai multor restricţii:

toate funcţiile clasei locale trebuie să fie definite în interiorul clasei;

clasele locale nu admit variabile de tip static;

clasele locale nu au acces la variabilele locale ale funcţiei în care au fost declarate.

Din cauza acestor restricţii, clasele locale sunt rar utilizate în programarea C++ !

Page 17: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

17

Clase locale. Clase imbricate. O clasă imbricată (denumită şi clasă internă) este o clasă

definită în interiorul altei clase.

O astfel de clasă este cunoscută numai în domeniul clasei în care a fost definită, de aceea numele acesteia trebuie să fie precedat de numele clasei care o conţine folosind operatorul de rezoluţie (::).

Utilizarea specifică a claselor imbricate este în mecanismele de tratare a excepţiilor.

Deoarece excepţiile sunt definite pentru o anumită clasă, este normal ca tipul excepţiei (definit ca o clasă) să aparţină clasei care o defineşte.

Funcții și clase friend

O funcţie nemembră a unei clase poate accesa datele private sau protected ale acesteia dacă este declarată funcţie de tip friend a clasei.

Pentru declararea unei funcţii f() de tip friend a clasei X se include prototipul funcţiei f(), precedat de specificatorul friend în definiţia clasei X, iar funcţia însăşi se defineşte în altă parte în program astfel:

class X{ //…… friend tip_returnat f(lista_argumente); }; ……… tip_returnat f(lista_argumente){ // corpul functiei }

Funcții și clase friend Funcții și clase friend

Dat fiind că o funcţie nu poate fi membră a două

clase, cel mai natural mod de înmulţire a unei matrice

cu un vector ar părea să fie prin definirea unei funcţii

nemembre multiply() care accesează elementele

celor două clase prin funcţiile de interfaţă get() şi set().

Page 18: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

18

Funcții și clase friend

Dar acest mod de operare poate fi foarte ineficient, dacă

funcţiile de interfaţă get() şi set() ar verifica încadrarea

argumentului (indicele) în valorile admisibile.

Soluţia pentru această problemă o constituie declararea

funcţiei multiply() ca funcţie friend în cele două clase.

Funcții și clase friend

Funcții și clase friend Este posibil ca o funcţie membră a unei clase să fie declarată

friend în altă clasă.

De asemenea, este posibil ca o întreagă clasă Y să fie declarată friend a unei clase X şi, în această situaţie, toate funcţiile membre ale clasei Y sunt funcţii friend ale clasei X şi pot accesa toate datele şi funcţiile membre ale acesteia.

class Y{

//………

};

class X{

friend class Y;

//………

};

Supraîncărcarea operatorilor

Forma generală a funcţiilor operator membre ale clasei

este următoarea:

tip_returnat operator#(lista_argumente){

// operaţii

}

unde semnul # reprezintă oricare din operatorii care pot fi

supraîncărcaţi

Page 19: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

19

Supraîncărcarea operatorilor

Operatorii care pot fi supraîncărcaţi prin asocierea la o

clasa sunt:

Operatori supraîncărcabili

+ - * / = < > += -= *= /=

<< >> <<= >>= == != <= >= ++ -- %

& ^ ! | ~ &= ^= |= && || %=

[] () , ->* -> new delete new[] delete[]

Supraîncărcarea operatorilor Operatorii de asignare care pot fi supraîncărcaţi :

T& T::operator #=( argumente)

returnează de obicei o referință la propriul obiect ( *this ).

Operator Sintaxa Operator Sintaxa

asignare a = b AND cu asignare a &= b

adunare cu asignare a += b OR cu asignare a |= b

scădere cu asignare a -= b

XOR cu asignare a ^=b

înmulțire cu

asignare

a *= b shift la stinga cu

asignare

a <<= b

împărțire cu

asignare

a /= b shift la dreapta cu

asignare

a >>= b

modulo și asignare a %= b

Supraîncărcarea operatorilor Operatorii de incrementare/decrementare care pot fi

supraîncărcaţi :

Operatorii prefix returnează referințe ( *this )..

Operatorii postfix returnează valori.

Parametrul int este ”dummy”, doar face diferența între prefix și

postfix. La apel este de obicei dat 0.

Operator Sintaxa Exemplu prototip pt clasa T

preincrementare ++a T& T::operator++();

predecrementare --a T& T::operator--();

postincrementare a++ T T::operator++(int);

postdecrementare a-- T T::operator--(int);

Supraîncărcarea operatorilor Operatorii aritmetici care pot fi supraîncărcaţi :

T T::operator#( argumente)

returnează de obicei o valoare.

Operator Sintaxa Operator Sintaxa

plus unar +a modulo a % b

minus unar -a negare bitwise ~a

adunare a + b AND a & b

scădere a - b OR a | b

înmulțire a * b XOR a ^ b

împărțire a / b shift la stînga a << b

shift la dreapta a >> b

Page 20: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

20

Supraîncărcarea operatorilor

Operatorii logici care pot fi supraîncărcaţi :

Operatorii returnează de obicei o valoare bool.

Operator Sintaxa Exemplu prototip pt clasa T

negare !a bool T::operator!() const;

AND a && b bool T::operator&&(const T2 &b) const;

OR inclusiv a || b bool T::operator||(const T2 &b) const;

Supraîncărcarea operatorilor

Operatorii de comparare care pot fi supraîncărcaţi :

Operatorii returnează de obicei o valoare bool.

Operator Sintaxa Exemplu prototip pt clasa T

egalitate a == b

bool T::operator#(const T2 &b) const;

diferit a != b

mai mic a < b

mai mare a > b

mai mic sau

egal

a <= b

mai mare sau

egal

a >= b

Supraîncărcarea operatorilor

Operatori diverși care pot fi supraîncărcaţi :

Operatorii returnează de obicei o referință sau un pointer.

Operator Sintaxa Exemplu prototip pt clasa T

apel funcție a(a1,a2) R T::operator()(Arg1 &a1, Arg2 &a2,...);

virgulă a,b T2& T::operator,(T2 &b);

conversie (type)a operator type()

Supraîncărcarea operatorilor

Operatorul , built-in. Ce se afișează la consolă?

#include <iostream>

int main()

{

int n = 1;

int m = (++n, std::cout << "n = " << n << '\n', ++n, 2*n);

std::cout << "m = " << (++m, m) << '\n';

}

Page 21: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

21

Supraîncărcarea operatorilor

Există câteva reguli care trebuie să fie respectate la supraîncărcarea operatorilor:

Funcţiile operator=(), operator()(), operator[]() şi operator ->() trebuie să fie membri nestatici ai clasei.

Cu excepţia funcţiei operator =() toate celelate funcţii operator pot fi moştenite.

Nu pot fi supraîncărcaţi operatorii pentru tipurile predefinite ale limbajului.

Funcţiile operator nu pot avea argumente implicite.

Exemplu: class Complex

Exemplu: class Complex int main(){

Complex c1(7.2,9.3);

Complex c2(0.4,-9.3);

Complex c3;

c3 = c1 + c2;

c3.display();

// afiseaza 7.6+j0

return 0;

}

#include <iostream>

using namespace std;

class Complex {

double re;

double im;

public:

Complex();

Complex(double, double);

Complex operator + (Complex);

void display(){

cout << re << "+j" << im << endl;

}

};

Complex Complex::operator + (Complex b){

Complex c;

c.re = re + b.re;

c.im = im + b.im;

return (c);

}

Exemplu: class Point

class Point{

double x, y;

public:

Point(){ x = 0; y = 0;}

Point(double a, double b){x = a; y = b;}

void display() {

cout << x << " " << y << endl;

}

};

void main(){

Point pct1(10,20);

Point pct2(30,40);

Point pct3;

}

Page 22: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

22

Exemplu: class Point

class Point{

double x, y;

public:

// ...

Point operator +(Point op2);

Point operator -(Point op2);

};

Point Point::operator +(Point op2){

Point temp;

temp.x = x + op2.x;

temp.y = y + op2.y;

return temp;

}

void main(){

Point pct1(10,20);

Point pct2(30,40);

Point pct3;

pct3 = pct1 + pct2;

pct3 =pct1.operator+(pct2);

}

Exemplu: class Point

class Point{

double x, y;

public:

// ...

Point operator +(Point op2);

Point operator -(Point op2);

double operator *(Point op2);

Point& operator *=(double v);

};

double Point::operator *(Point op2){ // produs scalar

return x*op2.x + y*op2.y;

}

void main(){

Point pct1(10,20);

Point pct2(30,40);

Point pct3;

pct3 = pct1 * pct2;

pct3 =pct1.operator*(pct2);

}

Exemplu: class Point

class Point{

double x, y;

public:

// ...

Point operator +(Point op2);

Point operator -(Point op2);

double operator *(Point op2);

Point& operator *=(double v);

};

Point& Point::operator *=(double v){ //!!modifică obiectul

x *= v;

y *= v;

return *this; //returnează referinţa la propriul obiect

}

void main(){

Point pct1(10,20);

Point pct2(30,40);

Point pct3;

pct3 = pct1 + pct2;

double p = pct1 * pct2;

pct1 *= 2;

}

Exemplu: class Point

class Point{

double x;

double y;

public:

// ...

Point operator ++();

Point operator ++(int a);

};

Point Point::operator ++(){ // incrementare prefix

++x;

++y;

return *this;

}

Point Point::operator ++(int a){ // incrementare postfix

Point temp(*this); // a ia valoarea 0

x++;

y++;

return temp;

}

void main(){

Point pct1(10,20);

Point pct2(30,40);

Point pct3;

++pct1;

pct2++;

}

Page 23: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

23

Funcții operator friend

class Point{

double x;

double y;

public:

//...

friend Point operator +(Point op1, Point op2);

friend Point operator ++(Point &p);

friend Point operator ++(Point &p, int a);

};

Point operator +(Point op1, Point op2){

Point temp;

temp.x = op1.x + op2.x;

temp.y = op1.y + op2.y;

return temp;

}

void main(){

Point pct1(10,20);

Point pct2(30,40);

Point pct3;

pct3 = pct1 + pct2;

}

Funcții operator friend

class Point{

double x;

double y;

public:

//...

friend Point operator +(Point op1, Point op2);

friend Point operator ++(Point &p);

friend Point operator ++(Point &p, int a);

};

Point operator++(Point &p){ // incrementare prefix

++p.x;

++p.y;

return p;

}

Point operator++(Point &p, int a){// incrementare postfix

Point temp(p);

p.x++;

p.y++;

return temp;

}

void main(){

Point pct1(10,20);

Point pct2(30,40);

++pct1;

pct2++;

}

Exemplu class Vector class Vector {

double v[4];

public:

Vector();

Vector(double *pv);

void set(int i, double e) {v[i]=e;}

double get(int i) const {return v[i];}

};

Vector::Vector(){

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

v[i]=0.0;

}

Vector::Vector(double *pv){

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

v[i]= pv[i];

}

void main()

{

double v[]={1,2,3,4};

Vector v1(v);

}

Exemplu class Vector class Vector {

double v[4];

public:

Vector();

Vector(double *pv);

Vector operator + (Vector);

void set(int i, double e) {v[i]=e;}

double get(int i) const {return v[i];}

};

Vector Vector::operator +(Vector a){

Vector b;

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

b.v[i] = v[i] + a.v[i];

return b;

}

void main()

{

double u[]={1,2,3,4};

double v[]={0,1,0,1};

Vector v1(u),v2(v),v3;

v3 = v1 + v2;

}

Page 24: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

24

Exemplu class Vector class Vector { double v[4]; public:

... Vector operator + (Vector); Vector operator + (double);

... }; Vector Vector::operator +(Vector a){ Vector b; for (int i=0;i<4;i++) b.v[i] = v[i] + a.v[i]; return b; } Vector Vector::operator +(double a) { Vector b; for (int i=0;i<4;i++) b.v[i] = v[i] + a; return b; }

void main()

{

double u[]={1,2,3,4};

double v[]={0,1,0,1};

Vector v1(u),v2(v),v3,v4;

v3 = v1 + v2;

v4 = v1 + 3.5;

}

Exemplu class Vector class Vector {

int n;

double* pv;

public:

Vector(int m);

Vector(int m, double *pvi);

~Vector();

};

Vector::Vector(int m){

n = m;

pv = new double[n];

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

pv[i]=0.0;

}

Vector::Vector(int m, double *pvi){

n = m;

pv = new double[n];

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

pv[i]= pvi[i];

}

void main(){

int nr;

cout << “Nr elem”;

cin >> nr;

Vector v1(nr);

}

Vector::~Vector(){

if (pv){

delete pv;

pv = NULL;

}

Exemplu class Vector class Vector {

int n;

double* pv;

public:

Vector(int n);

Vector(int n, double *pvi);

Vector operator + (Vector);

~Vector();

};

Vector Vector::operator +(Vector a)

{

Vector b(n);

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

b.v[i] = v[i] + a.v[i];

return b;

}

void main(){

int nr;

cout << “Nr elem”;

cin >> nr;

Vector v1(nr);

}

Vector::~Vector(){

if (pv){

delete pv;

pv = NULL;

}

Exemplu class Vector class Vector {

int n;

double* pv;

public:

Vector(int n);

Vector(int n, double *pvi);

Vector(Vector &v);

~Vector();

};

//Constructorul de copiere

Vector::Vector(Vector &v){

n = v.n;

pv = new double[n];

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

pv[i] = v.pv[i];

}

void main(){

int nr = 10;

Vector v1(nr);

Vector v2(v1);

Vector v3 = v2;

}

Vector::~Vector(){

if (pv){

delete pv;

pv = NULL;

}

Page 25: POO - c2 Functii ClaseSiObiecte SupraincarcareaOperatorilor

11/28/2014

25

Exemplu class Vector class Vector {

int n;

double* pv;

public:

Vector(int n);

Vector(int n, double *pvi);

Vector(Vector &v);

Vector operator = (Vector);

~Vector();

};

//Operatorul de asignare

Vector& Vector::operator =(Vector& a)

{

n = a.n;

pv = new double[n];

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

pv[i] = a.pv[i];

return *this; }

void main(){

int nr = 10;

Vector v1(nr);

Vector v2(v1);

Vector v3 = v2;

}

Vector::~Vector(){

if (pv){

delete pv;

pv = NULL;

}

Exemplu class Vector class Vector {

int n;

double* pv;

public:

Vector(int n);

Vector(int n, double *pvi);

Vector(Vector &v);

Vector operator = (Vector);

double operator [](int i);

~Vector();

};

//Operatorul de indexare

double Vector::operator[](int i){

if ((pv!=NULL) && (i<n))

return pv[i];

else

return 0;

}

void main(){

int nr=10;

Vector v1(nr);

Vector v2(v1);

Vector v3 = v2;

double d = v2[5];

}

Vector::~Vector(){

if (pv){

delete pv;

pv = NULL;

}