Sunteți pe pagina 1din 12

L7 MOTENIRE. CLASE DE BAZ.

CLASE DERIVATE Una dintre caracteristicile programrii orientate pe obiecte, ncapsularea, face posibil aplicarea mecanismului de motenire. Motenirea const n preluarea atributelor de la o clas numit clas de baz, la o alt clas numit clas derivat. Ca atare, clasele derivate posed toate caracteristicile clasei de baz, care pot fi mbuntite att funcional, ct i structural. O reprezentare a claselor sub aspectul motenirii conduce la o ierarhizare, adic o dispunere pe anumite nivele a acestora. Motenirea poate fi simpl sau multipl, dup cum clasa derivat motenete caracteristicile de la o clas de baz sau de la mai multe clase de baz. Derivarea claselor, n funcie de solicitri, reprezint un proces cu durat variabil, de aceea se recomand conceperea unor clase de baz ct mai simple. Procesul de motenire ofer o serie de avantaje care constau n: a) posibilitatea utilizrii unui cod comun pentru mai multe clase; b) obinerea extensiei unei clase fr a fi necesar o recompilare a clasei iniiale; c) ansa funciilor, care folosesc obiecte din clasa de baz, de a dispune i de obiecte dintr-o clas derivat a sa. d) utilizarea polimorfismului n timpul execuiei programului prin folosirea funciilor virtuale [L9] etc. Reutilizarea codului este posibil n programarea orientat pe obiecte, sub dou aspecte: 1) prin compunere - includerea de obiecte n cadrul altor obiecte; 2) prin motenire - crearea unor obiecte folosind o colecie de obiecte existente la un moment dat. Prin compunere, obiectul, care include un alt obiect, va avea ca elemente membre, toate elementele membre ale obiectului inclus, alturi de cele specifice lui. Accesul la membrii obiectului inclus se va realiza prin intermediul acestui obiect. # include<iostream.h> class punct { public: float u,v; void pp(float a, float b){u=a; v=b;} }; class cerc { public: punct O; float r; void dr(float raza){r=raza;} }; void main( ) { punct O;

Exemplu:

76

O.u=7.9; cerc c; c.dr(12); // c.r=12 c.O.pp(7.5,10.5); // c.O.a=7.5 , c.O.b=10.5 } Operaia de derivare obinut prin procesul de motenire constituie o variant mult mbuntit de reutilizare a codului. Sintaxa: class iden_clas_derivat: specificator_acces iden_clas_baz { // corpul clasei derivate }

Accesul la membrii din interiorul clasei derivate este determinat de specificatorul de acces. Accesul n clasa de baz poate fi public, private sau protected. Dac o clas derivat este de tip class i nu se precizeaz specificatorul de acces, atunci implicit va fi private, iar n cazul clasei derivate de tip struct, va fi public. Drepturile de acces ale clasei derivate asupra membrilor clasei de baz:

Specificator de acces sau Drept de acces n modificatorul de clasa de baz protecie din lista claselor de baz PUBLIC PUBLIC PRIVATE PUBLIC PROTECTED PUBLIC PUBLIC PRIVATE PRIVATE PRIVATE PROTECTED PRIVATE

Drept de acces n clasa derivat PUBLIC inaccesibil PROTECTED PRIVATE inaccesibil PRIVATE

n general, protected nu este folosit ca specificator de acces n procesul de motenire. Rolul su este de a permite accesarea unor membri care nu fac parte din seciunea public a clasei de baz, n clasa derivat. Indiferent de specificatorul de acces (public sau private) folosit, membrii din seciunea private a clasei de baz nu pot fi direct accesai n clasa derivat. Accesarea lor se face prin funciile membre motenite de la clasa de baz.

Folosind specificatorul de acces public, se mai spune, c transformm clasa de baz ntr-o clas public. Membrii protejai (protected) din clasa de baz rmn protejai i n clasa derivat. Dac se utilizeaz specificatorul de acces private, clasa de baz devine privat i toi membrii declarai public n ea devin privai n clasa derivat. Membrii protejai din clasa de baz devin privai n clasa derivat. Clasele derivate sunt tratate ca subclase ale clasei de baz, obiectele derivate pot fi atribuite obiectelor clasei de baz, fr a fi necesar conversia de tip. #n astfel de atribuiri se vor copia

77

