Sunteți pe pagina 1din 38

PROGRAMAREA ORIENTAT PE OBIECTE

Proiectarea orientat obiect POO


utilizeaz elementele programrii structurate

se bazeaz pe orientarea pe obiecte

extindere

organizarea de resurse soft ca i o colecie de obiecte, distincte i discrete, care nglobeaz att structuri de date ct i funciile de prelucrare ale acestora.

programarea clasic orientarea pe obiecte

ce trebuie fcut cu datele? (proceduri care s transforme datele n rezultate) datele i legturile ntre acestea (elemente prin care se modeleaz obiectele lumii reale) identificarea i dezvoltarea de componente software.

Ingineria software caracteristici ale componentelor:

o component trebuie s aib un set redus bine definit de responsabiliti; interaciunea dintre componente trebuie s fie minim; identificarea componentelor se realizeaz n momentul n care se imagineaz procesul de execuie a sistemului; o component reprezint o pereche constituit din:

entiti abstracte care realizeaz anumite aciuni, adic ndeplinesc anumite responsabiliti.

comportament

setul de aciuni pe care le realizeaz; descrierea comportamentului unei componente se mai numete i protocol.

stare

toate informaiile memorate n interiorul ei.

Implementarea componentelor software se face prin intermediul construciilor de tip clas, puse la dispoziie de limbajele de programare orientate obiect.

n general, pentru modelul de date orientat pe obiect, se consider definitorii urmtoarele concepte:

abstractizare, obiect, atribut, metod,

clas,

ncapsulare,

motenire,

polimorfism.

Abstractizarea procesul de simplificare a realitii prin reinerea caracteristicilor i comportamentelor eseniale i prin abstractizare se izoleaz aspectele eseniale de cele neeseniale, n funcie de perspectiva de pentru o aceeai problem, pot exista mai multe abstractizri, deci mai multe modele. Selectarea obiectelor abstracte i a claselor este un punct important n realizarea unui program. constituirea lor ntr-un model adecvat rezolvrii problemelor. abordare a problemei de rezolvat

Obiectul
- o entitate individualizat prin nume - conine o mulime de date funcii descriu proprietile i nivelul acestora definesc comportamentul.

- obiectele pot fi clasificate n mulimi. O mulime de obiecte de acelai fel constituie o clas de obiecte, descris prin modelul comun al obiectelor sale.

Clasa
- grup de obiecte care fac parte din ea - o clas este o descriere a proprietilor i comportamentului unui tip obiect; o clas poate fi considerat ca un tip special de dat, iar obiectele sale ca variabile de acest tip. - pentru identificarea claselor unui sistem trebuie luate n consideraie urmtoarele aspecte: Exist informaii care trebuiesc stocate sau analizate? Dac da, ele sunt posibile candidate pentru o clas. Exist sisteme externe cu care va comunica sistemul construit? Dac da, este normal s fie luate n considerare la modelarea sistemului. Exist biblioteci sau componente din proiecte anterioare care pot fi folosite? n caz afirmativ acestea conin clase candidate. Sunt device-uri n sistem care vor trebui gestionate? Orice device conectat la sistem nseamn o clas candidat care sa-l gestioneze. Exist pri organizaionale n sistem? Va fi nevoie de clase n care s fie implementate. Definirea unei clase se realizeaz prin: precizarea operanzilor sau a atributelor; funciile membre; proprietile asociate componentelor pentru a stabili modaliti de referire.

Obs: Atributele sunt de un anumit tip (de exemplu ntregi, reale, caractere etc.). Setul de valori ale atributelor unui obiect la un moment dat formeaz starea curent a obiectului respectiv. Funciile care definesc comportamentul obiectelor sunt cunoscute ca metode ale clasei. mpreun, atributele i metodele sunt membrii clasei, identificabili prin nume.

O clas este un tip de dat definit de utilizator printr-o construcie de forma:

Date sau atribute Membrii Funcii sau metode

Aa cum variabilele n programe sunt de tip global i local sau dup modul de alocare sunt statice i dinamice, analog, pentru a defini o anumit disciplin n manipularea claselor se asociaz grupurilor de elemente din clas un specificator de control al crui cmp de aciune este anulat de un altul. Specificatorii de control sunt: public ceea ce nseamn c elementul respectiv este accesibil oricrei clase externe; private membrul este accesibil numai de funcii din interiorul clasei sau de ctre funcii prietene (friend) ale clasei; protected similar cu private dar accesul se extinde pentru funciile membre i prietene derivate din clasa respectiv. Atunci, forma general de declaraie a unei clase devine:

Obs: - Efectul unui specificator de acces dureaza pna la urmatorul specificator de acces. - Implicit, daca nu se declara nici un specificator de acces, datele sau functiile membre sunt de tip private.

- O funcie membr a unei clase are acces la toate datele membre din clasa respectiv, indiferent de specificatorul de acces. - La proiectarea unei clase se au n vedere urmtoarele aspecte: funciile membru s acopere ntreaga gam de prelucrri; ntre variabilele i funciile membre s fie o concordan perfect pentru a nu apare erori n execuia programelor ce folosesc clase. - ntruct o clas este un tip de dat, declararea unui obiect se face asemntor oricrei declaraii de dat: nume_clas nume_obiect; - Declararea unui obiect mai este numit i instanierea clasei, n sensul c se creeaz o instan a acelei clase, o entitate concret din mulimea descris de clasa respectiv. - Pentru a pune n eviden faptul c un membru aparine unui obiect se utilizeaz formularea: nume_obiect. nume_membru. - O clas conine deci: - o parte protejata/privata care asigura implementarea clasei; - o parte publica care reprezint interfaa clasei respective cu celelalte seciuni din program Exemplul 1: pentru implementarea calculului cu numere raionale, se definete clasa Rational: #include<iostream.h> class rational { int p,q; public: void nr (int x=0 , int y=1) { p=x; q=y; } int numarator ( ) { return p; } int numitor ( ) { return q; } }; } main ( ) { rational a;//a este un obiect al clasei rational a.nr (4 , 5);//apelam f-ctia nr din obiectul a cout<<a.numarator( )<<a.numitor( );

