Differences

This shows you the differences between two versions of the page.

Link to this comparison view

poo-is-ab:laboratoare:08 [2024/11/17 22:24]
razvan.cristea0106 [Interfețe]
poo-is-ab:laboratoare:08 [2025/01/19 22:30] (current)
razvan.cristea0106
Line 1: Line 1:
-===== Laboratorul 08 - Clase abstracte și interfețe =====+===== Laborator 09 - Clase abstracte și interfețe =====
  
 **Autor: Răzvan Cristea** **Autor: Răzvan Cristea**
Line 15: Line 15:
 ==== Introducere ==== ==== Introducere ====
  
-Până în prezent, am explorat conceptul de **polimorfism timpuriu (early polymorphism sau compile-time polymorphism)**,​ care se manifestă atunci când **funcții/​metode** cu **același nume** sunt **diferențiate prin numărul sau tipul parametrilor**. ​Aceasta ​stă la baza conceptului de **supraîncărcare a funcțiilor (overloading)**,​ care permite definirea mai multor variante ale unei funcții în cadrul **aceleiași clase**, fiecare având un **comportament specific** în funcție de **semnătura sa**. Acest tip de polimorfism este decis la **compilare**,​ ceea ce înseamnă că alegerea funcției care va fi apelată se face de către **compilator** pe baza tipului argumentelor oferite.+Până în prezent, am explorat conceptul de **polimorfism timpuriu (early polymorphism sau compile-time polymorphism)**,​ care se manifestă atunci când **funcții/​metode** cu **același nume** sunt **diferențiate prin numărul sau tipul parametrilor**. ​Acest lucru stă la baza conceptului de **supraîncărcare a funcțiilor (overloading)**,​ care permite definirea mai multor variante ale unei funcții în cadrul **aceleiași clase**, fiecare având un **comportament specific** în funcție de **semnătura sa**. Acest tip de polimorfism este decis la **compilare**,​ ceea ce înseamnă că alegerea funcției care va fi apelată se face de către **compilator** pe baza tipului argumentelor oferite.
  
 De exemplu, dacă avem o funcție **''​adunare''​** supraîncărcată pentru a lucra cu numere întregi și cu numere reale, **compilatorul** determină **automat** care versiune a funcției urmează să fie apelată, în funcție de **tipul** datelor primite ca argumente. Avantajul acestui tip de polimorfism este **viteza de execuție**,​ deoarece decizia a fost deja luată **înainte** ca programul să ruleze. De exemplu, dacă avem o funcție **''​adunare''​** supraîncărcată pentru a lucra cu numere întregi și cu numere reale, **compilatorul** determină **automat** care versiune a funcției urmează să fie apelată, în funcție de **tipul** datelor primite ca argumente. Avantajul acestui tip de polimorfism este **viteza de execuție**,​ deoarece decizia a fost deja luată **înainte** ca programul să ruleze.
  
-Cu toate acestea, există cazuri în care decizia pentru funcția/​metoda ce trebuie apelată **nu** poate fi luată ​la de către compilator, ci doar în timpul execuției. Acest procedeu este cunoscut sub denumirea de **polimorfism întârziat (late binding sau run-time polymorphism)**. Acest concept este strâns legat de **suprascrierea funcțiilor (overriding)** și de utilizarea mecanismelor de **moștenire** și **funcții virtuale** în C++.+Cu toate acestea, există cazuri în care decizia pentru funcția/​metoda ce trebuie apelată **nu** poate fi luată de către compilator, ci doar în timpul execuției. Acest procedeu este cunoscut sub denumirea de **polimorfism întârziat (late binding sau run-time polymorphism)**. Acest concept este strâns legat de **suprascrierea funcțiilor (overriding)** și de utilizarea mecanismelor de **moștenire** și **funcții virtuale** în C++.
  
 ==== Overloading vs Overriding ==== ==== Overloading vs Overriding ====
  
-În continuare vom prezenta un tabel care prezintă diferențele clare între cele două forme de polimorfism.+În continuare vom prezenta un tabel care pune în evidență diferențele clare între cele două forme de polimorfism.
  
 ^        **Overloading (Compile-Time Polymorphism)** ​     ^        **Overriding (Run-Time Polymorphism)** ​          ^ ^        **Overloading (Compile-Time Polymorphism)** ​     ^        **Overriding (Run-Time Polymorphism)** ​          ^
