Sunteți pe pagina 1din 53

Cursul 5 - CLASE n C++, continuare

Pointeri la
date membru metode

Suprancrcare operatori Constructor de conversie vs.Operator de conversie Clase parametrizate


Declaraie template Definirea membrilor Instaniere(Specializare), Specializare utilizator Friend n template Membri statici n template Sintaxa Tipuri de derivare Constructori, Destructori Conversii standard Copiere Conflicte

Relaia de derivare

POO(C++)

Gh GRIGORAS

Pointeri la date membru Operatorii .* i ->*


Declaraie: tip Nume_clasa::*point_membru; tip Nume_clasa::*point_membru = &Nume_clasa::Nume_membru; Utilizare Nume_clasa obiect, *point_obiect; obiect.*point_membru = point_obiect ->*point_membru =

POO(C++)

Gh GRIGORAS

Pointeri la metode
Declaraie
tip (Nume_clasa::*point_func)(parametri); tip (Nume_clasa::*point_func)(parametri) = &Nume_clasa::Nume_metoda;

Utilizare:
(obiect.*point_func)(parametri); (point_obiect ->*point_func)(parametri);

Un pointer la o funcie membru, cand se instantiaza, trebuie s se potriveasc cu functia respectiva n trei elemente: numrul i tipurile argumentelor tipul valorii returnate tipul clasei a crei membru este
POO(C++) Gh GRIGORAS 3

Exemplu
//Pointeri la functii membru class C{ public: void f(int n=5) const {cout << "apel C::f(" << void g(int n) const {cout << "apel C::g(" << n void h(int n) const {cout << "apel C::h(" << n void i(int n) const {cout << "apel C::i(" << n }; void main(){ C c; C* pc = &c; void (C::*p_metoda)(int=0) const = &C::h; (c.*p_metoda)(7); (pc->*p_metoda)(); p_metoda = &C::f; (pc->*p_metoda)(8); (c.*p_metoda)(); c.f(); }

n <<")" << endl;} <<")" << endl;} <<")" << endl;} <<")" << endl;}

// apel C::h(7) apel C::h(0) apel C::f(8) apel C::f(0) apel C::f(5)

POO(C++)

Gh GRIGORAS

Atenie la declararea pointerilor


class Ex{ public: int fct(int a, int b){ return a+b;} }; //typedef int (Ex::*TF)(int,int); typedef int (*TF)(int,int); void main(){ Ex ex; TF f = Ex::fct; // eroare: f nu e pointer // al clasei Ex cout << (ex.*f)(2,3) << "\n"; }
POO(C++) Gh GRIGORAS 5

Suprancarcare operatori: operator@


Nu se pot supraincarca operatorii: :: scope resolution . acces la membru .* derefereniere membru ?: sizeof() Operatorii binari se definesc fie ca funcii membru nestatic cu un argument sau funcii nemembru cu 2 argumente

POO(C++)

Gh GRIGORAS

Suprancarcare operatori: operator@


Operatorii unari se definesc fie ca funcii membru nestatic fr argumente (cu un argument int pentru postfix) sau funcii nemembru cu 1 argument (2 argumente postfix); operator=, operator[], operator() i operator-> trebuie definii ca funcii membru nestatic; asta asigur c primul operand este lvalue
POO(C++) Gh GRIGORAS 7

Suprancarcare operatori
operator<< i operator>> nu pot fi definite ca metode; n std sunt definii aceti operatori i redefinirea ca metode ar nsemna modificarea claselor din std ceea ce este imposibil; operator<< i operator>> nu pot fi definite ca friend dac se folosete std; Pentru un operator binar x@y unde x este de tip X iar y de tip Y sistemul procedeaz astfel:
Dac X este o clas se determin dac X sau clasa sa de baz definete operator@ ca membru; dac da se folosete acest operator Dac nu, se caut declaraia lui operator@ n contextul ce conine x@y apoi n namespace-ul lui X, n namespace-ul lui Y i se ncearc aplicarea celui ce se potrivete mai bine. Condiia este ca cel puin un operand s fie de tip(clasa) utilizator.

POO(C++)

Gh GRIGORAS

Suprancarcare operator []
#include <iostream> using namespace std; class Cstring{ public: Cstring(char* s = "", int l = 0) ; Cstring(const Cstring&); char& operator[](int); Cstring& operator=(const Cstring&); int get_lung() { return lung;} private: char* rep; int lung; }; char& Cstring::operator[](int i){return *(rep+i);} Cstring::Cstring(char* s, int l):rep(s),lung((l==0)?strlen(s): l) { cout << "Sirul : '"<< rep; cout << "' are lungimea : " << lung << endl; }

