Differences

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

Link to this comparison view

poo-is-ab:laboratoare:03 [2024/09/28 21:54]
razvan.cristea0106
poo-is-ab:laboratoare:03 [2025/01/19 22:28] (current)
razvan.cristea0106
Line 1: Line 1:
-<​hidden>​===== Laborator 03 - Particularitățile clasei =====+===== Laborator 03 - Particularitățile clasei =====
  
 **Autor: Răzvan Cristea** **Autor: Răzvan Cristea**
Line 17: Line 17:
 În cadrul laboratorului anterior ne-am axat pe scrierea corectă a unei clase respectând **principiul încapsulării datelor**. În acest laborator atenția ne este îndreptată tot asupra modului în care o clasă este scrisă în așa fel încât să respecte principiile **OOP**, dar vom introduce noi tipuri de membri și de asemenea vom prezenta câteva din funcțiile membre care sunt **specifice** clasei. În cadrul laboratorului anterior ne-am axat pe scrierea corectă a unei clase respectând **principiul încapsulării datelor**. În acest laborator atenția ne este îndreptată tot asupra modului în care o clasă este scrisă în așa fel încât să respecte principiile **OOP**, dar vom introduce noi tipuri de membri și de asemenea vom prezenta câteva din funcțiile membre care sunt **specifice** clasei.
  
-Pentru a înțelege despre ce vom vorbi pe parcursul laboratorului propunem ca și clasă pentru exemplificare ​clasa **Conifer** căreia îi vom adăuga noutățile rând pe rând. De asemenea, pentru această clasă vom pune la dispoziție **constructori** și accesori de tip **get** și **set**.+Pentru a înțelege despre ce vom vorbi pe parcursul laboratorului propunem ca și exemplu ​clasa **Conifer**căreia îi vom adăuga noutățile rând pe rând. De asemenea, pentru această clasă vom pune la dispoziție **constructori** și accesori de tip **get** și **set** ​pentru fiecare membru.
  
 <code cpp> <code cpp>
Line 158: Line 158:
 Pentru a fi și mai clar ce s-a întâmplat pe linia ''​char* sir2 = sir1;''​ vom ilustra grafic după cum urmează. Pentru a fi și mai clar ce s-a întâmplat pe linia ''​char* sir2 = sir1;''​ vom ilustra grafic după cum urmează.
  
-{{ :​poo-is-ab:​laboratoare:​shallow_copy.jpg |}}+{{ :​poo-is-ab:​laboratoare:​shallow_copy.jpg?​direct&​600 ​|}}
  
 După cum se poate observa în imaginea de mai sus variabila **sir1** conține adresa **primului** element din vectorul de caractere (adresa caracterului '​I'​). Când am facut atribuirea ''​char* sir2 = sir1;''​ am făcut ca pointerul **sir2** să pointeze către adresa de pointare a lui **sir1**. Astfel orice modificare pe care o facem asupra lui **sir1** se va răsfrânge asupra lui **sir2**, valabil și invers după cum se poate observa pe linia unde am schimbat valoarea primului caracter prin intermediul lui **sir2**. Cu alte cuvinte pointerii **sir1** și respectiv **sir2** partajează aceeași zonă de memorie. După cum se poate observa în imaginea de mai sus variabila **sir1** conține adresa **primului** element din vectorul de caractere (adresa caracterului '​I'​). Când am facut atribuirea ''​char* sir2 = sir1;''​ am făcut ca pointerul **sir2** să pointeze către adresa de pointare a lui **sir1**. Astfel orice modificare pe care o facem asupra lui **sir1** se va răsfrânge asupra lui **sir2**, valabil și invers după cum se poate observa pe linia unde am schimbat valoarea primului caracter prin intermediul lui **sir2**. Cu alte cuvinte pointerii **sir1** și respectiv **sir2** partajează aceeași zonă de memorie.
Line 196: Line 196:
 Iar ca și ilustrare grafică lucrurile arată în felul următor. Iar ca și ilustrare grafică lucrurile arată în felul următor.
  