Exemplul 2: pentru implementarea calculului cu numere complexe, se definete clasa Complex care trebuie s aib o structur de tip articol pentru a grupa partea real i partea imaginar a numrului complex i s conin funcii membre pentru operaiile de adunare, scdere, nmulire, mprire, ridicare la putere i extragere de radical.

Obiect al clasei Complex (ca i variabilele, obiectele pot fi parametrii pentru funcii) (componenta c.img a obiectului cpl)

Obs: Funciile vor fi descrise n cadrul clasei numai dac au codul extrem de scurt i nu conin instruciuni de ciclare. Altfel, clasa va conine numai prototipul funciei. Atunci cnd se descrie ulterior corpul unei metode (funcii), pentru a specifica apartenena sa la clasa respectiv, numele metodei este prefixat cu numele clasei din care face parte, folosind operatorul de rezoluie (::), astfel: tip_rezultat nume_clas :: nume_metod(lista parametrilor) corp metod Exemplul 3: prin modificarea programului din exemplul 1 se obine: #include<iostream.h> class rational { int p,q; public: void nr (int x, int y); int numarator ( ); int numitor ( ); }; main ( ) { rational a; a.nr (4 , 5); cout<<a.numarator( )<<a.numitor( ); } void rational :: nr (int x=0 , int y=1) { p=x; q=y; } int rational :: numarator ( ) { return p; } int rational :: numitor ( ) { return q; } };

CREAREA, INITIALIZAREA SI DISTRUGEREA OBIECTELOR UNEI CLASE Pentru crearea si distrugerea obiectelor in C++ functii membre speciale constructori destructori.

Declararea obiectelor oricrei variabile.

are ca efect

alocarea de spaiu n memorie, la fel ca n cazul declarrii nu este iniializat

Pentru rezolvarea problemei iniializrii obiectelor exist posibilitatea utilizrii unor metode speciale, numite constructori. La terminarea ciclului de via al obiectelor, este necesar dezalocarea lor. Problema ncheierii ciclului de via al obiectelor este rezolvat prin utilizarea unor metode speciale numite destructori. Constructorii si destructorii se declara si se definesc similar cu celelalte functii membre, dar prezinta o serie de caracteristici specifice: *) numele lor coincide cu numele clasei careia ii apartin; destructorii se disting de constructori prin faptul ca numele lor este precedat de caracterul ~ *)nu pot returna nici un rezultat *)nu se pot utiliza pointeri catre constructori sau destructori *)constructorii pot avea parametri, destructorii insa nu. Un constructor fara parametri poarta denumirea de constructor implicit. *)in cazul in care o clasa nu dispune de constructori sau destructori, compilatorul de C++ genereaza automat un constructor respectiv destructor implicit. Sintaxa: id_clasa (lista_parametri);//prototip Un constructor poate fi: a) implicit: - fara parametri (definit de utilizator) care poate contine in corpul sau orice instructiune valida. Un astfel de constructor inline nu poate contine instructiuni cu caracter repetitiv. - generat de compilator (cand nu exista constructori definiti de utilizator in clasa respectiva). Corpul unui astfel de constructor nu contine nici o instructiune. b) cu parametri care, in totalitate sau partial, iau valori in mod implicit;

c) cu parametri care nu iau valori in mod implicit; d) cu conversie de tip; e) de copiere: - definit de utilizator; - generat implicit de compilator; Obs: n cazul n care clasa prezint constructori explicii valorile pentru iniializare sunt transmise acestuia la declararea obiectului, asemntor listei de parametri reali la apelul unei funcii: nume_clas nume_obiect(lista_valori); Exemple de costructori definiti de catre programator: Ex1: #include<math.h> #include<iostream.h> #include<conio.h> class complex {public: float x,y,m; //datele clasei void display(); float modul(); //metoda clasei complex() //constructor fara parametri definit de catre programator {cout<<endl<<"mesaj de la constructor"<<endl;} }; float complex::modul() {return sqrt(x*x+y*y);} void complex::display() {cout<<x<<"+"<<y<<"*i";} Testand programul se afiseaza pe ecran de trei ori mesajul: mesaj de la constructor, corespunzator fiecarei declarari a celor trei instante ale clasei complex.

complex q; //obiect(instantiere) a clasei complex void main() {complex q1, q2; // obiecte(instantieri) ale clasei complex getch(); clrscr(); }

Urmatorul exemplu contine in plus inca un constructor definit de catre programator, constructor ce are un parametru. Ex2 #include<math.h> #include<iostream.h> #include<conio.h> class complex {public: float x,y,m; //datele clasei void display(); float modul(); //metoda clasei complex() {cout<<endl<<"mesaj de la constructor"<<endl;} complex(float yy); }; complex::complex(float xx) {x=xx; y=0; } float complex::modul() {return sqrt(x*x+y*y); } void complex::display() {cout<<endl<<x<<"+"<<y<<"*i"; cout<<endl; } complex q; void main() {cout<<"Obiectul global q="; q.display(); complex q1; cout<<"Obiectul local q1, retine valori reziduale"; q1.display(); complex q2(6.7); //se apleleaza constructorul cu un parametru q2.display(); getch(); clrscr(); }

