MOSTENIREA

 

 

            OOP ofera posibilitatea refolosirii intr-un program a unei clase pe care am mai utilizat-o intr-un alt program, economisind astfel timp si efort de programare. Sunt situatii in care o clasa foloseste caracteristici ale unei clase existente, adaugand unul sau mai multe date membre sau functii membre. In acest caz, C++ ofera posibilitatea de a crea noul obiect pe baza caracteristicilor obiectului existent. Atunci cand o noua clasa este creata pe baza uneia deja existente, noua clasa este o clasa derivata.

 

Definitie: Prin mostenire se intelege acea proprietate a claselor prin care o clasa nou construita poate prelua datele si metodele unei clase mai vechi. Clasei noi i se pot adauga date si metode. Acest mecanism mai este cunoscut sub numele de „derivare a claselor”.

 

            Avantajul acestui procedeu este ca se poate prelua soft gata facut, care se dezvolta. Persoana care dezvolta softul nu trebuie sa cunoasca detaliile de implementare ale acestuia, ci doar documentatia de utilizare.

 

            Daca avem clasele X1, X2,…Xn, putem construi clasa Xn+1 care are, pe langa datele si metodele celor n clase enumerate, propriile date si metode. Clasele X1, X2,…Xn se numesc clase de baza, iar clasa Xn+1 clasa derivata.

           

Declaratia unei clase derivate:

 

class NumeClasaDerivata : modificator_acces NumeClasaDeBaza

      {

 //date si metode specifice clasei derivate

      }

 

Obiectele din clasa derivata vor avea acces atat la membrii din clasa de baza cat si la membrii din clasa derivata.

 

Atentie daca si in clasa de baza si in clasa derivata doi membri (camp de data sau metoda) se numesc la fel, in clasa derivata daca se va dori sa se faca referire la membrul din clasa de baza se va folosi operatorul de rezolutie precedat de numele clasei de baza, altfel referirea va fi in mod implicit la membrul din clasa curenta (clasa derivata).

 

 

class C1                                               //clasa de baza

   {public:

            tip1 camp1;

            metoda1();

            ………………..

 };

 

class C2: public C1                              //clasa derivata

    {public:

            tip1 camp1;

            metoda1();

            …………………….

};

void main()

{C2 ob;

  ob.camp1;               //acceseaza campul din clasa C2

  ob.C1::camp1;        //acceseaza campul din clasa C1

  ob.metoda1();         //acceseaza metoda din clasa C2

  ob.C1::metoda1();  //acceseaza metoda din clasa C1

 

}

 

 

Exemplu: Fie clasa Persoana ce are ca date membre numele, prenumele si anul nasterii unei persoane. Vrem sa cream clasa Student care are, pe langa datele persoanei, si facultatea, specializarea si anul la care studiaza. Derivam clasa Student din clasa Persoana.

 

#include<iostream.h>

#include<conio.h>

/*****************************************/

class persoana                       //clasa de baza

{public:

 char nume[20], prenume[20];

 int an;

 

 void afisare()

 {cout<<endl<<"datele persoanei "<<endl;

  cout<<nume<<" "<<prenume<<endl;

  cout<<"Are "<<2005-an<<" ani"<<endl;

 }

 

 void citire()

 {

 cout<<"numele ";

 cin>>nume;

 cout<<"prenumele ";

 cin>>prenume;

 }

};

 

 

/**************************************************************/

class student: public persoana         //clasa derivata

{public:

 char fact[20],spec[20];

 int an;

 

 void citire()

 {cout<<"facultatea ";

 cin>>fact;

 cout<<"specializarea ";

 cin>>spec;

 }

 

 void afisare()

 {cout<<endl<<"datele studentului "<<endl;

  cout<<"facultatea "<<fact<<endl;

  cout<<"specializarea "<<spec<<endl;

  cout<<"anul "<<an<<endl;}

 };

 

void main()

