Sunteți pe pagina 1din 26

Funcţii şi clase template

 Funcţii template
 Clase template
 Specializări
 Relaţii între clasele template
Funcţii template
 Programare generică (object, void * )
 Conversiile de adaptare la prototip pot produce pierderi de informaţii
 Conversiile de adaptare la prototip pot ascunde calcule ineficiente
 Pe referinţe şi pointeri conversiile sunt restricţionate

int suma (int a, int b ) { return a+b; }

void main( )
{
cout << suma(12.5, 2.5);
}

 Soluţia: scrierea aceleeaşi funcţii de mai multe ori, diferind doar tipul

1. folosind macrodefiniţii
2. definind funcţii template
Funcţii template

# define COMUTA_GEN(TIP) void comuta(TIP& a,TIP& b) \


{ TIP aux; aux =a; a = b; b = aux; }

COMUTA_GEN(int);
COMUTA_GEN(double);

#include <iostream.h>
#include <string.h>

template <class TIP>


void comuta ( TIP &a, TIP &b ) { TIP aux; aux = a, a = b,b = aux; }

void main( )
{
double x = 1.1, y =2.2;
comuta( x,y); cout <<x<<" "<<y<<endl;
int a =1,b =2;
comuta( a,b); cout <<a<<" "<<b<<endl;
}
Funcţii şi clase template

 Comparaţii între macrodefiniţii şi funcţii template


 Cine instanţiază funcţiile template, când şi cu ce parametri ?
 Ce se poate parametriza ?
 Cum sunt denumite funcţiile generate ?

template < class TIP>


template <typename TIP>
Funcţii template

 Cât de generale sunt funcţiile template ?


Ce îi trebuie unui tip de utilizator pentru a fi acceptat de funcţia template ?
class persoana
{
public: char nume[50];
persoana( char *n ="Noname") { strcpy(nume,n); }
friend ostream& operator<<(ostream &out, persoana p) { out << p.nume; return out; }
};

#include <iostream>
Using namespace std;
#include <string.h>
template <class TIP>
void comuta ( TIP &a, TIP &b ) { TIP aux; aux = a, a = b,b = aux; }

void main( )
{
double x = 1.1, y =2.2; comuta( x,y); cout <<x<<" "<<y<<endl;
persoana a (“A”), b (“B”); comuta( a,b); cout <<a<<" "<<b<<endl;
}

Dacă avea membri pointeri ?


Clase template

template < class T, int n>


class cls
{
T v[n];
};

void main( )
{
cls<double,10> ob1;
}

 Instanţiere şablon  clasă


 Instanţiere clasă  obiect
Clase template

template <class T>


class vector
{
T * pe;
int dim;
public: vector(int);
~vector( ) { delete[ ] pe; }
T& operator[ ] (int i) { return pe[i]; }
void afis(); void sort();
};
template <class T>
vector<T>:: vector(int n) :dim(n)
{
pe = new T[n];
for (int i = 0; i < dim; i++)
{ cout <<"\n elem_" << i << " "; cin >> pe[i]; }
}

 Cum se numeşte în realitate clasa ? Dar constructorul ei ?


Clase template
 Ce trebuie definit pentru a lucra pe tipul persoana ?
class persoana
{
public: char nume[40];
persoana( char *n="Noname") { strcpy(nume,n); }
friend ostream & operator<< ( ostream & iesire, persoana p )
{ iesire << p.nume << " "; return iesire; }
friend istream & operator>> ( istream & intrare, persoana & p )
{ cout << "Nume: "; intrare>> p.nume; return intrare; }
int operator> (persoana p) { return strcmp(nume,p.nume)>0 ? 1 :0; }
};

 Independenţa faţă de tipul de date !


void main()
{
vector<int> vi(3); vi.afis(); vi.sort(); vi.afis();
vector<persoana> vp(3); vp.afis(); vp.sort(); vp.afis();
}
Clase template
 limitările clasei vector: copy cons ? operator= ?
 instanţiere implicită:
- Instanţierea şablonului la momentul definirii unui obiect
void main()
{
vector<int> vi(3); vi.afis(); vi.sort(); vi.afis();
vector<persoana> vp(2); vp.afis(); vp.sort(); vp.afis();
}

 Ce se întâmplă dacă nu lucrăm cu obiecte, ci clasa template apare


doar în prototipul unei funcţii ?

int masoara( vector<int>& v1, vector<double>& v2)


{
int dim1=v1.spune_dim(), dim2=v2.spune_dim();
if(dim1==dim2) return 0;
else if(dim1<dim2) return -1; else return +1;
}
Clase template
 instanţe de template cu nume generice ?
template <class TT1, class TT2>
int masoara( vector<TT1>& v1, vector<TT2>& v2)
{
int dim1=v1.spune_dim(), dim2=v2.spune_dim();
if(dim1==dim2) return 0;
else
if(dim1<dim2) return -1;
else return +1;
}

 Altceva decât template propriu-zisă ! Ce face masoara( int, int ) ??

template <class TT1, class TT2>


int masoara( TT1 & v1, TT2 & v2)
{
// ........;
}
Clase template
 Momentul definirii şablonului << momentul instanţierii şablonului (vezi
STL)

template <class T=char, int n = 50>


class vector
{
T v[n];
public: int spune_dim() { return n; }
};

void main()
{
vector<> v1;
vector<double> v2;
vector<int, 4> v3;
cout<<v1.spune_dim()<<endl;
cout<<v2.spune_dim()<<endl;
cout<<v3.spune_dim();
}
Clase template
 Dacă nu dăm codul sursă al şablonului, ci doar codul obiect ?
 Instanţieri explicite
