Sunteți pe pagina 1din 18

CAPITOLUL 4

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).

Prinmostenire, un obiectpoatepreluaproprietatileobiectelordin clasade bază.

CAP. 4

4.1. Mecanismulmostenirii

Creareaierarhiilorde clase

Mostenireasimpla(unica):FiecareclasăaredoarosuperclasaStructuraarbore

Mostenireamultipla:OclasăaremaimultesuperclaseStructurareteaMostenireapoatefi:

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).niveldeaccesprivateprotectedpublic(friend)Mo
stenireprivateprotectedpublic

10

CAP. 4

4.1. Mecanismulmostenirii

Creareaierarhiilorde clase

private: membrii(date şimetode) la care accesulesteprivate pot fi


accesaţidoarprinmetodeleclasei(nivelde accesimplicit); protected: aceştimembripot fi
accesaţiprinfuncţiilemembreale claseişifuncţiilemembreale claseiderivate; public: membrii la care
accesul este public pot fi accesaţi din orice punct al domeniului de existenţă a clasei respective; friend:
aceştimembripot fi accesaţiprinfuncţiilemembreale funcţieiprietenespecificate.

Nivelulde accesla membriiuneiclase

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).

ÎnlimbajulC++, nivelulde accespoateprecizaşitipulde moştenire

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

4.2. MODUL DE DECLARARE A CLASELOR DERIVATE

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

4.2. MODUL DE DECLARARE A CLASELOR DERIVATE

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

4.2. MODUL DE DECLARARE A CLASELOR DERIVATE

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

4.3. CONSTRUCTORII CLASELOR DERIVATE

Creareaierarhiilorde clase

Constructoriişidestructoriisuntfuncţiimembrecare NUse moştenesc.


Lainstanţiereaunuiobiectdinclasaderivatăseapeleazămaiîntâiconstructoriiclaselordebază,înordineaîncare
aceştiaaparînlistadedeclarareaclaseiderivate.Ladistrugereaobiectelor,seapeleazăîntâidestructorulclaseid
erivate,apoidestructoriiclaselordebază.Transmitereaargumenteloruneifuncţiiconstructordinclasadebazăs
efacefolosindoformăextinsăadeclaraţieiconstructoruluiclaseiderivate,caretransmiteargumenteleunuisau
maimultorconstructoridinclasadebază.

18

CAP. 4

4.3. CONSTRUCTORII CLASELOR DERIVATE

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

4.3. CONSTRUCTORII CLASELOR DERIVATE

Creareaierarhiilorde clase

20

CAP. 4

4.4. MOŞTENIREA SIMPLĂ

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

4.5. MOŞTENIREA MULTIPLĂExerciţiu:Se implementează ierahia de clase din figura.

#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

CAP. 4Creareaierarhiilorde clase

4.5. MOŞTENIREA MULTIPLĂintmain() {derivatobiect(7,8); /*Constructor cls. bază1 7 Constructor bază2


8 Constructor derivat7 8 */ obiect.arata(); // 7 8 obiect.seteaza(1,2);obiect.aratax(); // x=1
obiect.aratay(); // y=2 obiect.arata(); // 1 2 /* Destructor derivat1 2 Destructor bază2 2 Destructor bază1
1 */ }

32

CAP. 4Creareaierarhiilorde clase

4.5. MOŞTENIREA MULTIPLĂAşacumilustreazăexemplul,ladeclarareaobiectuluiobiectdetipulderivats-


auapelatconstructoriiclaselordebază(bază1şibază2),înordineaîncareaparîndeclarareaclaseiderivate:maiîn
tâiconstructorulclaseibază1,încarexestedatămembruprotejată(accesibilădinclasaderivat);apoiconstructor
ulclaseibază2,încareyestedatămembruprotejată(accesibilădinclasaderivat);apoiconstructorulclaseideriva
tcareleîncorporeazăpeacesteaîntr-unsingurobiect.Clasaderivatnuaredatemembre,cidoarmetode(figura).