{clrscr();

persoana p1;

p1.citire();

cout<<"anul nasterii ";

cin>>p1.an;

p1.afisare();

 

student s1;

cout<<endl<<"citire date student: ";

s1.persoana::citire();

cout<<"anul nasterii ";

cin>>s1.persoana::an;

s1.citire();

cout<<"in ce an este studentul? ";

cin>>s1.an;

cout<<"datele din ambele clase "<<endl;

s1.persoana::afisare();

s1.afisare();

 

getch();

}

 

Observatie: Atunci cand se deriveaza o clasa din alta clasa, membrii privati ai clasei de baza sunt accesibili clasei derivate prin intermediul metodelor publice oferite de clasa de baza. Din aceasta cauza, o clasa derivata nu poate accesa direct un membru privat al clasei de baza prin utilizarea operatorului punct.

In ceea ce priveste folosirea (compilarea si editarea de legaturi) clasei derivate in sensul programarii, clasa de baza si cea derivata pot apare in acelati fisier sursa, sau pot fi declarate in fisiere diferite.

 

 

Probleme propuse:

 

1. Sa se defineasca clasa complex ca si clasa de baza apoi o clasa vector care sa mosteneasca clasa complex si care sa permita prelucrarea unui sir de numere complexe. Cerinte:

-se citesc n numere complexe

-sa se afiseze numerele in format complex

-sa se determine suma acelor n numere complexe

-sa se determine suma a doi vectori de numere complexe

 

Schimbarea domeniilor de acces prin derivare

 

-                     Indiferent de tipul derivarii, functiile membre ale clasei derivate nu au acces in zona private a clasei de baza.

-                     Prin derivare public, membrii publici si protected ai clasei de baza isi pastreaza caracterul de public, respectiv protected (derivarea publica, extinde domeniile public si protected si pentru membrii derivatei)

-                     Prin derivare protected, membrii public si protected ai clasei de baza devin protected pentru clasa derivata

-                     Prin derivare private, membrii public si protected ai clasei de baza devin membri private in clasa derivata

-                     Daca nu se specifica tipul accesului mostenit prin derivare, se considera implicit private.

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Modificator acces la membrii clasei de baza

Accesul in clasa derivata (noul acces) dobandit prin mostenire publica

Accesul in clasa derivata (noul acces) dobandit prin mostenire protejata

Accesul in clasa derivata (noul acces) dobandit prin mostenire privata

private

private

private

private

public

public

protected

private

protected

protected

protected

private

 

Observatie: Prin derivarea private, se opreste posibilitatea de a transmite catre un urmas dreptul de acces la clasa de baza, in cazul mai multor niveluri de derivare ierarhica. Pentru primul nivel de derivare, zonele public si protected sunt totusi accesibile. Prin derivarea protected, membrii public si protected ai clasei derivate pot fi transmisi mai departe si altor clase, prin derivare succesiva.

           

Constructorii claselor derivate

 

Constructorii si destructorii sunt functii membre care nu se mostenesc. La instantierea unui obiect din clasa derivata se apeleaza mai intai constructorii claselor de baza, in ordinea in care acestia apar in lista din declararea clasei derivate. La distrugerea obiectelor, se apeleaza intai destructorul clasei derivate, apoi destructorii claselor de baza.

Transmiterea argumentelor unei functii constructor din clasa de baza se face folosind o forma extinsa a declaratiei constructorului clasei derivate, care transmite argumentele unui sau mai multor constructori din clasa de baza.

In general, clasele utilizeaza constructori definiti de programator. In cazul in care acestia lipsesc, compilatorul genereaza automat un constructor implicit pentru clasa respectiva. Acelasi lucru se intampla si in cazul constructorilor de copiere.

La instantierea unui obiect din clasa derivata, o parte din valorile primite ca parametri folosesc la initializarea datelor membru ale claselor de baza, iar restul initializeaza datele membru specifice clasei derivate.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Fie clasa de baza B si D o clasa derivata a ei. Noua clasa D isi are proprii ei constructori, impliciti si/sau expliciti. Constructorii clasei D sunt responsabili si cu initializarea corecta a datelor mostenite. In mod normal, el apeleaza la constructorul lui B, chiar daca noi nu cerem acest lucru, dupa care completeaza clasa cu datele si functiile specifice clasei D.