-{{ :​poo-is-ab:​laboratoare:​deep_copy.jpg |}}+{{ :​poo-is-ab:​laboratoare:​deep_copy.jpg?​direct&​600 ​|}}
  
 Pașii pe care i-am aplicat pentru a realiza **deep copy** au fost alocarea unui nou spațiu de memorie pentru **sir2** și copierea caracterelor lui **sir1** în **sir2** cu ajutorul funcției **strcpy**. Astfel atunci când am schimbat valoarea primului caracter din **sir2** modificarea nu s-a propagat și pe **sir1**, deoarece acum cei doi pointeri **nu** mai partajează aceeași zonă de memorie. Pașii pe care i-am aplicat pentru a realiza **deep copy** au fost alocarea unui nou spațiu de memorie pentru **sir2** și copierea caracterelor lui **sir1** în **sir2** cu ajutorul funcției **strcpy**. Astfel atunci când am schimbat valoarea primului caracter din **sir2** modificarea nu s-a propagat și pe **sir1**, deoarece acum cei doi pointeri **nu** mai partajează aceeași zonă de memorie.
Line 258: Line 258:
 ==== Destructorul ==== ==== Destructorul ====
  
-Așa cum îi spune și numele această **metodă** se ocupă de distrugerea obiectelor atunci când aceastora li se încheie durata de viață în program. La fel ca și **constructorii**,​ **destructorul** are o serie de trăsături ce îl face ușor de recunoscut într-o clasă ​precum:+Așa cum îi spune și numele această **metodă** se ocupă de distrugerea obiectelor atunci când aceastora li se încheie durata de viață în program. La fel ca și **constructorii**,​ **destructorul** are o serie de trăsături ce îl fac ușor de recunoscut într-o clasă ​după cum urmează:
   - nu are **tip returnat** nici măcar **void**   - nu are **tip returnat** nici măcar **void**
   - denumirea destructorului este **aceeeași** cu a clasei din care face parte, dar pentru a putea fi diferențiat de constructori se pune înaintea lui operatorul **"​~"​**   - denumirea destructorului este **aceeeași** cu a clasei din care face parte, dar pentru a putea fi diferențiat de constructori se pune înaintea lui operatorul **"​~"​**
Line 307: Line 307:
 </​code>​ </​code>​
  
-<note warning>​Destructorul,​ fie că vorbim de cel generat de compilator sau de cel implementat de programator,​ **nu** se apelează **explicit** de către programator. Acest lucru va fi realizat de către **compilator automat** atunci când durata de viată a obiectului se încheie.</​note>​+<note warning>​Destructorul,​ fie că vorbim de cel generat de compilator sau de cel implementat de programator,​ **nu** se apelează **explicit** de către programator. Acest lucru va fi realizat de către **compilator ​în mod automat** atunci când durata de viață a obiectului se încheie.</​note>​
  
 ==== Constructorul de copiere ==== ==== Constructorul de copiere ====
  
-Constructorul de copiere (**Copy Constructor**) este o metodă specială a clasei, deoarece cu ajutorul lui putem copia conținutul unui obiect existent într-unul nou. Acest constructor este **unic** în clasă și respectă toate caracteristicile unui constructor obișnuit. Dacă nu este declarat și implementat de către programator,​ compilatorul se va ocupa el de generarea unui **copy constructor default**.+Constructorul de copiere (**Copy Constructor**) este o metodă specială a clasei, deoarece cu ajutorul lui putem copia conținutul unui obiect existent într-unul nou. Acest constructor este **unic** în clasă și respectă toate caracteristicile unui constructor obișnuit. Dacă **nu** este declarat și implementat de către programator,​ compilatorul se va ocupa el de generarea unui **copy constructor default**.
  
 <note warning>​**Constructorul de copiere** generat de către compilator face **shallow copy**, iar dacă în clasă avem **cel puțin** un membru de tip **pointer alocat dinamic**, programatorul va trebui să ofere o implementare pentru acest tip de constructor care să facă o **copiere profundă (deep copy)**.</​note>​ <note warning>​**Constructorul de copiere** generat de către compilator face **shallow copy**, iar dacă în clasă avem **cel puțin** un membru de tip **pointer alocat dinamic**, programatorul va trebui să ofere o implementare pentru acest tip de constructor care să facă o **copiere profundă (deep copy)**.</​note>​