numai membrii clasei de baz. Astfel de atribuiri nu se pot realiza dect cu obiecte bazate pe relaia de motenire. Exemplu: # include <iostream.h> class B // def.clasei de baz B { int k,l; public: void punct(int a,int b){k=a; l=b;} void afis( ){cout<<k<<" "<<l<<"\n";} }; class D:public B // def. clasei derivate D { int u; public: D(int w){u=w;} void afis_1( ){cout<<u<<"\n";} }; main( ) { D ob(5); ob.punct(6,9); // acces la un membru al clasei de baz B ob.afis( ); // acces la un membru al clasei de baz B ob.afis_1( ); // acces la un membru al clasei derivate D return 0; } Exemplu: #include<iostream.h> #include<conio.h> #include<math.h> #include<string.h> class baza { protected: int x; int y; public: baza(int xi=1,int yi=2) { x=xi; y=yi; } float r_x(){return x;} float r_y(){return y;} }; class derivata:public baza { protected: int k,l; public: derivata(int q=5,int p=3):baza(q,p) {k=q;l=p;} };

78

float ad_1(baza b,derivata d) { float f; f=b.r_x()+d.r_x(); return f; } float ad_2(baza b,derivata d) { float f_1; f_1=b.r_y()+d.r_y(); return f_1; } float dif_1(baza b,derivata d) { float f_2; f_2=b.r_x()-d.r_x(); return f_2; } float dif_2(baza b,derivata d) { float f_3; f_3=b.r_y()-d.r_y(); return f_3; } void main() { float u_1,u_2,u_3,u_4; clrscr(); baza b; derivata d; float f1,f2,f3,f4,f5; cout<<"\n"; u_1=b.r_x(); cout<<u_1; cout<<"\n"; u_2=b.r_y(); cout<<u_2; u_3=d.r_x(); cout<<"\n"<<u_3; u_4=d.r_y(); cout<<"\n"<<u_4; cout<<"\n"; f1=ad_1(b,d); cout<<"\n"<<f1; f2=ad_2(b,d); cout<<"\n"<<f2; f3=dif_1(b,d); cout<<"\n"<<f3; f4=dif_2(b,d); cout<<"\n"<<f4; cout<<"Lungimea segmentului:"; f5=sqrt(f4*f4+f3*f3); cout<<"\n"<<f5; derivata t(f1,f2); f3=dif_1(b,t);

79

cout<<"\n f3="<<f3; f4=dif_2(b,t); cout<<"\n f4="<<f4; cout<<"\n Lungimea noului; cout<<segment:"<<sqrt(f3*f3+f4*f4); } Se observ c specificatorul de acces fiind public (motenire public), obiectele de tip derivat (din clasa derivat) pot accesa direct membrii publici din clasa de baz.

Nu este permis transformarea unui membru private al clasei de baz ntr-un membru public sau protected al clasei derivate. Conversia de tipul (C_D*)->(C_B*) se poate realiza: a) implicit, dac specificatorul de acces este public; b) explicit, cu operatorul cast, dac specificatorul de acces este private. Conversia de tipul (C_B*)->(C_D*) se poate realiza doar explicit cu operatorul cast. Aceste conversii, n procesul de motenire, trebuie fcute cu mult atenie, la nivel de pointeri, pentru c pot conduce la erori greu de detectat. Pentru detalii vezi I.Mulea C++......

Specificatorul protected asigur o flexibilitate a mecanismului de motenire. De regul, un membru al unei clase declarat protected nu este accesibil dect membrilor clasei respective. Accesul la un membru protejat este acelai cu accesul la un membru privat cu o singur excepie, i anume, membru protejat poate fi motenit. Exemplu: # include<iostream.h> class B { protected: int u,v; // sunt membrii particulari pentru clasa B, dar accesibili pentru clasa derivat D public: void punct(int a, int b){u=a; v=b;} void afis( ){cout<<u<<" "<<v<<"\n";} }; class D: public B { int w; public: void expr( ){w=u+v;} // este permis accesul n D la membrii protected u i v din B void afis_1( ){cout<<w<<"\n";} }; main( ) { D ob; ob.punct(6,9); // este corect pentru D ob.afis( ); // idem ob.expr( ); ob.afis_1( ); return 0; } Dac membrii u i v ar fi fost declarai n clasa B private, atunci n D nu s-ar fi permis acces la ei i programul nu s-ar putea compila.

Dac, totui, se motenete o clas de baz cu protected, atunci membrii publici i protejai ai clasei de baz devin membrii protejai ai clasei derivate. Exemplu: # include <iostream.h>

80