Line 33: Line 33:
 | Are un impact **redus** asupra performanței,​ deoarece decizia se ia la compilare | Are un impact **ușor mai mare** asupra performanței,​ deoarece decizia se ia în timpul execuției | | Are un impact **redus** asupra performanței,​ deoarece decizia se ia la compilare | Are un impact **ușor mai mare** asupra performanței,​ deoarece decizia se ia în timpul execuției |
  
-**Suprascrierea** (overriding) implică păstrarea aceluiași antent al funcției – adică același tip de return și aceiași semnătura (numele și lista de parametri) – dar permite redefinirea completă a comportamentului acesteia într-o **clasă derivată**. Prin această abordare, o funcție virtuală din clasa de bază poate fi adaptată pentru a răspunde nevoilor specifice ale clasei derivate. Acest proces este esențial pentru **polimorfismul la timp de execuție**,​ oferind flexibilitate și posibilitatea de a extinde funcționalitățile într-un mod dinamic.+**Suprascrierea** (**overriding**) implică păstrarea aceluiași antent al funcției – adică același tip de return și aceeași semnătura (numele și lista de parametri) – dar permite redefinirea completă a comportamentului acesteia într-o **clasă derivată**. Prin această abordare, o funcție virtuală din clasa de bază poate fi adaptată pentru a răspunde nevoilor specifice ale clasei derivate. Acest proces este esențial pentru **polimorfismul la timp de execuție**,​ oferind flexibilitate și posibilitatea de a extinde funcționalitățile într-un mod dinamic.
  
-Pe de altă parte, **supraîncărcarea** (overloading) presupune existența mai multor funcții cu același nume în cadrul aceleiași clase, dar care diferă prin numărul sau tipul parametrilor. Deși semnăturile sunt distincte, logica generală a funcțiilor rămâne similară, acestea fiind utilizate pentru a oferi funcționalități variate în contexte diferite. Alegerea variantei corespunzătoare este realizată la timpul de compilare, ceea ce asigură o execuție rapidă.+Pe de altă parte, **supraîncărcarea** (**overloading**) presupune existența mai multor funcții cu același nume în cadrul aceleiași clase, dar care diferă prin numărul sau tipul parametrilor. Deși semnăturile sunt distincte, logica generală a funcțiilor rămâne similară, acestea fiind utilizate pentru a oferi funcționalități variate în contexte diferite. Alegerea variantei corespunzătoare este realizată la timpul de compilare, ceea ce asigură o execuție rapidă.
  
-<note important>​Astfel **suprascrierea** permite modificarea profundă a comportamentului unei funcții în cadrul unei ierarhii de clase, în timp ce **supraîncărcarea** oferă posibilitatea reutilizării aceluiași nume de funcție pentru a gestiona scenarii variate, păstrând însă consistența logicii.</​note>​+<note important>​Astfel **suprascrierea** permite modificarea profundă a comportamentului unei funcții în cadrul unei **ierarhii de clase**, în timp ce **supraîncărcarea** oferă posibilitatea reutilizării aceluiași nume de funcție pentru a gestiona scenarii variate, păstrând însă consistența logicii.</​note>​
  
 ==== Funcții virtuale ==== ==== Funcții virtuale ====