După ieşirea din blocul în care a fost declarată variabila obiect, se apelează automat destructorii, în
ordine inversă apelării constructorilor.

33

CAP. 4Creareaierarhiilorde clase

4.5. MOŞTENIREA MULTIPLĂAmbiguitãtiînmostenireamultiplãÎntr-o moştenire multiplă este posibil ca o


clasă să fie moştenită indirectde mai multe ori, prin intermediul unor clase care moştenesc, fiecare în
parte, clasa de bază. În situaţia apariţiei unei astfel de “moşteniri repetată”, în care o clasă ajunge să
moştenească de la aceeaşi clasă, pe drumuri diferite în reţea (vezi figura1, în care clasa D moşteneşte de
la aceeaşi clasă A, pe drumurile A-B-D, A-C-D), limbajul C++ oferă programatorului două strategii: 1)clasa
E poate avea două copii ale lui A, una pentru fiecare drum; 2)clasa D are o singură copie, iar A este clasă
virtuală de bază şi pentru C şi pentru B.

34

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

4.5. MOŞTENIREA MULTIPLĂEliminarea ambiguităţii apărute în situaţia prezentată se poate realiza în


două moduri:1.Prin păstrarea a două copii ale lui A, una pentru fiecare drum, specificând clasa de
apartenenţă: x.B::a = 2; // corect, a din B x.B::a = 3; // corect, a din C 2.Prin crearea unei singure copii a
clasei de bază în clasa derivată. Pentru aceasta este necesar ca acea clasă care ar putea produce copii
multiple prin moştenire indirectă (clasa A, în exemplul de mai sus) să fie declarată clasă virtualăîn clasele
care o introduc în clasa cu moştenire multipă. Clasa A va fi declaratăvirtuală, pentru clasele derivate B şi
C.

37

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

4.5. MOŞTENIREA MULTIPLĂ

De exemplu: class A { public: intx; /* ………………….*/ }; class B : virtual public A { /*……… */ }; class C :
virtual public A { /*…………………….*/ }; class D : public B, public C { /* ……………………. */ };

39

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase


4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂÎN CLASA DERIVATĂclass deriv:public
bază{ protected: double x, y; public: deriv(double dx=0,double dy=0,double bx=0,double
by=0):baza(bx,by) {x=dx; // x -membru redefinit în clasa derivată y=dy; // y
-membruredefinitînclasaderivată} void arată() const; }; void deriv::arată() const {cout<<"x dinclasăde
bază:"<<bază::x; cout<<"\ty din clasa de bază:"<<bază::y<<'\n'; cout<<"x din clasa derivată:"<<x;
cout<<"\tydinclasaderivată:"<<y<<'\n'; } main() { /*…………….*/} În metoda arată a clasei deriv, pentru a
face distincţieîntre datele membru ale

clasei deriv şi cele ale clasei bază, se foloseşte operatorul de rezoluţie.

41

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂintmain() {D x(1,2,3,4); /*


Constructor A1 Constructor B2 Constructor C3 Constructor D4 */ x.arată(); // apelul metodei arată din
clasa D, pentru obiectul x D.d=4 x.B::arată(); // apelul metodei arată din clasa B B.b=2 x.C::arată(); //
apelul metodei arată din clasa C C.c=3 x.A::arată(); // apelul metodei arată din clasa A A.a=1 /*
Destructor D Destructor C Destructor B Destructor A */ A u(10); // Constructor A 10 -ptr. obiectulu, de
tipA B v1(9, 7);// Constructor A 9 Constructor B 7 -ptr. obiectulv1, de tipB C v2(8,12);// Constructor A 8
Constructor C 12 -ptr. obiectulv2, de tipC D w(31, 9, 14, 35);// Constructor A 31 Constructor B 9
Constructor C 14 // ConstructorD35 -ptr. obiectulw, de tipD

44

CAP. 4Creareaierarhiilorde clase


4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂ// Se apelează metoda arată,
pentru obiectul curent u.arată(); // A.a=10 v1.arată(); // B.b=7 v2.arată(); // C.c=12 w.arată(); //
D.d=35 /* Destructor D Destructor C Destructor B Destructor A -ptr. obiectulw Destructor C Destructor A
-ptr. obiectulv2 Destructor B Destructor A -ptr. obiectulv1 Destructor A -ptr. obectulu */ }