Urmatorul exemplu permite prin intermediul mecanismului de supraincarcare definirea unui constructor cu doi parametri: Ex3: #include<math.h> #include<iostream.h> #include<conio.h> class complex {public: float x,y,m; //datele clasei void display(); float modul(); //metoda clasei complex() {cout<<endl<<"mesaj de la constructor"<<endl;} complex(float yy); complex(float xx, float yy); }; complex::complex(float xx) {x=xx; y=0; } complex::complex(float xx, float yy) {x=xx; y=yy; } float complex::modul() {return sqrt(x*x+y*y); } void complex::display() {cout<<endl<<x<<"+"<<y<<"*i"; cout<<endl; } complex q; void main() {cout<<"Obiectul global q="; q.display(); complex q1; cout<<"Obiectul local q1, retine valori reziduale"; q1.display(); complex q2(6.7); cout<<"q2="; q2.display(); complex q3(1.2,1.3); cout<<"q3="; q3.display(); getch(); clrscr(); }

Obs: Ca orice alta functie n limbajul C++, constructorii pot avea parametri impliciti , fiind numiti constructori cu parametri impliciti. Varianta constructorului cu parametri impliciti poate fi adoptata n toate cazurile n care constructorul nu necesita argumente. Daca toti parametrii unui constructor sunt impliciti, apelul constructorului are forma unei simple declaratii . Ex 4: Pentru clasa complex s-a definit un constructor cu parametri impliciti; din acest motiv s-a putut face declaratia "complex q;" #include<math.h> #include<iostream.h> #include<conio.h> class complex {public: float x,y,m; //datele clasei void display(); float modul(); //metoda clasei complex(float xx=0, float yy=0) {cout<<endl<<"mesaj de la constructorul cu parametri impliciti "<<endl; x=xx; y=yy; } }; float complex::modul() {return sqrt(x*x+y*y); } void complex::display() {cout<<endl<<x<<"+"<<y<<"*i"; cout<<endl; } complex q; //obiect neinitializat ; apelul nu se face in mod explicit void main() {cout<<"Obiectul global q="; q.display(); complex q1; //obiect neinitializat ; apelul nu se face in mod explicit cout<<"Obiectul local q1 "; q1.display(); La apelul explicit al constructorului: complex q2(6.7); // obiect initializatt. complexq4=complex() evaluarea expresiei complex() cout<<"q2="; conduce la: - Crearea unui obiect temporar de tip complex (obiect cu q2.display(); o adresa precisa, dar inaccesibil); complex q3(1.2,1.3); // obiect initializat. - Apelul constructorului pentru acest obiect temporar; cout<<"q3="; - Copierea acestui obiect temporar n q4. q3.display(); complex q4=complex(); // constructorul este apelat n mod explicit. q4.display(); getch(); clrscr();}

Constructori de copiere Functia principala a unui constructor este aceea de a initializa datele membre ale obiectului creat, folosind pentru aceasta operatie valorile primite ca argumente. O alta forma de initializare care se poate face la crearea unui obiect este prin copierea datelor unui alt obiect de acelasi tip.

operatie posibila prin intermediul constructorului de copiere Pentru o clasa, se poate defini un contructor de copiere, care sa permita copierea obiectelor. constructorul de copiere pentru clasa nume_clasa, are, de obicei, prototipul: nume_clasa (nume_clasa & ob); Parametrul transmis prin referinta este obiectul a carui copiere se realizeaza. Obs: Daca programatorul nu defineste un constructor de copiere, compilatorul genereaza un asemenea constructor, implicit. Ex 5: #include<math.h> #include<iostream.h> #include<conio.h> class complex {public: float x,y,m; //datele clasei void display(); float modul(); //metoda clasei complex(float xx=0, float yy=0) {cout<<endl<<"mesaj de la constructorul cu parametri impliciti "<<endl; x=xx; y=yy; } complex(complex &ob) //constructor de copiere { cout<<endl<<"operatie de copiere "; x=ob.x; y=ob.y; } }; float complex::modul() {return sqrt(x*x+y*y); } void complex::display() {cout<<endl<<x<<"+"<<y<<"*i"; cout<<endl; }

void main() {complex q1(1.2,1.3); cout<<"q1="; q1.display(); complex q2=q1; //se apeleaza constructorul de copiere cout<<"q2="; q2.display(); complex q3=complex(q1); //se apeleaza constructorul de copiere cout<<"q3="; q3.display(); getch(); clrscr(); }

Destructori Destructorii sunt metode ale claselor care actioneaza n sens invers, complementar, fata de constructori. Constructorii sunt folositi pentru alocarea memoriei, initializarea datelor membru sau alte operatii (cum ar fi, incrementarea unui contor pentru instantele clasei). Destructorul elibereaza memoria alocata de constructori. Constructorul este apelat n momentul declararii obiectelor. Destructorul este apelat automat, la iesirea din blocul n care este recunoscut acel obiect.

Proprietatile destructorilor : *)Destructorul are acelasi nume ca si clasa a carui metoda este; *)Numele destructorului este precedat de semnul ~; *)O clasa are un singur destructor; *)Destructorul nu are parametri si nu returneaza nici o valoare (antetul nu contine cuvntul cheie void, iar n corpul destructorului nu apare instructiunea return;); *)Daca programatorul nu a definit un destructor, compilatorul genereaza automat un destructor pentru clasa respectiva; *)Destructorii se apeleaza la ncheierea timpului de viata a obiectelor, n ordine inversa apelurilor constructorilor;