class B { protected: int u,v; // membrii protejai pentru clasa B, accesibili pentru clasa derivat D public: void punct(int a, int b){ u=a; v=b;} void afis(){cout<<u<<" "<<v<<"\n";} }; class D:protected B { int w; public: void expr( ){punct(9,11); w=u+v;} void afis_1( ){cout<<w<<" "; afis( );} }; main( ) { D ob; ob.expr ( ); // corect - este membru public din clasa D ob. afis_1( ); // idem return 0; } Incorect ar fi: ob.punct(6,9); ob.afis( ); pentru c s-ar folosi membrii protejai ai clasei D, dei sunt declarai publici n clasa B. Dac o clas derivat va deveni o clas de baz pentru o nou clas derivat, atunci orice membru protejat al clasei de baz iniiale (clas motenit cu public de ctre prima clas derivat), poate fi motenit ca protected de a doua clas derivat. Exemplu: # include <iostream.h> class B { protected: int u,v; public: void punct(int a, int b){u=a;v=b;} void afis( ){cout<<u<<" "<<v<<"\n";} }; class D_1:public B { //u i v sunt moteni\i direct ca protected din B int w; public: void expr( ){w=u+v;}// acces corect la u i v void afis_1( ){cout<<w<<"\n";} }; class D_2:public D_1 { // clasa derivat D_2 are clasa de baz D_1 int k; public: void expr_k( ){k=u*v;} // u i v sunt motenii indirect prin clasa D_1. Acces corect

81

void afis_k( ){cout<<k<<"\n";} }; main( ) { D_1 ob_1; D_2 ob_2; ob_1.punct(6,9); ob_1.afis( ); ob_1.expr( ); ob_1.afis_1( ); ob_2.punct(5,8); ob_2.afis( ); ob_2.expr_1 ( ); ob_2.expr_k( ); ob_2.afis_1( ); ob_2.afis_k( ); return 0; } Dac clasa B ar fi motenit cu specificatorul private, atunci toi membrii din B ar deveni membri private n clasa D_1, ceea ce nseamn c ei nu vor fi accesibili lui D_2. Totui, u i v (protected n B) continu s rmn accesibili lui D_1.

Ca o concluzie, dac clasa de baz B este motenit cu specificatorul de acces private n clasa derivat D_1, clasa D_1 continu s aib acces la membrii declarai public i protected din clasa B. Aceast proprietate nu se mai poate transmite n continuare.

ntr-o motenire pot fi folosite mai multe clase de baz (motenire multipl). Exemplu: # include <iostream.h> class B_1 { protected: int k; public; void afis_1( ){cout<<k<<"\n";} }; class B_2 { protected: int u: public: void afis_2( ){cout<<u<<"\n";}}; class D:public B_1,public B_2 { // motenire din dou clase de baz B_1,B_2 public: void punct(int a, int b){k=a; u=b; }; main( ) { D ob; ob.punct(9,3); //corect prin clasa D ob.afis_1( ); // corect din clasa B_1 ob.afis_2( ); // corect din clasa B_2

82

return 0; } Se observ c trebuie menionat specificatorul de acces la fiecare clas de baz motenit. Orice funcie, care opereaz cu un obiect din clasa de baz, va putea opera i asupra unui obiect din clasa derivat, deoarece clasa derivat include tot ceea ce conine clasa de baz, fr a recompila codul iniial al funciei. De aceea este necesar a vedea modul de organizare al fiierelor ntr-o astfel de ierarhie. Exemplu: #include<iostream.h> #define PI 3.141; class Punct { public: float x,y; void O(float x0,float y0){x=x0;y=y0;} void afis() { cout<<"X="<<x;cout<<"\n"; cout<<"Y="<<y; cout<<"\n"; } }; class Cerc:public Punct { public: float raza,A; void R(float r){raza=r;} float aria(){A=PI*raza*raza;return A;} void afis(){cout<<"RAZA="<<raza;cout<<"\n"; cout<<"Aria="<<A;} }; void main() { Punct p; p.O(2.5,-5.8); p.afis(); Cerc c; c.R(10.); c.aria(); c.afis(); } Analizai acest exemplu i precizai principalele sale caracteristici. Aplicaie: S se implementeze clasele "carte", "stare", "cititor", "fisa", cu scopul realizrii unei evidene cu privire la posibilitatea de a mprumuta o carte de la bibliotec. Se au n vedere urmtoarele condiii: - cititorul poate mprumuta o singur carte; - fiecare carte este unic n bibliotec; - mprumutul depinde de existena crii respective n bibliotec (dac nu este deja mprumutat). #include<iostream.h> #include<conio.h>

83