45

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂConcluzionând, identificarea


unei metode din clasa de bază redefinite în clasele derivate, se face prin una din modalităţile: Prin
legătura cu obiectul asupra căruia se aplică metoda (vezi apelurile metodei arată pentru obiectele u, v1,
v2, w); Prezenţa operatorului de rezoluţie (de exemplu, dacă pentru obiectul w se doreşte apelarea
metodei arată din clasa B, apelul va avea forma: w.A::arată(); ).

47

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

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

CAP. 4Creareaierarhiilorde clase

4.6. REDEFINIREA MEMBRILOR UNEI CLASE DE BAZĂ ÎN CLASA DERIVATĂ

În toate cazurile prezentate anterior, identificarea metodei redefinite se realizează în faza de


compilare.Este vorba de o legare inţială (timpurie), "early binding", în care toate informaţiile necesare
selectării metodei sunt prezentate din timp şi pot fi utilizate din faza de compilare.

51

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMAşacums-


asubliniat,unpointerlaoclasădebazăpoateprimicavaloareadresaunuiobiectdintr-
oclasăderivată.SăluămcaexemplusituaţiaîncareavânduntabloudepointerilaobiectedetipA,putemlucracuta
blourideobiecteeterogene,cuelementedetipuridiferite(B,CsauD);decelemaimulteori,informaţiileprivindti
pulobiectuluilacarepointeazăunelementaltablouluisuntdisponibileabiaînmomentulexecuţieiprogramului.
Încazulexemplificat,orezolvareaidentificăriimetodeiînmomentulexecuţieiprogramuluioconstituiefuncţiile
virtuale.

52

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMOfuncţievirtualăesteofuncţiecareestedeclaratădetipvirtualînclasadebazăşiredefinităîntr-
oclasăderivată.Redefinireauneifuncţiivirtualeîntr-
oclasăderivatădomină(override)definiţiafuncţieiînclasadebază.Funcţiadeclaratăvirtualînclasadebazăacţio
neazăcaodescrieregenericăprincaresedefineşteinterfaţacomună,iarfuncţiileredefiniteînclaselederivatepr
ecizeazăacţiunilespecificefiecăreiclasederivate.

53

CAP. 4Creareaierarhiilorde clase


4.7. FUNCŢII VIRTUALE ŞI
POLIMORFISMMecanismuldevirtualitateasigurăselecţia(dominarea)funcţieiredefiniteînclasaderivatănum
ailaapelulindirectalfuncţiei,printr-
unpointer1cătreunobiect.Laapeluldirect(funcţiemembrăapelatăpentruunobiect2cuajutoruloperatoruluid
eselecţiedirectă(.),“legând-
o”deobiect),funcţiilevirtualesecomportănormal,cafuncţiiredefinite.Deoarecemecanismuldevirtualitatese
manifestănumaiîncazulapeluluifuncţiilorprinintermediulpointerilorsevorprecizamaiîntâiaspecteleprivind
conversiiledepointeriîntreclaseledebazăşiclaselederivate.

54

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMConversiialepointerilorîntreclaseledebazăşiclasederivateConversiadintr-
unpointerlaoclasăderivatăînpointerlaoclasădebazăaacesteiaesteimplicită,dacăderivareaestedetippublicşi
nuexistă

ambiguităţi.Conversiadintr-
unpointerlaoclasădebazăînpointerlaoclasaderivatănuesteadmisăimplicit,însăpoatefirealizatăexplicit,prin
operatoruldeconversiecast.Rezultatuluneiastfeldeconversiiesteînsănedeterminat,decelemaimulteoripro
vocânderorideexecuţie.

55

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMObservaţii:

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

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISM

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

CAP. 4Creareaierarhiilorde clase


