Documente Academic
Documente Profesional
Documente Cultură
Creareaierarhiilorde clase
Creareaierarhiilorde clase
1.Mecanismulmoştenirii2.Declarareaclaselorderivate3.Constructoriiclaselorderivate4.
Mostenireasimpla5. Mostenireamultipla6. Redefinireamembriloruneiclasede bazain clasaderivata7.
FunctiivirtualesipolimorfismCAP. 4
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
Moştenireaesteocaracteristicăalimbajelordeprogramareorientateobiect,carepermiterefolosireacoduluişi
extindereafuncţionalităţiiclaselorexistente.Mecanismulmoşteniriipermitecreareauneiierarhiideclaseşitre
cereadelaclaselegeneralelaceleparticulare.
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
Aceastăproprietatesemanifestăprinfaptulcădinoriceclasăputemderivaalteclase.Procesulimplicălaînceput
definireaclaseidebazăcarestabileştecalităţilecomunealetuturorobiectelorcevorderivadinclasadebază(clas
ăierarhicsuperioara).
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
Mostenireasimpla(unica):FiecareclasăaredoarosuperclasaStructuraarbore
Mostenireamultipla:OclasăaremaimultesuperclaseStructurareteaMostenireapoatefi:
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
Informaţiacomunăapareînclasadebază,iarinformaţiaspecifică-
înclasaderivată.Clasaderivatăreprezintăospecializareaclaseidebază.Oriceclasăderivatămoşteneştedatele
membrusimetodeleclaseidebaza,deciacesteanutrebuieredeclarateinclasaderivata.
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
C++:încapsularea–
princontrolulaccesului,deoarecetoatedateleşifuncţiilemembresuntcaracterizateprintr-
unniveldeacces(rezultândastfelomareflexibilitate).niveldeaccesprivateprotectedpublic(friend)Mo
stenireprivateprotectedpublic
10
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
11
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
Publică, unde în clasa derivată nivelul de acces al membrilor este acelaşi ca în clasa de bază; Privată,
unde membrii protected şi public din clasa bază devin private în clasa derivată. Protejată(la
compilatoarelemainoi).
12
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
Când o clasă moşteneştemembrii unei alte clase, membrii clasei de bază devinmembrii ai clasei derivate.
Moştenireaprotejatăesteintermediarăceleipubliceşiceleiprivate.Încazulmoşteniriiprotejate,comparativcu
moştenireprivată,singuradiferenţăestecămembriipubliciaiclaseidebazădevinprotejaţiîntimpulderivăriloru
lterioare.
13
CAP. 4
4.1. Mecanismulmostenirii
Creareaierarhiilorde clase
În funcţie de modificatorii de acces la membrii clasei de bază, la membrii clasei derivate şi de tipul
moştenirii, lucrurile se pot rezuma astfel
Aşa cum se observă, în toate cazurile:-elementele private ale clasei de bază rămân particulare acesteia şi
nu sunt accesibile claselor derivate; -cele protejate sunt accesibile clasei derivate.
14
CAP. 4
Creareaierarhiilorde clase
Lamodulgeneral,ladeclarareauneiclasederivate,sespecificăolistăaclaselordebază,precedatedemodificator
uldeaccescareprecizeazătipulmoştenirii.class<nume_cls_deriv>:<modificator_de_acces><nume_clasă_d
e_bază> { //corpul clasei derivate -elemente specifice clasei derivate };
15
CAP. 4
Creareaierarhiilorde clase
Exemplu:
Declararea clasei derivate angajat, cu clasa de bază persoana (moştenire simplă): class persoana{ //
corpul clasei de bază }; class angajat: protected persoana{double salariu; };
16
CAP. 4
Creareaierarhiilorde clase
Exemplu:
Declararea clasei derivate interfaţă, cu clasele de bază fereastrăşi meniu(moştenire multiplă): class
fereastra{ //membriiclasei};class meniu{ //membriiclasei};class interfata: public fereastra, public
meniu{ //membriiclasei};
17
CAP. 4
Creareaierarhiilorde clase
18
CAP. 4
Creareaierarhiilorde clase
Îngeneral,claseleutilizeazăconstructoridefiniţideprogramator.Încazulîncareaceştialipsesc,compilatorulge
nereazăautomatunconstructorimplicitpentruclasarespectivă.Acelaşilucruseîntâmplăşiîncazulconstructori
lordecopiere.Lainstanţiereaunuiobiectdinclasăderivată,opartedinvalorileprimitecaparametrifolosesclaini
ţializareadatelormembrualeclaselordebază,iarrestuliniţializeazădatelemembruspecificeclaseiderivate.
19
CAP. 4
Creareaierarhiilorde clase
20
CAP. 4
Creareaierarhiilorde clase
Exemplu:
Se implementrează ierarhia de clase din figura: #include <iostream.h> class baza{ private: inta;
protected: double w; void seteaza_a(inta1) {a=a1;} void seteaza_w(intw1) {w=w1;}
Pentruaevidenţiaaspecteleprezentate,săconsiderămurmătoareleexemple,încaremoştenireaestesimplă:
21
public: intc;baza(inta1, double w1, intc1) {a=a1; w=w1; c=c1;cout<<"Constructor cls. baza\n";} ~baza()
{cout<<"Destructor baza\n";} void arată() {cout<<a<<' '<<w<<' '<<c<<'\n';} double calcul() {return
a+w+c;} friend ostream& operator<<(ostream&, constbaza&); }; 4.4. MOŞTENIREA SIMPLĂ
22
class deriv1: public baza{ intb; public: deriv1 (inta1, double w1, intc1, intb1):baza(a1, w1, c1) {b=b1;
cout<<"Constructor deriv1\n";} ~deriv1() {cout<<"Destructor deriv1\n";} double calcul() {return
w+c+b;} // membrula esteîncapsulat, nu poatefi folosit, fiindprivate // o alternativă pentru obţinerea
sumei tuturor datelor membre este: // double calcul(){return baza::calcul()+b;} friend
ostream&operator<<(ostream&, constderiv1 &); }; 4.4. MOŞTENIREA SIMPLĂ
23
class deriv2: protected baza{ intb; public: deriv2(inta1, double w1, intc1, intb1):baza(a1, w1, c1) {b=b1;
cout<<"Constructor deriv2\n";} ~deriv2() {cout<<"Destructor deriv2\n";} double calcul() {return w+c+b;}
friend ostream&operator<<(ostream&, constderiv2 &); }; 4.4. MOŞTENIREA SIMPLĂ
24
intmain() { baza x(1, 1.23, 2); // Constructor cls. baza deriv1 y(2, 2.34, 3, 4); // Constructor cls. baza
Constructor deriv1 deriv2 z(3, 3.45, 4, 5); // Constructor cls. baza Constructor deriv2 deriv3 v(4, 5.67, 6,
7); //Constructor cls. baza Constructor deriv3 cout<<"x="<<x<<'\n'<<"z="<<z<<'\n'<<"v="<<v<<'\n'; //
x=1 1.23 2 (x.a, x.w, x.c) // z=3.45 4 5 // v=5.67 6 7 cout<<"x.calcul()="<<x.calcul()<<'\n'; //
x.calcul()=4.23 cout<<"y.calcul()="<<y.calcul()<<'\n'; // y.calcul()=9.34
cout<<"z.calcul()="<<z.calcul()<<'\n'; // z.calcul()=12.45 cout<<"v.calcul()="<<v.calcul()<<'\n'; //
v.calcul()=18.67 cout<<"x.c="<<x.c<<'\n'; // x.c=2 cout<<"y.c="<<y.c<<'\n'; // y.c=3 /* Destructor deriv3
Destructor baza ptr. v Destructor deriv2 Destructor baza ptr. z Destructor deriv1 Destructor baza ptr. y
Destructor bazaptrx */ } 4.4. MOŞTENIREA SIMPLĂ
25
Observaţii:
În clasa de bază data membră aeste private, weste protectedşi ceste public. În clasa de bază, cât şi în
clasele derivate există constructori care iniţializează datele membru. Membrii privatedintr-o clasă de
bază (clasa bază, în cazul nostru) pot fi folosiţi doar în cadrul acesteia (de metodele sale), nuşi în clasele
derivate. Clasaderiv1: Membrii privaţi moşteniţi din clasa bază sunt inaccesibili (a există, dar este
încapsulat). Pentru a putea fi accesaţi, se folosesc metodele clasei bază (metoda calcul). Deoarece în
clasa deriv1 există o metodă cu acelaşi nume cu al unei metode din clasa de bază (redefinirea unei
metode în clasa derivată), se foloseşte operatorul de rezoluţie. baza::calcul( )sauy.baza::calcul( ) 4.4.
MOŞTENIREA SIMPLĂ
26
Clasaderiv2:Deoarecemoştenireaesteprotejată,membriipublicisauprotejaţidinclasabazădevinprotejaţiîncl
asaderiv2.Deaceea,dacăînfuncţiamainamîncercafolosirea:cout<<z.baza::calcul(),metodacalculesteinacce
sibilă,eadevenindprotejatăînclasaderiv3.Clasaderiv3:Deoarecemoştenireaesteprivată,membriipublicsaup
rotecteddinclasabazăaudevenitprivaţiînclasaderiv3.Sepotfolositoţimembriiclaseidebază,cuexcepţiacelor
privaţi(a).4.4. MOŞTENIREA SIMPLĂ
27
Laconstruireaunuiobiectdintr-
oclasăderivatădinclasabază,seapeleazămaiîntîiconstructoruldinclasadebază,apoiconstructorulclaseideriv
ate.Astfel,unobiectydinclasaderiv2incorporeazăunobiectdejainiţializatcuajutorulconstructoruluidinclasab
ază.Dacăpentruclasaderiv1defineamunconstructordeforma:deriv1(inta1,doubleb1,intc1,intb1)
{a=a1;b=b1;c=c1;d=d1;}nueracorect,deoarececlasabazănuareconstructorifărăparametri,decinuexistăcon
structorimplicit,iardataaesteinaccesibilăînderiv1.Apelareaconstructoruluiserealizeazăapelândexplicitcon
structoruldinclasabază.4.4. MOŞTENIREA SIMPLĂ
28
4.5. MOŞTENIREA MULTIPLĂO clasă poate să moştenească mai multe clase de bază, ceea ce înseamnă că
toţi membrii claselor de bază vor fi moşteniţi de către clasa derivată. În această situaţie apare
mecanismul moştenirii multiple.
29
#include <iostream.h> class bază1{ protected: intx; public: bază1 (int xx) {x=xx; cout<<"Constructor cls.
bază1\n"; cout<<x<<'\n';} ~baza1() {cout<<"Destructor bază1\n"; cout<<x<<'\n';} void aratax()
{cout<<"x="<<x<<'\n';} };
30
CAP. 4Creareaierarhiilorde clase
4.5. MOŞTENIREA MULTIPLĂclass bază2 { protected: inty; public: bază2 (int yy) {y=yy;
cout<<"Constructor bază2\n"<<y<<'\n';} ~bază2() {cout<<"Destructor bază2\n";} voidaratay()
{cout<<"y="<<y<<'\n';} }; class derivat: public bază1, public bază2 { public: derivat(int xx, int
yy):bază1(xx), bază2(yy) {cout<<"Constructorderivat\n"; cout<<x<<' '<<y<<'\n';} ~derivat()
{cout<<"Destructorderivat\n"; cout<<x<<' '<<y<<'\n';} intarata() {cout<<x<<' '<<y<<'\n';} void
seteaza(intxx, intyy) {x=xx; y=yy;} };
31
32
După ieşirea din blocul în care a fost declarată variabila obiect, se apelează automat destructorii, în
ordine inversă apelării constructorilor.
33
34
4.5. MOŞTENIREA MULTIPLĂFie schema de moştenire prezentată în figura1. La declararea unui obiect
din clasa D, membrii clasei A (int a) sunt moşteniţi de obiectul din clasa D în dublu exemplar (figura2.).
35
CAP. 4Creareaierarhiilorde clase
4.5. MOŞTENIREA MULTIPLĂclass A{ public: inta; //………. }; class B: public A{ /*…………..*/ }; class C:
public A{ /* …………………………..*/ }; class D: public B, public C { /* ……………………………*/ }; intmain() {D
x; //declarare obiectx de tipD x.a= 2; // eroareD::x esteambiguu; poatefi înbazaA aclaseiB // sauînbazaA
aclaseiC }
36
37
4.5. MOŞTENIREA MULTIPLĂO clasă de bază virtuală este moştenită o singură dată (figura) şi creează o
singură copie în clasele derivate, oferind astfel o modalitate de “partajare” a membrilor săi de către
clasele derivate.
38
De exemplu: class A { public: intx; /* ………………….*/ }; class B : virtual public A { /*……… */ }; class C :
virtual public A { /*…………………….*/ }; class D : public B, public C { /* ……………………. */ };
39
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂAşa cum s-a observat deja din
exerciţiile anterioare, membrii (fie date membru, fie metode) ai unei clase de bază pot fi redefiniţi în
clasele derivatedin aceasta. În următorul exemplu, datele membre x şi y din clasa baza sunt redefinite în
clasaderivată, deriv. Exemplul 1 (în care se redefinesc datele membre ale clasei de bază în clasa derivată)
class bază{ protected: double x, y; public: bază(double xx=0, double yy=0) {x=xx; y=yy;} };
40
41
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂÎn următorul exemplu, metoda
aratăeste redefinită în clasele B, C, D, iar clasa de bază A este clasă virtuală pentru clasele derivate (cu
scopul de crea o singură copie a membrilor acesteia şi a evita ambiguităţile, aşa cum s-a discutat
anterior)Exemplul2:
#include <iostream.h> class A{ inta; public: A(intaa) {a=aa; cout<<"Constructor A"<<a<<'\n';} ~A()
{cout<<”Destructor A”;} void arată() {cout<<"A.a="<<a<<'\n';} };
42
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂclass B: virtual public A{ intb;
public: B(intbb, intaa=0):A(aa) {b=bb;cout<<"Constructor B"<<b<<'\n';} ~B() {cout<<”Destructor B”;} void
arata() {cout<<"B.b="<<b<<'\n';} }; class C: virtual public A{ intc; public: C (intcc, intaa=0):A(aa) {c=cc;
cout<<"ConstructorC"<<c<<'\n';} ~C() {cout<<”Destructor C”;} void arata() {cout<<"C.c="<<c<<'\n';} };
class D: public B, public C{ intd; public: D(intaa, intbb, intcc, intdd):A(aa), B(bb), C(cc)
{d=dd;cout<<"Constructor D"<<d<<'\n';} ~D() {cout<<”Destructor D”;} void arată()
{cout<<"D.d="<<d<<'\n';} };
43
44
45
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂAşa cum se observă din
exemplul 2, metoda arată din clasa de bază A a fost redefinităîn clasele derivate B, C, D. În plus, metoda
are aceeaşi semnătură(acelaşi prototip) în toate clasele. Dacă nu ar fi fost redefinită în clasele derivate,
metoda arată (publică) din clasa de bază A ar fi fost moştenită de clasele derivate; redefinirea a fost
necesară pentru a putea vizualiza şi datele membre proprii claselor derivate. În cazul de faţă,
identificarea metodei apelate se realizează chiar în etapa compilării, datorită legăturii cu obiectul pentru
care a fost apelată. De exemplu, la apelul w.arată() se aplică metoda din clasa D (obiectul w e de tip D)
46
47
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂRedefinirea unei metode a unei
clase de bază într-o clasă derivată se numeşte polimorfism. Un pointer către o clasă de bază poate primi
ca valoare adresa unui obiect dintr-o clasă derivată. În această situaţie, în cazul metodelor redefinite, se
apelează metoda din clasa pointerilor, şi nu din clasa obiectului spre care pointează pointerul.
48
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂPentru exemplificare, vom
considera ierarhia de clase (A, B, C, D) ulterioară, şi programul de test: intmain() { A u(10), *PA; //
Constructor A 10 B v1(9, 7), *PB; // Constructor A 9 Constructor B 7 -ptr. v1 C v2(8,12), *PC; //
Constructor A 8 Constructor C 12 -ptr. v2 D w(31, 9, 14, 35), *PD; // Constructor A 31 Constructor B 9 //
Constructor C 14 Constructor D 35 PA=&u; PA->arată(); // Se selectează metoda arată din clasa A A.a=10
PA=&v1; PA->arată(); // Se selectează metoda arată din clasa A A.a=9 PB=&v1; PB->arată(); // Se
selectează metoda arată din clasa B B.b=7 PA=&w; PB=&w; PD=&w; u.arată(); // Apelul metodei arată
ptr. obiectul curent, clasa A A.a=31 PA->arată(); // Se selectează metoda arată din clasa A A.a=31 PB-
>arată(); // Se selectează metoda arată din clasa B B.b=9 PD->arată(); // Se selectează metoda arată din
clasa D D.d=35 }
49
4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂAşa cum se observă din
exemplu, pa, pb, pc şi pd sunt pointeri de tipurile A, B, C, respectiv D: A *pa;B*pb;C*pc;D*pd;
Înurmaatribuiriipa=&v1; pointerulpa (de tip A) vaconţineadresaobiectuluiv1 (de tip B). Apelul metodei
aratăredefinită în clasa derivată B pa->arată(); va determina selecţia metodei din clasa pointerului (A), şi
nu a metodei din clasa obiectului a cărui adresă o conţine pointerul.
50
51
52
53
54
ambiguităţi.Conversiadintr-
unpointerlaoclasădebazăînpointerlaoclasaderivatănuesteadmisăimplicit,însăpoatefirealizatăexplicit,prin
operatoruldeconversiecast.Rezultatuluneiastfeldeconversiiesteînsănedeterminat,decelemaimulteoripro
vocânderorideexecuţie.
55
1.Referinţelepotficonvertiteînmodasemănător:oreferinţălaunobiectdintr-
oclasăderivatăpoateficonvertităimplicitîntr-
oreferinţălaclasadebazăaacesteia,dacăderivareaestedetippublicşinuexistăambiguităţi.2.Referinţelenupo
tfiutilizateînmecanismuldevirtualitatedeoareceeletrebuiesăfieinţializateatâtladeclararecâtşilaconversie.
56
Exemplul1:
class A { public: virtual void arată(); //în loc de void arată() // . . . . }; class B : virtual public A
{ public:virtual void arată(); //înlocde voidarată() // . . . . }; class C : virtual public A { public: virtual void
arată(); //înlocde voidarată() // . . . . }; class D : public B, public C{ public:virtual void arată(); //înlocde
voidarată() // . . . . };
57
58
1.Deoarecemetodaaratăestevirtuală,s-
aselectatmetodapentruclasaobiectuluisprecarepointeazăpointerul.2.Dacăînclasadebazăsedeclarăometo
dăvirtuală,înclaselederivatemetodelecuaceeaşisemnaturăvorficonsiderateimplicitvirtuale(chiardacăelen
usuntdeclarate,explicit,virtuale).
59
60
-Dacăobiectulestedetipclasădebazănusepoatefolosiunpointerlaoclasăderivată-
Dacăobiectulestedetipclasăderivatăşipointerulestepointerlaclasăderivată,seselecteazăfuncţiaredefinităîn
clasaderivatărespectivă.-
Dacăobiectulestedetipclasăderivată,iarpointerulfolositesteunpointerlaoclasădebazăaacesteia,seselectea
zăfuncţiaredefinităînclasaderivatăcorespunzătoaretipuluiobiectului.
61
62
63
virtual<tip_ret> <nume_functie>(<lista_decl_pf>) = 0;
64
classbază{public:virtualvoidvirt_f()=0;//metodavirt_festemetodăvirtualăpură;}classvieţuitoare{public:virt
ualvoidnutriţie()=0;//nutriţieestemetodăvirtualăpură};
65
66
67
valoarede ieşire; de exemplu, din grade Farenheitîngrade Celsius, din inch încentimetri, etc.
classConvert{ protected: double x; // valoareintraredouble y; // valoareiesirepublic: Convert(double i){x
= i;} double getx(){return x;} double gety(){return y;} virtualvoid conv() = 0; //functievirtualapura}; Clasa
de bază abstractă Converteste folosită pentru crearea prin derivare a unei clase specifice fiecărui tip de
conversie de date dorit. Această clasă defineşte datele comune, necesare oricărui tip de conversie
preconizat, de la o valoare de intrare x la o valoare de ieşire y. Funcţia de conversie conv() nu se poate
defini în clasa
de bază, ea fiind specifică fiecărui tip de conversie în parte; de aceea funcţia conv( ) se declară funcţie
virtuală purăşi trebuie să fie redefinită în fiecare clasă derivată.
68
69
70
71
72
73
74
Polimorfismulintrodusprinmecanismuldevirtualitateestepolimorfismlaniveldeexecuţie,carepermitelegar
eatârzie(latebinding)întreevenimenteledinprogram,încontrastculegareatimpurie(earlybinding),proprieap
elurilorfuncţiilornormale(nevirtuale).
75
76
Programareacalculatoarelorşilimbajede programareII
77
78
CAP. 4
SFARSITUL Capitolului4
Creareaierarhiilorde clase