construcţia template <class T > nu apare completă, ci doar template
class
template class vector<int,10>;

 Funcţiile membre nu se instanţiază decât dacă se apeleză cu tipul respectiv;


putem şi forţa instanţierea funcţiei:

template class vector<int,10>:: vector(int);

template int masoara <int, double> (int,double);


Specializări în clase template
 Cum lucrează un vector de char * ?

template <class T>


class vector
{
T * pe;
int dim;
public: vector(int);
~vector( ) { delete[ ] pe; }
T& operator[ ] (int i) { return pe[i]; }
void afis(); void sort();
};

vector<char * > vs(3);


pe char ** pe;

sir1

sir2

sir3

sir4
Specializări în clase template
 Specializare constructor şi destructor, pe char *

#define L_SIR 100


vector<char*>::vector(int n):dim(n)
{
pe = new char*[dim];
cin.ignore(L_SIR,'\n');
for (int i = 0; i < dim; i++)
{
cout <<"\n elem_" << i << " ";
pe[i]=new char[L_SIR];
cin.getline(pe[i],L_SIR);
}
}
vector<char*>::~vector()
{
for (int i = 0; i < dim; i++) delete [L_SIR] pe[i];
delete [dim]pe;
}
Specializări în clase template

 Specializare sortare, pe char *

void vector<char*>::sort()
{
int i,j; char *aux;
for (i=0; i < dim-1; i++)
for ( j = i+1; j < dim; j++)
if(strcmp(pe[i], pe[j])>0)
{ aux= pe[i]; pe[i]=pe[j]; pe[j]=aux; }
}

 Specializările au prioritate în raport cu şabloanele


Specializări în clase template
 Specializarea întregii clase (vezi codul sursă)
template <> class vector<char*>
{
char **pe;
int dim;
public:
vector(int);
char*& operator[ ] (int i) { return pe[i]; }
void afis(); void sort();
int lungime_element(int);
~vector( );
};
// plus explicitarea celorlalte funcţii membre

 Trebuie să existe şi şablonul general !


 Trebuie să rescriem şi funcţiile care nu au modificări !
 Se pot adăuga noi metode şi date faţă de clasa generală !
Specializări în clase template
 Specializări parţiale:
clasă pe tip generic şi clasă pe pointer de tip generic

template<class T>
class cls
{
// sablon generic de clasa
};

template <class T>


class cls<T*>
{
// specializare pentru pointer la tip
};

 Diferă numele de clasă ?


Specializări în clase template
 Specializări parţiale: concretizare parţială a tipurilor generice

template<class T1,class T2>


class cls
{
// sablon general
};

template<class T1>
class cls<int>
{
// specializare partiala cu T2 concretizat în int
};

 Diferă numele de clasă ?


Relaţii între clasele template: derivarea

 Derivare clasă template din clasă template neinstanţiată

template <class T>


class vector
{
// conţinut clasa baza
};

template <class T>


class vect_sort: public vector<T>
{
// continut specific clasei derivate
};

 Vezi cod sursă detaliat.


Relaţii între clasele template: derivarea

 Derivare clasă template din clasă non-template

class b
{
public:
b() { }
virtual ~b() { }
};
template <typename T>
class d : public b
{
public:
T x;
d() { }
virtual ~d(){ }
};
void main()
{ b a; d<float> c;}
Relaţii între clasele template: derivarea

 Derivare clasă non-template din clasă template instanţiată

template <class T>


class b
{
public:
T x;
b() { }
virtual ~b() { }
};
class d : public b<int>
{
public: // ce devine T x; mostenit ??
d() { }
virtual ~d() { }
};
void main()
{ b<float> a; d c;}
Relaţii între clasele template: derivarea

 Moşteniri multiple din clase template

template<class T1>
class b1
{
protected: T1 a;
public: b1(T1 x):a(x) { }
void afis() { cout<<"Membru din b1:"<<a<<endl; }
};
template<class T2>
class b2
{
protected: T2 c;
public: b2(T2 x):c(x) { }
void afis() { cout<<"Membru din b2:"<<c<<endl; }
};
Relaţii între clasele template: derivarea

 Moşteniri multiple din clase template


template<class T1, class T2>
class d : public b1<T1>, public b2<T2>
{
public:
d(T1 y, T2 z):b1<T1>(y),b2<T2>(z) { }
void afis() { cout<<"Valorile :"<<a<<" si "<<c<<endl;
}
};

template<class T>
class d : public b1<T>, public b2<T>
{
public:
d(T y, T z):b1<T>(y),b2<T>(z) { }
void afis() { cout<<"Valorile :"<<a<<" si "<<c<<endl;
}
};
Relaţii între clasele template: compunerea
 o clasă inclusă într-un template, devine automat template.

template<class T>
class lista
{
class nod
{
friend lista;
T info;
nod *next;
public: nod(T k, nod *urm=NULL):info(k),next(urm) { }
nod *get_next() { return next; }
friend ostream& operator<<(ostream& os, nod* n)
{ os<<n->info; return os; }
};

nod *cap;
int n;
void sterge_tot(nod *);
public: lista():cap(NULL),n(0) { }
void ins_incep(T );
int count() { return n; }
friend ostream& operator<<(ostream& , lista& );
~lista() { sterge_tot(cap); }
};
Relaţii între clasele template: compunerea
 Compunerea template prin parametrizare cu altă clasă template

template<class T>
class persoana
{
char nume[50];
T sal;
public: persoana(char *np, T s):sal(s) { strcpy(nume, np); }
friend ostream& operator<<(ostream& os, persoana &p)
{
os<<p.nume<<" "<<p.sal;
return os;
}
};
template<class T> class salariati
{
public: lista< persoana<T> > ls; // + alte declaratii
};