typedef enum {impr,ret}mod_i; typedef enum{lib,ocup}stare; class nod { public: char*autor; char*titlu; char*data_i; char*data_r; }; int i=0,j=0; char data[8]; class carte { public: char*autor; char*titlu; stare stare_carte; void act_stare(stare); void afisare(); carte(); }; class cititor { protected: char*nume; char*adresa; int legit; public: int informare(carte&); void solicitare(carte&); void returnare(carte&); cititor(); }; class fisa:public cititor { nod carti[10]; int nr_crt; // prima intrare libera in fisa public: void imprumut(mod_i,carte&); void actualizare(mod_i,carte); void afis_inr(int i); fisa(){nr_crt=0;} }; void fisa::imprumut(mod_i tip_i,carte& cartea) { if(tip_i==impr) {cout<<"cititorul"<<nume<<"solicita cartea"; cout<<"\n"; cout<<cartea.titlu<<""<<"autor"<<cartea.autor; cout<<"\n"; if(!informare(cartea)){ cout<<"cartea solicit. este imprumutata:"; cout<<"\n";}

84

else { solicitare(cartea); actualizare(tip_i,cartea); cartea.act_stare(ocup); } } if(tip_i==ret) { cout<<"cititorul"<<nume<<"returneaza cartea"; cout<<"\n"; cout<<cartea.titlu<<" "<<"autorul:"<<cartea.autor; cout<<"\n"; returnare(cartea); actualizare(tip_i,cartea); cartea.act_stare(lib); } } void fisa::actualizare(mod_i tip_i,carte cartea) { if(tip_i==impr) { nr_crt++; carti[nr_crt].titlu=new char[10]; carti[nr_crt].titlu=cartea.titlu; carti[nr_crt].autor=new char[20]; carti[nr_crt].titlu=cartea.autor; carti[nr_crt].data_i=new char[8]; carti[nr_crt].data_i=data; cout<<"data imprumutului";cout<<"\n"; cin>>data; } if(tip_i==ret) { cout<<"data returnarii"; cout<<"\n"; cin>>data; carti[nr_crt].data_r=new char[8]; carti[nr_crt].data_r=data; } } void fisa::afis_inr(int i) { cout<<"titlu;"<<carti[i].titlu; cout<<"\n"; cout<<"autor:"<<carti[i].autor; cout<<"\n"; cout<<"imprumutata data:"<<carti[i].data_i; cout<<"\n"; cout<<"returnata data:"<<carti[i].data_r; cout<<"\n"; }

85

carte::carte() { j++; cout<<"date asupra cartii:"<<j; cout<<"\n"; titlu=new char[11]; cout<<"titlul cartii:\n"; cout<<"\n"; cin>>titlu; autor=new char[20]; cout<<"\n"; cout<<"autor\n"; cin>>autor; stare_carte=lib; } void carte::act_stare(stare st){stare_carte=st;} void carte::afisare() { cout<<"den.carte\n"<<titlu; cout<<"\n"; cout<<"autor\n"<<autor; cout<<"\n"; } int cititor::informare(carte& cartea) { if(cartea.stare_carte==lib)return 1; if(cartea.stare_carte==ocup)return 0; return 1; } void cititor::solicitare(carte& cartea) {cartea.act_stare(ocup);} void cititor::returnare(carte& cartea) {cartea.act_stare(lib);} cititor::cititor() { i++; cout<<"datele pentru fisa"<<i<<"\n"; cout<<"nume\n"; nume=new char[10]; cin>>nume; cout<<"\n"; cout<<"adresa\n"; adresa=new char[20]; cin>>adresa; cout<<"\n"; cout<<"legit\n"; cin>>legit; cout<<"\n"; } void main() { clrscr(); fisa tf[2]; carte tc[2];

86

tf[0].imprumut(impr,tc[0]); tf[1].imprumut(impr,tc[0]); tf[0].imprumut(ret,tc[1]); tf[1].imprumut(impr,tc[1]); getch(); }

Tema propus
1

2
3

1. S se realizeze o implementare C++ cu privire la: 1.1 evidena crilor din bibliotec la un moment dat; 1.2 evidena trenurilor de cltori dintr-o gar (nod feroviar); 1.3 evidena studenilor, biei i fete, din facultatea de informatic; Fiecare student i va propune o implementare care s satisfac ct mai exact cerinele enunate. 2. Pornind de la clasa de baz patrulater, s se implementeze clase derivate ale acestei clase. 3. S se implementeze clase derivate pornind de la clasa de baz grup. 4. S se realizeze o implementare a clasei derivate fig_geom_spaiu pornind de la clasa de baz fig_geom_plan (motenire simpl, motenire multipl). 5. n una din problemele propuse anterior, s se foloseasc reutilizarea codului pe baza compunerii n programarea orientat pe obiecte.

87

Evaluare