Sunteți pe pagina 1din 13

L2 CLASE C++. DECLARARE. IMPLEMENTARE.

INSTAN|IERI UTILITATEA OPERATORULUI "::" Atributele unei date utilizate n C++ sunt: - tipul care indic modul de memorare i operaiile permise; - clasa de memorie prin care se specific locul unde este memorat data respectiv; - durata de existen care reprezint intervalul de timp n care exist acea dat; - accesibilitatea care arat posibilitatea de acces la acea dat; - scopul care pune n eviden domeniul de vizibilitate al datei. Conectarea unor astfel de atribute (cunoscute din ANSI C) la variabile, poate fi: 1. static (intern) - n faza de compilare compilare ; 2. dinamic - n faza de execuie a programului ; 3. extern - cnd datele utilizate n modulul curent, aparin unui alt modul. Exist concepte care nu se pot implementa n limbajul C++, folosind tipurile predefinite de date, cum ar fi: ir de caractere, numr complex, list, arbore etc. Pentru un astfel de concept se va defini de ctre utilizator un tip abstract de date, care const ntr-o colecie de date ce admit aceeai reprezentare mpreun cu setul de operaii ce se pot efectua cu aceste date. n OOP, clasa constituie o generalizare a noiunii de tip de date, un ansamblu de obiecte similare (aceeai structur a datelor acionate de aceleai metode). Tipul abstract de date, definit de utilizator printr-o clas, se comport ca un tip predefinit. Cel mai frecvent tip_clas, utilizat n programarea orientat pe obiect, este class. Un obiect reprezint un element (o instan) al clasei respective. Clasa o putem interpreta ca o abstractizare logic, iar obiectul de tipul clasei respective, ca o existen fizic. Compilatorul ascunde detaliile interne ale acestui tip de date fa de mediu extern. Definiia unei clase cuprinde: a) declaraia clasei (specificarea datelor i prototipurilor funciilor componente, definiiile funciilor inline) ntr-un fiier antet ( care are identificatorul ncheiat cu .h sau .hpp); b) implementarea clasei (definiiile funciilor componente) pstrat ntr-un alt fiier ( pentru unele compilatoare identificatorul unui astfel de fiier se ncheie cu .cpp).

