diff --git a/POO_22_C_2022-05-12.md b/POO_22_C_2022-05-12.md new file mode 100644 index 0000000..f17b8cd --- /dev/null +++ b/POO_22_C_2022-05-12.md @@ -0,0 +1,138 @@ +## `dynamic_cast` +Operatorul `dynamic_cast` este folosit pentru a converti un obiect de la o anumita adresa la un alt obiect. Obiectele trebuie sa fie instanta aceleiasi ierarhii. Mai mult, unul dintre obiecte trebuie sa fie subobiect al unuia dintre obiecte. +```cpp +class Persoana +{ + char nume[50]; +public: + Persoana(const char* nume){strcpy(nume,nume);} + virtual char* getNume(){return nume;} + virtual ~Persoana(){} +}; +class student:public Persoana +{ + char matricol[20]; +public: + student(const char* nume, const char* matricol):Persoana(nume){strcpy(matricol, nrm);} + char* getMatricol(){return matricol;} +}; + +class profesor:public Persoana +{ + int vechime; +public: + profesor(const char* nume, const int v):Persoana(nume),vechime(v){} + int getVechime(){return vechime;} +}; + +void main() +{ + int n; + cin >> n; + Persoana** pers = new Persoana*[n]; + for(int i = 0; i < n; i++) + switch(rand(time(0))%3) + { + case 0: cin >> nume; pers[i] = new Persoana(nume): break; + case 1: cin >> nume >> matricol; pers[i] = new student(nume, matricol); break; + case 2: cin >> nume >> v; pers[i] = new profesor(nume, v); + } + /* + * Pentru vectorul pers, dupa ce a fost creat, dorim + * ca pentru fiecare componenta sa stim ce instantiere + * s-a facut (persoana, student sau profesor). + * Daca cunoastem acest lucru, pentru studenti si + * pentru profesori vom avea informatii suplimentare + * (numar matricol, respectiv vechime). + * In C++ nu exista un mecanism de a afla ce tip de + * informatie se afla la o anumita adresa, deci in + * exemplul nostru, pers[i] nu stim daca este instanta + * persoana, student sau profesor. + * In cazul in care o clasa in intregime sau cel putin + * o functie membra este virtuala informatii despre un + * un obiect instanta acelei clase se retin in VMT. Pe + * baza acestor informatii se poate identifica ce + * obiecte avem in memorie instanta clasei respective. + * Acest lucru se poate obtine apeland la operatorul + * + * dynamic_cast + * + * + */ + +... + + for (int i = 0; i < n; i++) + if(dynamic_cast(pers[i]) != nullptr) + cout << "student" << endl; + else if(dynamic_cast(pers[i]) != nullptr) + cout << "profesor" << endl; + else + cout << "persoana" << endl; + + /* + * dynamic_cast nu functioneaza (returneaza NULL), decat + * daca in clasa Persoana avem cel putin o metoda + * virtuala sau clasa este mostenita virtual. + */ + + for(int i = 0; i < n; i++) + delete pers[i]; + //daca nu avem destructor virtual in Persoana avem + //memory leak + delete[] pers; + +} +``` + +```cpp +student *s = dynamic_cast(pers[1]); +``` +Operatorul `dynamic_cast` se foloseste ca in exemplul de mai sus. Se incearca a se converti pointerul `pers[1]` la tipul `student*`. Acest lucru va fi posibil numai daca pentru `pers[i]` va exista si obiectul aferent instanta student (`pers[i]` s-a initializat cu un apel `new student`). In caz de reusita, operatorul returneaza pointerul catre obiectul `student` aflat in memorie. + +## Functii pur virtuale si clase abstracte +O functie membra unei clase poate fi declarata ca fiind pur virtuala. Evident, aceasta functie este virtuala. +```cpp +class ... +{ + virtual tip_returnat functieMembra (param) = 0; +} +``` + +O functie pur virtuala se recunoaste din faptul ca, dupa antetul ei, declarat virtual, apare specificatia ` = 0;`. O functie pur virtuala nu se implementeaza. O clasa care contine cel putin o functie pur virtuala devine **clasa abstracta**. O clasa abstracta nu poate fi instantiata. Clasele derivate dintr-o clasa abstracta, daca nu implementeaza toate functiile pur virtuale devin la randul lor clase abstracte. In Java trebuie scris `abstract`. +O clasa poate fi instantiata daca nu are functii pur virtuale si a implementat toate functiile pur virtuale mostenite, dintr-o eventuala clasa abstracta (mostenire directa). +O clasa care contine numai functii pur virtuale (ca metode) devine **interfata**. +O clasa abstracta, de obicei, descrie o ierarhie, trasand specificul acelei ierarhii. O clasa poate intra in ierarhia respectiva numai daca implementeaza toate metodele (specifice ierarhiei) clasei abstracte. +De exemplu: ierarhie figura geometrica. O clasa poate fi introdusa in aceasta ierarhie numai daca are metode pentru arie si perimetru. Cu alte cuvinte, oricine are arie si perimetru este figura geometrica. Ierarhia o deschidem cu o clasa abstracta avand cele doua metode pur virtuale. + +```cpp +class FigGeom +{ + char denumire[50]; +public: + void setDen(char* den){strcpy(denumire, den);} + virtual float arie() = 0; + virtual float perimetru() = 0; +}; + +class Dreptunghi:public FigGeom +{ + float x1, y1, x2, y2; +public: + Dreptunghi(float X1, float Y1, float X2, float Y2) + { + setDen("Dreptunghi"); + x1 = X1; + y1 = Y1; + x2 = X2; + y2 = Y2; + } + float arie(){return fabs((x2-x1)*(y2-y1));} + float perimetru(){return (fabs(x2-x1)+fabs(y2-y1))+2.f;} +}; +``` +TPA: Sa se implementeze ierarhia FigGeom din imaginea urmatoare: + +![Imagine: ierarhia FigGeom](https://cdn.discordapp.com/attachments/788436277388247050/974349459804815420/ierarhie-FigGeom.png) +Pentru fiecare trebuie sa implementati arie si perimetru. +Pornind de la ierarhia de mai sus putem oricand creea oricand un vector de figuri geometrice care contine obiecte (pointeri catre) instanta claselor derivate direct sau indirect din FigGeom. \ No newline at end of file diff --git a/README.md b/README.md index fae3acb..68f5865 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,8 @@ - functii virtuale - mecanismul de apelare a functiilor virtuale - destructori virtuali -- apelul unui constructor dintr-o clasa derivata \ No newline at end of file +- apelul unui constructor dintr-o clasa derivata +#### [Curs 11](https://github.com/tgpetrica/POO-courses/blob/main/POO_22_C_2022-05-12.md) +- ```dynamic_cast``` +- functii pur virtuale +- clase abstracte \ No newline at end of file