Line 363: Line 363:
 </​code>​ </​code>​
  
-Astfel **constructorul de copiere** este acum specializat pentru crearea de **clone reale** pentru ​obiecte ​de tip **Conifer**.+Astfel **constructorul de copiere** este acum specializat pentru crearea de **clone reale** pentru ​obiectele ​de tip **Conifer**.
  
 ==== Operatorul de atribuire ==== ==== Operatorul de atribuire ====
Line 431: Line 431:
 </​code>​ </​code>​
  
-<note warning>​Implementarea anterioară a **operatorului de asignare** are o vulnerabilitate și anume **nu** tratează situația în care obiectul este atribuit **sieși**. Astfel pot apărea probleme cu privire la eliberarea memoriei sau coruperea datelor. Pentru a putea avea o asignare sigură trebuie să facem verificarea de **auto-asignare** care garantează că **operatorul =** va funcționa corect în toate situațiile.</​note>​+<note warning>​Implementarea anterioară a **operatorului de asignare** are o vulnerabilitate și anume **nu** tratează situația în care obiectul este atribuit **sieși**. Astfel pot apărea probleme cu privire la eliberarea memoriei sau coruperea datelor. Pentru a putea avea o asignare sigură ​**trebuie** să facem verificarea de **auto-asignare** care garantează că **operatorul =** va funcționa corect în toate situațiile.</​note>​
  
 <code cpp> <code cpp>
Line 568: Line 568:
 </​code>​ </​code>​
  
-Deși membrul static **numarConifere** este privat noi ne propunem ​cumva să avem accest ​la el. Soluția este să implementăm un **getter** pentru acesta.+Deși membrul static **numarConifere** este privat noi totuși ​ne propunem să avem cumva acces la el. Soluția ​cea mai simplă ​este să implementăm un **getter** pentru acesta, astfel încât să respectăm și **principiul încapsulării datelor**.
  
 === Funcții statice === === Funcții statice ===
  
-La fel ca variabia ​statică **funcția statică** există pe întreaga durată de viață a programului. În **POO** o **funcție statică** la nivel de clasă este foarte asemănătoare cu o **metodă**. Totuși o metodă primește ca parametru pe prima poziție în lista de parametri **pointerul this**. În C++ chiar dacă acest parametru **nu** este vizibil în lista de parametri, la compilare există (acest procedeu ne este ascuns, dar în spate compilatorul adaugă acest parametru la toate **funcțiile membre**).+La fel ca variabila ​statică**funcția statică** există pe întreaga durată de viață a programului. În **POO** o **funcție statică** la nivel de clasă este foarte asemănătoare cu o **metodă**. Totuși o metodă primește ca parametru pe prima poziție în lista de parametri **pointerul this**. În C++ chiar dacă acest parametru **nu** este vizibil în lista de parametri, la compilare există (acest procedeu ne este ascuns, dar în spate compilatorul adaugă acest parametru la toate **funcțiile membre**).
  
-<note important>​**O ​**funcție statică** la nivel de clasă **nu** primește **pointerul this** ca parametru. Îi spunem **funcție statică** și **nu** metodă statică din acest motiv.**</​note>​+<note important>​**O funcție statică** la nivel de clasă **nu** primește **pointerul this** ca parametru. Îi spunem **funcție statică** și nu **metodă statică** din acest motiv.</​note>​
  
 În exemplul de mai jos am declarat un **getter** pentru a obține numărul de conifere. În exemplul de mai jos am declarat un **getter** pentru a obține numărul de conifere.
Line 618: Line 618:
 </​code>​ </​code>​
  
-Această funcție statică poate fi apelată fie prin **numele clasei** fie prin intermediul unui **obiect** după cum urmează.+Această ​**funcție statică** poate fi apelată fie prin **numele clasei** fie prin intermediul unui **obiect** după cum urmează ​în codul sursă de mai jos.
  
 <code cpp> <code cpp>
Line 642: Line 642:
 ==== ==== ==== ====
  
-Astfel am putut observa și înțelege cum putem folosi membrii statici și fucțiile statice la nivel de clasă.+Astfel am putut observa și înțelege cum putem folosi ​**membrii statici** și **fucțiile statice** la nivel de clasă.
  
 ==== Membri constanți ==== ==== Membri constanți ====
  