Ex 6: #include<math.h> #include<iostream.h> #include<conio.h> class complex {public: float x,y,m; //datele clasei void display(); float modul(); //metoda clasei complex(float xx=0, float yy=0) {cout<<endl<<"mesaj de la constructorul cu parametri impliciti "<<endl; x=xx; y=yy; } complex(complex &ob) { cout<<endl<<"operatie de copiere "; x=ob.x; y=ob.y; } ~complex () {cout<<endl<<"am apelat destructorul pentru"<<endl; //destructor display();} }; float complex::modul() {return sqrt(x*x+y*y); } void complex::display() {cout<<endl<<x<<"+"<<y<<"*i"; cout<<endl; } void main() {complex q1(1.1,1.1); cout<<"q1="; q1.display(); complex q2(2.2,2.2); cout<<"q2="; q2.display(); complex q3(3.3,3.3); cout<<"q3="; q3.display(); // getch(); }

Funcii inline

alternativ la utilizarea excesiv a macro-definiiilor din limbajul C.

Compilatorul nlocuiete orice apel al unei funcii inline cu codul acesteia. n felul acesta se elimin operaiile suplimentare de apel i revenire din funcie. Utilizarea funciilor inline mrete viteza de execuie a programului prin evitarea operaiilor pe stiv, ce au loc n cazul apelurilor de funcii obinuite, dar pltete drept pre pentru aceasta creterea dimensiunii codului executabil. Declaraia unei funcii inline este format din declaraia unei funcii obinuite precedat de cuvntul cheie inline: Sintaxa pentru definiia claselor permite declararea implicit a unei funcii inline. O funcie membr a unei clase definit (nu doar declarat) n interiorul clasei este implicit funcie inline:

Alt exemplu:

Metoda tipareste este declarat explicit, ea fiind doar declarat n cadrul clasei, iar n locul unde este definit este prefixat de cuvntul cheie inline.

O funcie membr definit n afara clasei este implicit o funcie normal (nu este inline). Dar i o astfel de funcie poate fi declarat explicit inline: Fie exemplul urmtor:

n acest exemplu, funcia set( ) din clasa Complex poate fi declarat explicit inline : inline void Complex::set(double x, double y){ } Obs: 1) Metodele care nu sunt membru al unei clase nu pot fi declarate inline dect explicit. 2)Funciile inline nu pot fi declarate funcii externe, deci nu pot fi utilizate dect n modulul de program n care au fost definite i nu pot conine instruciuni ciclice (while, for, do-while).

ncapsularea datelor (ascunderea informaiei)

ascunderea detaliilor de implementare ale unui obiect fa de lumea exterioar (aplicaiile care l folosesc). separarea elementelor unui tip de date abstract (clas) n dou pri: structura dat de implementarea acestuia definirea datelor i a funciilor membre comportarea accesat prin interfa

declaraiile datelor i funciilor membre de tip public

n C++ ncapsularea este ndeplinit prin dou aspecte: 1. folosirea claselor pentru unirea structurile de date i a funciilor destinate manipulrii lor; 2. folosirea seciunilor private i publice, care fac posibil separarea mecanismului intern de interfaa clasei;

Obs: 1) n general, respectnd principiul ncapsulrii, datele membre sunt declarate private sau protected i nu pot fi accesate direct (pentru citire sau scriere) din funcii nemembre ale clasei care nu sunt de tip friend (sau nu aparin unei clase friend a clasei respective). 2) Pentru citirea sau modificarea unora dintre datele membre protejate n clasa respectiv se pot prevedea funcii membre de tip public, care pot fi apelate din orice punct al domeniului de definiie al clasei i fac parte din interfaa clasei. De exemplu, pentru clasa Complex, o implementare care respect principiul ncapsulrii, dar, n acelai timp permite accesul la datele private ale clasei poate arta astfel:

Datele membre ale clasei (re i im) sunt date de tip private, iar accesul la acestea este posibil prin intermediul funciilor membre publice set(), setre(), setim(), etc.

Date i funcii membre de tip static


Cuvntul cheie static poate fi utilizat n prefixarea membrilor unei clase. Odat declarat static, membrul n cauz are proprieti diferite, datorit faptului c membrii statici nu aparin unui anumit obiect, ci sunt comuni tuturor instanierilor unei clase. 1) date membre statice: 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.

Datele membru statice, care sunt utilizate de ctre toate obiectele clasei, se definesc prin specificatorul static astfel:

Datele membru statice, se declar ( se iniializeaz) explicit n afara clasei :

Referirea (utilizarea) datelor membru statice se poate face astfel :

Exemplul 1: Se consider o clas S care conine o variabil normal v i o variabil static s. Data de tip static este declarat n clasa S i definit n afara acesteia, folosind operatorul de rezoluie. Se poate urmri evoluia diferit a celor dou variabile v i s prin crearea a dou obiecte x i y de tip S, i prin apelul funciilor incs() i incv() pentru obiectul x astfel:

La execuia acestui program se afieaz coninutul variabilelor s i v pentru obiectele x i y. Mesajele afiate sunt urmtoarele:

Diferena ntre comportarea unei date membre de tip static i a unei date normale este evident: dup incrementarea variabilelor s i v pentru obiectul x, obiectele x i y vd aceeai valoare a variabilei statice s i valori diferite ale variabilei normale v. Exemplul 2: n urmtorul exemplu, se numr cte Puncte sunt utlizate la un moment dat n program, utiliznd ca dat comun pentru toate punctele ( ntreaga clas) Nr_Ob:

