Parametrizare (Programare generică) - plan

• Clase parametrizate
– Declaraţie template – Definirea membrilor – Instanţiere (Specializare), Specializare utilizator – Friend în template – Membri statici în template

• Derivare - parametrizare • Ierarhia de clase STL:: IOS

POO(C++)

Gh GRIGORAS

1

Clase parametrizate
• Programare generică : programare ce utilizează tipurile ca parametri • În C++ - mecanismul template: clase template, funcţii template • Programatorul scrie o singură definiţie template iar C++, pe baza parametrilor, generează specializări care sunt compilate cu restul programului sursă • O funcţie template poate fi supraîncărcată cu:
– Funcţii template cu acelaşi nume dar parametri template diferiţi – Funcţii non – template cu acelaşi nume dar cu alţi parametri

• Clasele template se mai numesc tipuri parametrizate
POO(C++) Gh GRIGORAS 2

Template-uri
//Supraincarcare functii void swap(int& x, int& y){ int aux = x; x = y; y = aux; } void swap(char& x, char& y){ char aux = x; x = y; y = aux; } void swap(float& x, float& y){ float aux = x; x = y; y = aux; }
POO(C++) Gh GRIGORAS 3

Template-uri
int x = 23, y = 14; char c1 = 'o', c2 = '9'; double u = .5, v = 5.5; swap(x, y); swap(u, v); swap(c1, c2);

Polimorfism parametric:
– – utilizarea aceluiaşi nume pentru mai multe înţelesuri(polimorfism). înţelesul este dedus din tipul parametrilor (parametric).
Gh GRIGORAS 4

POO(C++)

Funcţie generică de interschimbare:
template <class T> void swap(T& x, T& y) { tip aux = x; x = y; y = aux; } int m = 8, n = 15; swap(m, n); // swap<int>(m, n); cout << endl << m << ", " << n << endl; double a = 10.0, b = 20.0; swap(a,b); // swap<double>(m, n); cout << endl << a << ", " << b << endl; complex z1(1.2, 2.3), z2(5.5, 2.2); swap(z1, z2); // swap<complex>(m, n);

Template-uri

POO(C++)

Gh GRIGORAS

