This shows you the differences between two versions of the page.
poo-is-ab:laboratoare:09 [2024/11/30 20:03] razvan.cristea0106 [Supraîncărcarea operatorului << pentru o clasă abstractă] |
poo-is-ab:laboratoare:09 [2025/01/19 22:30] (current) razvan.cristea0106 |
||
---|---|---|---|
Line 8: | Line 8: | ||
* recunoască un vector de obiecte neomogene | * recunoască un vector de obiecte neomogene | ||
- | * știe cum să aloce și să dezaloce memorie pentru un astfel de vector | + | * știe cum să aloce și să dezaloce memoria pentru un astfel de vector |
- | * înțeleagă importanța utilizării acestui vector corelat cu notiunea de suprascriere | + | * înțeleagă importanța utilizării acestui vector corelat cu noțiunea de suprascriere |
- | * prelucreze o colecție neomogenă de date cu ajutorul noțiunilor dobândite în laboratorul precedent | + | * prelucreze o colecție neomogenă de date |
- | * supraîncarce diverși operatori pentru clasa de bază pentru a-i putea folosi în prelucrarea vectorului | + | * supraîncarce diverși operatori pentru clasa de bază |
==== Introducere ==== | ==== Introducere ==== | ||
Line 19: | Line 19: | ||
==== Vector de obiecte neomogene ==== | ==== Vector de obiecte neomogene ==== | ||
- | Un **vector de obiecte neomogene** este o structură de date utilizată pentru a stoca și gestiona obiecte de tipuri diferite, dar care împărtășesc o relație comună definită printr-o **clasă abstractă** sau o **interfață**. Această abordare este posibilă datorită conceptului de **late binding**, care permite apelarea metodelor potrivite pentru fiecare obiect în funcție de tipul său concret, stabilit la momentul execuției. | + | Un **vector de obiecte neomogene** este o structură de date utilizată pentru a stoca și gestiona obiecte de tipuri diferite, dar care împărtășesc o relație comună definită printr-o **clasă abstractă** sau o **interfață**. Această abordare este posibilă datorită conceptului de **late binding**, care permite apelarea metodelor potrivite pentru fiecare pointer în funcție de tipul său concret, stabilit la momentul execuției. |
Acest tip de vector **nu** stochează **direct** obiectele, ci **pointeri la obiecte**. Acest lucru asigură flexibilitatea de a lucra cu tipuri diferite de obiecte, cu condiția ca acestea să implementeze toate **metodele virtuale** sau **virtual pure** definite în **clasa abstractă** sau **interfața** comună. | Acest tip de vector **nu** stochează **direct** obiectele, ci **pointeri la obiecte**. Acest lucru asigură flexibilitatea de a lucra cu tipuri diferite de obiecte, cu condiția ca acestea să implementeze toate **metodele virtuale** sau **virtual pure** definite în **clasa abstractă** sau **interfața** comună. | ||
Avantajele utilizării unui vector de obiecte neomogene sunt: | Avantajele utilizării unui vector de obiecte neomogene sunt: | ||
- | |||
- | * **Flexibilitate**: Posibilitatea de a combina obiecte derivate din clase diferite, dar compatibile | ||
* **Polimorfism**: Gestionarea comportamentelor variate ale obiectelor printr-o singură interfață | * **Polimorfism**: Gestionarea comportamentelor variate ale obiectelor printr-o singură interfață | ||
- | * **Scalabilitate**: Adăugarea de noi tipuri de obiecte devine ușoară, fără a modifica codul existent al vectorului | + | * **Scalabilitate**: Adăugarea de noi tipuri de obiecte devine ușoară, fără a modifica codul existent |
- | Astfel, vectorii de obiecte neomogene reprezintă un instrument esențial în gestionarea colecțiilor de date diverse, utilizând avantajele oferite de **polimorfism** și de principiile **POO**. Această tehnică facilitează crearea de sisteme **modulare** și **extensibile**, esențiale pentru aplicații complexe. | + | Astfel, **vectorii de obiecte neomogene** reprezintă un instrument esențial în gestionarea colecțiilor de date diverse, utilizând avantajele oferite de **polimorfism** și de principiile **POO**. Această tehnică facilitează crearea de sisteme **modulare** și **extensibile**, esențiale pentru aplicații complexe. |
- | Pentru a putea construi un vector de obiecte neomogene mai întâi avem nevoie de o ierarhie de clase iar exemplul din acest laboartor este realizat cu ajutorul claselor **ProdusElectronic** care este o interfață și respectiv **Laptop** și **Smartphone** care sunt clase concrete ce implementează interfața anterior menționată. | + | Pentru a putea construi un **vector de obiecte neomogene** mai întâi avem nevoie de o **ierarhie de clase** iar exemplul din acest laboartor este realizat cu ajutorul claselor **ProdusElectronic** care este o **interfață** și respectiv **Laptop** și **SmartPhone** care sunt **clase concrete** ce **implementează** interfața anterior menționată. |
- | Interfața **ProdusElectronic** contine metodele virtual pure ''**getPret**'' și respectiv ''**getProducator**'' și un destructor virtual pur. | + | Interfața **ProdusElectronic** conține metodele virtual pure ''**getPret**'' și respectiv ''**getProducator**'' și un destructor virtual pur. |
<code cpp> | <code cpp> | ||
Line 60: | Line 58: | ||
</code> | </code> | ||
- | Clasele Laptop și Smartphone pot fi observate mai jos. | + | Clasele **Laptop** și **SmartPhone** pot fi observate mai jos. |
<code cpp> | <code cpp> | ||
Line 180: | Line 178: | ||
</code> | </code> | ||
- | Pentru a putea declara un vector de obiecte neomogene vom folosi un **dublu pointer** la tipul interfeței **ProdusElectronic** pe care îl vom aloca dinamic folosind **operatorul new** după cum urmează. | + | Pentru a putea declara un **vector de obiecte neomogene** vom folosi un **dublu pointer** la tipul interfeței **ProdusElectronic** pe care îl vom aloca dinamic folosind **operatorul new** după cum urmează în blocul de cod de mai jos. |
<code cpp> | <code cpp> | ||
#include "Laptop.h" | #include "Laptop.h" | ||
- | #include "Smartphone.h" | + | #include "SmartPhone.h" |
int main() | int main() | ||
Line 207: | Line 205: | ||
</code> | </code> | ||
- | Tot ceea ce mai trebuie să facem acum este să dezalocăm memoria corespunzător. Dacă mai întâi am alocat vectorul și apoi am alocat câte un slot de memorie pentru fiecare pointer din vector la eliberarea memoriei vom porni în ordinea inversă după cum se poate observa în blocul de cod de mai jos. | + | Tot ceea ce mai trebuie să facem acum este să dezalocăm memoria corespunzător. Dacă mai întâi am alocat vectorul și apoi am alocat câte un slot de memorie pentru fiecare pointer din vector la eliberarea memoriei vom porni în ordinea inversă după cum se poate observa în codul de mai jos. |
<code cpp> | <code cpp> | ||
#include "Laptop.h" | #include "Laptop.h" | ||
- | #include "Smartphone.h" | + | #include "SmartPhone.h" |
int main() | int main() | ||
Line 249: | Line 247: | ||
În contextul exemplului prezentat anterior, ar fi foarte elegant să putem afișa elementele vectorului folosind **operatorul %%<<%%**, ceea ce ar simplifica și uniformiza procesul de afișare. Totuși, o problemă fundamentală apare din faptul că acest operator poate fi **supraîncărcat**, dar nu și **suprascris**. | În contextul exemplului prezentat anterior, ar fi foarte elegant să putem afișa elementele vectorului folosind **operatorul %%<<%%**, ceea ce ar simplifica și uniformiza procesul de afișare. Totuși, o problemă fundamentală apare din faptul că acest operator poate fi **supraîncărcat**, dar nu și **suprascris**. | ||
- | Acest lucru înseamnă că **operatorul %%<<%%** nu poate fi declarat **virtual**, astfel încât să permită apelul unei implementări specifice **clasei derivate** atunci când este utilizat printr-un **pointer** sau o **referință** la **clasa de bază**. Soluția implică de obicei definirea unei metode virtuale în **clasa abstractă** și utilizarea acesteia în supraîncărcarea **operatorului %%<<%%**. | + | Prin urmare **operatorul %%<<%%** nu poate fi declarat **virtual**, astfel încât să permită apelul unei implementări specifice **clasei derivate** atunci când este utilizat printr-un **pointer** sau o **referință** la **clasa de bază**. Soluția implică de obicei definirea unei metode virtuale în **clasa abstractă** și utilizarea acesteia în supraîncărcarea **operatorului %%<<%%**. |
Această abordare oferă o separare clară între logica specifică de afișare și mecanismul **operatorului %%<<%%**, respectând în același timp principiile polimorfismului. | Această abordare oferă o separare clară între logica specifică de afișare și mecanismul **operatorului %%<<%%**, respectând în același timp principiile polimorfismului. | ||
- | Așadar vom declara o metodă virtual pură în interfața ProdusElectronic și vom anunța compilatorul că vom supraîncărca și operatorul de afișare. | + | Așadar vom declara o metodă virtual pură în interfața **ProdusElectronic** și vom anunța compilatorul că vom supraîncărca și operatorul de afișare. |
<code cpp> | <code cpp> | ||
Line 278: | Line 276: | ||
std::ostream& operator<<(std::ostream& out, const ProdusElectronic* const& produsElectronic) | std::ostream& operator<<(std::ostream& out, const ProdusElectronic* const& produsElectronic) | ||
{ | { | ||
- | produsElectronic->afisare(out); | + | produsElectronic->afisare(out); // ne folosim de late binding |
return out; | return out; | ||
} | } | ||
Line 367: | Line 365: | ||
<code cpp> | <code cpp> | ||
#include "Laptop.h" | #include "Laptop.h" | ||
- | #include "Smartphone.h" | + | #include "SmartPhone.h" |
int main() | int main() | ||
Line 396: | Line 394: | ||
</code> | </code> | ||
+ | <note tip>În mod similar, procedăm și pentru ceilalți operatori, indiferent dacă sunt supraîncărcați ca **funcții membre** sau ca **funcții friend**. Acești operatori vor fi supraîncărcați **exclusiv** în **clasa de bază**, iar comportamentul lor specific poate fi ulterior personalizat în **clasele derivate** prin intermediul **suprascrierii**. | ||
+ | |||
+ | Acest lucru se realizează prin definirea unor **funcții virtual pure** în clasa de bază, care stabilesc comportamentul operatorului respectiv în **subclase**. Clasele derivate vor implementa aceste **funcții virtuale**, asigurând astfel logica specifică operatorului în funcție de cerințele fiecărei clase. Această abordare permite un design flexibil și robust, bazat pe mecanismul de **run time polymorphism**.</note> | ||
==== Concluzii ==== | ==== Concluzii ==== | ||
Line 402: | Line 403: | ||
== Vectori de obiecte neomogene == | == Vectori de obiecte neomogene == | ||
- | Am înțeles cum să declarăm și să populăm un vector de obiecte neomogene, folosind pointeri către clase abstracte. Acest lucru ne-a permis să lucrăm eficient cu obiecte care împărtășesc o interfață comună, dar pot avea implementări distincte. Vectorii de acest tip reprezintă o continuare firească a conceptelor de **clase abstracte** și **interfețe**, aprofundate în laboratorul anterior. | + | Am înțeles cum să declarăm și să populăm un vector de obiecte neomogene, folosind pointeri către clase abstracte sau interfețe. Acest lucru ne-a permis să lucrăm eficient cu obiecte care împărtășesc o interfață comună, dar pot avea implementări distincte. Vectorii de acest tip reprezintă o continuare firească a conceptelor de **clase abstracte** și **interfețe**, aprofundate în laboratorul anterior. |
== Destructor virtual pur == | == Destructor virtual pur == |