2) funcii membre statice: O funcie membr de tip static se declar n interiorul clasei i se definete n interiorul clasei sau n afara acesteia, folosind operatorul de rezoluie. O funcie membr static are vizibilitatea limitat la fiierul n care a fost definit i este independent de instanele (obiectele) clasei. Metodele statice, se definesc prin specificatorul static astfel:

Referirea ( utilizarea) metodelor statice se poate face astfel :

Exemplu: Fie, de exemplu clasa Task care conine o dat membr static i o funcie membr static:

Apelul unei funcii statice se poate face fie ca funcie membr a unui obiect din clasa respectiv, aa cum apare n primul apel din funcia fs2(), fie prin specificarea clasei creia i aparine, folosind operatorul de rezoluie. Obs: Specificatorul static are n C++ dou semnificaii: aceea de vizibilitate restricionat la nivelul fiierului n care sunt definite variabilele sau funciile i aceea de alocare static, adic obiectele exist i-i menin valorile lor de-a lungul execuiei ntregului program.

Funcii i Clase Prietene (Friend)


O funcie este prieten cu o clas dac are acces la datele membru private ale acelei clase. O funcie prieten poate fi o funcie global sau chiar o funcie membru a altei clase. O clas este prieten cu o alt clas dac ea are acces la datele membru ale acesteia. O funcie, respectiv o clas prieten se declar utiliznd cuvntul friend astfel: a) friend Tip_funcie Nume_funcie ( List_parametri_formali ); // Funcie friend global b) friend Tip_funcie Nume_clas::Nume_funcie(List_par._formali);// Funcie friend membru c) friend Nume_clas; // Clas friend Obs: 1) O funcie de tip friend este n esen o funcie standard, care nu este membr a clasei ci are numai acces la membrii de tip privat ai acelei clase. Orice functie poate fi prieten a unei clase, indiferent de natura acesteia. 2) Declaraia unei funcii prietene se poate face oriunde n cadrul declaraiei clasei i ofer funciei posibilitatea de a avea acces la oricare dintre membri. 3) Sunt posibile urmtoarele situaii: - funcie independent este prieten a unei clase; - funcie membr a unei clase este prietena altei clase; - funcie ce este prietena mai multor clase; - toate funciile unei clase y sunt prietene ale altei clase x; n acest caz se spune c clasa y este prieten a clasei x. 4) Modificatorii de acces nu au nicio influen asupra funciilor prieten, de aceea ele pot fi specificate oriunde n cadrul descrierii clasei. Deci declararea unei funcii prietene se poate face oriunde n cadrul declaraiei clasei (att in partea privata cat si in cea publica) si ofer funciei privilegiul de a avea acces la oricare dintre membri. Exemplul 1: n acest exemplu funcia Afieaz va fi scoas n afara clasei Complex i va fi declarat ca funcie prieten. class Complex { float p_reala, p_imaginara; public: friend void Afiseaza(Complex x); Complex(float a=0,float b=0); Complex(Complex &x); }; void Afiseaza(Complex x) { cout<<x.p_reala<<x.p_imaginara; } void main() { Complex a(1,2); Afiseaza(a); }

Exemplul 2: //S considerm un tip definit de utilizator: #include <iostream.h> class X { int u,v; public: X(int k, int q){u=k;v=q;} int dif(){return u*u-v*v;} }; void main() { X z(6,3); int p=z.dif(); cout<<"p="<<p; } Se obine pentru p valoarea 27, folosind funcia membr, dif( ). La acelai rezultat se va ajunge folosind funcia friend dif( ) a clasei X, care nu mai este funcie membr a acestei clase. #include <iostream.h> class X { int u,v; public: X(int k, int q){u=k;v=q;} friend int dif(X w); }; int dif(X w){return w.u*w.u-w.v*w.v;} void main() { X z(6,3); cout<<dif(z); } Obs : Exist dou situaii n declararea funciilor friend ale unei clase: a) se specific faptul c funcia membr a unei clase este funcie friend a unei alte clase. Mai exact, se declar funcia membr din prima clas ca fiind de tip friend n a doua clas. Exemplu: class Y; // se predeclar clasa care conine funcii prietene ale unei alte clase X class X { void F1(Y &a); // funcie membr a clasei X . }; class Y {

friend void X::F1(Y &a); //funcie friend pentru clasa Y .. }; b) se poate declara o ntreag clas prieten , n care toate funciile membre ale sale sunt funcii prietene ale unei alte clase. Exemplu: class Y; class X { .. void F1(Y &a); .. }; class Y { .. friend X; // se declar clasa X ca prieten a clasei Y(toate funcile membre // ale clasei X sunt funcii friend pentru clasa Y) .. };

Exemplul 3: Sa se defineasca tipul abstract de date complex care sa aiba functii membru pentru: - modul, argument - accesul la partea reala si imaginara a obiectelor de tip complex - afisarea obiectelor complexe - constructori pentru initializare si copiere Sa se scrie un program care realizeaza urmatoarele: citeste perechi de n numere care reprezinta fiecare, partea reala si respectiv imaginara a unui numar complex afiseaza: - numarul complex citit - suma numerelor complexe citite

Tem: Sa se defineasca o functie care ridica un numar complex la o putere intreaga pozitiva. Un numar complex se poate ridica la o putere intreaga folosind formula lui MOIVRE. Aceasta se exprima prin relatia:

((r*cos(a)+i*sin(a)))n = rn * (cos(n*a)+i*sin(n*a))
unde: r - este modulul numarului complex a este argumentul nr. Complex