5

}. a[j]). • Parametrii generici pot fi şi tipuri de bază template <class T. }. i++) for(int j=i+1. a[j]). j<n. j++) if (a[i] > a[j]) swap<T>(a[i]. i++) for(int j=i+1. i<n-1. i<n-1.• Funcţie generică de sortare: Template-uri template <class T> void naiveSort(T a[]. int n> void naivSort2(T a[]) { for (int i=0. int n) { for (int i=0. j<n. j++) if (a[i] > a[j]) swap<T>(a[i]. POO(C++) Gh GRIGORAS 6 .

3. double y[5] = {2.Template-uri • La apel.3. // eroare POO(C++) Gh GRIGORAS 7 . cout << endl.5. i++) cout << x[i] << ".4}. for (i=0. i<5. naivSort2<double.1. ".1.3. 5).5. i<5. for (i=0. double z[5] = {2. 5>(y).4}.1. naivSort2<double. int n = 5. ". cout << endl. pentru n trebuie transmisă o constantă: int i.5. naivSort<double>(x.4}. double x[5] = {2. i++) cout << x[i] << ". n>(z).

} D. Lucanu POO – Principii 8 . } poate fi parametrizat? void setValue(double newValue) { value = newValue.Abstractizare prin parametrizare void setValue(string newValue) { value = newValue.

Lucanu POO – Principii 9 .Clase parametrizate parametru parametru D.

parametri private: T value. public: void setValue(T newValue). utilizare } parametriza te parametri 10 D. }. public: DisplayBox(char *newLabel = ""). Lucanu POO – Principii .Clase parametrizate in C++ template <class T> class DisplayBox { declaratie private: string label. definitii template <class T> void DisplayBox<T>::setValue(T newValue) { value = newValue.

argument_template argument_template ::= tip_argument|declaratie_argument tip_argument ::= class identificator|typename identificator declaratie_argument::=<tip> identificator declaratie::= declaraţia unei clase sau funcţii POO(C++) Gh GRIGORAS 11 .Clase template (parametrizate) • Declaraţie template: template < lista_argumente_template > declaratie lista_argumente_template ::= argument_template| lista_argumente_template.

X1<Y. template< typename T1.. POO(C++) Gh GRIGORAS 12 . int i > class MyStack{}. class T2 = T1> class X2 {. template<class T. typename T2 > class X{}. template<class T> class allocator {}. class T2 > class X{}..}. X2<int> x2. template<class T1. typename T2 = allocator<T1> > class stack { }.}. template< class T1.. stack<int> MyStack.Clase parametrizate template< class T... Y aY. &aY> x1.}. // al doilea argument este implicit class Y {. template<class T1.. T* pT> class X1 {.

Clase parametrizate • Funcţiile membru ale unei clase template sunt funcţii template parametrizate cu parametrii clasei template respective • Definirea membrilor unei clase template: – Definiţie inline. la specificarea clasei – nu este specificat explicit template – Definiţie în afara specificării clasei – trebuie declarată explicit template: template <lista_argumente_template > nume_clasa_template<argum>::nume_functie_membru(parametri) { //Corp functie } • Compilatorul nu alocă memorie la declararea unui template POO(C++) Gh GRIGORAS 13 .

template void f(char). template MyStack<int. 6>::MyStack(). 6>.. template class MyStack<int..Clase parametrizate • Instanţiere template: procesul de generare a unei declaraţii de clasă (funcţie) de la o clasă(funcţie) template cu argumente corespunzătoare template class MyStack<class T. POO(C++) Gh GRIGORAS 14 . template<class T> void f(T) {.} template void f<int> (int).int n>{…}.

Cell& operator=(const Cell&). void setVal(Elt). }. } POO(C++) Gh GRIGORAS 15 .Clase parametrizate – Exemplul 1 template <class Elt> class Cell { public: Cell(). private: Elt* val. Cell(const Cell&). template <class Elt> Cell<Elt>::Cell() { val = new Elt. Elt getVal() const. // constructor de copiere ~Cell().

*val = *(c.. } template <class Elt> Cell<Elt>& Cell<Elt>::operator =(const Cell<Elt>& c) { //.Exemplul 1 . return *this. } template <class Elt> Cell<Elt>::~Cell() { delete val. *val = *(c.val). } POO(C++) Gh GRIGORAS 16 .val).cont template <class Elt> Cell<Elt>::Cell(const Cell<Elt>& c) { val = new Elt.

Array& operator=(const Array&). Elt). POO(C++) Gh GRIGORAS 17 .cont #include "cell. ~Array(). int nOfComp. private: Cell<Elt> *arr.h" template <class Elt> class Array { public: Array(int = 1). Cell<Elt>& operator[](int) const Cell<Elt>& operator[](int) const. Elt get(int). Array(const Aray&). }.Exemplul 1 . void set(int.

template <class Elt> Array<Elt>::~Array() { delete[] arr. }. template <class Elt> Elt Array<Elt>::get(int i) { if((i<0)||(i>=nOfComp)) throw "Index gresit. return arr[i].getVal().".Exemplul 1 . }. POO(C++) Gh GRIGORAS 18 . nOfComp = nMax. }.cont template <class Elt> Array<Elt>::Array(int nMax) { arr = new Cell<Elt>[nMax]. if(arr == NULL) throw “Memorie insuficienta ".

getVal() > y. const Cell<int>& y) { return x. } POO(C++) Gh GRIGORAS 19 .getVal(). } // pentru a sorta tablouri de celule de int-uri // trebuie definit operatorul de comparare: bool operator >(const Cell<int>& x. return arr[i].".Exemplul 1 .cont •Template: Supraîncărcare operatori template <class Elt> Cell<Elt>& Array<Elt>::operator[](int i) { if((i<0)||(i>=nOfComp)) throw "Index gresit.

1 .getVal()). Cell<T> temp. } if (i != (j-1)) a. for(i=1. } } typedef Cell<int> Int. temp. int n) { int i. j = i .cont // sortare prin insertie template <class T> void insert_sort(Array<T>& a. while((j >= 0) && (a[j] > temp)) { a.getVal()).i<n. POO(C++) Gh GRIGORAS 20 .set(j+1.Exemplul 1 .j. j--. a[j].i++) { temp = a[i].set(j+1. typedef Cell<char> Char.

Exemplul 2 template <class T> class Vector { public: Vector(int=0). n. int=0). const T& operator [](int) const. }. const Vector<T>& operator [](int) const.Clase parametrizate . template <class T> class Matrice { public: Matrice(int=0. }. Vector<T>& operator [](int). T& operator [](int). // … private: T* tab. POO(C++) Gh GRIGORAS 21 . private: Vector<T>* tabv. int n. int m.

if (i < 0 || i >= m) throw "index out of range". } template <class T> const Vector<T>& Matrice<T>::operator [](int i) const { cout << "Matrice<T>::operator [](int i) const" << endl. mm[2][3] = 7.5). const Matrice<double> mm(3.5).0.0. v[3] = 3. // apel varianta nonconst const Vector<int> vv(5). return tabv[i]. vv[4] = 4. return tab[i].Exemplul 2 template <class T> T& Vector<T>::operator [](int i) { cout << "Vector<T>::operator [](int i)" << endl. } Vector<int> v(5). m[1][2] = 5. POO(C++) Gh GRIGORAS 22 .// apel varianta const Matrice<double> m(3.

