Differences

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

Link to this comparison view

sd-ca:laboratoare:laborator-03 [2015/03/12 14:00]
gabriel.cristache [Exerciții]
sd-ca:laboratoare:laborator-03 [2016/02/21 19:51] (current)
darius.neatu
Line 1: Line 1:
-====== ​Laborator ​03 - Notiuni avansate de C++ ======+====== ​Articol ​03 - Notiuni avansate de C++ ======
  
-Responsabili 
-  * [[andrei.vasiliu2211@cti.pub.ro| Andrei Vasiliu]] 
-  * [[daniel.ciocirlan1607@cti.pub.ro| Daniel Ciocîrlan]] 
  
 ===== Obiective ===== ===== Obiective =====
  
-În urma parcurgerii acestui ​laborator ​studentul va: +În urma parcurgerii acestui ​articol ​studentul va:  
 +  * înțelege conceptul de template
  
-  * afla funcționalitățile claselor/​funcțiilor prietene +===== Templates =====
-  * realiza supraîncărcarea operatorilor din C++ +
-  * înțelege conceptul de copy constructor +
-  * înțelege conceptul de rule of three+
  
-=====  Clase/​metode prietene ​ =====+Motivul principal pentru care folosim C++ în cadrul SD este datorită funcționalității oferite de template-uri.
  
-Așa cum am văzut în primul laborator, fiecare membru al clasei poate avea 3 specificatori ​de acces: +Acestea permit generalizarea tipurilor ​de date folosite în interiorul funcțiilor și claselor.
-  * public +
-  * private +
-  * protected+
  
-Alegerea specificatorilor se face în special în funcție ​de ce funcționalitate vrem să exportăm din clasa respectivă.+Sintaxa pentru acestea este: 
 +<code c++> 
 +template <class identifier>​ declaratie;​ 
 +template <​typename identifier>​ declaratie;​ 
 +</​code>​ 
 +//​declaratie//​ poate fi fie o funcție, fie o clasă. 
 +Nu există nicio diferență între keyword-ul //class// și //​typename//​ - important este că ceea ce urmează după ele este un placeholder pentru un tip de date.
  
-Dacă vrem să accesăm datele private/​protejate din afara clasei, avem următoarele opțiuni: +==== Function Template ==== 
-  * Funcții care ne întorc/​setează valorile membre +În primul rând template-urile pot fi aplicate funcțiilor.
-  * Funcții/Clase prietene (friend) cu clasa curentă+
  