#include <iostream.h> #include <conio.h> #include <math.h> #define PI 3.14159265358979 class complex { double re; double im; public: double modul; double arg(); void afis(); friend void cp(complex&,int); void init(double x,double y) { re=x; im=y; modul=sqrt(re*re+im*im); } }; inline void complex::afis(){cout<<re<<"+i*"<<"("<<im<<")";} double complex::arg() { if(re==0.0&&im==0.0)return 0.0; if(im==0.0) if(re>0.0) return 0.0; else return PI; if(re==0.0) if(im>0.0)return (PI/2); else return (3*PI)/2; double a=atan(im/re); if(re<0.0)return PI+a; if(im<0.0)return 2*PI+a; return a; } void cp(complex &z,int n) { double r; double a; r=z.modul; a=z.arg(); double r_la_n=pow(r,(double)n); double aa=n*a; z.re=r_la_n*cos(aa); z.im=r_la_n*sin(aa); } void main() { complex u; u.init(-1,-1); cout<<"\n U="; u.afis(); cout<<"\n Modulul nr.U:"<<u.modul; cout<<"\n Nr. ridicat la putere:"; cp(u,3);
u.afis(); }

Exemplul 4:
// functii prietene (friend) #include <iostream.h> class CRectangle { int width, height; public: void set_values (int, int); int area (void) {return (width * height);} friend CRectangle duplicate (CRectangle); }; void CRectangle::set_values (int a, int b) { width = a; height = b; } CRectangle duplicate (CRectangle rtparam) { CRectangle rtres; rtres.width = rtparam.width*2; rtres.height = rtparam.height*2; return (rtres); } int main () { CRectangle rt, rtb; rt.set_values (2,3); rtb = duplicate (rt); cout << rtb.area(); } // clasa prietena (friend) #include <iostream.h> class CSquare; class CRectangle { int width, height; public: int area (void) {return (width * height);} void convert (CSquare a); }; class CSquare { private: int side; public: void set_side (int a) {side=a;} friend class CRectangle; }; void CRectangle::convert (CSquare a) { width = a.side; height = a.side; } int main () { CSquare sqr; CRectangle rt; sqr.set_side(4); rt.convert(sqr); cout << rt.area(); return 0; }

Din cadrul functiei duplicate, care este prietena cu CRectangle, nu este posibil accesul asupra membrilor width si height ale diverselor obiecte de tip CRectangle. De observat ca nici in declaratia lui duplicate() nici in utilizarea lui ulterioara din main() nu s-a considerat ca functia duplicate() ar fi membra a clasei CRectangle.

S-a declarat clasa CRectangle ca prietena a clasei CSquare astfel incat CRectangle poate accesa mebrii protected si private ai clasei CSquare, mai concret, data membru CSquare::side, care defineste latura patratului. Prima instructiune reprezinta un prototip vid al clasei CSquare. Aceasta este necesara pe motivul ca in cadrul functiei CResctangle se face referire la CSquare (ca parametru in functia convert()). Definitia lui CSquare este inclusa mai tarziu, iar daca nu ar fi fost instructiunea prototipului vid, clasa CSquare nu ar fi fost vizibila din cadrul definitiei lui CRectangle compilatorul ar fi sesizat o eroare, in acest caz.

Exemplul 5:
// functii prietene (friend) class Point { friend unsigned long Calcul(unsigned X, unsigned Y); public: fiend unsigned long AltaClasa::Calcul(unsigned X, unsigned Y); ... }; unsigned long Calcul(unsigned X, unsigned Y) { return X * Y / 2; } unsigned long AltaClasa::Calcul(unsigned X, unsigned Y); { ... }

Obs: Relatia de prietenie nu este tranzitiva. Daca o clasa A este prietena cu o clasa B, iar clasa B este prietena cu o clasa C, aceasata nu inseama ca A este prietena cu C. De asemenea, proprietatea de prietenie nu se mosteneste in clasele derivate !

Clase derivate. Moteniri

Motenirea

reprezint o relaie ntre clase

elementul definitoriu al OOP. Relaia permite constituirea unei noi clase, numit derivat (sau fiu) pornind de la clase existente, denumite de baz (sau printe). Motenirea simpl - n procesul de construire particip o singur clas de baz multipl - n procesul de construire particip mai multe clase de baz Derivarea permite definirea ntr-un mod simplu, eficient i flexibil a

unor clase noi prin adugarea unor funcionaliti claselor deja existente, fr s fie necesar reprogramarea sau recompilarea acestora. Derivarea claselor este legat de implementarea conceptului de motenire. O clas care asigur proprieti comune mai multor clase se definete ca o clas de baz. O clas derivat motenete de la una sau mai multe clase de baz toate caracteristicile acestora, crora le adaug alte caracteristici noi, specifice ei. Se spune c o clas D motenete o clas A, dac obiectele din clasa D conin toate atributele clasei A i au acces la toate metodele acestei clase. Dac D motenete A, atunci obiectele din D vor avea toate atributele i acces la toate metodele lui A, dar n plus: - D poate defini noi atribute i metode; - D poate redefini metode ale clasei de baz; - metodele noi i cele redefinite au acces la toate atributele dobndite sau nou definite.

