Differences

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

Link to this comparison view

sd-ca:laboratoare:laborator-02 [2016/02/21 19:34]
radu.stochitoiu
sd-ca:laboratoare:laborator-02 [2016/02/21 19:51] (current)
radu.stochitoiu
Line 3: Line 3:
 ===== Obiective ===== ===== Obiective =====
  
-În urma parcurgerii acestui ​laborator ​studentul va: +În urma parcurgerii acestui ​articol ​studentul va: 
  
-  * înțelege conceptul de template +  ​* învăța ce înseamnă o clasă 
-  * înțelege conceptul de referințdin C++ +  * învăța ce înseamnă constructor / destructor 
-  * înțelege conceptul ​de read-only introdus ​prin identificatorul ​const+  * afla funcționalitățile claselor / funcțiilor prietene 
 +  * realiza supraîncărcarea operatorilor din C++ 
 +  ​* înțelege conceptul de copy constructor 
 +  * înțelege conceptul de rule of three 
 + 
 + 
 + 
 +==== Clase ==== 
 + 
 +Formal am făcut deja primii pași mai sus pentru a implementa o clasă în C++, utilizând keyword-ul //​struct//​. 
 + 
 +Totuși, ce înseamnă o clasă? Nu trebuie decât să ne gândim la ce am făcut mai sus: 
 +  *am definit un tip de date 
 +  *i-am adăugat atribute (am definit ce proprietăți îl caracterizează:​ partea reală și partea imaginară) 
 +  *i-am adăugat metode (am definit cum se comportă: inițializarea și conjugarea) 
 + 
 +Cu această adăugare menționată,​ putem să ne referim la ceea ce înseamnă o **clasă**, respectiv un **obiect**. 
 + 
 +Ne referim la o **clasă** ca fiind o amprentă (blueprint) sau descriere generală. 
 +Un **obiect** sau o **instanță a clasei** este o variabilă concretă ce se conformează descrierii clasei. 
 + 
 +Vom numi **clasă** tipul de date definit de //struct complex// sau //class complex// și **obiect** o instanțiere (o alocare dinamică sau locală) a tipului de date. 
 + 
 +Când discutăm despre tipul de date //complex// ne referim la clasă. 
 +Când discutăm despre variabila //number// ne referim la un obiect, o instanță a clasei. 
 + 
 +==== Keyword-ul "​class"​ vs. "​struct"​ ==== 
 + 
 +Și totuși, C++ adăugă keyword-ul //class//. Care este diferența între //class// și //​struct//?​ 
 +Iată cum definim complet clasa de mai sus, separând antetul de implementare și de programul principal. 
 + 
 +<columns 100% 100% -> 
 +<code c++ complex.h>​ 
 +class Complex { 
 +    double re; 
 +    double im; 
 +     
 +    Complex conjugate();​  
 +}; 
 +</​code>​ 
 + 
 +<​newcolumn>​ 
 + 
 +<code c++ complex.cc>​ 
 +#include "​complex.h"​ 
 +Complex Complex::​conjugate() { 
 +    Complex conjugate;​ 
 +    conjugate.re = this->​re;​ 
 +    conjugate.im = -(this->​im);​ 
 +     
 +    return conjugate;​ 
 +
 +</​code>​ 
 + 
 +<​newcolumn>​ 
 + 
 +<code c++ main.cc>​ 
 +#include <​stdio.h>​ 
 +#include "​complex.h"​ 
 + 
 +int main() { 
 +    Complex number; 
 +    number.re = 2; 
 +    number.im = 4; 
 +     
 +    printf("​%.2lf %.2lf\n",​ number.re, number.im);​ 
 +     
 +    return 0; 
 +
 +</​code>​ 
 +</​columns>​ 
 + 
 + 
 + 
 + 
 +==== Specificatori de acces ==== 
 +Am observat mesajul de eroare în urma compilării fișierelor de mai sus. 
 + 
 +Astfel, **singura diferență** folosirea celor două keyword-uri este nivelul implicit de vizibilitate a metodelor și atributelor. 
 +  ***private** - pentru clasele declarate cu **class** 
 +  ***public** ​ - pentru clasele declarate cu **struct** 
 + 
 +Membri precedați de label-ul **private** pot fi folosiți numai în interiorul clasei, în cadrul metodelor acesteia. 
 +Ei nu pot fi citiți sau modificați ​din afara clasei. 
 + 
 +Iată cum puteam remedia soluția: 
 +<code c++ complex.h>​ 
 +class Complex { 
 +public: 
 +    double re; 
 +    double im; 
 + 
 +    Complex conjugate();​ 
 +}; 
 +</​code>​ 
 + 
 +==== Constructori și destructori ==== 
 + 
 +Studiați codul de mai jos. 
 + 
 +<columns 100% 100% -> 
 +<code c++ complex.h>​ 
 +class Complex { 
 +public: 
 +    // Constructor 
 +    Complex(double re, double im); 
 +     
 +    // Destructor 
 +    ~Complex();​ 
 +     
 +    double getRe(); 
 +    double getIm(); 
 +     
 +    Complex conjugate();​  
 + 
 +private: 
 +    double re; 
 +    double im; 
 +}; 
 +</​code>​ 
 + 
 +<​newcolumn>​ 
 + 
 +<code c++ complex.cc>​ 
 +#include "​complex.h"​ 
 +Complex::​Complex(double re, double im) { 
 +    this->re = re; 
 +    this->im = im; 
 +
 + 
 +Complex::​~Complex() { 
 +
 + 
 +Complex Complex::​conjugate() { 
 +    Complex conjugat(re,​ -im); 
 +    return conjugat; 
 +
 + 
 +double Complex::​getRe() { 
 +    return re; 
 +
 + 
 +double Complex::​getIm() { 
 +    return im; 
 +
 +</​code>​ 
 + 
 +</​columns>​ 
 + 
 +<code c++ main.cc>​ 
 +#include <​stdio.h>​ 
 +#include "​complex.h"​ 
 + 
 +int main() { 
 +    Complex number(2, 3); 
 +    printf("​%lf %lf\n",​ number.getRe(),​ number.getIm());​ 
 +     
 +    return 0; 
 +
 +</​code>​ 
 +</​columns>​ 
 + 
 +==== Constructor ==== 
 + 
 +Observăm două bucăți din cod în mod special: 
 +<code c++> 
 +Complex::​Complex(double re, double im); 
 +</​code>​ 
 +Linia de mai sus **nu are tip** returnat, spre deosebire de celelalte linii. 
 +Acesta este **constructorul** clasei, care este apelat în momentul alocării unui obiect. 
 + 
 +Ce operații sunt uzuale în constructor?​ 
 +  *inițializarea membrilor clasei cu valori predefinite sau date ca parametru 
 +  *alocarea memoriei pentru anumiți membri 
 + 
 +A doua bucată observată este: 
 +<code c++> 
 +Complex numar(2, 3); 
 +</​code>​ 
 +Până acum nu ați mai alocat astfel structurile. Ce se întâmplă în spate este exact ceea ce intuiți: este apelat constructorul obiectului și se execută instrucțiunile acestuia pentru variabila numar (reprezentată ca pointer prin this, direct în interiorul constructorului). 
 + 
 + 
 +În constructorul definit mai sus, tot ceea ce se întâmplă este să se inițializeze membri. Pentru asta, C++ vă pune la dispoziție o sintaxă simplă: 
 +<code c++> 
 +Complex::​Complex(double real, double imaginar) : 
 +    re(real), 
 +    im(imaginar) { 
 +
 +</​code>​ 
 + 
 +Cei doi constructori sunt identici ca funcționalitate. 
 + 
 +==== Copy-constructor ==== 
 + 
 +Reprezintă un tip de constructor special care se folosește când se dorește/​este necesară o copie a unui obiect existent. Dacă nu este declarat, se va genera unul default de către compilator. 
 + 
 +Poate avea unul din următoarele prototipuri 
 + 
 +   * MyClass(const MyClass&​ obj); 
 +   * MyClass(MyClass&​ obj); 
 + 
 +=== Când se apelează? === 
 + 
 +1) Apel explicit 
 + 
 +<code c++ explicit_copy_constructor_call.cpp>​ 
 +MyClass m; 
 +MyClass x = MyClass(m); /* apel explicit al copy-constructor-ului */ 
 +</​code>​ 
 + 
 +2) Transfer prin valoare ca argument într-o funcție 
 + 
 +<code c++ call_by_value.cpp>​ 
 +void f(MyClass obj); 
 +... 
 +MyClass o; 
 +f(o); /* se apelează copy-constructor */ 
 +</​code>​ 
 + 
 +3) Transfer prin valoare ca return al unei funcții 
 + 
 +<code c++ return_by_value.cpp>​ 
 +MyClass f() 
 +
 +    MyClass a; 
 +    return a; /* se apelează copy-constructor */ 
 +
 +</​code>​ 
 + 
 +4) La inițializarea unei variabile declarate pe aceeași linie 
 + 
 +<code c++ init.cpp>​ 
 +MyClass m; 
 +MyClass x = m; /* se apelează copy-constructor */ 
 +</​code>​ 
 + 
 + 
 +==== Destructor ==== 
 +Așa cum probabil ați observat, **constructorul** este apelat în mod **explicit** de către voi. **Destructorul** însă, în cazul de mai sus, este apelat **implicit** la terminarea blocului care realizează dealocărea automată a obiectului. 
 + 
 +Un destructor nu are parametri și se declară în interiorul clasei astfel: 
 +<code c++> 
 +~Complex();​ 
 +</​code>​ 
 + 
 +Dacă în constructor sau în interiorul clasei ați fi alocat memorie, cel mai probabil în destructor ați fi făcut curat și ați fi apelat free pe membrul respectiv. 
 + 
 +==== Rule of Three ==== 
 + 
 +Reprezintă un concept de ** must do** pentru C++. Astfel: 
 + 
 +<note important>​Dacă programatorul și-a declarat/​definit unul dintre ** constructor default**, ** operator de assignment** sau ** copy-constructor**,​ trebuie să îi declare/​definească și pe ceilalți 2</​note>​ 
 + 
 +Explicație:​ dacă funcționalitatea vreunuia dintre cei 3 se vrea mai specială decât cea oferită default, atunci mai mult ca sigur se dorește schimbarea funcționalității default și pentru ceilalți 2 rămași. 
 + 
 +<code c++ rule_of_3.cpp>​ 
 +class Complex 
 +
 +    private: 
 +        int re; 
 +        int im; 
 +    public: 
 +        Complex() 
 +        { 
 +            re = 0; 
 +            im = 0; 
 +            printf("​constructor default\n"​);​ 
 +        } 
 + 
 +        Complex(const Complex&​ c) 
 +        { 
 +            re = c.re; 
 +            im = c.im; 
 +            printf("​copy contructor\n"​);​ 
 +        } 
 + 
 +        void operator=(const Complex&​ c) 
 +        { 
 +            re = c.re; 
 +            im = c.im; 
 +            printf("​assignment operator\n"​);​ 
 +        } 
 +}; 
 +</​code>​ 
 + 
 +=====  Clase/​metode prietene ​ ===== 
 + 
 +Așa cum am văzut în primul articol, fiecare membru al clasei poate avea 3 specificatori de acces: 
 +  * public 
 +  * private 
 +  * protected 
 + 
 +Alegerea specificatorilor se face în special în funcție de ce funcționalitate vrem să exportăm din clasa respectivă. 
 + 
 +Dacă vrem să accesăm datele private/​protejate din afara clasei, avem următoarele opțiuni: 
 +  * Funcții care ne întorc/​setează valorile membre 
 +  * Funcții/​Clase prietene (friend) cu clasa curentă.  
 + 
 +O funcție prieten are următoarele proprietăți:​ 
 +  * O funcţie este considerată prietenă al unei clase, dacă în declararea clasei, este declarată funcţia respectivă precedată de specificatorul **friend** 
 +  * Declararea unei funcţii prieten poate fi făcută în orice parte a clasei(publică,​ privată sau protejată). 
 +  * Definiţia funcţiei prieten se face global, în afara clasei. 
 +  * Funcția declarată ca **friend** are acces liber la orice membru din interiorul clasei. 
 + 
 + 
 +O clasă prieten are următoarele proprietăți:​ 
 +  * O clasă B este considerată prieten al unei clase A, dacă în declararea clasei A s-a întâlnit expresia: ''​friend class B''​ 
 +  * Clasa B poate accesa orice membru din clasa A, fără nici o restricție. 
 + 
 +De asemenea, dacă clasa A este considerată prieten cu clasa B, nu înseamnă că si clasa B este considerată prieten cu clasa A. Nici tranzitivitatea nu este valabilă în relaţia de prietenie dintre clase. 
 + 
 +Exemplu: 
 + 
 +<code cpp> 
 +class Complex{ 
 + 
 +private: 
 +    int re; 
 +    int im; 
 +public: 
 +    int GetRe(); 
 +    int GetIm(); 
 +    friend double ComplexModul(Complex c);   //am declarat fct ComplexModul ca prieten 
 +    friend class Polinom; ​  //​Acum clasa Polinom care acces deplin la membrii **re** și **im** 
 +}; 
 + 
 +double ComplexModul(Complex c) 
 +
 +   ​return sqrt(c.re*c.re+c.im*c.im); ​ //are voie, intrucat e prietena 
 +
 + 
 +</​code>​ 
 + 
 +===== Supraîncarcarea operatorilor ===== 
 + 
 +Un mecanism specific C++ este supraîncarcarea operatorilor, ​prin care programatorul poate asocia noi semnificaţii operatorilor deja existenţi. De exemplu, dacă dorim ca două numere complexe să fie adunate, în C trebuie să scriem funcții specifice, nenaturale. În C++ putem scrie foarte ușor: 
 + 
 +<code c> 
 +Complex a(2,3); 
 +Complex b(4,5); 
 +Complex c=a+b; //​operatorul + a fost supraîncarcat pentru a aduna două numere complexe 
 +</​code>​ 
 + 
 +Acest lucru este posibil, întrucât un operator este văzut ca o funcție, cu declarația:​ 
 + 
 +     ​tip_rezultat operator#​(listă_argumente);​ 
 + 
 +Așadar pentru a supraîncărca un operator pentru o anumită clasă, este necesar să declarăm funcția următoare în corpul acesteia: 
 +     ​tip_rezultat operator#​(listă_argumente);​ 
 + 
 + 
 +Există câteva restricții cu privire la supraîncarcare:​ 
 + 
 +  * Nu pot fi supraîncărcaţi operatorii: ::, ., .*, ?:, sizeof. 
 +  * Setul de operatori ai limbajul C++ nu poate fi extins prin asocierea de semnificaţii noi unor caractere, care nu sunt operatori, de exemplu nu putem defini operatorul === . 
 +  * Prin supraîncărcarea unui operator nu i se poate modifica aritatea (astfel operatorul ! este unar şi poate fi redefinit numai ca operator unar).  
 +  * Asociativitatea şi precedenţa operatorului se menţin. 
 +  * La supraîncărcarea unui operator nu se pot specifica argumente cu valori implicite. 
 + 
 + 
 + 
 +==== Operatori supraîncărcaţi ca funcţii prieten ==== 
 + 
 + 
 + 
 +Un operator binar va fi reprezentat printr-o funcţie nemembră cu două argumente, iar un operator unar, printr-o funcţie nemembră cu un singur argument. 
 + 
 +Utilizarea unui operator binar sub forma **a#b** este interpretată ca **operator#​(a,​b)**. 
 + 
 +Argumentele sunt clase sau referinţe constante la clase.  
 + 
 + 
 +==== Supraîncărcarea operatorilor << şi >> ==== 
 + 
 +În C++, orice dispozitiv de I/O este văzut drept un stream, așadar operațiile de I/O sunt operații cu stream-uri, care se definesc în felul următor: 
 +  * **Citire**: se execută cu operatorul de extracție >>, membru al clasei istream 
 +  * **Scriere**:​ se execută cu operatorul de inserție <<, membru al clasei ostream 
 + 
 +Acești operatori pot fi supraîncărcați pentru o clasă pentru a defini operații de I/O direct pe obiectele clasei.  
 + 
 +Supraîncărcarea se poate efectua folosind funcții friend utilizând următoarea sintaxă: 
 + 
 +<code c> 
 +istream&​ operator>>​ (istream&​ f, clasa & ob);        //Acum pot scrie in >> ob 
 +ostream&​ operator<<​ (ostream&​ f, const clasa & ob);  //Acum pot scrie out << ob 
 +</​code>​ 
 +  
 +<note important>​Operatorii >> și << întorc fluxul original, pentru a scrie înlănțuiri de tipul ''​f>>​ob1>>​ob2''​. </​note>​ 
 + 
 +Funcţiile operator pentru supraîncărcarea operatorilor de I/O le vom declara ca funcţii prieten al clasei care interacţionează cu fluxul. 
 + 
 +<code c++ Complex.h> ​  
 +#include <​iostream>​ 
 + 
 +class Complex 
 +
 +public: 
 +    double re; 
 +    double im; 
 +  
 +    Complex(double real=0, double imag=0): re(real), im(imag) {}; 
 +  
 +    //​supraîncărcarea ​ operatorilor +, - ca functii de tip "​friend"​  
 +    friend Complex operator+(const Complex&​ s, const Complex&​ d); 
 +    friend Complex operator-(const Complex&​ s, const Complex&​ d); 
 +     
 +    //funcţii operator pentru supraîncărcarea operatorilor de intrare/​ieşire ​  
 +    //declarate ca funcţii de tip "​friend" ​   
 +    friend std::​ostream&​ operator<<​ (std::​ostream&​ out, const Complex&​ z); 
 +    friend std::​istream&​ operator>>​ (std::​istream&​ is, Complex&​ z); 
 +}; 
 +</​code>​ 
 + 
 +<code c++ Complex.cpp> ​  
 +#include "​complex.h"​ 
 + 
 +Complex operator+(const Complex&​ s, const Complex&​ d){ 
 +  return Complex(s.re+d.re,​s.im+d.im);​ 
 +
 +  
 +Complex operator-(const Complex&​ s, const Complex&​ d){ 
 +  return Complex(s.re-d.re,​s.im-d.im);​ 
 +
 +  
 +std::​ostream&​ operator<<​(std::​ostream&​ out, const Complex&​ z){ 
 +   out << "​("​ << z.re << ","​ << z.im << "​)"<<​ std::​endl;​ 
 +   ​return out; 
 +
 +  
 +std::​istream&​ operator>>​(std::​istream&​ is, Complex&​ z){ 
 +  is >> z.re >> z.im; 
 +  return is; 
 +
 +</​code>​ 
 + 
 + 
 +<code c++ main.cpp>​ 
 +#include "​complex.h"​ 
 + 
 +int main() { 
 + ​Complex a(1,1), b(-1,2); 
 + ​std::​cout << "A: " << a << "B: " << b; 
 + ​std::​cout << "A+B: " << (a+b); 
 + ​std::​cin >> b; 
 + ​std::​cout << "B: " << b; 
 + ​a=b;​ 
 + ​std::​cout << "A: " << a << "B: " << b; 
 +}</​code>​ 
 + 
 +==== Operatori supraîncărcaţi ca funcţii membre ==== 
 + 
 +Funcţiilor membru li se transmite un argument implicit **this** (adresa obiectului curent), motiv pentru care un operator binar poate fi implementat printr-o funcţie membru nestatică cu un singur argument. ​  
 + 
 +Operatorii sunt interpretați în modul următor: 
 +  * Operatorul binar **a#b** este interpretat ca **a.operator#​(b)** 
 +  * Operatorul unar prefixat **#a** este interpretat ca **a.operator#​()** 
 +  * Operatorul unar postfixat **a#** este interpretat ca **a.operator#​(int)** 
 + 
 +<code c++ Complex.h>​ 
 +#include <​iostream>​ 
 + 
 +class Complex 
 +
 +public: 
 +    double re; 
 +    double im; 
 +  
 +    Complex(double real, double imag): re(real), im(imag) {}; 
 +  
 +    //operatori supraîncărcaţi ca funcţii membre 
 +    Complex operator+(const Complex&​ d); 
 +    Complex operator-(const Complex&​ d); 
 +    Complex&​ operator+=(const Complex&​ d); 
 +     
 +    friend std::​ostream&​ operator<<​ (std::​ostream&​ out, const Complex&​ z); 
 +    friend std::​istream&​ operator>>​ (std::​istream&​ is, Complex&​ z); 
 +}; 
 +</​code>​ 
 + 
 +<code c++ Complex.cpp>​ 
 +#include "​complex.h"​ 
 + 
 +Complex Complex::​operator+(const Complex&​ d){ 
 +  return Complex(re+d.re,​ im+d.im); 
 +
 +  
 +Complex Complex::​operator-(const Complex&​ d){ 
 +  return Complex(re-d.re,​ im-d.im); 
 +
 +  
 +Complex&​ Complex::​operator+=(const Complex&​ d){ 
 +  re+=d.re; 
 +  im+=d.im; 
 +  return *this; 
 +
 +  
 +std::​ostream&​ operator<<​(std::​ostream&​ out, const Complex&​ z){ 
 +   out << "​("​ << z.re << ","​ << z.im << "​)"<<​ std::​endl;​ 
 +   ​return out; 
 +
 +  
 +std::​istream&​ operator>>​(std::​istream&​ is, Complex&​ z){ 
 +  is >> z.re >> z.im; 
 +  return is; 
 +
 +</​code>​ 
 + 
 +==== Supraîncărcarea operatorului de atribuire ==== 
 + 
 +Așa cum am amintit mai sus, majoritatea operatorilor pot fi supraîncărcați. O atenție importantă trebuie acordată operatorului de atribuire, dacă nu este supraîncărcat,​ realizează o copiere membru cu membru. 
 + 
 +Pentru obiectele care nu conţin date alocate dinamic la iniţializare,​ atribuirea prin copiere membru cu membru funcţionează corect, motiv pentru care nu se supraîncarcă operatorul de atribuire. 
 + 
 +<note important>​Pentru clasele ce conţin date alocate dinamic, copierea membru cu membru, executată în mod implicit la atribuire conduce la copierea pointerilor la datele alocate dinamic, în loc de a copia datele.</​note>​ 
 + 
 +Operatorul de atribuire poate fi redefinit numai ca funcţie membră, el fiind legat de obiectul din stânga operatorului =, motiv pentru care va întoarce o referinţă la obiect. 
 + 
 +<code c++ String.h>​ 
 +class String{ 
 +  char* s; 
 +  int n; // lungimea sirului 
 + 
 +  public: 
 + String();​  
 + String(const char* p);  
 + String(const String& r); 
 + ~String();​  
 + String&​ operator=(const String& d); 
 + String&​ operator=(const char* p); 
 +}; 
 + 
 + 
 +</​code>​ 
 + 
 +<code c++ String.cpp>​ 
 +#include "​String.h"​ 
 +#include <​string.h>​ 
 + 
 +String& String::​operator=(const String& d){ 
 +  if(this != &​d){ ​   //evitare autoatribuire 
 +    if(s)            //​curatire 
 +      delete [] s; 
 +    n=d.n; ​          //​copiere 
 +    s=new char[n+1];​ 
 +    strcpy(s, d.s); 
 +  } 
 +  return *this; ​     //intoarce referinta la obiectul modificat 
 +
 + 
 +String& String::​operator=(const char* p){ 
 +  if(s) 
 +      delete [] s; 
 +  n=strlen(p);​ 
 +  s=new char[n+1];​ 
 +  strcpy(s, p); 
 +  return *this; 
 +
 + 
 +</​code>​
  
  
Line 16: Line 574:
     *[**2p**] Setati tipul de return a metodelor de tip getter astfel incat sa puteti modifica valorea intoarsa.     *[**2p**] Setati tipul de return a metodelor de tip getter astfel incat sa puteti modifica valorea intoarsa.
     *[**1p**] Arătați funcționalitatea prin adăugarea de cod în fișierul main.cpp. Rezolvați, dacă e cazul, toate erorile/​leak-urile depistate de Valgrind.     *[**1p**] Arătați funcționalitatea prin adăugarea de cod în fișierul main.cpp. Rezolvați, dacă e cazul, toate erorile/​leak-urile depistate de Valgrind.
-</​hidden>​ 
  
   *[**5p**] Clasa Complex - clasă ce implementează conceptul de număr complex   *[**5p**] Clasa Complex - clasă ce implementează conceptul de număr complex
Line 33: Line 590:
     *[**2p**] Alocați o instanță de tip MappingEntry local și dinamic (utilizând new / delete).     *[**2p**] Alocați o instanță de tip MappingEntry local și dinamic (utilizând new / delete).
     *[**1p**] Arătați funcționalitatea prin adăugarea de cod în fișierul main.cpp. Rezolvați, dacă e cazul, toate erorile/​leak-urile depistate de Valgrind.     *[**1p**] Arătați funcționalitatea prin adăugarea de cod în fișierul main.cpp. Rezolvați, dacă e cazul, toate erorile/​leak-urile depistate de Valgrind.
-<​hidden>​+
   *[**5p**] Clasa Punct2D - clasă ce implementează conceptul de punct în plan   *[**5p**] Clasa Punct2D - clasă ce implementează conceptul de punct în plan
     *[**2p**] Implementați și folosiți utilizând template-uri clasa Punct2D, adăugând constructor și destructor.     *[**2p**] Implementați și folosiți utilizând template-uri clasa Punct2D, adăugând constructor și destructor.
Line 44: Line 601:
  
  
-</​hidden>​+
  
   *[**5p**] Clasa Punct2D - clasă ce implementează conceptul de punct în plan   *[**5p**] Clasa Punct2D - clasă ce implementează conceptul de punct în plan
Line 61: Line 618:
     *[**1p**] Arătați funcționalitatea prin adăugarea de cod în fișierul main.cpp. Rezolvați, dacă e cazul, toate erorile/​leak-urile depistate de Valgrind.     *[**1p**] Arătați funcționalitatea prin adăugarea de cod în fișierul main.cpp. Rezolvați, dacă e cazul, toate erorile/​leak-urile depistate de Valgrind.
  
-<​hidden>​+
 ===== Interviu ===== ===== Interviu =====
  
-Această secțiune nu este punctată și încearcă să vă facă o oarecare idee a tipurilor de întrebări pe care le puteți întâlni la un job interview (internship,​ part-time, full-time, etc.) din materia prezentată în cadrul ​laboratorului.+Această secțiune nu este punctată și încearcă să vă facă o oarecare idee a tipurilor de întrebări pe care le puteți întâlni la un job interview (internship,​ part-time, full-time, etc.) din materia prezentată în cadrul ​articolului.
  
   * Care este diferența între struct și class în C++?   * Care este diferența între struct și class în C++?
sd-ca/laboratoare/laborator-02.1456076070.txt.gz · Last modified: 2016/02/21 19:34 by radu.stochitoiu
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