4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMÎn urma acestei modificări, rezultele execuţiei programului
anterior ar fi fost: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
B B.b=7 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=10 PA->arată(); // Se selectează
metoda arată din clasa D D.d=35 PB->arată(); // Se selectează metoda arată din clasa D D.d=35 PD-
>arată(); // Se selectează metoda arată din clasa D D.d=35 }

58

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMObservaţie:

1.Deoarecemetodaaratăestevirtuală,s-
aselectatmetodapentruclasaobiectuluisprecarepointeazăpointerul.2.Dacăînclasadebazăsedeclarăometo
dăvirtuală,înclaselederivatemetodelecuaceeaşisemnaturăvorficonsiderateimplicitvirtuale(chiardacăelen
usuntdeclarate,explicit,virtuale).

59

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMÎncazuluneifuncţiideclaratevirtualăînclasadebazăşiredefiniteînclasaderivată,redefinireame
todeiînclasaderivatăareprioritatefaţădedefinireaeidinclasadebază.Astfel,ofuncţievirtualădeclaratăînclasa
debazăacţioneazăcaunsubstitutpentrupăstrareadatelorcarespecificăoclasăgeneralădeacţiunişideclarăfor
mainterfeţei.Laprimavedere,redefinireauneifuncţiivirtualeîntr-
oclasăderivatăparesimilarăcusupraîncărcareauneifuncţieiobişnuite.Totuşi,nuesteaşa,deoareceprototipul
uneimetodevirtualeredefinitetrebuiesăcoincidăcucelspecificatînclasadebază.Încazulsupraîncărcăriiuneifu
ncţiinormale,caracteristicileprototipurilortrebuiesădifere(printipulreturnat,numărulşi/sautipulparametril
or).

60

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMDacăofuncţieestedefinităcafuncţievirtualăînclasadebazăşiredefinităînclaselederivate,laape
lulacesteiacafuncţiemembrăaunuiobiectpentrucaresecunoaşteunpointer,seselecteazăfuncţiadupătipulo
biectului,nualpointerului.Suntposibilemaimultesituaţii:

-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

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMAcestaestemecanismuldevirtualitateşielpermiteimplementareapolimorfismuluiînclaselede
rivate.Ofuncţieredefinităîntr-
oclasăderivatădominăfuncţiavirtualăcorespunzătoaredinclasadebazăşioînlocuieştechiardacătipulpointer
uluicucareesteaccesatăestepointerlaclasadebază.Polimorfismul,adicăapeluluneifuncţiidintr-
oclasăderivatăprinpointerdetipclasădebază,esteposibilnumaiprinutilizareapointerilorlaobiecte.

62

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMMetodevirtualepure


Înunelesituaţii,oclasădebază(dincaresederiveazăalteclase)auneiierarhii,poatefiatâtdegenerală,astfelîncât
unelemetodenupotfidescriselaacestnivel(atâtdeabstract),cidoarînclaselederivate.Acestemetodesenumes
cfuncţiipure.Metodelevirtualepuresuntmetodecaresedeclară,nusedefinesclaacestniveldeabstractizare.

63

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMMetodevirtualepure


Metodelevirtualepuresuntmetodecaresedeclară,nusedefinesclaacestniveldeabstractizare.Ometodăvirtu
alăpurătrebuiesăfieprezentăînoriceclasăderivată.Ofuncţievirtualăpurăesteofuncţiecarenuaredefiniţieîncl
asadebază,iardeclaraţiaeiaratăînfelulurmător:

virtual<tip_ret> <nume_functie>(<lista_decl_pf>) = 0;

64

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMExemple:

