This shows you the differences between two versions of the page.
|
poo-is-ab:laboratoare:10 [2025/09/23 20:14] razvan.cristea0106 |
poo-is-ab:laboratoare:10 [2025/12/04 09:00] (current) razvan.cristea0106 [Vector de obiecte neomogene] |
||
|---|---|---|---|
| Line 15: | Line 15: | ||
| ==== Introducere ==== | ==== Introducere ==== | ||
| - | În acest laborator vom aprofunda utilizarea **claselor abstracte** și a **interfețelor**, concentrându-ne pe un aspect important al **POO** și anume gestionarea colecțiilor de date **neomogene**. Dacă până acum am lucrat cu **pointeri** pentru a manipula obiecte derivate din **clase abstracte** sau **interfețe**, acum vom explora cum putem organiza și gestiona aceste obiecte utilizând colecții de date, cum ar fi **vectorii**. Pentru o mai bună înțelegere a noțiunilor legate de **clase abstracte** și **interfețe** se recomandă citirea [[poo-is-ab:laboratoare:08|laboratorului 9]]. | + | În acest laborator vom aprofunda utilizarea **claselor abstracte** și a **interfețelor**, concentrându-ne pe un aspect important al **POO** și anume gestionarea colecțiilor de date **neomogene**. Dacă până acum am lucrat cu **pointeri** pentru a manipula obiecte derivate din **clase abstracte** sau **interfețe**, acum vom explora cum putem organiza și gestiona aceste obiecte utilizând colecții de date, cum ar fi **vectorii**. Pentru o mai bună înțelegere a noțiunilor legate de **clase abstracte** și **interfețe** se recomandă citirea [[poo-is-ab:laboratoare:09|laboratorului 9]]. |
| ==== Vector de obiecte neomogene ==== | ==== Vector de obiecte neomogene ==== | ||
| Line 40: | Line 40: | ||
| public: | public: | ||
| - | virtual ~ProdusElectronic() = 0; // destructor virtual pur | + | virtual ~ProdusElectronic() = 0; // destructor virtual pur |
| - | virtual float getPret() const = 0; | + | virtual float getPret() const = 0; |
| - | virtual char* getProducator() const = 0; | + | virtual char* getProducator() const = 0; |
| }; | }; | ||
| </code> | </code> | ||
| + | |||
| + | <note>Așa cum am discutat în cadrul laboratorului anterior, atunci când declarăm o metodă ca fiind **virtual pură**, clasa care o conține devine automat o **clasă abstractă**. Totuși, faptul că o **funcție membră** este marcată drept virtual pură **nu ne împiedică deloc** să îi oferim o implementare în clasa unde a fost declarată. Această marcare, exprimată prin sintaxa **''= 0''**, are rolul de a face clasa **neinstanțiabilă**, **nu de a interzice existența unei definiții**. Cu alte cuvinte, putem avea în continuare un **comportament de bază** pentru metoda respectivă, chiar dacă **obligăm subclasele** să o **suprascrie**.</note> | ||
| + | |||
| + | În cele ce urmează vom exemplifica printr-o secvență de cod ceea ce am menționat anterior. | ||
| + | |||
| + | <code cpp> | ||
| + | #include <iostream> | ||
| + | |||
| + | class A | ||
| + | { | ||
| + | public: | ||
| + | |||
| + | // Metoda este marcata ca fiind virtual pura -> clasa devine abstracta | ||
| + | // Totusi ii putem oferi o implementare | ||
| + | virtual void f() = 0; | ||
| + | }; | ||
| + | |||
| + | // Implementarea metodei virtual pure trebuie sa fie in afara clasei, | ||
| + | // deoarece limbajul C++ nu permite definirea unei metode virtual pure direct in interiorul clasei | ||
| + | void A::f() | ||
| + | { | ||
| + | std::cout << "Comportament default din A::f()\n"; | ||
| + | } | ||
| + | |||
| + | class B : public A | ||
| + | { | ||
| + | public: | ||
| + | |||
| + | // B suprascrie metoda f si foloseste implementarea din clasa de baza | ||
| + | void f() override | ||
| + | { | ||
| + | std::cout << "B::f() - inainte de apelul bazei\n"; | ||
| + | A::f(); // se apeleaza metoda superclasei | ||
| + | std::cout << "B::f() - dupa apelul bazei\n"; | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | class C : public A | ||
| + | { | ||
| + | public: | ||
| + | |||
| + | // C suprascrie metoda f si inlocuieste complet comportamentul | ||
| + | void f() override | ||
| + | { | ||
| + | std::cout << "C::f() - comportament complet redefinit\n"; | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // A a; // eroare de compilare, clasa nu este instantiabila | ||
| + | // A* ptr = new A(); // nu se poate, clasa nu este instantiabila | ||
| + | |||
| + | A* p1 = new B(); | ||
| + | A* p2 = new C(); | ||
| + | |||
| + | std::cout << "--- Apel prin B ---\n"; | ||
| + | p1->f(); | ||
| + | |||
| + | std::cout << "\n--- Apel prin C ---\n"; | ||
| + | p2->f(); | ||
| + | |||
| + | delete p1; | ||
| + | delete p2; | ||
| + | |||
| + | return 0; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | În continuare propunem un tabel în care se prezintă caracteristicile metodelor virtuale și respectiv virtual pure pentru a rezuma explicațiile oferite mai sus. | ||
| + | |||
| + | ^ Caracteristică ^ Metodă virtuală ^ Metodă virtuală pură ^ | ||
| + | | Obligă clasa derivată să o suprascrie? | Nu | Da | | ||
| + | | Clasa devine abstractă? | Nu | Da | | ||
| + | | Are implementare în clasa de bază? | Da (obligatoriu) | Nu neapărat | | ||
| + | | Poate fi apelată din subclasă? | Da | Da | | ||
| + | | Sintaxă | ''virtual void f();'' | ''virtual void f() = 0;'' | | ||
| + | | Permite instanțierea clasei de bază? | Da | Nu | | ||
| + | | Apelabilă prin pointer la tipul bazei? | Da | Da | | ||
| <note important>În C++, unui **destructor virtual pur** trebuie să îi oferim o **implementare** deoarece va fi **întotdeauna apelat** atunci când un **obiect derivat** este **distrus**. Această cerință se bazează pe mecanismul de distrugere a obiectelor, care implică apelarea destructorilor **în ordine inversă** a **constructorilor**, inclusiv pentru clasa de bază.</note> | <note important>În C++, unui **destructor virtual pur** trebuie să îi oferim o **implementare** deoarece va fi **întotdeauna apelat** atunci când un **obiect derivat** este **distrus**. Această cerință se bazează pe mecanismul de distrugere a obiectelor, care implică apelarea destructorilor **în ordine inversă** a **constructorilor**, inclusiv pentru clasa de bază.</note> | ||
| - | Prin urmare vom furniza o implementare pentru destructorul clasei **ProdusElectronic** după cum urmează în secțiunea de cod de mai jos. | + | Odată înțelese conceptele privind metodele virtuale și virtual pure, putem oferi implementarea destructorului clasei **ProdusElectronic**, așa cum este ilustrată în codul următor. |
| <code cpp> | <code cpp> | ||
| ProdusElectronic::~ProdusElectronic() | ProdusElectronic::~ProdusElectronic() | ||
| { | { | ||
| - | // chiar daca nu scriem nimic este necesar sa existe pentru a putea functiona corect dezalocarea memoriei | + | // chiar daca nu scriem nimic este necesar sa existe pentru a putea functiona corect dezalocarea memoriei |
| } | } | ||
| </code> | </code> | ||
| Line 63: | Line 142: | ||
| class Laptop : public ProdusElectronic | class Laptop : public ProdusElectronic | ||
| { | { | ||
| - | float pret; | + | float pret; |
| - | char* producator; | + | char* producator; |
| public: | public: | ||
| - | Laptop(); | + | Laptop(); |
| - | Laptop(const float& pret, const char* producator); | + | Laptop(const float& pret, const char* producator); |
| - | ~Laptop(); | + | ~Laptop(); |
| - | float getPret() const override; | + | float getPret() const override; |
| - | char* getProducator() const override; | + | char* getProducator() const override; |
| }; | }; | ||
| </code> | </code> | ||
| Line 80: | Line 159: | ||
| class SmartPhone : public ProdusElectronic | class SmartPhone : public ProdusElectronic | ||
| { | { | ||
| - | float pret; | + | float pret; |
| - | char* producator; | + | char* producator; |
| public: | public: | ||
| - | SmartPhone(); | + | SmartPhone(); |
| - | SmartPhone(const float& pret, const char* producator); | + | SmartPhone(const float& pret, const char* producator); |
| - | ~SmartPhone(); | + | ~SmartPhone(); |
| - | float getPret() const override; | + | float getPret() const override; |
| - | char* getProducator() const override; | + | char* getProducator() const override; |
| }; | }; | ||
| </code> | </code> | ||
| - | Iar implementările metodelor celor două clase se pot observa în blocurile de mai jos. | + | Iar implementările metodelor celor două clase se pot observa în blocurile de cod de mai jos. |
| <code cpp> | <code cpp> | ||
| Laptop::Laptop() | Laptop::Laptop() | ||
| { | { | ||
| - | pret = 0.0f; | + | pret = 0.0f; |
| - | producator = nullptr; | + | producator = nullptr; |
| } | } | ||
| Laptop::Laptop(const float& pret, const char* producator) | Laptop::Laptop(const float& pret, const char* producator) | ||
| { | { | ||
| - | this->pret = pret; | + | this->pret = pret; |
| - | if (producator != nullptr) | + | if (producator != nullptr) |
| - | { | + | { |
| - | this->producator = new char[strlen(producator) + 1]; | + | this->producator = new char[strlen(producator) + 1]; |
| - | strcpy(this->producator, producator); | + | strcpy(this->producator, producator); |
| - | } | + | } |
| - | else | + | else |
| - | { | + | { |
| - | this->producator = nullptr; | + | this->producator = nullptr; |
| - | } | + | } |
| } | } | ||
| Laptop::~Laptop() | Laptop::~Laptop() | ||
| { | { | ||
| - | if (producator != nullptr) | + | if (producator != nullptr) |
| - | { | + | { |
| - | delete[] producator; | + | delete[] producator; |
| - | } | + | } |
| } | } | ||
| float Laptop::getPret() const | float Laptop::getPret() const | ||
| { | { | ||
| - | return pret; | + | return pret; |
| } | } | ||
| char* Laptop::getProducator() const | char* Laptop::getProducator() const | ||
| { | { | ||
| - | return producator; | + | return producator; |
| } | } | ||
| </code> | </code> | ||
| Line 140: | Line 219: | ||
| SmartPhone::SmartPhone() | SmartPhone::SmartPhone() | ||
| { | { | ||
| - | pret = 0.0f; | + | pret = 0.0f; |
| - | producator = nullptr; | + | producator = nullptr; |
| } | } | ||
| SmartPhone::SmartPhone(const float& pret, const char* producator) | SmartPhone::SmartPhone(const float& pret, const char* producator) | ||
| { | { | ||
| - | this->pret = pret; | + | this->pret = pret; |
| - | if (producator != nullptr) | + | if (producator != nullptr) |
| - | { | + | { |
| - | this->producator = new char[strlen(producator) + 1]; | + | this->producator = new char[strlen(producator) + 1]; |
| - | strcpy(this->producator, producator); | + | strcpy(this->producator, producator); |
| - | } | + | } |
| - | else | + | else |
| - | { | + | { |
| - | this->producator = nullptr; | + | this->producator = nullptr; |
| - | } | + | } |
| } | } | ||
| SmartPhone::~SmartPhone() | SmartPhone::~SmartPhone() | ||
| { | { | ||
| - | if (producator != nullptr) | + | if (producator != nullptr) |
| - | { | + | { |
| - | delete[] producator; | + | delete[] producator; |
| - | } | + | } |
| } | } | ||
| float SmartPhone::getPret() const | float SmartPhone::getPret() const | ||
| { | { | ||
| - | return pret; | + | return pret; |
| } | } | ||
| char* SmartPhone::getProducator() const | char* SmartPhone::getProducator() const | ||
| { | { | ||
| - | return producator; | + | return producator; |
| } | } | ||
| </code> | </code> | ||
| Line 186: | Line 265: | ||
| int main() | int main() | ||
| { | { | ||
| - | int nrProduse = 5; | + | int nrProduse = 5; |
| - | ProdusElectronic** produse = new ProdusElectronic * [nrProduse]; // vector de obiecte neomogene | + | ProdusElectronic** produse = new ProdusElectronic * [nrProduse]; // vector de obiecte neomogene |
| - | produse[0] = new Laptop(5499.99f, "HP"); // late binding | + | produse[0] = new Laptop(5499.99f, "HP"); // late binding |
| - | produse[1] = new SmartPhone(2499.99f, "Motorola"); | + | produse[1] = new SmartPhone(2499.99f, "Motorola"); |
| - | produse[2] = new Laptop(3000.0f, "Asus"); | + | produse[2] = new Laptop(3000.0f, "Asus"); |
| - | produse[3] = new Laptop(7999.99f, "Lenovo"); | + | produse[3] = new Laptop(7999.99f, "Lenovo"); |
| - | produse[4] = new SmartPhone(3999.99f, "Apple"); | + | produse[4] = new SmartPhone(3999.99f, "Apple"); |
| - | for (int i = 0; i < nrProduse; i++) | + | for (int i = 0; i < nrProduse; i++) |
| - | { | + | { |
| - | std::cout << "Pretul produsului este: " << produse[i]->getPret() << '\n'; | + | std::cout << "Pretul produsului este: " << produse[i]->getPret() << '\n'; |
| - | std::cout << "Numele producatorului este: " << produse[i]->getProducator() << "\n\n"; | + | std::cout << "Numele producatorului este: " << produse[i]->getProducator() << "\n\n"; |
| - | } | + | } |
| - | return 0; | + | return 0; |
| } | } | ||
| </code> | </code> | ||
| Line 213: | Line 292: | ||
| int main() | int main() | ||
| { | { | ||
| - | int nrProduse = 5; | + | int nrProduse = 5; |
| - | ProdusElectronic** produse = new ProdusElectronic * [nrProduse]; | + | ProdusElectronic** produse = new ProdusElectronic * [nrProduse]; |
| - | produse[0] = new Laptop(5499.99f, "HP"); // late binding | + | produse[0] = new Laptop(5499.99f, "HP"); // late binding |
| - | produse[1] = new SmartPhone(2499.99f, "Motorola"); | + | produse[1] = new SmartPhone(2499.99f, "Motorola"); |
| - | produse[2] = new Laptop(3000.0f, "Asus"); | + | produse[2] = new Laptop(3000.0f, "Asus"); |
| - | produse[3] = new Laptop(7999.99f, "Lenovo"); | + | produse[3] = new Laptop(7999.99f, "Lenovo"); |
| - | produse[4] = new SmartPhone(3999.99f, "Apple"); | + | produse[4] = new SmartPhone(3999.99f, "Apple"); |
| - | for (int i = 0; i < nrProduse; i++) | + | for (int i = 0; i < nrProduse; i++) |
| - | { | + | { |
| - | std::cout << "Pretul produsului este: " << produse[i]->getPret() << '\n'; | + | std::cout << "Pretul produsului este: " << produse[i]->getPret() << '\n'; |
| - | std::cout << "Numele producatorului este: " << produse[i]->getProducator() << "\n\n"; | + | std::cout << "Numele producatorului este: " << produse[i]->getProducator() << "\n\n"; |
| - | } | + | } |
| - | for (int i = 0; i < nrProduse; i++) | + | for (int i = 0; i < nrProduse; i++) |
| - | { | + | { |
| - | delete produse[i]; // eliberam fiecare slot din vector | + | delete produse[i]; // eliberam fiecare slot din vector |
| - | } | + | } |
| - | delete[] produse; // stergem vectorul | + | delete[] produse; // stergem vectorul |
| - | return 0; | + | return 0; |
| } | } | ||
| </code> | </code> | ||
| Line 247: | Line 326: | ||
| Î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**. | ||
| - | 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 %%<<%%**. | + | 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 de afișare %%<<%%**. |
| 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. | ||
| Line 258: | Line 337: | ||
| protected: | protected: | ||
| - | virtual void afisare(std::ostream& out) const = 0; // va fi folosita pentru operatorul << | + | virtual void afisare(std::ostream& out) const = 0; // va fi folosita pentru operatorul << |
| public: | public: | ||
| - | virtual ~ProdusElectronic() = 0; | + | virtual ~ProdusElectronic() = 0; |
| - | virtual float getPret() const = 0; | + | virtual float getPret() const = 0; |
| - | virtual char* getProducator() const = 0; | + | virtual char* getProducator() const = 0; |
| - | friend std::ostream& operator<<(std::ostream& out, const ProdusElectronic* const& produsElectronic); | + | friend std::ostream& operator<<(std::ostream& out, const ProdusElectronic* const& produsElectronic); |
| }; | }; | ||
| </code> | </code> | ||
| Line 276: | Line 355: | ||
| std::ostream& operator<<(std::ostream& out, const ProdusElectronic* const& produsElectronic) | std::ostream& operator<<(std::ostream& out, const ProdusElectronic* const& produsElectronic) | ||
| { | { | ||
| - | produsElectronic->afisare(out); // ne folosim de late binding | + | produsElectronic->afisare(out); // ne folosim de late binding |
| - | return out; | + | return out; |
| } | } | ||
| </code> | </code> | ||
| Line 286: | Line 365: | ||
| class Laptop : public ProdusElectronic | class Laptop : public ProdusElectronic | ||
| { | { | ||
| - | float pret; | + | float pret; |
| - | char* producator; | + | char* producator; |
| protected: | protected: | ||
| - | void afisare(std::ostream& out) const override; | + | void afisare(std::ostream& out) const override; |
| public: | public: | ||
| - | Laptop(); | + | Laptop(); |
| - | Laptop(const float& pret, const char* producator); | + | Laptop(const float& pret, const char* producator); |
| - | ~Laptop(); | + | ~Laptop(); |
| - | float getPret() const override; | + | float getPret() const override; |
| - | char* getProducator() const override; | + | char* getProducator() const override; |
| }; | }; | ||
| </code> | </code> | ||
| Line 307: | Line 386: | ||
| class SmartPhone : public ProdusElectronic | class SmartPhone : public ProdusElectronic | ||
| { | { | ||
| - | float pret; | + | float pret; |
| - | char* producator; | + | char* producator; |
| protected: | protected: | ||
| - | void afisare(std::ostream& out) const override; | + | void afisare(std::ostream& out) const override; |
| public: | public: | ||
| - | SmartPhone(); | + | SmartPhone(); |
| - | SmartPhone(const float& pret, const char* producator); | + | SmartPhone(const float& pret, const char* producator); |
| - | ~SmartPhone(); | + | ~SmartPhone(); |
| - | float getPret() const override; | + | float getPret() const override; |
| - | char* getProducator() const override; | + | char* getProducator() const override; |
| }; | }; | ||
| </code> | </code> | ||
| Line 330: | Line 409: | ||
| void Laptop::afisare(std::ostream& out) const | void Laptop::afisare(std::ostream& out) const | ||
| { | { | ||
| - | out << "Pretul laptopului este: " << pret << '\n'; | + | out << "Pretul laptopului este: " << pret << '\n'; |
| - | out << "Numele producatorului de laptopuri este: "; | + | out << "Numele producatorului de laptopuri este: "; |
| - | if (producator != nullptr) | + | if (producator != nullptr) |
| - | { | + | { |
| - | out << producator << '\n'; | + | out << producator << '\n'; |
| - | } | + | } |
| - | else | + | else |
| - | { | + | { |
| - | out << "N/A\n"; | + | out << "N/A\n"; |
| - | } | + | } |
| } | } | ||
| </code> | </code> | ||
| Line 347: | Line 426: | ||
| void SmartPhone::afisare(std::ostream& out) const | void SmartPhone::afisare(std::ostream& out) const | ||
| { | { | ||
| - | out << "Pretul smartphone-ului este: " << pret << '\n'; | + | out << "Pretul smartphone-ului este: " << pret << '\n'; |
| - | out << "Numele producatorului de smartphone-uri este: "; | + | out << "Numele producatorului de smartphone-uri este: "; |
| - | if (producator != nullptr) | + | if (producator != nullptr) |
| - | { | + | { |
| - | out << producator << '\n'; | + | out << producator << '\n'; |
| - | } | + | } |
| - | else | + | else |
| - | { | + | { |
| - | out << "N/A\n"; | + | out << "N/A\n"; |
| - | } | + | } |
| } | } | ||
| </code> | </code> | ||
| Line 369: | Line 448: | ||
| int main() | int main() | ||
| { | { | ||
| - | int nrProduse = 5; | + | int nrProduse = 5; |
| - | ProdusElectronic** produse = new ProdusElectronic * [nrProduse]; | + | ProdusElectronic** produse = new ProdusElectronic * [nrProduse]; |
| - | produse[0] = new Laptop(5499.99f, "HP"); | + | produse[0] = new Laptop(5499.99f, "HP"); |
| - | produse[1] = new SmartPhone(2499.99f, "Motorola"); | + | produse[1] = new SmartPhone(2499.99f, "Motorola"); |
| - | produse[2] = new Laptop(3000.0f, "Asus"); | + | produse[2] = new Laptop(3000.0f, "Asus"); |
| - | produse[3] = new Laptop(7999.99f, "Lenovo"); | + | produse[3] = new Laptop(7999.99f, "Lenovo"); |
| - | produse[4] = new SmartPhone(3999.99f, "Apple"); | + | produse[4] = new SmartPhone(3999.99f, "Apple"); |
| - | for (int i = 0; i < nrProduse; i++) | + | for (int i = 0; i < nrProduse; i++) |
| - | { | + | { |
| - | std::cout << produse[i] << '\n'; // se foloseste operatorul << definit in interfata ProdusElectronic | + | std::cout << produse[i] << '\n'; // se foloseste operatorul << definit in interfata ProdusElectronic |
| - | } | + | } |
| - | for (int i = 0; i < nrProduse; i++) | + | for (int i = 0; i < nrProduse; i++) |
| - | { | + | { |
| - | delete produse[i]; | + | delete produse[i]; |
| - | } | + | } |
| - | delete[] produse; | + | delete[] produse; |
| - | return 0; | + | return 0; |
| } | } | ||
| </code> | </code> | ||
| Line 396: | Line 475: | ||
| <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**. | <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> | + | Acest lucru se realizează prin definirea unor **metode virtual pure** în clasa de bază, care stabilesc comportamentul operatorului respectiv în **subclase**. Clasele derivate vor implementa aceste **metode 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 ==== | ||