This shows you the differences between two versions of the page.
|
poo-is:laboratoare:09 [2020/09/29 22:37] eduard.ciurezu [Derivarea din/de Clase Template] |
— (current) | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Laboratorul 09: Functii si Clase Template ===== | ||
| - | In cadrul acestui laborator vom aprofunda concepte de programare generica, mai exact **functiile si clasele template**. Acestea ne vor permite sa reutilizam cod deja scris in contexte cat mai variate. | ||
| - | Ca referinte externe, recomandam urmatorul capitol din [[https://discourse-production.oss-cn-shanghai.aliyuncs.com/original/3X/2/3/2380479dcb8e375425884a10da232730bbc7f88d.pdf|Absolute C++]]: | ||
| - | * Capitolul 16 (Chapter 16: Templates, pag. 694-729) | ||
| - | |||
| - | ====== Functii Template ====== | ||
| - | <note>Template = Sablon</note> | ||
| - | **Functiile template** sunt utilizate pentru a substitui implementari multiple pentru o functie atunci cand singura diferenta dintre acestea apare numai prin faptul ca folosim alte tipuri de date. Semnatura functiei are acelasi numar de parametri, insa tipurile de date difera. | ||
| - | |||
| - | Spre exemplu, intr-o aplicatie exista posibilitatea de a avea nevoie de **o functie de sortare** pentru diferite tipuri de date (**int**, **double**, **char**). In loc sa scriem cate o functie **sort()** pentru fiecare tip de date, putem scrie **o singura functie template** generica care sa primeasca tipul de date ca parametru. | ||
| - | |||
| - | **Functiile template** folosesc cuvantul **template** pentru a preciza compilatorului faptul ca este vorba de o functie speciala, iar intre **<>** se precizeaza care sunt **tipurile generice** folosite de functie: **<Continut>**. | ||
| - | |||
| - | Tipul generic **T** este specificat prin: | ||
| - | **typename T** sau **class T**. | ||
| - | |||
| - | <note>Functia este **parametrizata** dupa tipurile de date generice, nu specializata pe un singur tip de date. | ||
| - | |||
| - | **Un parametru template** este un tip special de parametru care poate sa fie folosit pentru a transmite **un tip generic** ca argument intr-o functie.</note> | ||
| - | |||
| - | Functiile template se declara astfel: | ||
| - | <code c++>template <class tip1, ... , class tipN> | ||
| - | tip_de_date_returnat nume_functie(semnatura) { ... };</code> | ||
| - | sau | ||
| - | <code c++>template <typename tip1, ... , typename tipN> | ||
| - | tip_de_date_returnat nume_functie(semnatura) { ... };</code> | ||
| - | |||
| - | **Exemplu:** | ||
| - | |||
| - | <code cpp Max.cpp> | ||
| - | #include <iostream> | ||
| - | using namespace std; | ||
| - | |||
| - | //Functie pentru maximul dintre doua numere de tip int | ||
| - | int myMax(int x, int y) { | ||
| - | return (x > y) ? x : y; | ||
| - | } | ||
| - | |||
| - | //Functie pentru maximul dintre doua numere de tip double | ||
| - | double myMax(double x, double y) { | ||
| - | return (x > y) ? x : y; | ||
| - | } | ||
| - | |||
| - | //Functie pentru maximul dintre doua date de tip char | ||
| - | char myMax(char x, char y) { | ||
| - | return (x > y) ? x : y; | ||
| - | } | ||
| - | </code> | ||
| - | Observam ca cele trei functii difera doar prin **tipul de date returnat** si prin **tipurile de date ale parametrilor**, astfel putem folosi o singura functie tamplate pentru generalizare si evitam scrierea a trei functii diferite. | ||
| - | <code cpp MaxTemplate.cpp> | ||
| - | #include <iostream> | ||
| - | using namespace std; | ||
| - | |||
| - | //Functie pentru maximul dintre doua date de tipul generalizat T | ||
| - | template <typename T> | ||
| - | T myMax(T x, T y) { | ||
| - | return (x > y) ? x : y; | ||
| - | } | ||
| - | |||
| - | int main() { | ||
| - | cout << myMax<int>(21, 10) << endl; //apelam functia pentru tipul de date int | ||
| - | cout << myMax<double>(0.07, 31.56) << endl; //apelam functia pentru tipul de date double | ||
| - | cout << myMax<char>('a', 'x') << endl; //apelam functia pentru tipul de date char | ||
| - | return 0; | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | <note important>Tipul unui **parametru template** este determinat **in momentul compilarii**. | ||
| - | |||
| - | La apelul unei **functii template** legarea se face in **mod static**. | ||
| - | |||
| - | **NU** o sa putem avea functii virtuale template.</note> | ||
| - | |||
| - | <note tip>In afara de tipuri generice, **functiile template** pot fi parametrizate si dupa **parametri obisnuiti**, similari cu cei folositi in functii.</note> | ||
| - | |||
| - | <code c++> | ||
| - | //Functie template cu parametru generic si parametru de tip int | ||
| - | template <typename T, int dim> | ||
| - | T sum(T *vect) { | ||
| - | T s(0); | ||
| - | for (int i = 0; i < dim; i++) { | ||
| - | s += vect[i]; | ||
| - | } | ||
| - | | ||
| - | return s; | ||
| - | } | ||
| - | |||
| - | //Utilizare | ||
| - | int main() { | ||
| - | int n = 10; | ||
| - | int *vect1 = new int[n]; | ||
| - | double *vect2 = new double[n]; | ||
| - | | ||
| - | for (int i = 0; i < n; i++) { | ||
| - | vect1[i] = i; | ||
| - | vect2[i] = (double) i / 2; | ||
| - | } | ||
| - | | ||
| - | cout << sum<int, 10>(vect1) << endl; //Functia este specializata pentru int, iar dim = 10 | ||
| - | cout << sum<double, 10>(vect2) << endl; //Functia este specializata pentru double, iar dim = 10 | ||
| - | | ||
| - | return 0; | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | <note tip>Putem specifica un **tip default** pentru un **tip generic**, iar daca acesta nu este specificat la apelul functiei, se va folosi tipul default.</note> | ||
| - | |||
| - | <code c++> | ||
| - | //Parametrul generic este setat default int, iar parametrul int este setat default la valoarea 10 | ||
| - | template <typename T = int, int dim = 10> | ||
| - | T sum(T *vect) { | ||
| - | T s(0); | ||
| - | for (int i = 0; i < dim; i++) { | ||
| - | s += vect[i]; | ||
| - | } | ||
| - | | ||
| - | return s; | ||
| - | } | ||
| - | </code> | ||
| - | Acum, pentru vectorul nostru **vect1** cu **10** elemente de tip **int** putem apela astfel: | ||
| - | <code c++> | ||
| - | cout << sum<>(vect1) << endl; //Nu specificam niciun tip si vor fi folosite cele default | ||
| - | </code> | ||
| - | |||
| - | <note warning>**Nu** toate versiunile de compilatoarele permit argumente (tipul sau valoarea) template | ||
| - | default pentru functii **(permis de la C++11 in sus)**.</note> | ||
| - | ====== Clase Template ====== | ||
| - | <note>Exista posibilitatea realizarii de **clase template** – cu **atribute template** si/sau functii membre care folosesc **atribute de tipuri generice**.</note> | ||
| - | |||
| - | Sintaxa pentru **clasele template**: | ||
| - | <code c++> | ||
| - | template <class tip1, ... , class tipN> | ||
| - | class nume_clasa { | ||
| - | tip1 a; | ||
| - | tip2 b; | ||
| - | ... | ||
| - | tipN *vect; | ||
| - | //Alte atribute si/sau metode | ||
| - | }; | ||
| - | </code> | ||
| - | sau | ||
| - | <code c++> | ||
| - | template <typename tip1, ... , typename tipN> | ||
| - | class nume_clasa { | ||
| - | tip1 a; | ||
| - | tip2 b; | ||
| - | ... | ||
| - | tipN *vect; | ||
| - | //Alte atribute si/sau metode | ||
| - | }; | ||
| - | </code> | ||
| - | <note>Ca si in cazul functiilor template, se pot transmite si parametri care nu sunt tipuri de date intre **<>** sau **tipuri template default**.</note> | ||
| - | |||
| - | **Exemplu:** | ||
| - | <code c++ TemplateClass.cpp> | ||
| - | #include <iostream> | ||
| - | using namespace std; | ||
| - | |||
| - | //Clasa template | ||
| - | template <class T> | ||
| - | class myPair { | ||
| - | private: | ||
| - | T a, b; //Atribute de tip T | ||
| - | public: | ||
| - | myPair(T first, T second) { a = first; b = second; } //Constructor cu parametrii | ||
| - | T getMax(); //Functie template | ||
| - | }; | ||
| - | |||
| - | template <class T> | ||
| - | T myPair<T>::getMax() { | ||
| - | return (a > b) ? a : b; | ||
| - | } | ||
| - | |||
| - | int main () { | ||
| - | myPair<int> Obj(100, 75); | ||
| - | cout << Obj.getMax() << endl; //Se va afisa 100 | ||
| - | return 0; | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | <note> | ||
| - | **Functiile template** sunt un exemplu de **polimorfism la compilare** (compile time polymorphism) ca si supradefinirea functiilor. | ||
| - | |||
| - | Fiecare apel specializat al unei functii/clase template conduce la compilare la generarea **cate unei instante pentru fiecare specializare**. | ||
| - | |||
| - | Daca o functie/clasa template contine o **variabila locala statica/atribut static** – fiecare instantiere a clasei template va contine **copia proprie a variabilei/atributului static**. | ||
| - | </note> | ||
| - | |||
| - | ====== Derivarea din/de Clase Template ====== | ||
| - | |||
| - | **Modele de derivare simpla:** | ||
| - | * O clasa **obisnuita** derivata dintr-o clasa **template** | ||
| - | * O clasa **template** derivata dintr-o clasa **obisnuita** de baza | ||
| - | * O clasa **template** derivata dintr-o alta clasa **template** | ||