In cazul destructorului, lucrurile stau similar, numai ca ele se deruleaza in ordine inversa. La crearea unui obiect derivat, ordinea de executie este:

-       constructor de baza

-       constructor derivat

iar la eliberarea memoriei:

-       destructor derivat

-       destructor de baza

 

            Exemplu: Fie clasa Angajat care mosteneste clasa Persoana. Observati definirea constructorului clasei derivate!!!

           

class Persoana {

     char nume[20];

     int varsta;

     long tel;

public:

     Persoana(char c[20],int v,long t)

          {strcpy(nume,c);

          varsta=v;

          tel=t;}

     void afis()

            {cout<<nume<<"  "<<varsta<<"  "<<tel<<endl;}

     ~Persoana()

          {cout<<"am apelat destructorul clasei Persoana"<<endl;}

     };

 

class Angajat : public Persoana {

public:

     char functia[15];

     long sal;

     int vechime;

     Angajat(char c[20],int v,long t,char f[15],long s,int vech):Persoana(c,v,t)

          {strcpy(functia,f);

           sal=s;

           vechime=vech;}

     void afis_angajat()

          {afis();

           cout<<functia<<"  "<<vechime<<"  "<<sal<<endl;}

     ~Angajat()

          {cout<<"am apelat destructorul clasei Angajat"<<endl;}

     };

 

void main()

{Persoana p1("Popescu",30,422078);

 p1.afis();

 Angajat a1("Ionescu B.",33,319968,"profesor",4000000,9);

 a1.afis_angajat();

}

 

La distrugerea obiectelor, se va afisa:

am apelat destructorul clasei Persoana – pentru p1

am apelat destructorul clasei Persoana – pentru a1

am apelat destructorul clasei Angajat – pentru a1

 

Daca clasa derivata nu are constructori expliciti, valorile sunt cele puse de constructorul din clasa de baza. Exista un constructor de copiere implicit, care sta la baza conversiilor unui Angajat intr-o Persoana.

 

Mostenirea multipla

 

O clasa poate sa mosteneasca mai multe clase de baza, ceea ce inseamna ca toti membrii claselor de baza vor fi mosteniti de clasa derivata. In aceasta situatie apare mecanismul mostenirii multiple.

 

Exercitiu:  Se implementeaza ierahia de clase din figura.

 

#include <iostream.h>

class baza1     {

protected:

      int x;

public:

      baza1 (int xx)

          {x=xx;cout<<"Constructor cls. baza1\n";

cout<<x<<'\n';}

      ~baza1()

          {cout<<"Destructor baza1\n"<<x<<'\n';}

      void aratax()

          {cout<<"x="<<x<<'\n';}

};

 

class baza2 {

protected:

      int y;

public:

      baza2 (int yy)

          {y=yy; cout<<"Constructor baza2\n"<<y<<'\n';}

      ~baza2()

{cout<<"Destructor baza2\n";}

      void aratay(){cout<<"y="<<y<<'\n';}

};

 

class derivat: public baza1, public baza2 {

public:

      derivat(int xx, int yy):baza1(xx), baza2(yy)

          {cout<<"Constructor derivat\n"; cout<<x<<' '<<y<<'\n';}

      ~derivat()

          {cout<<"Destructor derivat\n"; cout<<x<<' '<<y<<'\n';}

      int arata(){cout<<x<<' '<<y<<'\n';}

      void seteaza(int xx, int yy){x=xx; y=yy;}

};

 

void main()

{

derivat obiect(7,8);/*Constructor cls. baza1  7     Constructor baza2 

8   Constructor derivat  7  8  */

obiect.arata();      // 7 8

obiect.seteaza(1,2);

obiect.aratax();          // x=1

obiect.aratay();          // y=2

obiect.arata();      // 1 2

/* Destructor derivat 1 2      Destructor baza2 2   Destructor baza1  1 */

}

 