-Evident într-o clasă pot exista și membri constanți pentru a permite distincția între obiecte. De obicei un membru constant are un scop bine definit spre exemplu poate fi un cod unic de identificare a obiectului. În lumea reală o persoană este identificată unic după CNP-ul acesteia care știm foarte bine că este unic.+Evident într-o clasă pot exista și **membri constanți** pentru a permite ​**distincția** între obiecte. De obicei un membru constant are un scop bine definit spre exemplu poate fi un cod unic de identificare a obiectului. În lumea reală o persoană este identificată unic după CNP-ul ​(codul numeric personal) ​acesteia care știm foarte bine că nu mai poate fi modificat sau atribuit altei persoane.
  
-În cazul exemplului nostru putem să asigurăm unicitatea membrilor constanți folosindu-ne de membrul static. Să urmărim modul în care am declarat în clasa **Conifer** un atribut constant.+În cazul exemplului nostru putem să asigurăm ​**unicitatea** membrilor constanți folosindu-ne de **membrul static**. Să urmărim modul în care am declarat în clasa **Conifer** un **atribut constant** denumit **codUnic**.
  
 <code cpp> <code cpp>
Line 683: Line 683:
 </​code>​ </​code>​
  
-<note warning>​Un atribut constant **nu** poate fi inițializat în interiorul constructorilor,​ deoarece **obiectul există** și compilatorul ​i-a alocat deja o valoare ​default ​ce nu mai poate fi modificată. Prin urmare inițializarea membrilor constanți se face **obligatoriu** în **lista de inițializare a constructorului**. Această listă de inițializare îi spune compilatorului că înainte de crearea obiectului are de atribuit valori pentru anumiți membri.</​note>​+<note warning>​Un atribut constant **nu** poate fi inițializat în **interiorul constructorilor**, deoarece **obiectul ​deja există** și în plus, compilatorul a alocat deja o valoare ​random pentru **membrul constant** ​ce **nu** mai poate fi modificată. Prin urmare ​**inițializarea membrilor constanți** se face **obligatoriu** în **lista de inițializare a constructorului**. Această listă de inițializare îi spune compilatorului că înainte de crearea ​efectivă a obiectului are de atribuit valori pentru anumiți membri.</​note>​
  
 În exemplul de cod de mai jos am pus în lumină modul în care este inițializat un membru constant. În exemplul de cod de mai jos am pus în lumină modul în care este inițializat un membru constant.
Line 751: Line 751:
 Un alt aspect important pe care l-am explorat este utilizarea membrilor **statici** și **constanți** pentru a implementa mecanisme de generare automată a codurilor unice. Am demonstrat cum membrii **statici** permit partajarea unei valori comune între toate instanțele unei clase, iar membrii **constanți** oferă garanția că anumite valori rămân neschimbate pe toată durata de viață a obiectelor. Aceste mecanisme sunt esențiale pentru gestionarea eficientă a resurselor și pentru menținerea consistenței și integrității datelor într-o aplicație **OOP**. Un alt aspect important pe care l-am explorat este utilizarea membrilor **statici** și **constanți** pentru a implementa mecanisme de generare automată a codurilor unice. Am demonstrat cum membrii **statici** permit partajarea unei valori comune între toate instanțele unei clase, iar membrii **constanți** oferă garanția că anumite valori rămân neschimbate pe toată durata de viață a obiectelor. Aceste mecanisme sunt esențiale pentru gestionarea eficientă a resurselor și pentru menținerea consistenței și integrității datelor într-o aplicație **OOP**.
  
-De asemenea am putut vedea în linii mici ce înseamnă **supraîncărcarea** unui operator și ce presupune aceasta, mai multe detalii vom da în laboratorul următor când vom studia și alți operatori nu doar pe cel de asignare.</​hidden>​+De asemenea am putut vedea în linii mici ce înseamnă **supraîncărcarea** unui operator și ce presupune aceasta, mai multe detalii vom da în laboratorul următor când vom studia și alți operatori nu doar pe cel de asignare.
poo-is-ab/laboratoare/03.1727549694.txt.gz · Last modified: 2024/09/28 21:54 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