This shows you the differences between two versions of the page.
|
poo-is-ab:laboratoare:09 [2025/11/23 15:14] razvan.cristea0106 [Metode virtuale] |
poo-is-ab:laboratoare:09 [2025/12/09 11:26] (current) razvan.cristea0106 [Metode virtuale] |
||
|---|---|---|---|
| Line 19: | Line 19: | ||
| 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ă 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 **metode virtuale** în C++. | + | Cu toate acestea, există cazuri în care decizia pentru 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 **metode virtuale** în C++. |
| ==== Overloading vs Overriding ==== | ==== Overloading vs Overriding ==== | ||
| Line 28: | Line 28: | ||
| | Se aplică funcțiilor/metodelor din **aceeași clasă, același namespace, sau același fișier** | Apare în ierarhiile de clase (**moștenire**) | | | Se aplică funcțiilor/metodelor din **aceeași clasă, același namespace, sau același fișier** | Apare în ierarhiile de clase (**moștenire**) | | ||
| | Funcțiile/metodele au **același nume**, dar **diferă** prin **numărul, tipul sau ordinea parametrilor** | O metodă dintr-o clasă derivată **suprascrie** comportamentul unei **metode virtuale** din clasa de bază | | | Funcțiile/metodele au **același nume**, dar **diferă** prin **numărul, tipul sau ordinea parametrilor** | O metodă dintr-o clasă derivată **suprascrie** comportamentul unei **metode virtuale** din clasa de bază | | ||
| - | | Alegerea funcției/metodei este făcută de către **compilator** pe baza semnăturii acesteia | Alegerea metodei care va fi apelată este făcută la **momentul execuției**, în funcție de **tipul dinamic** al obiectului | | + | | Alegerea funcției/metodei este făcută de către **compilator** pe baza semnăturii acesteia | Alegerea metodei care va fi apelată este făcută la **runtime**, în funcție de **tipul dinamic** al obiectului | |
| - | | **Nu** necesită metode virtuale/virtual pure. | **Necesită** utilizarea metodelor virtuale/virtual pure în clasa de bază. | | + | | **Nu** necesită metode virtuale/virtual pure | **Necesită** utilizarea metodelor virtuale/virtual pure în clasa de bază | |
| | Este o formă de polimorfism timpuriu (**early binding**) | Este o formă de polimorfism întârziat (**late binding**) | | | Este o formă de polimorfism timpuriu (**early binding**) | Este o formă de polimorfism întârziat (**late binding**) | | ||
| | 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 | | ||
| Line 99: | Line 99: | ||
| </code> | </code> | ||
| - | <note>În C++ există **două** tipuri de metode virtuale și anume: **metode virtuale** și **metode virtual pure**. Diferența între cele două tipuri constă în faptul că o metodă virtual pură **nu** are implementare în **clasa de bază**.</note> | + | <note>În C++ există **două** tipuri de metode virtuale și anume: **metode virtuale** și **metode virtual pure**. Diferența între cele două tipuri constă în faptul că unei metode virtual pure **îi poate lipsi** implementarea în **clasa de bază**.</note> |
| - | În limbajul C++ pentru a declara o funcție virtuală într-o clasă se utilizeaza cuvântul cheie **virtual**. Dacă am spus funcție virtuală asta înseamnă că în clasa de bază acea funcție va avea implementare. Ca și exemplu vom propune clasele **Animal** și **Caine**. | + | În continuare propunem ca și exemplu practic clasele **Animal** și **Caine**, unde ne dorim să punem în evidență conceputul de **late binding** și să adăugăm informații noi cu privire la acestă noțiune nouă pe care o învățăm. |
| <code cpp> | <code cpp> | ||
| Line 133: | Line 133: | ||
| </code> | </code> | ||
| - | În funcția **main** vom demostra faptul că deși câinele este un animal se vor apela metodele specifice tipurilor de date din cauza faptului că în clasa Animal metoda **''afisare''** nu este declarată ca fiind virtuală. | + | În funcția **main** vom demostra faptul că deși câinele este un animal, totuși vom observa că se vor apela metodele specifice tipurilor de date din cauza faptului că în clasa Animal metoda **''afisare''** nu este declarată ca fiind virtuală. |
| <code cpp> | <code cpp> | ||
| Line 215: | Line 215: | ||
| </code> | </code> | ||
| - | <note important>Cuvântul cheie **override** în **C++** este folosit pentru a specifica în mod **explicit** că o funcție membră dintr-o **clasă derivată** suprascrie o metodă **virtuală** din **clasa de bază**. Acest mecanism oferă mai multă siguranță în ceea ce privește **suprascrierea** metodelor și ajută la prevenirea **erorilor de programare**.</note> | + | <note important>Cuvântul cheie **override** în **C++** este folosit pentru a specifica în mod **explicit** că o funcție membră dintr-o **clasă derivată** suprascrie o **metodă virtuală** din **clasa de bază**. Acest mecanism oferă mai multă siguranță în ceea ce privește **suprascrierea** metodelor și ajută la prevenirea **erorilor de programare**.</note> |
| ==== Clase abstracte ==== | ==== Clase abstracte ==== | ||
| - | În limbajul C++, o **clasă abstractă** este o clasă care conține **cel puțin** o **metodă virtuală pură**. **Metoda virtuală pură** este o funcție declarată în clasa de bază, dar care **nu are o implementare** în această clasă, **obligând** astfel **clasele derivate** să o **suprascrie**. O **clasă abstractă** este utilizată pentru a defini un comportament **general** care trebuie să fie specificat în **mod detaliat** în **clasele derivate**. | + | În limbajul C++, o **clasă abstractă** este o clasă care conține **cel puțin** o **metodă virtuală pură**. **Metoda virtuală pură** este o funcție membră declarată în clasa de bază, dar care **nu are neapărat o implementare** în această clasă, **obligând** astfel **clasele derivate** să o **suprascrie**. O **clasă abstractă** este utilizată pentru a defini un comportament **general** care trebuie să fie specificat în **mod detaliat** în **clasele derivate**. |
| - | <note warning>O clasă abstractă **nu** poate fi folosită pentru a crea **obiecte**. Este concepută să fie doar o bază pentru alte clase care o vor moșteni. În schimb se pot instanția **pointeri** de tipul acestei clase care să fie inițializati cu ajutorul **claselor derivate**. Un alt aspect ce trebuie menționat este faptul că **orice** clasă derivată dintr-o clasă abstractă **trebuie** să implementeze **toate** metodele virtual pure, altfel va deveni ea însăși o **clasă abstractă**.</note> | + | <note warning>O clasă abstractă **nu** poate fi folosită pentru a crea **obiecte**. Este concepută să fie doar o bază pentru alte clase care o vor **moșteni**. În schimb se pot instanția **pointeri** de tipul acestei clase care să fie inițializati cu ajutorul **claselor derivate**. Un alt aspect ce trebuie menționat este faptul că **orice** clasă derivată dintr-o clasă abstractă **trebuie** să implementeze **toate** metodele virtual pure, altfel va deveni ea însăși o **clasă abstractă**.</note> |
| O clasă abstractă poate avea membri și metode precum constructori, getteri, setteri și destructor care vor fi apelate în clasele derivate. În continuare vom prezenta modul în care putem pune în evidență conceptul de **late binding** transformând clasa **Animal** într-o clasă abstractă. | O clasă abstractă poate avea membri și metode precum constructori, getteri, setteri și destructor care vor fi apelate în clasele derivate. În continuare vom prezenta modul în care putem pune în evidență conceptul de **late binding** transformând clasa **Animal** într-o clasă abstractă. | ||
| Line 371: | Line 371: | ||
| | **Membri de date** | Nu poate avea membri | Poate avea membri | | | **Membri de date** | Nu poate avea membri | Poate avea membri | | ||
| | **Constructori** | Nu poate avea constructori | Poate avea constructori | | | **Constructori** | Nu poate avea constructori | Poate avea constructori | | ||
| - | | **Moștenire multiplă** | Este utilizată pentru moștenirea multiplă, mai ales pentru a defini contracte comune | Este utilizată în ierarhii simple sau complexe, dar poate genera ambiguități în moștenirea multiplă | | + | | **Moștenire multiplă** | Este utilizată pentru moștenirea multiplă, mai ales pentru a defini contracte comune | Este utilizată în ierarhii de clase, dar poate genera ambiguități în moștenirea multiplă | |
| | **Scop** | Definește un contract strict pentru clasele derivate | Definește un comportament parțial și oferă reutilizarea codului | | | **Scop** | Definește un contract strict pentru clasele derivate | Definește un comportament parțial și oferă reutilizarea codului | | ||
| | **Destructor** | Destructorul virtual pur este obligatoriu atunci când în clasele derivate există membri de tip pointer alocați dinamic | Destructorul virtual trebuie implementat atunci când există pointeri alocați dinamic în clasele derivate | | | **Destructor** | Destructorul virtual pur este obligatoriu atunci când în clasele derivate există membri de tip pointer alocați dinamic | Destructorul virtual trebuie implementat atunci când există pointeri alocați dinamic în clasele derivate | | ||