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

Templates

Motivul principal pentru care folosim C++ în cadrul SD este datorită funcționalității oferite de template-uri.

Acestea permit generalizarea tipurilor de date folosite în interiorul funcțiilor și claselor.

Sintaxa pentru acestea este:

template <class identifier> declaratie;
template <typename identifier> declaratie;

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.

Function Template

În primul rând template-urile pot fi aplicate funcțiilor.

Un exemplu comun și simplu este următorul:

template<typename T>
T getMax(T a, T b) {
    return a > b ? a : b;
}

Funcția poate fi apelată astfel:

getMax<int>(2, 3);
getMax<double>(3.2, 4.6);

Class Template

Concret, să presupunem că avem o 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).

Vrem să putem folosi codul clasei indiferent de tipul de date al membrului.

Iată cum putem face acest lucru:

KeyStorage.h
template<typename T>
class KeyStorage {
public:
    int key;
    T member;
};

În funcția main, să presupunem că vrem să folosim clasa cu membrul de tip long.

main.cpp
#include "KeyStorage.h"
 
int main() {
    KeyStorage<long> keyElement;
    return 0;
}

Practic, oriunde folosim tipul de date T în clasă, este înlocuit cu tipul pe care îl specificăm.

Where's the magic happening?

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.

Template-urile sunt de fapt indicii pentru compilator pentru a genera cod la rândul lui! 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.

Ce trebuie să rețineți din asta? Totul se întâmplă la compile time, nu la run time.

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.

Asta înseamnă că:

  • Trebuie să scrieți întreaga implementare în header! sau
  • 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>;

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).

Clasa KeyStorage

Iată mai jos o structură mai dezvoltată pentru clasa KeyStorage, în care cheia este setată în constructor. .

KeyStorage.h
template<typename T>
class KeyStorage {
public:
    KeyStorage(int k);
    ~KeyStorage();
 
    T getMember();
    T setMember(T element);
 
private:
    T member;
    int key;
};

Implementarea completa a ei poate fi realizată:

  • în header (în cazul template-urilor, acest mod este cel mai indicat).
  • în fișierul de implementare .cc / .cpp (al cărui schelet parțial îl găsiți mai jos).
KeyStorage.cpp
#include "KeyStorage.h"
 
template<typename T>
KeyStorage<T>::KeyStorage(int k) {
//TODO
}
 
template<typename T>
KeyStorage<T>::~KeyStorage() {
}
 
//TODO: restul metodelor.
 
// La sfarsit, cu tipurile de date pe care le veti folosi.
template class KeyStorage<int>;
template class KeyStorage<long>;
  • [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.1456076011.txt.gz · Last modified: 2016/02/21 19:33 by darius.neatu
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