Declararea unei clase este similar cu a unei structuri: class id-clas { // date i funcii particulare specificator de acces: // date i funcii } list de obiecte; Lista de obiecte este opional. n mod implicit, datele i funciile declarate ntr-o clas devin proprii clasei respective. De aceea, ele se vor numi date membre, respectiv funcii membre (metode) ale acelei clase. Domeniul unui identificator de clas este local i ncepe din momentul declarrii clasei i se ncheie la finele blocului respectiv. Dac o clas este declarat n afara oricrei funcii, domeniul su este ntregul fiier. Domeniul membrilor unei clase coincide cu domeniu clasei respective. 11

n general, o clas conine: - o parte protejat care are rolul de a asigura implementarea clasei; - o parte public care reprezint interfaa clasei respective cu celelalte clase prezente n program. Protecia membrilor ntr-o clas se asigur cu ajutorul unor specificatori de acces / modificatori de protecie: public, protected, private. ntr-o clas, la finalul cuvntului cheie, care precizeaz modul de acces, se afl ntotdeauna ":". La membrii aflai sub aciunea specificatorului private se permite accesul doar prin funciile membre ale clasei respective i prin funcii friend (prieten) ale sale (vezi L 5). Membrii unei clase, declarai n seciunea public, pot fi accesai i din alte puncte ale programului C++, din exteriorul clasei respective. Specificatorul protected are aceleai caracteristici ca i private, n plus, membrii astfel protejai sunt accesibili i claselor derivate (vezi L7).

Prototipurile funciilor membre se afl n declaraia clasei respective, iar definiiile lor (cu excepia celor inline) se dau n exteriorul declaraiei clasei, folosind operatorul de rezoluie de domeniu "::". Acesta indic faptul, c domeniul funciei respective este acelai cu domeniu clasei din care face parte. Sintaxa definiiei unei funcii membre a unei clase: tip id_clas::id_func_membr(...){...}; Exemplu: class A { //declarare clas private: int u,v,w; //declarare (explicit) de variabile membre protejate public: void prelucreaza(int fu,int fv,int fw); //prototip funcie membr public }; void A::prelucreaza(int fu,int fv, int fw) //definirea funciei membr { u+=fu; v+=fv; w+=fw; }

A o1,o2,o3; // instanieri ale clasei A O instaniere a unei clase const n declararea unei variabile (un obiect) de tipul clasei respective. Prin construcia o1.prelucreaza(3,4,5); se observ c obiectul o1 apeleaz funcia membr "prelucreaza" cu parametrii efectivi 3,4,5. Efectul const n adunarea acestor valori la valorile variabilelor membre corespunztoare lui o1.

n C++, obiectele unei clase se pot manipula folosind funciile membre i operatorii definii pentru acea clas. O astfel de funcie, ca i n C, accept, de regul, unul sau mai muli parametri i returneaz o valoare. Mecanismul de transmitere prin valoare const n primirea de ctre funcie a parametrilor actuali ntr-o stiv (stack), care este o structur de date de tip LIFO. Aceast funcie preia parametrii din stiv i i folosete n blocul su, fr a avea acces la 12

locaiile lor de memorie. Ea folosete doar copii locale ale acestor parametrii, care vor fi eliminate din stiv la revenirea din funcie. Prin urmare, printr-un astfel de mecanism, funcia respectiv nu-i poate modifica parametrii cu care a fost apelat. n C++, se utilizeaz conceptul de referin, nume alternativ pentru un obiect, care poate fi utilizat la fel ca obiectul referit. Referina reprezint adresa obiectului respectiv, deosebinduse de pointer prin faptul, c ea nu este o variabil real. Ea este iniializat n momentul definirii i valoarea ei nu se poate modifica ulterior. Exemplu: int *p ; // pointer la un ntreg (neiniializat) int &a_1=a; //referin la o variabil ntreag

Exemplu: void acces(int &a, int v){a=v;} Se observ c a este un parametru de tip referin. Exist diferene ntre apelul cu pointeri i apelul cu referine. Operatorul de apartenen, n prima situaie, este ->, iar, n a doua situaie, este .. Exemplu: int k; acces(k,30); //apelul funciei cu parametru tip referin. Nu se transmite adresa. Exemplu: // transmiterea parametrilor prin pointer, referin, valoare struct data_c { int zi; int luna; int an; } void ind_dat(data_c *d) // parametru - pointer { int z,l,a; z=d->zi; cout<<z<<\n; l=d->luna; cout<<l<<\n; a=d->an; cout<<a<<\n; } void ind_dat_1(data_c &d) //parametru - referin { int z,l,a; z=d.zi; cout<<z<<\n; l=d.luna; cout<<l<<\n; a=d.an; cout<<a<<\n; } void ind_dat_2(data_c d) //parametru - valoare { int z,l,a; z=d.zi; cout<<z<<\n; l=d.luna; cout<<l<<\n; 13

a=d.an; cout<<a<<\n; } // Apelul: data_c data_crt; int_dat(&data_crt); int_dat_1(data_crt); int_data_2(data_crt); Ca o concluzie, referina se folosete n transmiterea de parametri, dac: a) funcia trebuie s modifice parametrii actuali de la apel; b) funcia nu modific parametrii actuali, dar trebuie evitat copierea obiectelor n stiv (economie de memorie). n acest ultim caz, se va folosi specificatorul const, pentru a indica faptul, c parametrul transmis prin referin, nu trebuie modificat de funcia respectiv. Exemplu: void ind_dat_3(data_c const &d) { int z,l,a; z=d.zi; cout<<z<<\n; l=d.luna; cout<<l<<\n; a=d.an; cout<<a<<\n; } n aceast situaie nu exist riscul ca funcia s modifice, n mod accidental, parametrul. Valoarea returnat de funcie poate fi o referin la un obiect, dac dorim s folosim aceast valoare ca membru stng al unei atribuiri. Acest lucru este valabil doar atunci cnd suntem asigurai de faptul, c obiectul respectiv exist i dup revenirea din funcie. Exemplu: // urmtoarea funcie va returna o copie a celui de al k-lea element dintr-un //ir? Explicai ce se ntmpl n urmtoarele situaii. char tab(char*s, int k) { return s[k];} char &tab(char *s, int k) { return s[k];} char ch; char*s=INFORMATICA; ch=tab(s,10); ch=I; ntr-o declaraie de clas se poate modifica accesul ori de cte ori este necesar. 14

Exemplu: # include<iostream.h.> # include <.string.h> class salariat { char nume[30]; // dat membr ( declarat la fel ca n C ) public: void scrie_n(char *n); void cit_n(char *n); private: double salariu; public: void scrie_s(double s); double cit_s( ); }; void salariat ::scrie_n(char *n) { strcpy(nume,n); } void salariat::cit_n(char *n) { strcpy(n,nume); } void salariat ::scrie_s(double s) {salariu=s;} double salariat ::cit_s( ) {return salariu;} main ( ){ salariat George; char nume[30]; George.scrie_n("George Popescu");//accesarea cu operatorul "." George.scrie_s(800000); George.cit_n(nume); cout<<nume<<"are suma:"; cout<<George.cit_s( )<<"pe lun"; return 0; } Tipurile struct i union reprezint cazuri particulare de clase care se distaneaz de conceptul OOP. Diferene ntre class i struct: - datele membre n struct, n mod implicit, sunt publice. - membrii din class, n mod implicit, sunt protejai privat.

Operatorul :: mai este numit i operator de scop. Scopul i accesibilitatea unui identificator se pune n eviden cu ajutorul acestui operator. Sintaxa: ::variabil operator;

Exemplu: .. int i; // declararea lui i ca variabil global void f1(void) { 15

int i; // declararea lui i ca variabil local n funcia f1 .. i++; // incrementarea lui i, variabil local n funcia f1 .. } void f2(void) { int i; // declararea lui i ca variabil local n funcia f2 ::i++; // incrementarea lui i global dei este mascat de declararea unui i // local .. } n stnga operatorului :: se poate afla cel mult un identificator de clas. n C++, variabilele locale pot fi create n orice poziie din cod. Exemplu: // utilizm C++ ca extensie a lui C

# include <stdio.h> int k=70; //variabil global int main( ) { .. for(register int k=1; k<30; k++ ) //declarare variabi local k { printf("%d\n",::k/k);} // se refer la mprirea variabilei globale la variabila local return 0; } S se rescrie acest segment de program folosind construciile proprii lui C++. Se pot folosi, cnd este util, nume de funcii standard de bibliotec (read, write,fopen etc.) drept nume de funcii utilizator, urmnd a fi reutilizate ntr-o anumit manier. Exemplu: //definirea funciei utilizator int A::fopen(char*pn="fis.dat",char*pa="rt") { .. ::fopen(pn, pa); // apel la funcie de bibliotec }

Din urmtorul exemplu reiese cum se poate utiliza operatorul "::" n cadrul unei funcii membre att cu variabile membre ct i cu variabile globale.

Exemplu: int v=20; // declarare variabil global cu domeniul de tip fiier care ncepe // din acest punct class beta { int v; // declarare variabil membr void f( ); //declarare funcie membr (prototip) } c1,c2; 16

void beta::f( ) //definiia funciei membr { v++; // incrementarea variabilei membre v ::v++; //incrementarea variabilei globale v } Cum se poate utiliza o construcie de forma: ID_CLASA::MEMBRU ? Exemplu: class A { int c; //declararea unei variabile membre public: void f( ); }; void A::f( ) { int y;//declararea unei variabile locale diferit de variabila membr int c; // declararea variabilei locale c n funcia membr A::c=300; // se refer la variabila membr c c++; // se incrementeaz variabila local c } Una din motivaiile prezenei identificatorului clasei n faa operatorului "::" este impus i de faptul, c trebuie s se disting funciile cu acelai identificator care aparin la clase diferite. n plus, se permite operarea direct cu variabila membr, fr precizri suplimentare cu privire la identitatea sa. Mai exact, toate variabilele folosite ntr-o funcie membr a unei clase i nedeclarate n ea, se presupun, n mod implicit, ca fiind membre ale acelei clase. Dac prin procesul de compilare nu se stabilete aceasta, se va trece la identificarea lor ca variabile globale. O dat membr a unei clase, nu poate fi de tipul definit prin clasa respectiv, dar poate fi pointer ctre tipul respectiv, sau o referin la acest tip. Exemplu: class A { A*p; . A&r; }; Dac revenim la cele dou posibiliti de implementare ale unei clase, una structural i cealalt orientat pe obiecte, se poate observa c mai apare o diferen de form. n timp ce prima se bazeaz pe transmiterea de parametri prin adres, cea de-a doua ar prea c renun la acest mod de transmitere. n realitate, fiecare funcie membr posed un argument ascuns, numit this, care se transmite automat funciei de ctre compilator. Acest argument este un pointer ctre obiectul care apeleaz funcia. Orice apel la o funcie membr a unei clase, poziioneaz acest pointer la obiectul de tipul clasei respective, care acioneaz apelul. n momentul apelului, acest pointer apare ca un parametru suplimentar, care nu este vizibil n mod direct. Ne putem referi la acest pointer prin cuvntul cheie this, care n OOP este cunoscut ca pointer la self. Fiind un cuvnt cheie, el nu se poate declara explicit, ci numai implicit. n orice funcie nestatic membr a unei clase A, pointerul this este declarat implicit. 17

A*this; El este necesar la scrierea funciilor membre care manipuleaz direct pointeri i nu la referiri de membri. Exemplu: //o secven cu privire la inserarea unui nod ntr-o list dublu nlnuit class lista_d{ lista_d *prec; lista_d *succ; public: void insert(lista_d *) .. }; void lista_d::insert(lista_d *p) { p->succ=succ; p->prec=this; succ->prec=p; succ=p; } n ultimele instruciuni, dac am utiliza n mod explicit operatorul this, ar rezulta: p->succ=this->succ; this->succ->prec=p; this->succ=p; Cu toate c utilizarea explicit a pointerului this se ntlnete mai rar, el poate fi menionat n cadrul unei funcii membre. Exemplu: # include<stdio.h> # include<iostream.h> # include<string.h> # include<conio.h> class student { public: char nume[30]; int Scrie(char*n,long t=0); void Afis( ); void Afis1( ); long Telefon( ); long tel; }; // mai multe implementari in aceeasi clasa - caracteristica a functiilor membre void student::Afis( ) { for(int k=0;k<35;k++) printf("*"); printf("\n"); printf("Numele studentului:%s\n",nume); printf("Telefonul:%ld\n",tel); }

void student::Afis1( ) { for(int k=0;k<35;k++)printf("*"); printf("\n"); printf(" Numele studentului:%s",this->nume); printf("\n"); printf("Telefonul:%ld\n",this->tel); 18

} // In aceasta situatie, utilizarea explicita a pointerului this, nu este necesara long student::Telefon( ){return tel;} // functie de acces care are rolul doar de a returna valoarea unei date int student::Scrie(char*n,long t) { clrscr( ); strcpy(nume,n); tel=t; return 1; } char*Nume="Vlad Stefanita"; long Telefon=198764; void main( ) { student s; s.Scrie(Nume,Telefon); s.Afis( );printf("\n"); s.Afis1( ); }

Exist situaii n care este obligatorie utilizarea pointerului this. De exemplu, atunci cnd se dorete ca unei funcii membre a unui obiect s i se transmit adresa obiectului respectiv (vezi implementarea unei stive). De reinut faptul, c o funcie de acces are scopul de a verifica coninutul unei date, nainte ca aceasta s fie, eventual, modificat. Modificarea unor date private este permis numai prin intermediul funciilor membre.

Aplicaie: S se implementeze tipul abstract complex pentru calculul sumei a dou numere complexe. #include <iostream.h> #include <conio.h> class complex { int re[10]; int im[10]; public: int cit(void); void afis(); int sum_1(void); int sum_2(void); }; int complex::cit(void) { for(int i=1;i<=2;i++){ cout<<"\n Dati partea reala a numarului complex_1:"; cin>>re[i]; cout<<"\n Dati partea imaginara a numarului complex_2:"; cin>>im[i]; } return 1; } 19

int complex::sum_1(void) { int s1=0; for(int i=1;i<=2;i++) s1+=re[i]; return s1; } int complex::sum_2(void) { int s2=0; for(int i=1;i<=2;i++) s2+=im[i]; return s2; } void complex::afis() { cout<<"\n Suma numerelor complexe:" } void main() { complex c; clrscr(); c.cit(); c.afis(); }

<<sum_1()<<"+i*"<<sum_2();

Aplicaie: S se implementeze clasa student n care s se foloseasc urmtoarele funcii membre: o funcie prin care s se citeasc numele, prenumele i notele obinute la o sesiune de examene de ctre un student; o funcie pentru afiare; o funcie pentru calculul mediei de promovare. #include <iostream.h> #include <conio.h> #include <math.h> class student{ char nume[20]; char prenume[20]; int nota[5]; public: int id_student(void); void afis(void); double media(void); }; int student::id_student(void) { cout<<"\n Nume student:"; cin>>nume; cout<<"\n Prenume student:"; cin>>prenume; for (int k=1;k<=5;k++) { cout<<"Nota"<<k<<"\n"; cin>>nota[k];} return 1; 20

} void student::afis(void) { cout<<"\n Nume student:"; cout<<nume; cout<<"\n Prenume student:"; cout<<prenume<<"\n"; for (int k=1;k<=5;k++) { cout<<"Nota"<<k<<"\n"; cout<<nota[k]; cout<<"\n"; } cout<<"\n Media:"; cout<<media(); } double student::media(void) { double m=0.0; for (int k=1;k<=5;k++) if(nota[k]<5){cout<<"\n Student restantier"; cout<<"\n Nu se calculeaza media!"; return 0; } else m = m+nota[k]; if (nota[k]<5)return 0; else return m/5; } void main (void) { student s; clrscr(); s.id_student(); s.afis(); getch(); }