classbază{public:virtualvoidvirt_f()=0;//metodavirt_festemetodăvirtualăpură;}classvieţuitoare{public:virt
ualvoidnutriţie()=0;//nutriţieestemetodăvirtualăpură};

65

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMOclasăcucelpuţinometodăvirtualăpurăsenumeşteclasăabstractă(clasavieţuitoareesteabstr
actăşi,caurmare,nupoatefiinstanţiată).Deoareceoclasăabstractăconţineunasaumaimultefuncţiipentrucar
enuexistădefiniţii(funcţiivirtualepure),nupotficreateinstanţe(obiecte)dinaceaclasă,darpotficreaţipointeriş
ireferinţelaastfeldeclaseabstracte.Oclasăabstractăestefolosităîngeneralcaoclasăfundamentală,dincarese
construiescalteclaseprinderivare;constituieuncadrusuportdelacaresăseponrneascăîndefinireaobiectelor.
Claseleabstracteauroluldeaajutalaorganizareastructurii(reţelei)demoştenire.
PROGRAMAREACALCULATOARELORŞILIMBAJEDE PROGRAMAREII

66

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMCompilatorulnupermitecreareadeobiectedinclasaabstractă,cidoardinclaselederivate,cuco
ndiţiacaacesteclasederivatesăfurnizezeimplementărialefuncţiilevirtualepure.Funcţiilevirtualepuresemoşt
enesccaşifuncţiilevirtualeobişnuite.Orice clasă derivată dintr-o clasă abstractă este, la rândul ei
clasăabstractă(şi deci nu se pot crea instanţe ale acesteia) dacănu se redefinesctoate funcţiile virtuale
pure moştenite. Dacă o clasă redefineşte toate funcţiile virtuale pure ale claselor ei de bază, devine clasă
normală (ne-abstractă) şi pot fi create instanţe (obiecte) ale acesteia.

67

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMExemplul7: Program de conversiea unordate dintr-o valoarede


intrareîntr-o

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

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMclassFC: public Convert{ // clasaFC de conversiegrade


Farenheitin grade Celsius public: FC(double i):Convert(i){} void conv(){y = (x-32)/1.8;} }; classIC: public
Convert{ // clasaIC de conversieinch in centimetripublic: IC(double i):Convert(i){} void conv(){y = 2.54*x;}
};

69

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMintmain (){ Convert* p = 0; // pointer la bazacout<<"Introduceti


valoarea si tipul conversiei: "; double v; char ch; cin>> v >> ch; switch (ch){ case 'i': //conversieinch -> cm
(clasaIC) p = new IC(v); break; case 'f': //conv. Farenheit-> Celsius (clasaFC) p = new FC(v); break; } if (p)
{ p->conv(); cout<< p->getx() << "---> " << p->gety()<< endl; delete p; } } În funcţia main() se execută o
conversie a unei valori introduse de la consolă, folosind un tip de conversie (o clasă derivată) care se
selectează pe baza unui caracter introdus la consolă.

70

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMAcestaesteunexempluîncareestedestuldepregnantănecesitateafuncţiilorvirtuale:deoarece
nusecunoaşteînmomentulcompilăriitipuldeconversiecaresevaefectua,sefoloseşteunpointerlaclasadebază
pentruoriceoperaţie(creareaunuiobiectdeconversienou,apelulfuncţieiconv(),afişarearezultatelor,distrug
ereaobiectuluilaterminareaprogramului).Singuradiferenţierecarepermiteselecţiacorectăafuncţiilor,esteti
pulobiectuluicreat,caredepindedetipulconversieicerutedelaconsolă.

71

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMÎnacestmomentsepotprecizamaidetaliatasemănărileşidiferenţeledintre:funcţiilesupraînc
ărcate(overloaded),funcţiileredefinite(redefined)şifuncţiilevirtualeredefinite(overrided).Întoateaceste
situaţiinumelefuncţiiloresteacelaşi.

72

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMÎncazulfuncţiilorsupraîncărcate,listadeargumentetrebuiesădifereastfelîncâtselecţiauneivar
ianteafuncţieisăpoatăfifăcutăfărăambiguitatedupătipulargumentelordeapel.Funcţiileredefiniteşifuncţiile
virtualeredefinitetrebuiesăaibăacelaşiprototip.Dintremaimultefuncţii(ofuncţiedefinităvirtualînclasadebaz
ăşiredefinităînclaselederivate),selecţiavarianteifuncţieisefacedupătipulobiectuluipentrucareesteinvocată
.Dintremaimultefuncţiinevirtuale(ofuncţiedefinităfărăspecificatorulvirtualînclasadebazăşiredefinităînclas
elederivate),selecţiavarianteifuncţieisefacedupătipulpointeruluicucareesteinvocată.

73

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMPolimorfismAşacumauilustratexempleleanterioare,ofuncţievirtualădeclaratăînclasadebază
acţioneazăcaunsubstitutpentrupăstrareadatelorcarespecificăoclasăgeneralădeacţiunişideclarăformaunei
interfeţecomune,iarfuncţiileredefiniteînclaselederivateprecizeazăacţiunilespecificefiecăreiclasederivate(
metodespecificediferitelorfuncţionalităţi).Obiectelecuaceeaşiinterfaţăpotfisubstituiteunulaltuialaruntim
e(obiectelesevorcomportaînfuncţiedetipullor).Aceastăcomportare,careasigurăsimplificareaşiorganizarea
sistemelordeprogramecomplexe,estecunoscutăsubnumeledepolimorfism.

74

CAP. 4Creareaierarhiilorde clase


4.7. FUNCŢII VIRTUALE ŞI POLIMORFISMPolimorfism

Polimorfismulintrodusprinmecanismuldevirtualitateestepolimorfismlaniveldeexecuţie,carepermitelegar
eatârzie(latebinding)întreevenimenteledinprogram,încontrastculegareatimpurie(earlybinding),proprieap
elurilorfuncţiilornormale(nevirtuale).

1.Conceptede bazaale programariiorientate


peobiecte2.Clasesiobiecte3.Supraincarcareaoperatorilor4.Creareaierarhiilorde clase5.Operatiide intrare/
iesirein limbajulC++6.Implementariale modelelorde
date7.Functiisiclasegenerice8.ExceptiisitratareaacestoraCuprinsulCursului

75

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMIntercorelarea(legarea)timpuriesereferălaevenimentelecaresedesfăşoarăîntimpulcompilăr
ii:apeluridefuncţiipentrucaresuntcunoscuteadreseledeapel(funcţiinormale,funcţiisupraîncărcate,operato
risupraîncărcaţi,funcţiimembrenevirtuale,funcţiifriend).Apelurilerezolvateîntimpulcompilăriibeneficiazăd
eoeficienţăridicată.

76

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMTermenuldelegaretârziesereferălaevenimentedintimpulexecuţiei.Înastfeldeapeluri,adresa
funcţieicareurmeazăsăfieapelatănuestecunoscutădecâtînmomentulexecuţieiprogramului.Funcţiilevirtual
esuntevenimenteculegaretârzie:accesullaastfeldefuncţiisefaceprinpointerlaclasadebază,iarapelareaefec
tivăafuncţieiestedeterminatăîntimpulexecuţieidetipulobiectuluiindicat,pentrucareestecunoscutpointerul
laclasasadebază.

Programareacalculatoarelorşilimbajede programareII

77

CAP. 4Creareaierarhiilorde clase

4.7. FUNCŢII VIRTUALE ŞI


POLIMORFISMAvantajulprincipalallegăriitârzii(permisădepolimorfismulasiguratdefuncţiilevirtuale)îlcons
tituesimplitateaşiflexibilitateaprogramelorrezultate.Bineînţeles,existăşidezavantaje,celmaiimportantfiind
timpulsuplimentarnecesarselecţieifuncţieiapelateefectivdintimpulexecuţiei,ceeaceconducelauntimpdee
xecuţiemaimarealprogramelor.Cualtecuvinte,folosireafuncţiilorvirtualetrebuierezervatănumaipentrusitu
aţiiîncaresuntînmodrealnecesare,atuncicândbeneficiuladusdepolimorfismdepăşeştecostulsuplimentarde
execuţie.

78

CAP. 4
SFARSITUL Capitolului4

Creareaierarhiilorde clase

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