Asa cum ilustreaza exemplul, la declararea obiectului obiect de tipul derivat s-au apelat constructorii  claselor de baza (baza1 si baza2), in ordinea in care apar in declararea clasei derivate: mai intai constructorul clasei baza1, in care x este data membru protejata (accesibila din clasa derivat); apoi constructorul clasei baza2 , in care y este data membru protejata (accesibila din clasa derivat); apoi constructorul clasei derivat care le incorporeaza pe acestea intr-un singur obiect. Clasa derivat nu are date membre, ci doar metode.

 


Dupa iesirea din blocul in care a fost declarata variabila

obiect, se apeleaza automat destructorii, in ordine

inversa apelarii constructorilor.

 

 

 

 

Exercitii:

1.      Sa se implementeze ierarhia de clase din figura alaturata, cu

membrii pe care ii considerati necesari.

 

2.      Concepeti o ierarhie de clase a figurilor geometrice.

Ca date membre pot fi considerate pozitia, dimensiunile

si atributele de desenare (culoare, tip linie). Metodele

vor permite operatii de afisare, deplasare, stergere,

modificarea atributelor figurii. Clasa de baza va avea

proprietatile generale ale oricarei figuri: coordonatele

pe ecran si vizibilitate.

 

3.      Din clasa matrice, sa se deriveze clasa c_matrice, care

reprezinta o matrice de complecsi.

 

 

 

 

4.      Sa se defineasca o clasa coada care sa permita adaugarea si listarea elementelor. Sa se defineasca o noua clasa lista care sa permita si inserarea si stergerea unui element. Sa se concateneze 2 liste (se va supraincarca operatorul +). Sa se defineasca o noua clasa, lista_circulara, care sa mosteneasca clasa lista si care sa treaca o lista liniara in lista circulara si afiseaza o lista circulara.

 

5.      Sa se defineasca o clasa vector care va permite: citirea, afisarea si ordonarea unui vector. Sa se defineasca o clasa multime derivata din vector care sa permita in plus operatii cu multimi. Sa se supraincarce operatorul ! astfel incat un vector sa contina numai elemente distincte.

 

6.      sa se defineasca o clasa segment apoi o clasa triunghi derivata. Sa se calculeze aria si perimetrul triunghiului.

 

7.      Sa se defineasca o clasa matrice care sa permita citirea, afisarea si calculul sumei elementelor de pe o linie. Sa se defineasca o noua clasa graf_neorientat care sa permita prelucrarea grafurilor neorientate memorate prin matrice: parcurgere in adancime si conexitate.

 

8.      sa se defineasca clasa sir care are ca date membru sirul si lungimea lui si care sa permita urmatoarele prelucrari: concatenarea a doua siruri, stergerea unui caracter de pe pozitia k, inserarea unui caracter pe pozitia k, stergerea caracterului c.

 

9.       definiti o clasa fisier cara sa permita prelucrarea fisierelor text. Ca date membru vom avea numele fisierului, iar ca metode urmatoarele:

a)determinarea numarului de caractere printabile
b) compararea a doua fisiere

c) concatenarea a doua fisiere

 

10.  definiti o clasa numar_mare care sa permita operatii cu numere mari: citirea , suma si produsul a 2 numere mari

 

 

11.  sa se defineasca o clasa care contine ca membri un numar si descompunerea sa in factori primi si o metoda ce realizeaza descompunerea numarului in factori primi. Sa se determine produsul a doua numere descompuse in factori primi. Sa se determine cmmmc si cmmdc a doua numere exprimat in factori primi. Sa se determine cmmmc si cmmdc a n numere.

12.  sa se defineasca clasa matrice patratica rara unde pt elementele nenule se cunosc coordonatele si valoare retinuta. Sa se afiseze elementele de pe linia x, coloana y, suma a doua matrici, diagonala principala, secundara.

13.  sa se defineasca o clasa polinom care sa permita operatii specifice