Deci prin derivare sunt construite clasele din aproape n aproape, organiznduse pe niveluri de agregare. Clasele agregate de pe nivelul k preiau operanzii i funciile membre ale claselor de pe nivelul k-1, care intr prin derivare n componena lor, precum i proprietile acestora. n limbajul C++ este permis motenirea multipl. Pentru a defini o clas fiu ca fiind derivat dintr-o clas printe (sau mai multe clase printe), se procedeaz astfel: class nume_clasa_fiu : lista_clase_printe { descriere membri noi ai clasei fiu}; n lista claselor printe se specific numele claselor printe, separate prin virgul i, eventual, precedate de modificatori de acces se pot folosi modificatorii public sau private. Obs: 1) Pentru fiecare clas printe se poate specifica un modificator de acces. Dac nu se specific niciun modificator de acces atunci, implicit, se consider modificatorul public. 2) O clas derivat are acces la membrii clasei printe care au fost definii ca fiind publici sau protejai i nu are acces la membrii privai. Prin derivare se construiesc ierarhii de clase, deci din clasa fiu se pot deriva alte clase noi. 3) ntruct ierarhiile de clase nu sunt definitive, ci ofer posibilitatea extinderii prin adugarea de noi clase derivate, se prefer ca la derivare s se foloseasc modificatorul de acces public. De aceea acesta este modificatorul explicit. Exemplul 1: Fie clasa Punct care implementeaz entitatea punct geometric. Aceasta are atributele x i y, care reprezint coordonatele punctului n plan. Este inclus o singur metod, care deseneaz punctul pe ecran.