POO(C++)

Gh GRIGORAS

Suprancarcare operator []
int main(){ Cstring p1("Popescu Ion"), p2("Ionescu Paul"); cout << " \nSirul p1 folosind operator[] : ; cout << endl; for ( int i = 0; i < p1.get_lung(); i++) cout << p1[i]; p1 = p2; cout << " \nNoul sir p1 folosind operator[]: ; cout << endl; for ( i = 0; i < p1.get_lung(); i++) cout << p1[i]; return 0; }

POO(C++)

Gh GRIGORAS

10

Operator () Obiecte funcii


class Matrice{ public: enum { max_Size = 20}; Matrice(int s1, int s2) :size1(s1), size2(s2){} int& operator()(int, int); int get_s1(){return size1;} int get_s2(){return size2;} private: int a[max_Size]; int size1,size2; };

POO(C++)

Gh GRIGORAS

11

Suprancarcare operator ()
int& Matrice::operator()(int i, int j){ if(i < 0 || i >= size1) throw "Primul indice gresit\n"; if(j < 0 || j >= size2) throw "Al doilea indice gresit\n"; return a[i*size2 + j]; } int main(){ Matrice a(3, 4); int i, j; for (i = 0; i < a.get_s1(); i++) for(j =0; j < a.get_s2(); j++) a(i, j) = 2*i + j; for (i = 0; i < a.get_s1(); i++) { for(j =0; j < a.get_s2(); j++) cout << a(i, j) << " "; cout << endl; } try{ cout << a(1, 2) << endl; cout << a(2, 8) << endl; } catch(char* s){cout << s ;} return 0; } POO(C++) Gh GRIGORAS 12

Suprancarcare operator ()
/* 0 2 4 4 Al */

1 3 5

2 4 6

3 5 7

doilea indice gresit

POO(C++)

Gh GRIGORAS

13

CLASE: Suprancrcare operatori


Minimizarea numrului funciilor ce au acces direct la reprezentare:
Operatorii ce modific valoarea primului argument, ca membri ( ex. +=) Operatorii ce produc noi valori, ca funcii externe (ex. +, -, )

