Sunteți pe pagina 1din 15

L4 MEMBRII DE TIP STATIC NTR-O CLAS

Att funciile ct i datele membre ale unei clase se pot declara static. n mod firesc, un obiect posed o copie proprie a variabilelor instaniate ale clasei din care provine. Exist posibilitatea de a defini membrii care sunt comuni tuturor obiectelor clasei respective. Ei sunt membri statici i se vor declara cu ajutorul cuvntului cheie static. Aadar, spre deosebire de membrii obinuii ai unei clase, pentru membrii de tip static, nu se mai creaz copii individuale pentru fiecare obiect, indiferent de numrul de obiecte ale clasei respective. Cnd se creaz primul obiect, toate variabilele de tip static sunt iniializate cu zero.

Trebuie neles, c n C++, o declaraie este echivalent cu o descriere a datei respective, iar o definire nseamn de fapt, existena acelei date. De aceea, cnd se declar o dat membr static ntr-o clas, nu o definim i deci nu i se aloc memorie. Pentru aceti membri statici trebuie s se dea o definiie global n exteriorul clasei. Este necesar a se face o distincie ntre utilizarea cuvntului cheie static prin care se declar variabile statice i membrii statici ai unei clase. Exemplu: class secvena{ public: char*caractere; int dim,lung; static char ss; //membru static secvena(int d); //constructor cu un parametru . }; void main( ) { secvena o1,o2,o3; // instaniere fr iniializare . };

Fiecare din cele trei obiecte o1,o2,o3 aparin aceleiai clase secvena. Ele vor avea un "coninut" propriu (dim,lung), dar cu un acelai sfrit de ir de caractere "ss" prezent ca membru static. Faptul c se va aciona asupra tuturor celor trei obiecte de acest tip va fi pus n eviden printr-o declaraie de forma: tip id_clas::id_membru_static= Exemplu: char secvena::ss='$'; ceea ce este mai convenabil dect succesiunea secvena o1(60); o1.ss='$';. Exemplu: # include <iostream.h> class exemplu{ static int x;//membru static al clasei exemplu int y; public: void init(int , int ); void afi( ); }; int exemplu::x; //definete x n exteriorul clasei void exemplu::afi( ){

42

cout<<"Scrie pe x (static):"<<x; cout<<"Scrie pe y (nestatic):"<<y; cout<<"\n"; }; void exemplu::init(int a,int b){x=a;y=b;} void main( ){ exemplu u,v; u.init(1,1); //se iniializeaz x cu 1 u.afi( ); v.init(3,3); //valoarea lui x se schimb, devine 3 v.afi( ); u.afi( ); //valoarea lui x se schimb, pentru c x este comun pentru ambele // obiecte } Se observ c x a fost declarat ca membru static n clasa exemplu, dar, obligatoriu, este definit n exteriorul acestei clase pentru a i se putea aloca memorie.

Instanierea unui membru static se poate face fie n programul principal, fie naintea sa, dar nu n declararea unei clase. De regul,instanierea membrilor statici se va realiza n acelai fiier n care se implementeaz metodele (funciile membre) ale clasei respective.

Cnd se iniializeaz un membru static nu se menioneaz cuvntul cheie static. Exemplu: #include<iostream.h> class model { public: static int k; }; int model::k; //definirea variabilei statice k main() { model::k=1999;//initializarea cout<<"Valoarea initiala a lui k:"<<model::k; cout<<"\n"; model b; // creare obiect al clasei model cout<<"Valoarea lui b.k:"<<b.k; return 0; } Se observ c variabila membr k este declarat static. Ea exist nainte de a fi creat orice obiect al clasei respective, i se poate iniializa oriunde. Variabila k fiind o variabil static i public, se poate utiliza direct n funcia principal main( ). }i dup creerea obiectului b, valoarea lui k rmne nemodificat.

De regul, variabilele membre statice, se folosesc cu scopul de a asigura controlul accesului la unele resurse comune. Mai exact, se pot crea mai multe obiecte, fiecare avnd posibilitatea s scrie ntr-un fiier pe disc. Deoarece, doar un singur obiect are dreptul s scrie ntr-un fiier la un moment dat, vom declara o variabil static care va indica momentul n care este folosit fiierul i cnd acesta este liber. Fiecare obiect va controla aceast variabil static nainte de a scrie n fiier.

Exemplu: #include <iostream.h>

43

class control { static int gest; public: int ocup(); void liber(){gest=0;} }; int control::gest; //se defineste variabila statica gest int control::ocup() { if(gest)return 0; //opereaza gest else{ gest=1; return gest;} // gest este assignata obiectului } main() { control ob_1,ob_2; if(ob_1.ocup()) cout<<"ob_1 are acces la gestn"; if(!ob_2.ocup()) cout<<"ob_2 nu are acces la gestn"; ob_1.liber(); //gest este liber if(ob_2.ocup()) cout<<"ob_2 poate folosi gestn"; return 0; } Datele membre statice se iniializeaz n afara constructorilor tocmai pentru c o astfel de dat reprezint o zon comun care nu se multiplic la fiecare instaniere a clasei respective. De aceea, o astfel de iniializare se produce odat cu definirea datei respective, n exteriorul oricrei funcii. Exemplu: class student { char nume[25]; int vrsta; static int an_stud; static long int bursa; }; Iniializarea datelor membre statice: int student::an_stud=2; long int student::bursa= 800000; Dac ar lipsi identificatorul clasei i operatorul "::", datele respective ar deveni date globale care se iniializeaz cu valorile respective. Asignri de forma: student::an_stud=2; student::bursa= 800000; sunt admise dac ele se afl n corpul unei funcii membre (date protejate) a clasei respective.

44

Astfel de atribuiri, de regul, nu se consider iniializri i se folosesc, cnd se apeleaz funcia membr care le conine. O astfel de iniializare nu se accept pentru date membre statice. Dac astfel de date nu sunt corect iniializate, ele vor primi automat valoarea zero, dac este setat opiunea iniializare implicit cu zero. Exemplu: #include<iostream.h> #include<math.h> class complex { float re,im; static int nr_ob; //variabil membr static public: char c; void afis( ); static void init(int,int); //funcie membr static (prototip) }ob; void complex::afis( ){cout<<ob.re<<"+i*("<<ob.im<<")";} void complex::init(int a,int b){ob.re=a;ob.im=b;} void main( ) { char c; int nr_ob=0,b_2=8,b_1=32; complex o1; o1.init(b_1++,b_2--); nr_ob++; o1.afis ( ); cout<<"n"; do{ complex o1; o1.init(b_1++,-b_2--); nr_ob++; o1.afis( ); cout<<"\n"; }while (b_2!=0); cout<< \n"; cout<<"Nr_obiecte create:"<<nr_ob; } Nu se accept iniializarea unor variabile membre statice, dac domeniul de existen al clasei respective este local. Membrii statici privai se pot iniializa n acelai fel, dar accesul la ei va respecta regimul privat.

Variabilele globale, ca i membrii statici, au acelai rol, dar numele lor nu va fi protejat n interiorul unei clase. Dac se folosesc membrii statici, se obine o combinaie ntre date globale i locale prezente n acea clas. Utilizarea variabilelor membre statice conduce la eliminarea a ct mai multe variabile globale din program. Analizai urmtoarea secven i semnalai erorile care apar: class punct { public: static int x0,y0; int x,y;

45

punct(int xi, int yi); }; punct::x0=28; static int y0=30; int punct::x0=28; int punct::y0=30; Un pointer la un membru static al unei clase este interpretat ca un pointer obinuit, n schimb, el se deosebete de cel obinuit prin sintaxa definirii lui. Exemplu: class A { public: //....................... static float f; private: //....................... }; // Se definete un pointer la variabila membr static a clasei A float *p.f=&A::f; Exist o serie de restricii atunci cnd se declar static unele funcii membre ale unei clase: a) Ele au acces doar la membrii de tip static ai clasei i bineneles, la funciile i datele globale. b) Nu pot avea un pointer de tip this. c) Nu poate exista, pentru aceeai funcie, o versiune static i una nestatic. d) Funciile membre statice au aplicaii limitate, iar o corect utilizare a lor impune o preiniializare a datelor private de tip static, nainte de crearea efectiv a unui obiect. Exemplu: # include <iostream.h> class ex_static { static int k; public: static void init(int u){k=u;} void afi( ){cout<<k;} }; int ex_static::k; // definete obiectul k void main ( ) { ex_static::init(500); // se iniializeaz data static nainte de crearea obiectelor ex_static u; u.afi( ); }

O variabil constant se declar astfel: const tip iden_var=valoare; Exemplu: const int x=12;

Un obiect constant se declar astfel:

46

const tip_clas iden_ob(l1,l2,); Exemplu: const punct O(0,0);

Dac se declar un obiect constant, atunci este permis numai apelarea funciilor membre ale acestuia care au fost declarate constante. #ntr-o clas, funciile membre constante se declar utiliznd cuvntul cheie const plasat imediat dup nchiderea parantezelor ce cuprind parametrii funciei respective. Printre funciile membre ale unui obiect constant care pot fi apelate se afl i constructorii care nu vor fi declarai constani. class complex{ private: double re,im; public: complex(double x0, double y0){re=x0; im=y0;} int valoarea( )const {return;} void afis( ); .. }; void main( ) { const complex z(2,3); double w=z.valoare( ); . }

Exemplu:

Accesul la datele membre ale unei clase se poate realiza prin apelarea unei funcii de acces, aspect caracteristic ncapsulrii, dar el necesit un consum semnificativ de timp. Se tie c la apelul unei funcii, parametrii sunt depui n memoria stiv, sunt salvai n mai multe registre i apoi rememorai cnd se produce returnarea. Exist ns funciile inline, des utilizate n C++, care sunt folosite n mod uzual mpreun cu clasele. O astfel de funcie este o funcie de dimensiune mic care nu se apeleaz, codul ei dezvoltndu-se n interior, n fiecare punct n care se identific. Definiia ei este precedat de cuvntul cheie inline. Exemplu: # include <iostream.h> inline int min(int u, int v) { return u<v?u:v; } main( ) { cout<<min(100,50); return 0; }

O declarare inline implicit const n definirea unei astfel de funcii n corpul unei clase. Se poate vorbi i de o declarare explicit a unei astfel de funcii, dac ea este doar declarat n corpul clasei n care este funcie membr, iar definirea propriu-zis a sa se va face n exteriorul clasei folosind cuvntul cheie inline. O funcie definit n declararea unei clase, automat este transformat ntr-o funcie inline, chiar dac nu este precizat cuvntul cheie inline n definiia sa. Exemplu: class student

47

{ private: char nume[25]; char adresa[30]; public: char*Adresa( ) {return adresa;} // automat este o funcie inline char*Nume( ){return nume;} // idem }; Exist restricii referitor la funciile inline pentru c ele sunt expandate de compilator n expresii macro, deci n acel moment trebuie cunoscut corpul funciei, att ca form, ct i din punct de vedere al coninutului, fapt greu de realizat n cazul n care ele ar conine structuri repetitive. Exemplu: // utilizarea funciilor inline ca funcii membre ale unei clase # include <iostream.h> class A{ int u,v; public: void init(int k, int l); void afi( ); }; inline void A::init(int k, int l){u=k; v=l; } inline void A::afi( ){cout<<u<<" "<<v<<"\n";} void main( ) { A x; x.init(7,12); x.afi( ); } n acest exemplu, se observ cum se pot utiliza funciile inline ca funcii membre ale unei clase.

Aplicaie: S se implementeze o clas ir care s permit efectuarea unor operaii cu iruri, ca: iniializare, copiere, atribuirea unui ir unui alt ir, afiarea lor. Se vor utiliza constructori, destructor, funcii inline. #include <iostream.h> #include<conio.h> #include<string.h> class sir { char *ps; int lg; public: sir(char*s); sir(int nr_car=30); sir(const sir&); ~sir(); int ret_lg(); void afis(); }; sir::sir(char*s) { lg=strlen(s);

48

ps=new char[lg+1]; strcpy(ps,s); } sir::sir(int dim) { lg=dim; ps=new char[lg+1]; *ps='\0'; } sir::sir(const sir&s) { lg=s.lg; ps=new char[lg+1]; strcpy(ps,s.ps); } sir::~sir() { delete ps; } inline int sir::ret_lg() {return lg;} inline void sir::afis( ) { cout<<ps; cout<<"\n"; } void main( ) { sir s_1("C++ este o extensie a lui C"); sir s_2 ("C++ este un limbaj orientat pe obiect"); sir s_3("Se invata in anul II"); sir s_4=s_1; cout<<"s_1:"<<"\n"; cout<<s_1.ret_lg( )<<"\n"; s_1.afis( ); cout<<"s_2:"<<"\n"; cout<<s_2.ret_lg( )<<"\n"; s_2.afis( ); cout<<"s_3:"<<"\n"; cout<<s_3.ret_lg( )<<"\n"; s_3.afis( ); cout<<"s_4:"<<"\n"; cout<<s_4.ret_lg( )<<"\n"; s_4.afis( ); } Aplicaie: S se scrie un program C++ pentru citirea,validarea,afiarea unei date calendaristice curente i pe cea urmtoare ei. Se vor utiliza funcii declarate static i funcii inline. #include<iostream.h> #ifndef_STDIO.H #include<stdio.h> #define_STDIO.H #endif enum boolean{false,true};

49

class data_c { int zi,luna,an; static int min_z,min_l,min_a; static int max_z,max_l,max_a; static int tab_zi[13]; static char*tab_luna[13]; static char*min_err; static char*max_err; static char*err_dc; static void afis(char*sir); static void verif(); public: boolean valid_dc(); static boolean valid_dc_min(); static boolean valid_dc_max(); boolean an_bisect(); static boolean dc_min_bisect(); static boolean dc_max_bisect(); static boolean var_calend(int z,int l,int a); data_c(); data_c(int z,int l, int a); data_c(const data_c&); int ret_zi(); int ret_luna(); int ret_an(); void afis_dc(); data_c*dat_min(); data_c*dat_max(); void modif_min(); void modif_max(); int cit_dat(); boolean ad_zi(int z); long dif_dat(data_c*d); char*den_luna(); int zi_an(); boolean zi_luna(int z,int a); int nr_zile_luna(); }; int data_c::min_z=1; int data_c::min_l=1; int data_c::min_a=1900; int data_c::max_z=31; int data_c::max_l=12; int data_c::max_a=2010; intdata_c::tab_zi[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; char*data_c::tab_luna[13]={"lunainexist.","ian","feb", "martie","apr","mai","iunie","iulie","aug","sept","oct","nov","dec"}; char*data_c::err_dc="data calendaristica eronata \n"; char*data_c::min_err="data minima eronata \n"; char*data_c::max_err="data maxima eronata \n"; inline int bis(int a){ return a%4==0 && a%100==0 ||a%400==0;} boolean data_c::var_calend(int z,int l,int a) {

50

if(a<1900||a>2010) return false; if(a<data_c::min_a||a>data_c::max_a) return false; if(l<1||l>12)return false; if(a==data_c::min_a&&l<data_c::min_l||a==data_c::max_a &&l>data_c::max_l)return false; if(z<1||z>tab_zil+(l==2&&bis(a)))return false; if(a==data_c::min_a&&l==data_c::min_l&&z<data_c::min_z || a==data_c::max_a&&l==data_c::max_l&&z>data_c::max_z) return false; return true; } inline void data_c::afis(char*sir) {cout<<"Se afiseaza sirul_data"<<sir;} inline boolean data_c::valid_dc() { return var_calend(zi,luna,an); } inline boolean data_c::valid_dc_min() {return var_calend(data_c::min_z,data_c::min_l, data_c::min_a);} inline boolean data_c::valid_dc_max() {return var_calend(data_c::max_z,data_c::max_l, data_c::max_a);} boolean data_c::an_bisect() {if(bis(an)) return true; else return false;} boolean data_c::dc_min_bisect() { if(bis(data_c::min_a))return true; else return false; } boolean data_c::dc_max_bisect() { if(bis(data_c::max_a))return true; else return false; }

void data_c::verif() { if(data_c::valid_dc_min()==false) { data_c::afis(data_c::min_err); data_c::min_z=1; data_c::min_l=1; data_c::min_a=1900; } if(data_c::valid_dc_max()==false) { data_c::afis(data_c::max_err); data_c::max_z=31; data_c::max_l=12; data_c::max_a=2010; } } data_c::data_c(int z,int l,int a)

51

{ data_c::verif(); zi=z; luna=l; an=a; if(valid_dc()==false) { afis(data_c::err_dc); zi=data_c::min_z; luna=data_c::min_l; an=data_c::min_a;} } inline data_c::data_c() {data_c::verif();} data_c::data_c(const data_c &d) { zi=d.zi; luna=d.luna; an=d.an; if(valid_dc()==false) { afis(data_c::err_dc); zi=data_c::min_z; luna=data_c::min_l; an=data_c::min_a; } } inline int data_c::ret_zi(){return zi;} inline int data_c::ret_luna(){return luna;} inline int data_c::ret_an(){return an;} inline void data_c::afis_dc() { cout<<"ziua:"<<zi<<"\t"<<"luna:"<<luna<<"\t"<<"anul:"<<an; } data_c*data_c::dat_min() { data_c*d_min=new data_c(data_c::min_z,data_c::min_l,data_c::min_a); return d_min; } data_c*data_c::dat_max() { data_c*d_max=new data_c(data_c::max_z,data_c::max_l,data_c::max_a); return d_max; } void data_c::modif_min() { data_c::min_z=zi; data_c::min_l=luna; data_c::min_a=an; data_c::verif(); } void data_c::modif_max() { data_c::max_z=zi;

52

data_c::max_l=luna; data_c::max_a=an; data_c::verif(); } int data_c::cit_dat() { int i; for(;;){ for(;;){ cout<<"\n"; cout<<"ZIUA:"; cin>>i; if(i>0&&i<=31)break; if(cin.eof()) return 0; cout<<"Zi eronata \n"; fflush(stdin); //videaza zona de intrare } zi=i; for(;;){ cout<<"LUNA:"; cin>>i; if(i>0&&i<=12) break; if(cin.eof())return 0; cout<<"Luna eronata \n"; fflush(stdin); } luna=i; for(;;){ cout<<"ANUL:"; cin>>i; if(i>=1900&&i<=2010) break; if(cin.eof())return 0; cout<<"Anul eronat \n"; fflush(stdin); } an=i; if(valid_dc()==true)break; cout<<"Data calendaristica:"; cout<<zi<<"."<<luna<<"."<<an<<"este eronata"; } return 1; } int data_c::zi_an() { int b=bis(an); int z=zi; for(int i=1;i<luna;i++) z+=data_c::tab_zi[i]+(i==2&&b); return z; } boolean data_c::zi_luna(int z,int a) { int b=bis(a); if(z>365+b){ cout<<"Ziua:"<<z<<"este eronata \n";

53

return false; } if(a<1900||a>2010){ cout<<"Anul:"<<a<<"este eronat \n"; return false; } int i=1; do{ int j=data_c::tab_zi[i]+(i==2&&b); if(z<=j) break; z-=j; i++; }while(1); zi=z; luna=i; an=a; return valid_dc(); } inline char*data_c::den_luna() {returnluna<1||luna>12?data_c::tab_luna[0]:data_c:: tab_luna[luna]; } boolean data_c::ad_zi(int z) { int total_zi=zi_an(); total_zi+=z; int zile_din_an=365+bis(an); if(total_zi>=0) while(total_zi>=zile_din_an) { total_zi-=zile_din_an; an++; if(an<=2010) zile_din_an=365+bis(an); } else{ an--; zile_din_an=365+bis(an); while(total_zi>=zile_din_an) { total_zi+=zile_din_an; an--; if(an>=1900) zile_din_an=365+bis(an); } total_zi+=zile_din_an; } if(total_zi==0){ zi=31; luna=12; an--; return valid_dc(); } boolean bl=zi_luna(total_zi,an); return bl; }

54

long data_c::dif_dat(data_c*d) { long zi_an_1=zi_an(); long zi_an_2=d->zi_an(); long dif_zi=zi_an_1-zi_an_2; int an_1,an_2; if(an<d->an) { an_1=an; an_2=d->an; } else { an_1=d->an; an_2=an; } long dif_zi_an=0; while(an_1<an_2) { int b=bis(an_1); dif_zi_an+=365+b; an_1++; } if(an<d->an) dif_zi_an=-dif_zi_an; return dif_zi+dif_zi_an; } void main() { for(;;){ data_c data_cit; if(data_cit.cit_dat()==0) break; cout<<"ZIUA:"<<data_cit.ret_zi(); cout<<"\n"; cout<<"Luna:"<<data_cit.ret_luna(); cout<<"\n"; cout<<"ANUL:"<<data_cit.ret_an(); cout<<"Verif.data_cit:"; cout<<data_cit.var_calend(data_cit.ret_zi(), data_cit.ret_luna(),data_cit.ret_an()); data_c data_urm=data_cit; cout<<"\n"; cout<<"ZILE DIN AN:"<<data_cit.zi_an(); cout<<"\n"; cout<<"DENUMIREA LUNII CURENTE: " << data_cit.den_luna(); cout<<"\n"; cout<<"VALIDARE:"<<data_cit.valid_dc(); cout<<"\n"; cout<<"VERIF. DAT_MIN:"<<data_cit.valid_dc_min(); cout<<"\n"; cout<<"VERIF.DAT_MAX:"<<data_cit.valid_dc_max(); cout<<"\n"; cout<<"ZIUA URMATOARE:"; data_urm.ad_zi(1); cout<<"\n"; data_urm.afis_dc();

55

} } Tematica propus 1. S se scrie un program C++ care s citeasc, de la intrarea standard, o succesiune de date calendaristice, s le afieze mpreun cu datele calendaristice corespunztoare aceleeai zile, dar cu luna i anul urmtor celui precizat n data curent. 2. S se realizeze un program asemntor cu cel de la (1), prin care se cere afiarea datei curente (citit), numrul de zile din luna respectiv care urmeaz acestei date, anul bisect care precede, respectiv urmeaz anului curent. 3. Se consider matricele 1 0 2 0 si V = U = 1 1 1 1 asupra crora acioneaz de p ori urmtoarele operaii: T=U*V, V=U, U=T. S se determine elementele matricelor U i V dup efectuarea a p operaii descrise anterior, fr a calcula la fiecare pas aceste elemente. 4. Un vas are o capacitate de m litri. El se umple cu ap. Realizai un program C++ prin care s se poat distribui n mod egal aceast cantitate de ap, folosind alte dou vase cu capacitatea de (m/2)+1 respectiv (m/2)-1 litri (m este un multiplu de 4). 5. Se consider dou iruri de lungimi egale. Asupra lor pot aciona urmtoarele operaii: un caracter c din ir_1 care se afl pe poziia k i poate schimba locul cu cel care se afl pe poziia k-1 n acelai sir, dac Cod_ASCII_1(k) > Cod_ASCII_1(k-1) (unde prin Cod_ASCII_1(k) se nelege codul ASCII al caracterului care se afl pe poziia k n ir_1); aceeai operaie ca la punctul a) se poate realiza i asupra caracterelor din ir_2, dac Cod_ASCII_2(k) < Cod_ASCII_2(k-1); un caracter oarecare dintr-un ir i poate schimba locul cu un alt caracter din cellalt ir, dac ele ocup aceeai poziie n irurile respective. Dndu-se dou perechi de astfel de iruri (una considerat ca fiind iniial i cealalt final), scriei un program C++ prin care s se decid dac prin operaiile descrise mai sus, aplicate perechii iniiale, se poate ajunge la cea final. S se afieze, n caz afirmativ, irul transformrilor succesive care se realizeaz. Toate caracterele dintr-o pereche se consider distincte dou cte dou.

56

Evaluare