This is an old revision of the document!


Articol 02 - Noțiuni de C++

Obiective

În urma parcurgerii acestui laborator studentul va:

  • înțelege conceptul de template
  • înțelege conceptul de referințe din C++
  • înțelege conceptul de read-only introdus prin identificatorul const
  • Învățăm ce înseamnă constructor / destructor

Constructori și destructori

Studiați codul de mai jos.

complex.h
class Complex {
public:
    // Constructor
    Complex(double re, double im);
 
    // Destructor
    ~Complex();
 
    double getRe();
    double getIm();
 
    Complex conjugate(); 
 
private:
    double re;
    double im;
};
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;
}
main.cc
#include <stdio.h>
#include "complex.h"
 
int main() {
    Complex number(2, 3);
    printf("%lf %lf\n", number.getRe(), number.getIm());
 
    return 0;
}

Constructor

Observăm două bucăți din cod în mod special:

Complex::Complex(double re, double im);

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:

Complex numar(2, 3);

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ă:

Complex::Complex(double real, double imaginar) :
    re(real),
    im(imaginar) {
}

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

explicit_copy_constructor_call.cpp
MyClass m;
MyClass x = MyClass(m); /* apel explicit al copy-constructor-ului */

2) Transfer prin valoare ca argument într-o funcție

call_by_value.cpp
void f(MyClass obj);
...
MyClass o;
f(o); /* se apelează copy-constructor */

3) Transfer prin valoare ca return al unei funcții

return_by_value.cpp
MyClass f()
{
    MyClass a;
    return a; /* se apelează copy-constructor */
}

4) La inițializarea unei variabile declarate pe aceeași linie

init.cpp
MyClass m;
MyClass x = m; /* se apelează copy-constructor */

Rule of Three

Reprezintă un concept de must do pentru C++. Astfel:

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

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.

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");
        }
};

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:

~Complex();

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.

  • [5p] Clasa Complex - clasă ce implementează conceptul de număr complex
    • [2p] Implementați și folosiți utilizând template-uri clasa Complex, adăugând constructor și destructor.
    • [2p] Adăugați clasei Complex metode pentru adunare, scădere și înmulțire cu un alt număr complex.
    • [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.
  • [3p] Simple use of const
    • [0.5p] Creati un pointer variabil la o variabila de tip intreg constanta (in 2 moduri).
    • [0.5p] Creati un pointer constant la o variabila de tip intreg non-constanta.
    • [0.5p] Creati un pointer constant la o variabila de tip intreg constanta.
    • [1.5p] Initializati pointerul si variabila referita pentru fiecare caz. Explicati si rezolvati erorile de compilare.
  • [5p] Clasa MappingEntry - conține 2 membri de tipuri potențial diferite și realizează, din punct de vedere conceptual, asocierea între două valori (una se numește cheie, iar cealaltă valoare).
    • [2p] Implementați și folosiți utilizând template-uri clasa MappingEntry de mai sus adăugând constructor și destructor.
    • [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.
  • [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] Adăugați clasei Punct2D metode pentru determinarea proiecțiilor pe axe (OX/OY), respectiv pentru determinarea distanței față de un alt Punct2D.
    • [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.
  • [5p] Clasa Complex - clasă ce implementează conceptul de număr complex
    • [2p] Implementați și folosiți utilizând template-uri clasa Complex, adăugând constructor și destructor.
    • [2p] Adăugați clasei Complex metode pentru adunare, scădere și înmulțire cu un alt număr complex.
    • [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.
  • [2p bonus] Clasa KeyStorage
    • [2p] Implementați și folosiți utilizând template-uri clasa KeyStorage de mai sus adăugând constructor și destructor.
    • [2p] Alocați o instanță de tip KeyStorage 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.

Bibliografie

sd-ca/laboratoare/laborator-02.1456076280.txt.gz · Last modified: 2016/02/21 19:38 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