Line 338: Line 338:
 </​code>​ </​code>​
  
 +Iar în continuare vom prezenta clasele **Cerc** și **Patrat**.
  
 +<code cpp>
 +class Cerc : public FiguraGeomertica
 +{
 + int raza;
 +
 +public:
 +
 + Cerc(const int& raza = 0);
 +
 + float getArie() const override;
 + float getPerimetru() const override;
 +};
 +</​code>​
 +
 +Iar mai jos sunt prezentate implementările metodelor aferente clasei **Cerc**.
 +
 +<code cpp>
 +Cerc::​Cerc(const int& raza)
 +{
 + this->​raza = raza;
 +}
 +
 +float Cerc::​getArie() const
 +{
 + return 3.14f * raza * raza;
 +}
 +
 +float Cerc::​getPerimetru() const
 +{
 + return 2 * 3.14f * raza;
 +}
 +</​code>​
 +
 +Declarația clasei **Patrat** se poate observa mai jos.
 +
 +<code cpp>
 +class Patrat : public FiguraGeomertica
 +{
 + int latura;
 +
 +public:
 +
 + Patrat(const int& latura = 0);
 +
 + float getArie() const override;
 + float getPerimetru() const override;
 +};
 +</​code>​
 +
 +Iar implementările metodelor sunt disponibile mai jos.
 +
 +<code cpp>
 +Patrat::​Patrat(const int& latura)
 +{
 + this->​latura = latura;
 +}
 +
 +float Patrat::​getArie() const
 +{
 + return(float) latura * latura;
 +}
 +
 +float Patrat::​getPerimetru() const
 +{
 + return(float) 4 * latura;
 +}
 +</​code>​
 +
 +Iar ca și exemplu de testare a funcționalităților în funcția main avem:
 +
 +<code cpp>
 +int main()
 +{
 + FiguraGeomertica* pfg1 = new Cerc(4);
 +
 + std::cout << "Aria cercului este: " << pfg1->​getArie() << '​\n';​
 + std::cout << "​Perimetrul cercului este: " << pfg1->​getPerimetru() << '​\n';​
 +
 + FiguraGeomertica* pfg2 = new Patrat(5);
 +
 + std::cout << "​\nAria patratului este: " << pfg2->​getArie() << '​\n';​
 + std::cout << "​Perimetrul patratului este: " << pfg2->​getPerimetru() << '​\n';​
 +
 + delete pfg1;
 + delete pfg2;
 +
 + return 0;
 +}
 +</​code>​
 +
 +<note important>​În cazul clasei **FiguraGeometrica** nu este necesară implementarea unui destructor virtual pur deoarece în clasele derivate **nu** există membri de tip pointer **alocați dinamic**. Prin urmare ordinea de apel a destructorilor este cea **corectă**,​ adică sunt apelați mai întâi destructorii claselor derivate (**Cerc** și **Patrat**) și la final va fi apelat destructorul superclasei.</​note>​
 +
 +==== Concluzii ====
 +
 +Acest laborator a abordat concepte avansate legate de **POO** în limbajul C++, punând accent pe mecanismele de **virtualizare**,​ diferențele dintre **overloading** și **overriding**,​ și utilizarea **claselor abstracte** și a **interfețelor**.
 +
 +== Virtualizarea în C++ ==
 +
 +  * **Metodele virtuale** oferă flexibilitatea necesară pentru implementarea **polimorfismului dinamic**, unde comportamentul funcțiilor este stabilit în timpul execuției (**late binding**).
 +
 +  * **Metodele virtual pure** obligă clasele derivate să implementeze funcționalitățile esențiale, asigurând astfel că fiecare clasă derivată își definește comportamentul specific.
 +
 +== Overloading vs Overriding ==
 +
 +  * **Overriding** este asociat cu polimorfismul dinamic (**run-time polymorphism**) și presupune redefinirea comportamentului unei metode virtuale din clasa de bază în clasele derivate.
 +
 +  * **Overloading** este asociat cu polimorfismul timpuriu (**compile-time polymorphism**) și permite mai multe metode cu același nume, dar semnături diferite, în cadrul aceleiași clase.
 +
 +  * Este important să folosim cuvântul cheie **override** pentru a face codul mai sigur și mai lizibil, prevenind erorile legate de semnături greșite sau lipsa suprascrierii.
 +
 +== Clase Abstracte și Metode Virtual Pure ==
 +
 +  * **Clasele abstracte** oferă un punct de plecare pentru proiectarea ierarhiilor complexe, combinând funcționalitățile comune și abstractizarea.
 +
 +  * O **metodă virtual pură** este o metodă **fără** implementare în clasa de bază, iar clasa devine abstractă dacă conține cel puțin o astfel de metodă.
 +
 +  * Destructorii virtuali sunt obligatorii în clasele abstracte pentru a asigura o eliberare corectă a resurselor în ierarhiile de moștenire.
 +
 +== Interfețele în C++ ==
 +
 +  * **Interfețele** sunt un caz particular de clase abstracte care conțin **doar** metode virtual pure.
 +
 +  * Ele definesc **contracte stricte** între clase și sunt utilizate pentru a implementa moștenirea multiplă într-un mod clar și organizat, fără ambiguități.
 +
 +==== ====
 +
 +Acest laborator a evidențiat rolul important al mecanismului de **virtualizare**,​ al **claselor abstracte** și al **interfețelor** în proiectarea sistemelor software flexibile și extensibile. Am înțeles diferențele esențiale dintre **overloading** și **overriding** și importanța implementării corecte a **metodelor virtuale**, pentru a asigura funcționarea corectă și eficientă a aplicațiilor **orientate obiect**.
poo-is-ab/laboratoare/08.1731875078.txt.gz · Last modified: 2024/11/17 22:24 by razvan.cristea0106
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0