class punct { int x,y; public: void deseneaza(); }; void punct::deseneaza(); { //corpul nu este descris in acest exemplu } Fie clasa Cerc care implementeaz entitatea geometric cerc. Aceasta este descris prin coordonatele centrului cercului i raza sa. Ca urmare clasa Cerc poate fi derivat din clasa Punct, adugnd un nou atribut (raza) i o nou metod, pentrud esenarea cercului. Clasa Cerc motenete clasa Punct, deci un obiect de tipul Cerc va avea ca membri coordonatele x,y motenite i ca atribut propriu Raza. class cerc: punct { float raza; public: void deseneaza(); }; void cerc::deseneaza() { //corpul nu este descris in acest exemplu } Clasa cerc o s aib ca membri atributele x, y i raza i metodele deseneaz (motenit de la clasa Punct, care va fi folosit pentru desenarea centrului cercului) i deseneaz (nou definit, care va fi folosit pentru desenarea cercului). Funcia Distana, definit pentru calculul distanei dintre punctul curent i punctul p, dat ca parametru, este accesibil i pentru obiectele Cerc i va calcula distana dintre centrul cercului i un alt punct, primit ca parametru. Funcia Arie calculeaz aria din interiorul cercului, fiind nou definit. Funcia Deseneaz este redeclarat de clasa Cerc, lucru impus de codul diferit pe care trebuie s-l aib pentru desenarea obiectelor din aceast clas (cerc sau alt figur).

Motenirea simpl Exemplul 2: Se consider un program care descrie organizarea personalului unei instituii fr folosirea claselor derivate. O clas numit Angajat deine date i funcii referitoare la un angajat al instituiei: class Angajat{ char *nume; float salariu; public: Angajat(); Angajat(char *n, float sal); Angajat(Angajat& r); void display(); }; Angajat::display(){ cout << nume << << salariu << endl; } Diferite categorii de angajai necesit date suplimentare fa de cele definite n clasa Angajat, corespunztoare postului pe care l dein. De exemplu, un ef de secie (administator) este un angajat (deci sunt necesare toate datele care descriu aceast calitate) dar mai sunt necesare i alte informaii, de exemplu precizare seciei pe care o conduce. De aceea, clasa Administator trebuie s includ un obiect de tipul Angajat, la care adaug alte date:

class Administrator{ Angajat ang; int sectie; public: void display(); }; Un administrator este un angajat, de aceea clasa Administrator se poate construi prin derivare din clasa Angajat astfel: class Administrator : public Angajat { int sectie; public: void display(); } Aceast operaie care se poate reprezenta schematic prin indicarea derivrii cu o sgeat (arc direcionat) de la clasa derivat la clasa de baz.

Motenirea multipl: Este posibil motenirea din mai multe clase de baz. De exemplu: class X : public Y, public Z, .public W { // corpul clasei }; Evident, specificatorii de acces pot s difere (pot fi oricare din public, private, protected). O clas de baz se numete baz direct dac ea este menionat n lista de clase de baz. O clas de baz se numete baz indirect dac nu este baz direct dar este clas de baz pentru una din clasele menionate n lista claselor de baz. ntr-o clas derivat se motenesc att membrii bazelor directe ct i membrii bazelor indirecte.

De exemplu, se completeaz programul de descriere a organizrii personalului unei instituii i pentru alte categorii de personal (personal temporar, consultant, secretar, director), prin adugarea cte unei clase pentru fiecare categorie de personal. Modul n care aceste clase se deriveaz din anumite clase de baz evideniaz relaiile de ierarhie ntre categoriile pe care le reprezint: class Personal { /* */ }; class Angajat : public Personal{ /* */ }; class Administrator : public Angajat { /* */ }; class Director : public Administrator { /* */ }; class Secretara : public Angajat { /* */ }; class Temporar : public Personal { /* */}; class Consultant : public Temporar, public Administrator { /* */ }; Aceast organizare a claselor se poate descrie printr-un graf aciclic direcionat astfel:

Clasa (nodul) din vrful ierarhiei reprezint categoria cea mai general a ierarhiei, iar toate celelalte motenesc, direct sau indirect, din aceast clas de baz, fiind clase mai specializate.

Controlul accesului la membrii clasei de baz Accesul la membrii clasei de baz motenii n clasa derivat este controlat de specificatorul de acces (public, protected, private) din declaraia clasei derivate. O regul general este c, indiferent de specificatorul de acces declarat la derivare, datele de tip private n clasa de baz nu pot fi accesate dintr-o clas derivat. O alt regul general este c, prin derivare, nu se modific tipul datelor n clasa de baz. Motenirea de tip public a clasei de baz Dac specificatorul de acces din declaraia unei clase derivate este public, atunci: Datele de tip public ale clasei de baz sunt motenite ca date de tip public n clasa derivat i deci pot fi accesate din orice punct al domeniului de definiie al clasei derivate. Datele de tip protected n clasa de baz sunt motenite protected n clasa derivat, deci pot fi accesate numai de funciile membre i friend ale clasei derivate. Exemplu: Diverse situaii de acces la membrii clasei de baz din clasa derivat atunci cnd specificatorul de acces este public: class Base { int a; protected: int b; public: int c; void seta(int x){a = x; cout << "seta din baza\n";} void setb(int y){b = y; cout << "setb din baza\n";} void setc(int z){c = z; cout << "setc din baza\n";} }; class Derived : public Base { int d; public: void seta(int x) { a = x; // eroare, a este private } void setb(int y) {

b = y; cout << "setb din derivata\n"; } void setc(int z) { c = z; } }; } Motenirea de tip protected a clasei de baz Dac specificatorul de acces din declaraia clasei derivate este protected, atunci toi membrii de tip public i protected din clasa de baz devin membri protected n clasa derivat. Bineneles, membrii de tip private n clasa de baz nu pot fi accesai din clasa derivat.

Motenirea de tip private a clasei de baz Dac specificatorul de acces din declaraia clasei derivate este private, atunci toi membrii de tip public i protected din clasa de baz devin membri de tip private n clasa derivat i pot fi accesai numai din funciile membre i friend ale clasei derivate. Bineneles, membrii de tip private n clasa de baz nu pot fi accesai din clasa derivat. Motenirea multipl: O clas poate avea mai multe clase de baz directe, dac acestea sunt specificate n declaraia clasei. n exemplul urmtor este prezentat clasa Derived care motenete dou clase de baz, Base1 i Base2.

class Base1 { protected: int x; public: Base1(int i) { cout << "Constructor baza 1\n"; x = i; } ~Base1() { cout <<"Destructor baza 1\n"; } int getx(){return x;} }; class Base2{ protected: int y; public: Base2(int j){ cout << "Constructor baza 2\n"; y = j; } int gety() { return y;} ~Base2() { cout <<"Destructor baza 2\n"; } }; class Derived : public Base1, public Base2 { int d; public: Derived (int i, int j); ~Derived(){ cout << "Destructor derivata\n"; } }; Derived::Derived(int i, int j): Base1(i), Base2(j){ cout << "Constructor derivata\n"; } void fbm(){ Derived obd(3,4); cout << obd.getx() << " "<< obd.gety() << endl; }

n funcia fbm() este creat obiectul Derived. obd de clas

Constructorul clasei Derived transfer cte un argument constructorilor fiecrei clase de baz, care iniializeaz datele membre x i y. La execuia funciei fbm() se afieaz urmtoarele mesaje, care indic ordinea n care sunt apelai constructorii i destructorii clasei derivate i ai claselor de baz: Constructor baza 1 Constructor baza 2 Constructor derivata 3 4 Destructor derivata Destructor baza 2 Destructor baza 1

Avantajele folosirii motenirii: reutilizabilitatea cnd o funcionalitate este motenit din alt clas, codul respectiv nu trebuie rescris, el trebuie doar apelat n noul context; o alt implicaie este legat de fiabilitatea codului, deoarece prin motenire, o anumit funcionalitate este scris doar la nivelul unei clase i apoi motenit i utilizat n toate clasele derivate; consistena interfeei cnd dou sau mai multe clase sunt derivate din aceeai clas printe, se asigur faptul c comportamentul motenit este acelai pentru toate clasele; componentele software motenirea d posibilitatea programatorilor s construiasc componente software reutilizabile i gruparea lor n biblioteci; n acest fel, efortul de dezvoltare al unui produs nou este diminuat prin utilizarea de librrii cu funcionalitate deja implementat; dezvoltarea rapid de prototipuri atunci cnd sistemul software este construit folosindu-se componente reutilizabile, timpul de dezvoltare este concentrat pe nelegerea elementelor specifice ale sistemului; astfel se construiesc versiuni de sistem, numite prototipuri, care pun accent pe aspectele critice ale sistemului. Un prototip este dezvoltat, utilizatorii l folosesc, iar a doua versiune a sistemului este realizat pe baza experienei acumulat cu prima i a feedbackului de la utilizatori. Dei motenirea prezint foarte multe avantaje, exist i o serie de costuri de care trebuie s se in seama n momentul proiectrii ierarhiilor de clase: viteza de execuie este influenat prin prisma faptului c metodele motenite, care au un caracter mai general, sunt de regul mai lente dect codul specializat; ns afectarea vitezei de execuie este compensat cu creterea vitezei de dezvoltare; dimensiunea programelor este influenat n sensul c devine mai mare n cazul programelor care folosesc librrii de componente, dect programele care folosesc cod specializat, deoarece nu toate componentele dintr-o librrie sunt folosite n proiect, dar librria trebuie adugat n totalitatea sa; complexitatea programelor o ierarhie de clase introduce un anumit grad de complexitate n sistem; cu ct ierarhia este mai mare, nivelurile de abstractizare mai multe, cu att sistemul care folosete aceast ierarhie este mai complex.

S-ar putea să vă placă și