Aplicaie: S se scrie un program C++ pentru calculul ariei i perimetrului unui dreptunghi folosind dou clase (Punct, Dreptunghi). #include <iostream.h> #include <conio.h> class Punct{ float x,y; public: void init(float, float); float df_x(Punct&); float df_y(Punct&); 21

}; void Punct::init(float a, float b) {x=a;y=b;} float Punct:: df_x(Punct &a) { float d; d=a.x-x; return d; } float Punct:: df_y(Punct &a) { float d; d=y-a.y; return d; } class Dreptunghi { Punct p_st_sus,p_dr_jos; public: void init(float,float,float, float); float Aria(void); float Perimetru(void); }; void Dreptunghi::init(float xs,float ys,float xd, float yd){ p_st_sus.init(xs,ys); p_dr_jos.init(xd,yd); } float Dreptunghi::Aria(void) { float l,L,a; l=p_st_sus.df_y(p_dr_jos); L=p_st_sus.df_x(p_dr_jos); a=l*L; return a; } float Dreptunghi::Perimetru(void) { float l,L,p; l=p_st_sus.df_y(p_dr_jos); L=p_st_sus.df_x(p_dr_jos); p=2*(l+L); return p; } void main(void) { Dreptunghi dr; float arie,perim; dr.init(1,20,15,1); arie=dr.Aria(); perim=dr.Perimetru(); cout<<"Aria="<<arie<<"\n Perimetru = "<<perim<<"\n"; getch(); } TEMATIC PROPUS 22

1. S se scrie un program C++ pentru calculul ariei i perimetrului unui triunghi, ptrat, romb,trapez etc. (vezi ultima aplicaie).
2.

S se defineasc tipurile abstracte Punct i Vector. S se citeasc coordonatele a doi vectori din plan i s se afieze norma i produsul lor scalar. S se defineasc un tip abstract List. Implementai o list simplu nlnuit i efectuai operaii ca: inserarea unui nod n anumite condiii date, tergerea unui nod, concatenarea a dou liste, folosind funcii membre corespunztoare.

3.

4. S se scrie un program C++ prin care s se obin o implementare a clasei numerelor raionale. Definii funcii membre corespunztoare pentru a realiza o conversie a datelor de tip ntreg sub form raional. 5. S se realizeze un program C++ pentru implementarea unei structuri tip stiv, respectiv coad. Definii funcii membre care s acioneze n astfel de structuri conform operaiilor cunoscute.
6.

Folosii, n programele ce rezolv problemele anterioare, transmiterea de parametri prin valoare, pointeri i referin. Precizai de fiecare dat ce deosebiri exist.

23