Differences

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

Link to this comparison view

sd-ca:laboratoare:laborator-01 [2015/03/03 16:39]
silviu_emil.popescu [Exercitii]
sd-ca:laboratoare:laborator-01 [2016/02/21 19:49] (current)
radu.stochitoiu
Line 1: Line 1:
-====== ​Laborator ​01 - Introducere in C++ ======+====== ​Articol ​01 - Introducere in C++ ======
  
-Responsabili  +În cadrul acestui articol ne propunem să ilustrăm conceptele din C++ cu care veți lucra pe parcursul acestui semestru.
-  * [[mailto:​daniel.ciocirlan@cti.pub.ro | Daniel Ciocîrlan]] +
-  * [[mailto:​andrei.vasiliu2211@cti.pub.ro | Andrei Vasiliu]]+
  
-În cadrul acestui laborator ne propunem să ilustrăm conceptele din C++ cu care veți lucra pe parcursul acestui semestru. +Într-un mod extrem de simplist spus C++ este un superset al limbajului C, iar tot ceea ce ați învățat în C la [[http://​ocw.cs.pub.ro/​courses/​programare| PC]] se poate compila cu un compilator pentru limbajul C++, funcționalitatea rămânând aceeași.
- +
-Într-un mod extrem de simplist spus C++ este un superset al limbajului C, iar tot ceea ce ați învățat în C la [[http://​ocw.cs.pub.ro/​courses/​programare-ca| PC]] se poate compila cu un compilator pentru limbajul C++, funcționalitatea rămânând aceeași.+
  
 ===== Obiective ===== ===== Obiective =====
Line 13: Line 9:
 Ne dorim să: Ne dorim să:
   *Realizăm tranziția de la C la C++   *Realizăm tranziția de la C la C++
 +  * înțelege conceptul de referințe din C++
 +  * înțelege conceptul de read-only introdus prin identificatorul const
   *Înțelegem ce presupune definirea unei clase   *Înțelegem ce presupune definirea unei clase
-  *Învățăm ce înseamnă constructor / destructor 
 ===== De ce C++? ===== ===== De ce C++? =====
-Pentru că C++ permite implementarea structurilor de date cu tipuri de date generice, prin intermediul template-urilor,​ într-un mod care nu presupune trecerea la programarea orientată pe obiecte. În cadrul acestui ​laborator ​nu ne așteptăm să dobândiți cunoștințe (elementare sau avansate) legate de programarea obiectuală,​ întrucât în anul II există un [[http://​elf.cs.pub.ro/​poo|curs]] dedicat acestui lucru.+Pentru că C++ permite implementarea structurilor de date cu tipuri de date generice, prin intermediul template-urilor,​ într-un mod care nu presupune trecerea la programarea orientată pe obiecte. În cadrul acestui ​articol ​nu ne așteptăm să dobândiți cunoștințe (elementare sau avansate) legate de programarea obiectuală,​ întrucât în anul II există un [[http://​elf.cs.pub.ro/​poo|curs]] dedicat acestui lucru.
  
-Vă încurajăm însă să citiți cât mai multe despre C++ pe parcurs și să cereți lămuriri suplimentare din partea asistenților de la laborator. 
 ===== Sintaxa C++ ===== ===== Sintaxa C++ =====
- 
-==== De la structuri C la clase C++ ==== 
  
 ==== Definirea structurii ==== ==== Definirea structurii ====
-În cadrul laboratorului de Programarea Calculatoarelor am învățat să declarăm și să folosim tipuri de date complexe, [[http://​ocw.cs.pub.ro/​courses/​programare-ca/​laboratoare/​lab10 | structuri]] în limbajul C. Pentru a recapitula, iată mai jos un exemplu simplu de astfel de structură, pentru a reprezenta un număr complex.+În cadrul laboratorului de Programarea Calculatoarelor am învățat să declarăm și să folosim tipuri de date complexe, [[http://​ocw.cs.pub.ro/​courses/​programare/​laboratoare/​lab10| structuri]] în limbajul C. Pentru a recapitula, iată mai jos un exemplu simplu de astfel de structură, pentru a reprezenta un număr complex.
 <columns 400px 100% -> <columns 400px 100% ->
  
Line 172: Line 166:
 </​code>​ </​code>​
  
-==== 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>​ 
- 
- 
-====Compilare==== 
- 
-Sursele C++ se compilează folosind compilatorul **g++**. Acesta permite exact aceleași opțiuni de bază ca și **gcc**, compilatorul utilizat pentru sursele de C. 
- 
-  * Încercați să compilați și să rulați codul din cele 3 fișiere de mai sus. 
- 
-<code bash> 
-g++ complex.cc main.cc -o exemplu 
-</​code>​ 
-Ce observați? 
- 
-Înlocuiți acum keyword-ul //class// cu keyword-ul //struct// și compilați din nou. 
- 
-==== 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. 
- 
-==== 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. 
  
 ==== Alocarea / Dealocarea dinamică ==== ==== Alocarea / Dealocarea dinamică ====
Line 437: Line 226:
 **Atenție** Nu convertiți matricea de mai sus la un pointer dublu, deoarece cele două nu sunt același lucru (prima este un vector de ''​N''​ pointeri care pointează către liniile matricei, pe când a doua este o zonă continuă de memorie în care compilatorul accesează elementele la fel ca într-o matrice clasică). **Atenție** Nu convertiți matricea de mai sus la un pointer dublu, deoarece cele două nu sunt același lucru (prima este un vector de ''​N''​ pointeri care pointează către liniile matricei, pe când a doua este o zonă continuă de memorie în care compilatorul accesează elementele la fel ca într-o matrice clasică).
  
-===== Exercitii ===== 
  
-  *[**2p**] Parcurgeți laboratorul ​în întregime ​și discutați cu asistentul vostru eventualele neclarități.+===== Referințe ===== 
 + 
 +In C++ există două modalități de a lucra cu adrese de memorie:  
 +  * pointeri (la fel ca cei din C)  
 +  * referințe. 
 + 
 +Referinţa poate fi privită ca un pointer constant inteligent, a cărui iniţializare este forţată de către compilator (la definire) şi care este dereferenţiat automat. 
 + 
 +Semantic, referințele reprezintă aliasuri ale unor variabile existente. La crearea unei referinţe, aceasta trebuie iniţializată cu adresa unui obiect (nu cu o valoare constantă). 
 + 
 +Sintaxa pentru declararea unei referințe este: 
 + 
 +    tip& referinta = valoare; 
 + 
 +Exemplu: 
 +<code > 
 +    int x=1, y=2; 
 +    int& rx = x; //​referinta 
 +    rx = 4; //​modificarea variabilei prin referinta 
 +    rx = 15; //​modificarea variabilei prin referinta 
 +    rx =y; //​atribuirea are ca efect copierea continutului  
 +           //din y in x si nu modificarea adresei referintei 
 +</​code>​ 
 + 
 +Spre deosebire de pointeri: 
 +  * referinţele sunt iniţializate la creare (pointerii se pot iniţializa oricând) 
 +  * referinţa este legată de un singur obiect şi această legătură nu poate fi modificată pentru un alt obiect 
 +  * referințele nu au operații speciale, toți operatorii aplicați asupra referințelor sunt de fapt aplicați asupra variabilei referite(de exemplu extragerea adresei unei referințe va returna adresa variabilei referite) 
 +  * __nu există referinţe nule__ – ele sunt întotdeauna legate de locaţii de memorie 
 + 
 +Referinţele se folosesc: 
 +  * în listele de parametri ale funcţiilor 
 +  * ca valori de întoarcere ale funcţiilor 
 +__Motivul__ pentru aceste tipuri de utilizări este unul destul de simplu: când se transmit parametrii funcțiilor,​ se copiază conținutul variabilelor transmise pe stivă, lucru destul de costisitor. Prin transmiterea de referințe, nu se mai copiază nimic, așadar intrarea sau ieșirea dintr-o funcție sunt mult mai putin costisitoare. 
 + 
 +==== Keyword const==== 
 + 
 +În C++, există mai multe întrebuințări ale cuvântului cheie **const**:​ 
 +  * specifică un obiect a cărui valoare nu poate fi modificată 
 +  * specifică metodele unui obiect read-only care pot fi apelate 
 + 
 +Pentru a specifica, un obiect a cărui valoare nu poate fi modificată,​ **const** se poate folosi în următoarele feluri: 
 +  * ''​const tip variabila'' ​  ​=> specifică o variabilă constantă 
 +  ​''​tip const& referinta_ct = variabilă;'' ​  => specifică o referință constantă la un obiect, obiectul neputând fi modificat 
 +  ​''​const int *p_int'' ​   => specifică un pointer la int modificabil,​ dar conținutul locației de memorie către care ''​p_int''​ arată __nu__ se poate modifica. 
 +  ​''​int ​const p_int'' ​   => specifică un pointer la int care nu poate fi modificat (Variabilei ''​p_int''​ nu i se poate asigna nici o valoare, dar conținutul locației de memorie către care ''​p_int''​ arată se poate modifica) 
 + 
 + 
 +Orice obiect constant poate apela doar funcții declarate constante. O funcție constantă se declară folosind sintaxa: 
 +<code c>  
 +     void fct_nu_modifica_obiect() const; //am utilizat cuvântul cheie const 
 +                       //​dupa declarația funcției fct_nu_modifica_obiect 
 +</​code> ​     
 + 
 +Această declaratie a functiei garantează faptul că obiectul pentru care va fi apelată nu se va modifica. 
 + 
 +Regula de bază a apelării membrilor de tip funcție ai claselor este: 
 +  * funcțiile ''​const''​ pot fi apelate pe toate obiectele 
 +  * funcțiile non-const pot fi apelate doar pe obiectele non-const. 
 + 
 +Exemple: 
 + 
 +<code cpp> 
 +//​declarație 
 +class Complex { 
 +private: 
 +    int re; 
 +    int im; 
 +public: 
 +    Complex();​ 
 +    int GetRe() const; 
 +    int GetIm() const; 
 +    void SetRe(int re); 
 +    void SetIm(int im); 
 +}; 
 + 
 + 
 +//apelare 
 +Complex c1; 
 +const Complex c2; 
 +c1.GetRe(); ​  //​corect 
 +c1.SetRe(5); ​ //corect 
 +c2.GetRe(); ​  //​corect 
 +c2.SetRe(5); ​ //​incorect 
 + 
 +</​code>​ 
 + 
 + 
 +====  Funcții care returnează referințe ​ ==== 
 + 
 +Pentru clasa Complex, definim funcţiile care asigură accesul la partea reală, respectiv imaginară a unui număr complex: 
 +   ​double getRe(){ return re; } 
 +   ​double getIm(){ return im; } 
 + 
 +Dacă am dori modificarea părţii reale a unui număr complex printr-o atribuire de forma: 
 +   ​z.getRe()=2.;​ 
 +constatăm că funcţia astfel definită nu poate apărea în partea stângă a unei atribuiri.  
 + 
 +Acest neajuns se remediază impunând funcţiei să returneze o referinţă la obiect, adică: 
 +   ​double&​ getRe(){ return re; } 
 + 
 +Codul de mai sus returnează o referință către membrul ''​re''​ al obiectului ''​Complex z'',​ așadar orice atribuire efectuată asupra acestui câmp va fi vizibilă și în obiect. 
 + 
 +====Compilare==== 
 + 
 +Sursele C++ se compilează folosind compilatorul **g++**. Acesta permite exact aceleași opțiuni de bază ca ș**gcc**, compilatorul utilizat pentru sursele de C. 
 + 
 +  * Încercați să compilați și să rulați codul din cele 3 fișiere de mai sus. 
 + 
 +<code bash> 
 +g++ complex.cc main.cc -o exemplu 
 +</​code>​ 
 +Ce observați?​ 
 + 
 +Înlocuiți acum keyword-ul //class// cu keyword-ul //struct// și compilați din nou. 
 <​hidden>​ <​hidden>​
   *[**3p**] Clasa Complex   *[**3p**] Clasa Complex
sd-ca/laboratoare/laborator-01.1425393558.txt.gz · Last modified: 2015/03/03 16:39 by silviu_emil.popescu
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