Sunteți pe pagina 1din 32

MOTENIRE SIMPL.

DEFINIIE, SINTAX, MODIFICATORI DE ACCES, FUNCII VIRTUALE, POLIMORFISM


CURS 8 - PROGRAMARE II

CUPRINS
Motenire Clase derivate Modificatori de acces

Constructori i destructori
Supradefinirea operatoriilor Supradefinirea funciilor Funcii virtuale Destructori virtuali Polimorfism

MOTENIRE (INHERITANCE)
Definiie Motenirea este un mecanism care permite unei clase A s moteneasc atribute i metode ale unei clase B. n acest caz obiectele clasei A au acces la membrii clasei B fr a fi nevoie s le redefinim

Terminologie
Clas de baz
Clasa care este motenit

Clas derivat
O clas specializat a clasei de baz

Relaia kind-of nivel de clas


Triunghiul este un tip (kind-of) Poligon

Relaia is-a nivel de obiect


Obiectul triungiRosu este un (is-a) Poligon

EXEMPLU
Poligon

Dreptunghi

Triunghi

EXEMPLU APLICARE MOTENIRE


Poligon

Dreptunghi

Triunghi

TIPURI DE MOTENIRE N C++


Simpl

Multipl

DEFINIREA UNEI IERARHII DE CLASE


Sintax
class NumeleClaseiDerivate : modificatorDeAccess NumeleClaseiDeBaz

unde
modificatorDeAcces specific tipul derivrii private (valoare implicit) protected public

Orice clas poate fi clas de baz

MODIFICATORI DE ACCESS
Funciile membre ale clasei derivate au acces la membrii publici i protected ai clasei de baz Pentru a controla accesul la membrii clasei de baz sunt folosii specificatorii de acces
Clasa de Baz private protected public private protected public private protected public Modificatorul de acces private private private protected protected protected public public public Ce se poate accesa in clasa derivat nu este accesibil private private nu este accesibil protected protected nu este accesibil protected public Ce se poate accesa n exterior nu este accesibil nu este accesibil nu este accesibil nu este accesibil nu este accesibil nu este accesibil nu este accesibil nu este accesibil public