class complex{ public: complex& operator+=(const complex a); // private: double re, im; }; inline complex& complex:: operator+=(const complex a){ re += a.re; im += a.im; return *this; } complex operator+(complex a, complex b){ complex s = a; return s+= b; }

POO(C++)

Gh GRIGORAS

14

CLASE: Constructor de conversie


Constructorul de conversie definete o conversie(ce se aplic implicit) de la un tip (de baza) la un tip utilizator
X::X(tip_de_baza m)
punct(int i) : x(i), y(0) {} // int -> punct data(int d):zi(d), luna(luna_curenta()), an(anul_curent()) {} // int -> data complex(double r) : re(r), im(0){} // double -> complex void f(){ complex z = 2; // z = complex(2) 3 + z; // complex(3) + z; z += 3; // z += complex(3); 3.operator+=(z); // eroare 3 += z; // eroare }

POO(C++)

Gh GRIGORAS

15

CLASE: Constructor de conversie


Constructorul de conversie poate suplini definiiile unor operatori; pentru clasa complex nu-i necesar a defini:
complex operator+(double, complex); complex operator+(complex, double);

Un constructor de conversie nu poate defini:


O conversie implicit de la un tip utilizator la un tip de baz O conversie de la o clas nou la o clas definit anterior, fr a modifica declaraiile vechii clase Soluia: Operatorul de conversie

POO(C++)

Gh GRIGORAS

16

CLASE: Operatorul de conversie


este o funcie membru: X::operator T()const; care definete o conversie de la tipul X la tipul T Exemplu:
class Clock{ public: Clock(int = 12, int = 0, int = 0); Clock tic_tac(); friend ostream& operator<<(ostream&, Clock&); Clock operator++(); Clock operator++(int); operator int(); // Conversie Clock --> int // Ora 8:22 AM devine 822 // Ora 8.22 PM devine 2022 private: int ora; int min; int ap; // 0 pentru AM, 1 pentru PM };
POO(C++) Gh GRIGORAS 17

CLASE: Conversie
Ambiguitate constructor de conversie/operator de conversie:
class Apple { public: operator Orange() const; // Apple -> Orange }; class Orange { public: Orange(Apple); // Apple -> Orange }; void f(Orange) {} int main() { Apple a; f(a); } //error C2664:'f' : cannot convert parameter 1 from //'class Apple' to 'class Orange'
POO(C++) Gh GRIGORAS 18

CLASE: Conversie
Ambiguitate operatori conversie/suprancrcare funcii:
class Orange {}; class Pear {}; class Apple { public: operator Orange() const; // conversie Apple -> Orange operator Pear() const; // conversie Apple -> Pear }; // Supraincarcare eat(): void eat(Orange); void eat(Pear); int main() { Apple c; eat(c); // Error: Apple -> Orange or Apple -> Pear ??? }
POO(C++) Gh GRIGORAS 19

Clase parametrizate
Programare generic : programare ce utilizeaz tipurile ca parametri n C++ - mecanismul template: clase template, funcii template Programatorul scrie o singur definiie template iar C++, pe baza parametrilor, genereaz specializri care sunt compilate cu restul programului surs O funcie template poate fi suprancrcat cu:
Funcii template cu acelai nume dar parametri template diferii Funcii non template cu acelai nume dar cu ali parametri

Clasele template se mai numesc tipuri parametrizate


POO(C++) Gh GRIGORAS

20

Clase parametrizate
Declaraie template:
template < lista_argumente_template > declaratie lista_argumente_template :: argument_template| lista_argumente_template, argument_template argument_template :: tip_argument|declaratie_argument tip_argument :: class identificator|typename identificator declaratie_argument::<tip> identificator declaratie:: declaraia unei clase sau funcii

POO(C++)

Gh GRIGORAS

21

Clase parametrizate
template< class T, int i > class MyStack{}; template< class T1, class T2 > class X{}; template< typename T1, typename T2 > class X{}; template<class T> class allocator {}; template<class T1, typename T2 = allocator<T1> > class stack { }; stack<int> MyStack; // al doilea argument este implicit class Y {...}; template<class T, T* pT> class X1 {...}; template<class T1, class T2 = T1> class X2 {...}; Y aY; X1<Y, &aY> x1; X2<int> x2;

POO(C++)

Gh GRIGORAS

22

Clase parametrizate
Funciile membru ale unei clase template sunt funcii template parametrizate cu parametrii clasei template respective Definirea membrilor unei clase template:
Definiie inline, la specificarea clasei nu este specificat explicit template Definiie n afara specificrii 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 23

Clase parametrizate
Instaniere template: procesul de generare a unei declaraii de clas (funcie) de la o clas(funcie) template cu argumente corespunztoare template class MyStack<class T,int n>{}; template class MyStack<int, 6>; template MyStack<int, 6>::MyStack(); template<class T> void f(T) {...} template void f<int> (int); template void f(char);
POO(C++) Gh GRIGORAS 24

Clase parametrizate Exemplul 1


template <class Elt> class Cell { public: Cell(); Cell(const Cell&); // constructor de copiere ~Cell(); Elt getVal() const; void setVal(Elt); Cell& operator =(const Cell&); private: Elt* val; }; template <class Elt> Cell<Elt>::Cell() { val = new Elt; }

POO(C++)

Gh GRIGORAS

25

Clase parametrizate - Exemplu 1


template <class Elt> Cell<Elt>::Cell(const Cell<Elt>& c) { val = new Elt; *val = *(c.val); } template <class Elt> Cell<Elt>::~Cell() { delete val; } template <class Elt> Cell<Elt>& Cell<Elt>::operator =(const Cell<Elt>& c) { *val = *(c.val); return *this; }

POO(C++)

Gh GRIGORAS

26

Clase parametrizate - Exemplu 1


#include "cell.h" template <class Elt> class Array { public: Array(int = 1); Array(const Aray&); ~Array(); Elt get(int); void set(int, Elt); Array& operator =(const Array&); Cell<Elt>& operator [](int) const Cell<Elt>& operator [](int) const; private: Cell<Elt> *arr; int nOfComp; };

POO(C++)

Gh GRIGORAS

27

Clase parametrizate - Exemplu 1


template <class Elt> Array<Elt>::Array(int nMax) { arr = new Cell<Elt>[nMax]; if(arr == NULL) throw Memorie insuficienta "; nOfComp = nMax; }; 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(); };
POO(C++) Gh GRIGORAS 28

Clase parametrizate - Exemplu 1


Template: Suprancrcare operatori
template <class Elt> Cell<Elt>& Array<Elt>::operator [](int i) { if((i<0)||(i>=nOfComp)) throw "Index out of range."; return arr[i]; } // pentru a sorta tablouri de celule de int-uri // trebuie definit operatorul de comparare: bool operator >(const Cell<int>& x, const Cell<int>& y) { return x.getVal() > y.getVal(); }

POO(C++)

Gh GRIGORAS

29

Clase parametrizate - Exemplu 1


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

Clase parametrizate - Exemplu 2


template <class T> class Vector { public: Vector(int=0); T& operator [](int); const T& operator [](int) const; // private: T* tab; int n; }; template <class T> class Matrice { public: Matrice(int=0, int=0); Vector<T>& operator [](int); const Vector<T>& operator [](int) const; private: Vector<T>* tabv; int m, n; };
POO(C++) Gh GRIGORAS 31

Clase parametrizate - Exemplu 2


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

Clase parametrizate
O versiune a unui template pentru un argument template particular este numit o specializare O definiie alternativ pentru o clas(funcie) template ( de ex. pentru a funciona cnd argumentul template este pointer) este numit specializare definit de utilizator

POO(C++)

Gh GRIGORAS

33

Clase parametrizate - Specializri


template <class T> class Vector { public: Vector(int=0); T& operator [](int); const T& operator [](int) const; private: T* tab; int n; }; Vector<int> vi; Vector<Punct*> vpp; Vector<string> vs; Vector<char*> vpc;
POO(C++) Gh GRIGORAS 34

Specializri:

Clase parametrizate - Specializri


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 // };
POO(C++) Gh GRIGORAS 35

Clase parametrizate - Specializri


template <class T> void swap(T& x, T& y){ T t = x; x = y; y = t; }

Specializare pentru Vector<T> :


template <class T> void swap(Vector<T>& a, Vector<T>& b){ a.swap(b); }

n clasa Vector<T>, metoda:


template <class T> void Vector<T>:: swap(Vector<T>& a){ swap(v, a.v); swap(sz, a.sz); }

POO(C++)

Gh GRIGORAS

36

Clase parametrizate
Dou instanieri ale unei clase template sunt echivalente dac parametrii template ce reprezint tipuri sunt aceeai iar ceilali au aceleai valori MyString<char> s1; MyString<unsigned char> s2; typedef unsigned char Uchar; MyString <Uchar> s3;

POO(C++)

Gh GRIGORAS

37

Clase parametrizate - friend


Funcii(clase) friend n clase template:
Dac funcia friend acceseaz un parametru template, aceasta trebuie s fie template. n acest caz o instaniere este friend doar pentru instanierile clasei template cu aceiai parametri (friend legat). Prieteni template nelegai - are ali parametri template Dac funcia friend nu acceseaz parametri template , este friend pentru toate instanierile clasei

POO(C++)

Gh GRIGORAS

38

Clase parametrizate - friend


template <class T> class X { //.. friend void f1(); // f1 friend pentru toate specializarile friend void f2(X<T>& ); // f2(X<float>&) friend pentru X<float> friend class Y; friend class Z<T>; friend void A::f3(); friend void C<T> :: f4(X<double>&); // };
POO(C++) Gh GRIGORAS 39

Clase parametrizate
Membri statici n template uri
Fiecare specializare a unei clase template are copia proprie a mebrilor static, att date ct i funcii Datele statice trebuiesc iniializate, global sau pe specializri
template<class T, int n> class ClasaN{ static const int cod; // }; template<class T, int n> const int ClasaN<T, n>::cod = n; template<> const int ClasaN<int, 10>::cod =50
POO(C++) Gh GRIGORAS 40

Relaia de motenire Clase derivate


Structurarea unui concept: definirea unei ierarhii de tipuri i a unei relaii de ordine (parial) pe aceste tipuri. Tipul D este un subtip al (o specializare a) tipului B: toate obiectele de tip D sunt de tip B. Specializarea se poate face prin:
Restricionarea domeniului de valori a obiectelor de tip B Adugarea de noi operaii la cele definite pe tipul B n anume condiii, printr-o nou definire a membrilor
POO(C++) Gh GRIGORAS 41

Relaia de motenire Clase derivate


Reutilizarea codului existent: o clas reutilizeaz structura de date i codul definit pentru o clas existent. Acest lucru se face prin:
mbogirea clasei prin adugarea de noi membri Redefinirea unor membri Restricionarea domeniului de vizibilitate pentru anumii membri; n acest caz nu mai este vorba de o ierarhie de tipuri ci de o ierarhie de clase; stiva este o lista n care inseria (extragerea) se face doar n top

POO(C++)

Gh GRIGORAS

42

Relaia de motenire Clase derivate

n C++ : clas de baz (superclas), clas derivat (subclas) Motenire simpl, motenire multipl
B B1 B2

POO(C++)

Gh GRIGORAS

43

Clase derivate
Sintaxa:
Motenire simpl:

class ClsDer:tip_mot ClsBaza {};


Motenire multipl:

class ClsDer :tip_mot ClB1, tip_mot ClB2, { }; tip_mot :: public|protected|private

POO(C++)

Gh GRIGORAS

44

Clase derivate
Nivele de protecie(acces) a membrilor unei clase:
public: cunoscut de oricine protected: cunoscut de clasa proprietar, prieteni i de clasele derivate private: cunoscut de clasa proprietar i de prieteni

Tipuri de motenire:
public: membii public (protected) n baz rmn la fel n clasa derivat protected: membrii public n clasa de baz devin protected n clasa derivat private: membrii public i protected din clasa de baz devin private n clasa derivat; este tipul implicit de motenire POO(C++) Gh GRIGORAS 45

Clase derivate
Relaia friend nu este motenit, nu este tranzitiv n modul de derivare private se poate specifica pstrarea proteciei unor membri:
class D:private B{ protected: B::p; public: B::q; // };

Accesul la membrii : Funciile membru ale unei clase de baz pot fi redefinite n clasa derivat:
Ele pot accesa doar membrii public sau protected din clasa de baz Pot accesa funciile din clasa de baz folosind operatorul ::

POO(C++)

Gh GRIGORAS

46

Clase derivate
Constructori, Destructori
Constructorii i destructorii nu se motenesc Constructorii clasei derivate apeleaz constructorii clasei de baz: Constructorii implicii nu trebuie invocai Constructorii cu parametri sunt invocai n lista de iniializare Ordinea de apel: constructor clas de baz, constructori obiecte membru, constructor clas derivat Obiectele clasei derivate se distrug n ordine invers: destructor clas derivat, destructori membri, destructor clas de baz
POO(C++) Gh GRIGORAS 47

Ierarhia RxR
RxR x : float y : float setX() setY() getX() getY() modul()

Complex PctPlan transl() mutaLa() conj() operator+() operator*() operator-()

RxRxR z : float setZ() getZ()

PlanComplex phi() rho()

PctSpatiu mutaLa() transl()

POO(C++)

Gh GRIGORAS

48

Ierarhia RxR
class RxR { protected: double x, y; public: RxR(double un_x = 0, double un_y = 0) : x(un_x), y(un_y) {} ~RxR() {} void setX(double un_x) { x = un_x; } double getX() {return x;} void setY(double un_y) { y = un_y; } double getY() { return y; } double modul(); }; class PctPlan : public RxR { public: PctPlan(double un_x=0, double un_y=0) : RxR(un_x, un_y) {} ~PctPlan() {} void translCu(double, double); void mutaLa(PctPlan&); };

POO(C++)

Gh GRIGORAS

49

Ierarhia RxR
class Complex : public RxR { public: Complex(double un_x=0, double un_y=0) : RxR(un_x, un_y) {} Complex conj(); Complex operator+ (Complex&); }; class RxRxR : public RxR { protected: double z; public: RxRxR(double un_x, double un_y, double un_z) : RxR(un_x, un_y), z(un_z) {} void setZ(double un_z) { z = un_z; } double getZ() {return z;} double modul(); }; class PlanComplex : public PctPlan, public Complex {};
POO(C++) Gh GRIGORAS 50

Clase derivate - Conversii standard


Un obiect al clasei derivat poate fi convertit implicit la unul din clasa de baz O adres a unui obiect derivat poate fi convertit implicit la o adres de obiect din clasa de baz Un pointer la un obiect derivat poate fi convertit implicit la un pointer la obiect din clasa de baz Conversia reciproc poate fi definit cu un constructor n clasa derivat

POO(C++)

Gh GRIGORAS

51

Clase derivate Copiere


Copierea o face constructorul de copiere i operator= n cazul membrilor pointeri acetia trebuie s existe explicit Ordinea de apel a constructorului de copiere:
Clasa de baz Clasa derivat Ordinea de apel

implicit explicit implicit explicit

implicit implicit explicit explicit

clasa baza, clasa derivat clasa baza, clasa derivat constructorul clasei derivate constructorul clasei derivate trebuie sa apeleze constructorul clasei de baz
Gh GRIGORAS 52

POO(C++)

Clase derivate Conflicte


Conflict de metod: metode cu acelai nume n clase incomparabile A, B ce deriveaz o clas D Conflict de clas: clasa D derivat din A1 i A2 iar aceste sunt derivate din B: B este accesibil pe dou ci din D

POO(C++)

Gh GRIGORAS

53