pentru a funcţiona când argumentul template este pointer) este numită specializare definită de utilizator POO(C++) Gh GRIGORAS 23 .Specializări • O versiune a unui template pentru un argument template particular este numită o specializare • O definiţie alternativă pentru o clasă(funcţie) template ( de ex.

}. Vector<int> vi. T& operator [](int). Vector<string> vs. int n. private: T* tab. • Specializări: POO(C++) Gh GRIGORAS 24 . const T& operator [](int) const. Vector<Punct*> vpp.Clase parametrizate . Vector<char*> vpc.Specializări template <class T> class Vector { public: Vector(int=0).

Clase parametrizate . // … }. POO(C++) Gh GRIGORAS 25 .Specializări • Specializare a clasei Vector<T> pentru pointeri la void: template<> class Vector<void*>{ // specializare fara parametri template void** p. • Specializare a clasei Vector<T> pentru pointeri la T: template<class T> class Vector<T*>{ // specializare cu parametri template //… }.

} • În clasa Vector<T>.Clase parametrizate .n). metoda: template <class T> void Vector<T>:: swap(Vector<T>& a){ swap(tab. T& y){ T t = x.tab).Specializări template <class T> void swap(T& x. Vector<T>& b){ a. y = t. x = y. a.swap(b). } • Specializare pentru Vector<T> : template <class T> void swap(Vector<T>& a. swap(n. } POO(C++) Gh GRIGORAS 26 . a.

MyString<unsigned char> s2. POO(C++) Gh GRIGORAS 27 .Clase parametrizate • Două instanţieri ale unei clase template sunt echivalente dacă parametrii template ce reprezintă tipuri sunt aceeaşi iar ceilalţi au aceleaşi valori MyString<char> s1. MyString <Uchar> s3. typedef unsigned char Uchar.

Clase parametrizate – relaţia friend • Funcţii(clase) friend în clase template: – Dacă funcţia friend accesează un parametru template.are alţi parametri template – Dacă funcţia friend nu accesează parametri template . este friend pentru toate instanţierile clasei POO(C++) Gh GRIGORAS 28 . aceasta trebuie să fie template. – Prieteni template “nelegaţi” . În acest caz o instanţiere este friend doar pentru instanţierile clasei template cu aceiaşi parametri (friend “legat”).

friend void f1(). //… }. friend void C<T> :: f4(X<double>&).Clase parametrizate – relaţia friend template <class T> class X { //. // f2(X<float>&) friend pentru X<float> friend class Y. friend void A::f3().. friend class Z<T>. POO(C++) Gh GRIGORAS 29 . // f1 friend pentru toate specializarile friend void f2(X<T>& ).

template<> const int ClasaN<int. template<class T. // }. 10>::cod =50 POO(C++) Gh GRIGORAS 30 . “global” sau pe specializări template<class T. int n> class ClasaN{ static const int cod.Membri statici în template –uri • Fiecare specializare a unei clase template are copia proprie a membrilor static. int n> const int ClasaN<T. atât date cât şi funcţii • Datele statice trebuiesc iniţializate. n>::cod = n.

parametrizare • Se poate defini o clasă parametrizată prin derivare – de la o clasă parametrizată – de la o instanţă a unei clase parametrizate – de la o clasă obişnuită • Se poate defini o clasă obişnuită prin derivare de la o instanţă a unei clase parametrizate POO(C++) 2005-2006 Gh GRIGORAS 31 .Derivare .

Derivare . template <class T> class FisierCitireScriere: public FisierCitire<T>. public FisierScriere<T> {}. template <class T> class FisierScriere: public virtual Fisier<T> {}.parametrizare template <class T> class Fisier: protected fstream {}. POO(C++) 2005-2006 Gh GRIGORAS 32 . template <class T> class FisierCitire: public virtual Fisier<T> {}.

assert (s != 0). } void push(TYPE c) { s[++top] = c. } TYPE top_of()const { return s[top].} ~stack() { delete []s. } bool empty()const { return top == EMPTY. } void reset() { top = EMPTY. int max_len. int top. TYPE* s.} bool full()const { return top == max_len .} private: enum { EMPTY = -1 }. top(EMPTY) {s = new TYPE[size].Exemplu template <class TYPE> class stack { public: explicit stack(int size = 100) // doar explicit : max_len(size). } TYPE pop() { return s[top--]. POO(C++) 2005-2006 Gh GRIGORAS 33 .1. }.Derivare şi parametrizare .

POO(C++) 2005-2006 Gh GRIGORAS 34 . template <class Type> class safe_stack : public stack<Type> { public: // push.} }. } char pop() {assert (!empty()).Exemplu class safe_char_stack : public stack<char> { public: // push.Derivare şi parametrizare . pop sigure void push(Type c) { assert (!full()). stack<Type>::push(c). stack<char>::push(c). return (stack<Type>::pop()).} }. return (stack<char>::pop()). pop sigure void push(char c) { assert (!full()). } char pop() {assert (!empty()).

Ierarhia de clase STL:: IOS ios_base Mostenire virtuala ios<> istream<> ostream<> istringstream<> ifstream<> iostream<> ostringstream<> ofstream<> fstream<> stringstream<> POO(C++) 2005-2006 Gh GRIGORAS 35 .

class T = char_traits<E> > class basic_istream : virtual public basic_ios<E.uri parametrizate cu un tip caracter iar numele lor au prefixul basic_ : template <class E. • char_traits<E> conţine informaţii pentru manipularea elementelor de tip E template <class E. T> { //… }.Ierarhia de clase iostream • Clasele cu sufixul <> sunt template . class T = char_traits<E> > class basic_ios : public ios_base { //… }. POO(C++) 2005-2006 Gh GRIGORAS 36 .

Ierarhia de clase streambuf streambuf<> filebuf<> stringbuf<> POO(C++) 2005-2006 Gh GRIGORAS 37 .

T> { public: explicit basic_iostream(basic_streambuf<E. public basic_ostream<E. class T = char_traits<E>> class basic_iostream : public basic_istream<E. virtual ~basic_iostream(). T>* sb). T>. }. POO(C++) 2005-2006 Gh GRIGORAS 38 .Clasa basic_iostream template <class E.

Fisierul header <iosfwd> typedef basic_ios<char. fstream. char_traits<char> > basic_ifstream<char. char_traits<char> > basic_fstream<char. char_traits<char> > iostream. char_traits<char> > ostream. char_traits<char> > ios. char_traits<char> > istream. typedef basic_ostream<char. typedef basic_istream<char. ofstream. typedef typedef typedef typedef basic_iostream<char. POO(C++) 2005-2006 Gh GRIGORAS 39 . ifstream. char_traits<char> > basic_ofstream<char.

cu buffer POO(C++) 2005-2006 Gh GRIGORAS 40 . // mesaje eroare. //fluxul standard de iesire ostream cerr.Clasa ostream • Un obiect din ostream (flux de ieșire) este un mecanism pentru conversia valorilor de diverse tipuri în secvenţe de caractere • În <iostream>: ostream cout.fara buffer ostream clog. // mesaje eroare.

basic_ostream& operator<< (float n). basic_ostream& put(E c). // pozitia way (= beg. // noua positie pos basic_ostream& seekp(off_type off.operator<< (în ostream) basic_ostream& operator<< (const char *s). basic_ostream& operator<< (unsigned short n). basic_ostream& operator<< (bool n). basic_ostream& operator<< (long double n). basic_ostream& operator<< (int n). // goleste bufferul pos_type tellp().p[n-1] basic_ostream& flush(). streamsize n).…. basic_ostream& operator<< (long n). basic_ostream& operator<< (char c). cur. basic_ostream& operator<< (short n). basic_ostream& operator<< (double n). // scrie c basic_ostream& write(E *p. // scrie p[0]. basic_ostream& operator<< (unsigned long n). ios_base::seek_dir way). basic_ostream& operator<< (unsigned int n). // pozitia curenta basic_ostream& seekp(pos_type pos). end) + off POO(C++) 2005-2006 Gh GRIGORAS 41 . basic_ostream& operator<< (void * n).

Formatare. cout << hex << i << '\t' << j << '\t' << k << endl. k = 24. cin >> i >> hex >> j >> k. j = 16. cout << i << '\t' << j << '\t' << k << endl. } /* 10 16 24 12 20 30 a 10 18 Introdu 3 intregi: 42 11 12a 42 17 298 */ POO(C++) 2005-2006 Gh GRIGORAS 42 . fișierul <iomanip> void main() { int i = 10. cout << dec << i << '\t' << j << '\t' << k << endl. cout << "Introdu 3 intregi: " << endl. cout << oct << i << '\t' << j << '\t' << k << endl.

Manipulatori MANIPULATOR endl ends flush dec hex oct ws skipws noskipws showpoint noshowpoint showpos noshowpos boolalpha noboolalpha POO(C++) 2005-2006 Scrie newline Scrie NULL in string Goleste Baza 10 Baza 16 Baza 8 Ignoră spaţiile la intrare Ignoră spaţiile Nu ignoră spaţiile Se scrie punctul zecimal şi zerourile Nu se scriu zerourile. nici punctul Scrie + la numerele nenegative Nu scrie + la numerele nenegative Scrie true si false pentru bool Scrie 1 si 0 pentru bool Gh GRIGORAS EFECTUL FISIERUL iostream iostream iostream iostream iostream iostream iostream iostream iostream iostream iostream iostream iostream iostream iostream 43 .

Manipulatori MANIPULATOR scientific fixed left right internal setw(int) setfill(char c) setbase(int) setprecision(int) setiosflags(long) resetiosflags(long) EFECTUL Notaţia ştiinţifică pentru numere reale Notaţia punct fix pentru numere reale Aliniere stânga Aliniere dreapta Caract. de umplere intre semn si valoare Seteaza dimensiunea câmpului Caracterul c înlocueşte blancurile Setarea bazei Seteaza precizia in flotant Seteaza bitii pentru format Reseteaza bitii pentru format FISIERUL iostream iostream iostream iostream iostream iomanip iomanip iomanip iomanip iomanip iomanip POO(C++) 2005-2006 Gh GRIGORAS 44 .

cout << scientific << c << endl.-200.89 -2.25.05.25.89.3 ******-201 *****-201.1 ******11. c = -200. cout << setw(10) << b << endl. cout << setw(10) << c << endl.00890e+002 text pentru test text pentru test POO(C++) 2005-2006 Gh GRIGORAS 45 . cout << a << '.05. char d. cout << setw(15) << setprecision(5) << c << endl.11.89 ******12.' << b << '. cout << setfill(' ') << right << showpoint. -200.' << c << endl. cout << setfill('*') << setprecision(3).double a = 12. cout << setw(10) << showpoint << c << endl. 12. cin >> noskipws. b = 11. cout << setw(10) << a << endl. while(cin >>d) cout << d.

//fluxul standard de intrare • În basic_istream este definit operator>> pentru tipurile fundamentale POO(C++) 2005-2006 Gh GRIGORAS 46 .Clasa istream • Un obiect din istream (flux de intrare) este un mecanism pentru conversia caracterelor în valori de diverse tipuri • În <iostream>: istream cin.

int_type delim = T::eof()). streamsize n. int sync(). // pune c in buferul de intrare basic_istream& unget(). E delim). basic_istream& seekg(off_type off. E delim). basic_istream& get(E& c). E delim).Funcţii utile în istream streamsize gcount() const. // citeste fara a-l extrage basic_istream& read(E *s. int_type get(). // flush input POO(C++) 2005-2006 Gh GRIGORAS 47 . basic_istream& getline(E *s. // pune inapoi ultimul citit pos_type tellg(). basic_istream& get(E *s. streamsize n). int_type peek(). basic_istream& get(E *s. streamsize n). basic_istream& get(basic_streambuf<E. // peek cel mult n basic_istream& putback(E c). streamsize n). basic_istream& seekg(pos_type pos). T> *sb. streamsize readsome(E *s. basic_istream& getline(E *s. basic_istream& ignore(streamsize n = 1. streamsize n. streamsize n). ios_base::seek_dir way). T> *sb). basic_istream& get(basic_streambuf<E.

cout. ofstream). cerr. corespondenţa lor cu dispozitivele (fișierele ) standard este făcută de sistem • Programatorul poate crea fluxuri proprii – obiecte ale clasei fstream (ifstream.Fișiere • Într-un program C++ fluxurile standard cin. Atașarea fluxului creat unui fișier sau unui string se face de programator: – la declarare cu un constructor cu parametri – după declarare prin mesajul open() POO(C++) 2005-2006 Gh GRIGORAS 48 . clog sunt disponibile.

explicit basic_fstream(const char *s. • Metode: bool is_open() const. ios_base::openmode mode = ios_base::in | ios_base::out).Fișiere • Constructorii clasei fstream: explicit basic_fstream(). void open(const char *s. ios_base::openmode mode = ios_base::in | ios_base::out). void close(). POO(C++) 2005-2006 Gh GRIGORAS 49 .

void open(const char *s.Fișiere de intrare • Constructorii clasei ifstream: explicit basic_ifstream(). • Metode: bool is_open() const. void close(). ios_base::openmode mode = ios_base::in). explicit basic_ifstream(const char *s. ios_base::openmode mode = ios_base::in). POO(C++) 2005-2006 Gh GRIGORAS 50 .

is_open()) { while (! myfile. } myfile. return 0.close().line). if (myfile. int main () { string line. }else cout << "Unable to open file".cpp"). cout << line << endl. ifstream myfile ("file.#include <fstream> #include <iostream> #include <string> using namespace std. } POO(C++) 2005-2006 Gh GRIGORAS 51 .eof() ) { getline (myfile.

explicit basic_ofstream(const char *s. • Metode: bool is_open() const.Fișiere de ieșire • Constructorii clasei ofstream: explicit basic_ofstream(). void open(const char *s. ios_base::openmode which = ios_base::out | ios_base::trunc). POO(C++) 2005-2006 Gh GRIGORAS 52 . void close(). ios_base::openmode mode = ios_base::out | ios_base::trunc).

\n".#include <iostream> #include <fstream> using namespace std.close(). } else cout << "Unable to open file".txt"). if (myfile.\n". myfile << "This is another line. } POO(C++) 2005-2006 Gh GRIGORAS 53 . int main () { ofstream myfile ("example. myfile. return 0.is_open()){ myfile << "This is a line.

poziţionare la sfârșit înainte de fiecare inserţie • ate. trunchiază un fișier existent la prima creare a fluxului ce-l controlează POO(C++) 2005-2006 Gh GRIGORAS 54 .ios_base::openmode • app. citirea fișierului în mod binar și nu în mod text • in. permite extragerea (fișier de intrare) • out. poziţionare la sfârșit la deschiderea fișierului • binary. permite inserţia (fișier de ieșire) • trunc.

T. ios_base::openmode mode = ios_base::in | ios_base::out).Clasa stringstream • Permite ca stringurile să fie tratate ca fișiere: explicit basic_stringstream(ios_base::openmode mode = ios_base::in | ios_base::out). explicit basic_stringstream(const basic_string<E.A>& x. POO(C++) 2005-2006 Gh GRIGORAS 55 .

return 0. int i."). int main() { stringstream s("This is initial string. } POO(C++) 2005-2006 Gh GRIGORAS 56 . s >> str >> i >> d. // get string string str = s. cout << str << " " << i << " " << d. double d. cout << str << endl. // output to string stream s << "Numbers: " << 10 << " " << 123.str().#include <iostream> #include <sstream> using namespace std.2.