MODIFICATORI DE ACCES
class B{ public: int a; protected: int b; private: int c; }; class D1: B{ /*derivare private*/ void foo(){ int _a=a; //Ok int _b=b; //Ok int _c=c; //eroare: B::c este privat } }; class D2: protected B{ void foo(){ int _a=a; //Ok int _b=b; //Ok int _c=c; //eroare: B::c este privat } }; class D3: public B{ void foo(){ int _a=a; //?? int _b=b; //?? int _c=c; //?? } }; class DD : D1 { void foo(); }; void DD::foo() { a = 10; // ?? b = 20; // ?? c = 30; // ?? } int main(int argc, char** argv) { D1 d1; D2 d2; D3 d3; int v1=d1.a; //eroare: B::a nu este accesibil int v2=d1.b; //eroare: B::b este protected int v3=d1.c; //eroare: B::c nu este accesibil int v4=d2.a; //eroare: B::a nu este accesibil int v5=d2.b; //eroare: B::b este protected int v6=d2.c; //eroare: B::c este privat int v7=d3.a; //OK int v8=d3.b; //eroare: B::b este protected int v9=d3.c; //eroare: B::c este privat return 0; }

CE SE MOTENETE?
n pricipiu, fiecare membru al clasei de baz este motenit de clasa derivat Doar cu diferite permisiuni de acces Dar, exist cteva excepii Constructorii Destructorii

Operatorul =
Funciile friend

10

CONSTRUCTORII I DESTRUCTORII
Constructori Prima dat se apeleaz constructorul clasei de baz i apoi constructorul clasei derivate Destructori Sunt apelai n ordine invers fa de constructori, mai nti se apeleaz destructorul clasei derivate apoi cel al clasei de baz

11

CONSTRUCTORII I DESTRUCTORII
class Ferma { protected: char* nume; public: Ferma(){ cout << "Ferma: Default constructor " << this <<endl; } Ferma(char* nume){ cout << "Ferma: Full constructor " << this <<endl; . } ~Ferma(){ cout << "Ferma: Destructor " << this <<endl; } }; class FermaAgricola : public Ferma{ protected: int suprafata; public: FermaAgricola(){ cout << "FermaAgricola: Default constructor << this <<endl; } FermaAgricola(char* nume, int suprafata){ cout << "FermaAgricola: Full constructor<< this <<endl;; . } ~FermaAgricola(){ cout << "FermaAgricola: Destructor " << this <<endl; } };

Main() FermaAgricola fa;

Rezultat Ferma: Default constructor 0x28ff18 FermaAgricola: Default constructor 0x28ff18 FermaAgricola: Destructor 0x28ff18 Ferma: Destructor 0x28ff18

FermaAgricola fa(FermaA, 30);

12

Ferma: Default constructor 0x28ff18 FermaAgricola: Full constructor 0x28ff18 FermaAgricola: Destructor 0x28ff18 Ferma: Destructor 0x28ff18

CONSTRUCTORII I DESTRUCTORII
class Ferma { protected: char* nume; public: Ferma(){ cout << "Ferma: Default constructor " << this <<endl; } Ferma(char* nume){ cout << "Ferma: Full constructor " << this <<endl; . } ~Ferma(){ cout << "Ferma: Destructor " << this <<endl; } }; class FermaAgricola : public Ferma{ protected: int suprafata; public: FermaAgricola(){ cout << "FermaAgricola: Default constructor << this <<endl; } FermaAgricola(char* nume, int suprafata){ cout << "FermaAgricola: Full constructor<< this <<endl;; . } ~FermaAgricola(){ cout << "FermaAgricola: Destructor " << this <<endl; } };

Main() FermaAgricola fa;

Rezultat Ferma: Default constructor 0x28ff18 FermaAgricola: Default constructor 0x28ff18 FermaAgricola: Destructor 0x28ff18 Ferma: Destructor 0x28ff18

FermaAgricola fa(FermaA, 30);

13

Ferma: Default constructor 0x28ff18 FermaAgricola: Full constructor 0x28ff18 FermaAgricola: Destructor 0x28ff18 Ferma: Destructor 0x28ff18

CONSTRUCTORII I DESTRUCTORII
class Ferma { protected: char* nume; public: Ferma(){ cout << "Ferma: Default constructor " << this <<endl; } Ferma(char* nume){ cout << "Ferma: Full constructor " << this <<endl; . } ~Ferma(){ cout << "Ferma: Destructor " << this <<endl; } }; class FermaAgricola : public Ferma{ protected: int suprafata; public: FermaAgricola(){ cout << "FermaAgricola: Default constructor << this <<endl; } FermaAgricola(char* nume, int suprafata) : Ferma(nume) { cout << "FermaAgricola: Full constructor<< this <<endl;; . } ~FermaAgricola(){ cout << "FermaAgricola: Destructor " << this <<endl; } };

Main() FermaAgricola fa;

Rezultat Ferma: Default constructor 0x28ff18 FermaAgricola: Default constructor 0x28ff18 FermaAgricola: Destructor 0x28ff18 Ferma: Destructor 0x28ff18

FermaAgricola fa(FermaA, 30);

14

Ferma: Full constructor 0x28ff18 FermaAgricola: Full constructor 0x28ff18 FermaAgricola: Destructor 0x28ff18 Ferma: Destructor 0x28ff18

CONSTRUCTORUL DE COPIERE
Clasa derivat nu are definit un contructor de copiere => se apeleaz constructorul de copiere creat de compilator Clasa derivat are definit un contructor de copiere => se apeleaz constructorul de copiere definit (ex. FermaAnimale a(Ferma 1, 20), copie(a);)

Cum se poate modifica codul astfel nct s se realizeze i o copie a atributelor clasei de baz?
FermaAgricola(const FermaAgricola& f){ cout << "FermaAgricola: Copy constructor " << this <<endl; } Ferma: Default constructor 0x28ff10 FermaAgricola: Copy constructor 0x28ff10 FermaAgricola: Destructor 0x28ff10 Ferma: Destructor 0x28ff10

15

CONSTRUCTORUL DE COPIERE
Apelarea constructorului supraclasei
FermaAgricola(const FermaAgricola& f) : Ferma(f.nume){ cout << "FermaAgricola: Copy constructor " << this <<endl; this->suprafata = f.suprafata; } Ferma: Full constructor 0x28ff10 FermaAgricola: Copy constructor 0x28ff10 FermaAgricola: Destructor 0x28ff10 Ferma: Destructor 0x28ff10

Apelarea constructorului de copiere al supraclasei

FermaAgricola(const FermaAgricola& f) : Ferma(f){ cout << "FermaAgricola: Copy constructor " << this <<endl; this->suprafata = f.suprafata; }

Ferma: Copy constructor 0x28ff10 FermaAgricola: Copy constructor 0x28ff10 FermaAgricola: Destructor 0x28ff10 Ferma: Destructor 0x28ff10

16

SUPRADEFINIREA OPERATORILOR
Funciile operator membre ale clasei de baz sunt motenite de clasele derivate i pot fi redefinite n clasele derivate EXCEPIE Operatorul =()
Dac este definit n clasa derivat, el este apelat, dar nu se mai apeleaz cel din clasa de baz Dac nu este definit n clasa derivat, se apeleaz implicit copierea pentru atributele clasei derivate i operatorul =() definit n clasa de baz

17

CONVERSII DE TIP
Permise Nepermise

D B *D *B *B (B*)*D
FermaAgricola fa("fermaAgr", 30), *pfa; Ferma f("ferma2"), *pf; FermaAgricola fa2(fa); fa2.setSuprafata(100);

B D *B *D

Output

cout << "Conversie implicita FermaAgricola -> Ferma\n"; f = fa; cout << f << endl; cout << "Conversie implicita FermaAgricola -> *Ferma\n"; pf = &fa2; cout << *pf << endl; cout << "Conversie explicita *Ferma -> *FermaAgricola\n"; pfa = (FermaAgricola*)pf; cout << *pfa << endl;

fermaAgr

fermaAgr

18

fermaAgr 770887

REDEFINIREA FUNCIILOR MEMBRE


Ce este supradefinirea funciilor?
void Ferma::afisare() { cout << nume; } void FermaAgricola::afisare() { cout << nume <<" cu suprafata " << suprafata; } void FermaAgricola::modificareNume(char * nume) { cout << "Ferma agricola: '"; afisare(); if (nume!=NULL){ this->nume = new char[strlen(nume)+1]; strcpy(this->nume, nume); cout << "' isi schimba numele in '"; afisare(); cout <<"'\n" } }

Ferma agricola: 'fermaAgr cu suprafata 30' isi schimba numele in 'Ferma ABC 2'

19

REDEFINIREA FUNCIILOR MEMBRE

Ce este supradefinirea funciilor?


void Ferma::afisare() { cout << nume; } void FermaAgricola::afisare() { cout << nume <<" cu suprafata " << suprafata; } void FermaAgricola::modificareNume(char * nume) { cout << "Ferma agricola: '"; afisare(); if (nume!=NULL){ this->nume = new char[strlen(nume)+1]; strcpy(this->nume, nume); cout << "' isi schimba numele in '"; Ferma::afisare(); cout <<"'\n" } }

Ferma agricola: 'fermaAgr cu suprafata 30' isi schimba numele in 'Ferma ABC 2'

20

FUNCII VIRTUALE
void Ferma::afisare() { cout << "Ferma: "<< nume << endl; }

void FermaAgricola::afisare() { cout << "Ferma Agricola: " << nume <<" cu suprafata " << suprafata << endl; }
int main() { Ferma *ff; FermaAgricola ffa("Ferma Buzias", 300); ff = &ffa; ff->afisare(); return 0; }

Care este varianta de afiare dorit? Output Varianta A Ferma: Ferma Buzias

Ce se va afia?

Varianta B Ferma Agricola: Ferma Buzias cu suprafata 300

21

FUNCII VIRTUALE
Soluia Adugarea unui cmp care specific tipul obiectului Funcii viruale

Tipuri de legturi
Static (early binding)
Versiunea funciei apelate se stabilete n momentul compilrii

Dinamic (late binding)


Versiunea funciei apelate se stabilete n timpul execuiei programului

22

FUNCII VIRTUALE
Sintax

virual prototipFuncie;
Caracteristici Atributul virtual este motenit Este un tip special de funcie care determin tipul derivat corespunztor pentru o funcie cu acelasi prototip Specificarea cuvntului virtual n faa funciei Sunt funcii membre nestatice Redefinirea i redeclararea funciilor virtuale n clasele derivate nu este obligatorie Constructori nu pot fi funcii virtuale Redefinirea sau schimbarea prototipului este acceptabil doar dac se modific valoarea de return

23

FUNCII VIRTUALE
class Ferma{ ..... virtual void afisare() { cout << "Ferma: "<< nume << endl; } }; void FermaAgricola::afisare() { cout << "Ferma Agricola: " << nume <<" cu suprafata " << suprafata << endl; } int main() { Ferma *ff; FermaAgricola ffa("Ferma Buzias", 300); ff = &ffa; ff->afisare(); return 0; }

Output Varianta A Ferma: Ferma Buzias Varianta B Ferma Agricola: Ferma Buzias cu suprafata 300

24

DESTRUCTORII VIRTUALI
Ar trebui ca destructori claselor baz s fie declarai virtuali? De ce da sau de ce nu?

25

DESTRUCTORII VIRTUALI
Ar trebui ca destructori claselor baz s fie declarai virtuali? De ce da sau de ce nu? Da! Trebuie s tergem ntotdeauna i pointerii din subclase (altfel apare riscul de memory leaks)

26

DESTRUCTORII VIRTUALI
class Base1 { public: ~Base1() { std::cout << "~Base1()\n"; } }; class Derived1 : public Base1 { public: ~Derived1() { std::cout << "~Derived1()\n"; } }; class Base2 { public: virtual ~Base2() { std::cout << "~Base2()\n"; } }; class Derived2 : public Base2 { public: ~Derived2() { std::cout << "~Derived2()\n"; } }; int main() { Base1* bp = new Derived1; delete bp; Base2* b2p = new Derived2; delete b2p; }

27

DESTRUCTORII VIRTUALI
class Base1 { public: ~Base1() { std::cout << "~Base1()\n"; } }; class Derived1 : public Base1 { public: ~Derived1() { std::cout << "~Derived1()\n"; } }; class Base2 { public: virtual ~Base2() { std::cout << "~Base2()\n"; } }; class Derived2 : public Base2 { public: ~Derived2() { std::cout << "~Derived2()\n"; } }; int main() { Base1* bp = new Derived1; delete bp; Base2* b2p = new Derived2; delete b2p; }

~Base1() ~Derived2() ~Base2()

28

POLIMORFISM
Polimorfismul este abilitatea de a folosi o metod sau un operator n moduri diferite Tipuri de polimorfism Run-time
Motenire i funcii virtuale

Compile-time
Template-uri

Ad-hoc
Supradefinirea operatorilor (operatorul + se comport diferit pentru tipul int i string)

Parametric

29

Conversia de tip (casting)

POSIBLE ERORI
Specificatorul de acces implicit pentru motenire este private. O eroare des ntlnit este de a omite specificatorul de acces public Constructori nu pot fi funcii virtuale

30

SUMAR
Motenirea O metod care permite refolosirea codului Folosirea motenirii publice pentru polimorfism Folosirea motenirii private pentru ncapsulare Polimorfism

Folosirea de pointeri la clasele de baz


Legtura static/dinamic

31

CURS VIITOR
Funcii pur virtuale Clase abstracte Motenirea multipl Type casting

32

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