-O funcție prieten are următoarele proprietăți+Un exemplu comun șsimplu ​este următorul
-  * O funcţie ​este considerată prietenă al unei clase, dacă în declararea clasei, este declarată funcţia respectivă precedată de specificatorul **friend** +<​code ​c++> 
-  * Declararea unei funcţii prieten poate fi făcută în orice parte a clasei(publică,​ privată sau protejată). +template<typename T
-  * Definiţia funcţiei prieten se face global, în afara clasei. +T getMax(T a, T b{ 
-  * Funcția declarată ca **friend** are acces liber la orice membru din interiorul clasei. +    return ​a > b ? a : b;
- +
- +
-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>​ </​code>​
  
-===== Supraîncarcarea operatorilor ===== +Funcția ​poate fi apelată astfel
- +<code c++
-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: +getMax<​int>​(2, 3); 
- +getMax<​double>​(3.2, 4.6);
-<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>​ </​code>​
  
-Acest lucru este posibilîntrucât un operator este văzut ca funcție, cu declarația:+==== Class Template ==== 
 +Concretsă presupunem că avem clasă numită KeyStorage care are: 
 +  *o cheie (de tip int) 
 +  *un membru de date generic (al cărui tip de date nu îl știm la momentul scrierii clasei).
  
-     ​tip_rezultat operator#​(listă_argumente);​+Vrem să putem folosi codul clasei indiferent de tipul de date al membrului.
  
-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: +Iată cum putem face acest lucru
-     ​tip_rezultat operator#​(listă_argumente);​ +<code c++ KeyStorage.h> 
- +template<typename T
- +class KeyStorage ​{
-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: public:
-    ​double re+    ​int key
-    ​double im; +    ​T member;
-  +
-    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>​
  
-<code c++ Complex.cpp> ​  +În funcția main, să presupunem că vrem să folosim clasa cu membrul de tip long. 
-#include "complex.h"+<code c++ main.cpp> 
 +#include "KeyStorage.h"
  
-Complex operator+(const Complex&​ s, const Complex&​ d){ +int main() { 
-  ​return Complex(s.re+d.re,​s.im+d.im);​ +    ​KeyStorage<longkeyElement
-+    return ​0;
-  +
-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>​
  
 +Practic, oriunde folosim tipul de date T în clasă, este înlocuit cu tipul pe care îl specificăm.
  
-<code c++ main.cpp>​ +==== Where'​s the magic happening? ==== 
-#include "​complex.h"+Sunt destul de multe lucruri de spus despre template-uri,​ dar ne vom concentra pe lucrurile care schimbă modul în care ați implementat până acum.
  
-int main() { +Template-urile sunt de fapt indicii pentru compilator pentru ​genera cod la rândul lui! 
- ​Complex a(1,1), b(-1,2); +Practic, voi îi spuneți compilatorului un șablon generic pe care ați vrea să-l folosiți și el trebuie să fie pregătit să îl pună la dispoziția voastră când aveți nevoie.
- ​std::​cout << "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ţca funcţii membre ====+Ce trebuie să reținețdin asta? Totul se întâmplă la **compile time**, nu la run time.
  
-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 +Compilatorul practic analizează modul în care voi folosiți clasa respectivă și generează pentru fiecare mod în care o folosiți șablonul corespunzător. 
 +Folosirea KeyStorage<​int>​ și KeyStorage<​float>​ determină compilatorul să genereze cod pentru ambele clase (înlocuind o dată T cu int și altă cu float)
 +  
 +==== Guideline-uri implementare ==== 
 +Pentru că totul se întâmplă la compile timeînseamnă că în momentul în care compilatorul întâlnește secvența de cod ce folosește template-uri trebuie să știe //toate// modurile în care aceasta este folosita.
  
-Operatorii sunt interpretați în modul următor+Asta înseamnă că: 
-  * Operatorul binar **a#b** este interpretat ca **a.operator#​(b)** +  *Trebuie să scrieți întreaga implementare în header! //sau// 
-  * Operatorul unar prefixat **#​a** ​este interpretat ca **a.operator#​()** +  *Scrieți descrierea clasei generice în header, în fișierul de implementare fiecare metodă declarată ​este de fapt o funcție cu template și la sfârșitul implementării adăugat //template class numeclasa<​numetip>//;​
-  * Operatorul unar postfixat **a#** este interpretat ca **a.operator#​(int)**+
  
-<code c++ Complex.h> +Ultimul rând de fapt forțează folosirea template-ului cu un anumit tip de date și deci compilatorul generează cod corespunzător (trebuie să scrieți asta pentru toate tipurile).
-#include <​iostream>​+
  
-class Complex +==== Clasa KeyStorage ==== 
-{+Iată mai jos o structură mai dezvoltată pentru clasa KeyStorage, în care cheia este setată în constructor. 
 +
 +<code c++ KeyStorage.h>​ 
 +template<​typename T> 
 +class KeyStorage ​{
 public: public:
-    ​double re; +    ​KeyStorage(int k); 
-    double im; +    ​~KeyStorage();
-  +
-    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); +    ​T getMember(); 
-    ​friend std::​istream&​ operator>> ​(std::​istream&​ is, Complex&​ z);+    ​T setMember(T element)
 +     
 +private: 
 +    T member; 
 +    int key;
 }; };
-</​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>​ </​code>​
  
-==== Supraîncărcarea operatorului de atribuire ==== +Implementarea completa ​ei poate fi realizată
- +  *în header (în cazul template-uriloracest mod este cel mai indicat)
-cum am amintit mai sus, majoritatea operatorilor pot fi supraîncărcați. O atenție importantă trebuie acordată operatorului de atribuiredacă nu este supraîncărcat,​ realizează o copiere membru cu membru+  *în fișierul ​de implementare ​.cc .cpp (al cărui schelet parțial îl găsiți mai jos).
- +
-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> +<code c++ KeyStorage.cpp> 
-#include "String.h" +#include "KeyStorage.h"
-#include <​string.h>​+
  
-String& String::operator=(const String& d){ +template<​typename T> 
-  ​if(this != &​d){ ​   //evitare autoatribuire +KeyStorage<​T>​::KeyStorage(int k) { 
-    if(s)            //​curatire +//TODO
-      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){ +template<​typename T> 
-  if(s) +KeyStorage<​T>​::~KeyStorage() {
-      delete [] s; +
-  n=strlen(p);​ +
-  s=new char[n+1];​ +
-  strcpy(s, p); +
-  return *this;+
 } }
  
-</code>+//TODO: restul metodelor.
  
-==== Copy-constructor ====+// La sfarsit, cu tipurile de date pe care le veti folosi. 
 +template class KeyStorage<​int>;​ 
 +template class KeyStorage<​long>;​
  
-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>​ </​code>​
 +<​hidden>​
  
-2) Transfer prin valoare ca argument într-o funcție +  ​-[**5p**] Implementati clasa **Fractie**,​ cu următoarele particularități: 
- +    [**2p**] doi constructori:​ 
-<code c++ call_by_value.cpp>​ +      - primul vid 
-void f(MyClass obj); +      - al doilea va primi ca argumente numitorul și numărătorul 
-... +    - Se vor implementa ​funcţii membre pentru: 
-MyClass o; +      - [**0.5p**] determinarea numitorului și numărătorului 
-f(o); /* se apelează copy-constructor ​*/ +      ​[**1p**] supraîncărcarea operatoriilor de comparație ​<>, == (aveți grijă la egalitatea a două fracții) 
-</​code>​ +      - [**0.5p**] supraîncărcarea operatorilor +, 
- +      - [**bonus 1p**] Supraîncărcați operatorii ​++ și -- unari astfel încât numărul rațional reprezentat să crească/​scadă cu o unitateCăutați să vedeți cum se face diferența între ++ prefixat ​și postfixat. 
-3) Transfer prin valoare ca return al unei funcții +  ​[**5p**] Implementaţi clasa template ​**Vector** care să permită lucrul cu vectori de obiecte, cu următoarele particularități: 
- +    - Vor exista doi constructori:​ 
-<code c++ return_by_value.cpp> +      - primulvid, va inițializa numărul de elemente la 0 și pointerul de elemente la NULL 
-MyClass f() +      - al doilea va primi ca argument numărul de elemente ​și va aloca memorie pentru pointer 
-+    - [**0.5p**] Se va defini și un destructor, care va dezaloca memoria alocată dinamic 
-    MyClass a; +    ​- Se vor implementa funcţii friend ​(nemembrepentru: 
-    return a; /se apelează copy-constructor ​*+      - [**1p**] testul de egalitate a doi vector ( supraîncărcarea operatorului ​== ) 
-+      - [**0.5p**] supraîncărcarea operatorului << ​(pentru scriere
-</code> +      - [**0.5p**] supraîncărcarea operatorului >> ​(pentru citire
- +    - Se vor implementa funcţii membre pentru: 
-4) La inițializarea unei variabile declarate pe aceeașlinie +      - [**1p**] supraîncărcarea operatorului de atribuire între două obiecte de tip vector 
- +      - [**0.5p**] supraîncărcarea operatorului de indexare [] ce va permite accesul la elementele individuale prin indexare **Operatorul de indexare** este un operator ​binar, având ca prim termen obiectul care se indexează, iar ca al doilea termen indicele. (//''​obiect[indice]''​ este interpretat ca ''​obiect.operator[](indice)''​//.
-<code c++ init.cpp> +
-MyClass m; +
-MyClass x = m; /se apelează copy-constructor */ +
-</​code>​ +
- +
-==== 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ă defaultatunci 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>+
  
 <note warning>​Tipul parametrului pentru copy-constructor trebuie să fie identic cu cel al parametrului pentru operatorul de assignment</​note>​ <note warning>​Tipul parametrului pentru copy-constructor trebuie să fie identic cu cel al parametrului pentru operatorul de assignment</​note>​
-===== Exerciții ===== 
-  - [**3p**] Implementați clasa **Complex**,​ cu următoarele particularități:​ 
-    - [**1p**] Vor exista doi constructori:​ 
-      - primul, vid, va inițializa părțile reală și imaginară la 0 
-      - al doilea va primi ca argumente partea reală și imaginară 
-    - Se vor implementa **funcţii membre** pentru: 
-      - [**0.5p**] determinarea părților reale și imaginare (getteri) 
-      - [**0.5p**] supraîncărcarea operatorului == folosind acelaşi criteriu de comparație ca la mate :) 
-      - [**0.5p**] supraîncărcarea operatorilor +, - pentru a permite operaţii cu două argumente numere complexe 
-      - [**0.5p**] supraîncărcarea operatorului - unar pentru negatul unui număr complex 
-      - [**bonus 1p**] supraîncărcarea operatorului ++ prefixat care să crească partea reală cu o unitate, ++ postfixat care să crească partea imaginară cu o unitate. Căutați sau întrebați asistentul să vedeți cum știe compilatorul să facă diferența între operatorii prefixați și postfixați. 
-  ​ 
  
- - [**4p**] Implementaţi clasa template **Set** care să permită lucrul cu mulțimi de obiecte, cu următoarele particularități:​ 
-    - Constructorul va primi dimensiunea maximă de elemente care pot fi ținute în mulțime și va aloca spațiul necesar. 
-    - [**0.5p**] Se va defini și un destructor, care va dezaloca memoria alocată dinamic. 
-    - Se vor implementa funcţii membre pentru: 
-      - [**1p**] supraîncărcarea operatorului += pentru adăugarea unui nou element în mulțime (dacă elementul există deja în mulțime atunci nu va mai fi adăugat). 
-      - [**0.5p**] supraîncărcarea operatorului -= pentru eliminarea unui element din mulțime. 
-    - Se vor implementa funcţii friend (nemembre) pentru: 
-      - [**1p**] testul de egalitate a două mulțimi ( supraîncărcarea operatorului == ): două mulțimi sunt egale daca conțin aceleași elemente. 
-      - [**0.5p**] supraîncărcarea operatorului << (pentru scriere). 
-      - [**0.5p**] supraîncărcarea operatorului >> (pentru citire). 
- 
-<​hidden>​ 
 ===== Exerciții ===== ===== Exerciții =====
   - [**3p**] Implementați clasa **Complex**,​ cu următoarele particularități:​   - [**3p**] Implementați clasa **Complex**,​ cu următoarele particularități:​
Line 437: Line 196:
       - [**1p**] supraîncărcarea operatorului de atribuire între două obiecte de tip vector       - [**1p**] supraîncărcarea operatorului de atribuire între două obiecte de tip vector
       - [**0.5p**] supraîncărcarea operatorului de indexare [] ce va permite accesul la elementele individuale prin indexare **Operatorul de indexare** este un operator binar, având ca prim termen obiectul care se indexează, iar ca al doilea termen indicele. (//''​obiect[indice]''​ este interpretat ca ''​obiect.operator[](indice)''//​.       - [**0.5p**] supraîncărcarea operatorului de indexare [] ce va permite accesul la elementele individuale prin indexare **Operatorul de indexare** este un operator binar, având ca prim termen obiectul care se indexează, iar ca al doilea termen indicele. (//''​obiect[indice]''​ este interpretat ca ''​obiect.operator[](indice)''//​.
 +
   - [**4p**] Implementaţi clasa template **Set** care să permită lucrul cu mulțimi de obiecte, cu următoarele particularități:​   - [**4p**] Implementaţi clasa template **Set** care să permită lucrul cu mulțimi de obiecte, cu următoarele particularități:​
     - Constructorul va primi dimensiunea maximă de elemente care pot fi ținute în mulțime și va aloca spațiul necesar.     - Constructorul va primi dimensiunea maximă de elemente care pot fi ținute în mulțime și va aloca spațiul necesar.
sd-ca/laboratoare/laborator-03.1426161614.txt.gz · Last modified: 2015/03/12 14:00 by gabriel.cristache
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