Sunteți pe pagina 1din 629

Programare orientata-

obiect (POO)
utilizand C++
Dorel Lucanu
Gheorghe Grigoras
D. Lucanu POO Proiectarea de clase
Bibliografie
H. Schildt: C++ manual complet, Teora, 2000
D. Kaler, M.J. Tobler, J. Valter: C++, Teora, 2000
Bjarne Stroustrup: The C++ Programming Language,
Adisson-Wesley, 3
nd
edition, 1997
Martin Fowler. UML Distilled: A Brief Guide to the Standard
Object Modeling Language (3rd Edition). Addison-Wesley
Professional, 3 edition, 2003
Manuale electronice
Bruce Eckel : Thinking in C++, 2nd Edition
*** : Online C++ tutorial
Donald Bell. UML basics: An introduction to the Unified
Modeling Language
SGI Standard Template Library Programmer's Guide
D. Lucanu POO Proiectarea de clase
Organizare
pagina curs:
se vor face (cel putin) saptamanal schimbari
http://portal.info.uaic.ro/curs/poo/default.aspx
laboratoarele
dezvoltarea iterativa a unui proiect (agenda de
contacte)
examinare
pe parcurs: 1 test (sapt. 16)
50% din nota finala
laborator 2 evaluari a temelor (sapt. 8, 15)
50% din nota finala
conditii de promovabilitate
50% din punctajul total maxim
40% din punctajul maxim la fiecare proba (lab., test)

Organizare cursuri
15, 22 feb introducere in POO
1 martie declaratii clase in CPP
8 martie modelare partea 1
15 martie ierarhii in CPP
22 martie clase parametrizate si ierarhia I/O
29 martie modelare partea 2
4-9 aprilie evaluare teme laborator
12 polimorfism in CPP
19 aprilie STL partea 1
3 mai proiectare 1
10 mai proiectare 2
17 mai exceptii
24 mai STL partea 2
sapt 15 evaluare teme lab
sapt 16 test
D. Lucanu POO Proiectarea de clase
Teme laborator
Tema 1
accent pe modelare (organizarea claselor, dinamica
obiectelor, descrierea acestora in C++)
Tema 2
accent pe proiectare (sabloane)
D. Lucanu POO Proiectarea de clase
D. Lucanu POO Proiectarea de clase
Curs 1
Primul pas in POO
principii de baza
concepte
Clase si obiecte
atribute, metode, stari
declararea claselor si obiectelor in C++
utilizarea obiectelor in C++
constructori, destructori
exemple
dezvoltarea unei aplicatii utilizand patternul model-
view-controller (cu interfata text)
D. Lucanu POO Principii 7
Principii de baza ale POO
abstractizare
pastrarea aspectelor importante (generale) si
ignorarea detaliilor nesemnificative (specifice)
incapsulare
ascunderea implementarii fata de client; clientul
depinde doar interfata
modularizare
impartirea unui sistem complex in parti (module)
manevrabile
ierarhizare
clasificarea pe nivele de abstractizare
polimorfism
aceeasi forma sintactica poate avea diferite intelesuri
in functie de contextul de utilizare
D. Lucanu POO Principii 8
Concepte POO
obiecte
clase
atribute
metode
mesaje
supraincarcare
suprascriere
legare dinamica
interfata
relatii dintre clase
generalizare
specializare
mostenire
compozitie
asociere
pachet
subsistem
modelare
Obiecte - informal
un obiect reprezinta o entitate care poate fi fizica,
conceptuala sau software
entitate fizica
tren, angajat CFR (?)
entitate conceptuala
proces chimic, rationament matematic
entitate software
structura de date, program
D. Lucanu POO Proiectarea de clase
D. Lucanu POO Proiectarea de clase
Obiecte definitie mai formala
un obiect este o abstractie, concept sau orice alt
lucru ce are un inteles strans legat de domeniul
problemei
un obiect este caracterizat de:
identitate
nume,
stare
exprimata prin atribute
valorile atributelor la un moment dat definesc o
stare
comportarea
data de multimea metode (servicii, operatii
publice)


Un obiect are identitate
fiecare obiect are identitate unica, chiar daca starea sa
este identica cu a altui obiect
D. Lucanu POO Proiectarea de clase
Un obiect are stare
starea unui obiect este una dintre conditiile in care acesta
poate exista
starea se poate schimba de-a lungul timpului
este data de valorile atributelor + legaturi (instante ale
relatiilor)
D. Lucanu POO Proiectarea de clase
nume Ion Ion
nr. marca 2143576
functia conferentiar
status preda POO
Un obiect are comportament
determina cum un obiect actioneaza si reactioneaza la
cererile altor obiecte
D. Lucanu POO Proiectarea de clase
atribuie(CS1207)
confirma(CS1207)
Clase
O clasa descrie unul sau mai multe obiecte ce pot fi
precizate printr-un set uniform de atribute si metode.
un obiect este o instanta a clasei
o clasa este o abstractizare
pastreaza trasaturile (atribute, metode) esentiale
ignora ce nu este esential

D. Lucanu POO Proiectarea de clase
D. Lucanu POO Proiectarea de clase
Clase - reprezentare grafica
nume
atribute
metode
D. Lucanu POO Proiectarea de clase
Clasa Cont (versiunea 01)
Specificarea clasei

Un cont bancar:
are un titular, sold, o rata a dobinzii, numar de cont si
se pot efectua operatii de depunere, extragere,
actualizare sold

Extragerea atributelor:
titular, sold, rata a dobinzii, numar de cont

Extragerea metodelor
depunere, extragere, actualizare sold
Completarea specificatiei (analiza)
actualizare sold data ultimei operatii
D. Lucanu POO Proiectarea de clase
Clase (continuare)
o clasa joaca roluri diferite in cadrul unei aplicatii software
furnizor de servicii pentru clasele client
client pentru clasele ale caror servicii sunt necesare
in descrierea propriei comportari
definitia unei clase presupune:
combinarea datelor cu operatii
ascunderea informatiei
clasele client nu acces la implementarea metodelor
D. Lucanu POO Proiectarea de clase
Combinarea datelor cu operatiile asupra lor
datele si operatiile asupra lor sint incluse in aceeasi unitate
sintactica
datele si procesele devin legate
sold
depune( )
sold
depune( )
Cont
C++: clase, structuri
D. Lucanu POO Proiectarea de clase
Ascunderea informatiei
modul de structurare a datelor nu este cunoscut
actiunile asupra datelor sint realizate numai prin
operatiile (metodele) clasei
si anumite actiuni pot fi ascunse: e.g., validare a contului
clientul clasei Cont:
cont.sold += suma
cont.depune(suma)
OK!
D. Lucanu POO Proiectarea de clase
Incapsulare
Incapsulare
= Ascundere
Combinare
+
D. Lucanu POO Proiectarea de clase
Combinarea: avantaje
defineste clar ce structuri de date sint manevrate si care
sunt operatiile legale asupra lor

adauga programului modularitate

scade riscul ca datele sa fie alterate de programele
"slabe"

faciliteaza ascunderea informatiei
D. Lucanu POO Proiectarea de clase
Ascunderea informatiei: avantaje
programe mai sigure si fiabile

elibereaza clasele client de grija cum sint manevrate
datele

previne aparitia erorilor produse de clasele client ce
manevreaza datele utizind cod "slab"


D. Lucanu POO Proiectarea de clase
Incapsulare (Combinare + Ascundere): avantaje
combinare + ascunderea informatiei = protejarea datelor

previne aparitia erorilor prin limitarea accesului la date

asigura portabilitatea programelor

faciliteaza utilizarea exceptiilor

interfata unei clase = operatiile cu care o clasa utilizator
poate manevra datele
D. Lucanu POO Proiectarea de clase
Structurarea nivelului de acces la informatie
limitarea
accesului la
informatii
sectiuni publice
sectiuni private
D. Lucanu POO Proiectarea de clase
Count.h
private:
string *owner;
string countNo;
double sold;
assignCountNo();
releaseCountNo();
};

class Count
{
public:
Count(char*);
~Count();
void
deposit(double);
void draw(double);
double balance();








constructor
destructor
D. Lucanu POO Proiectarea de clase
Count.cpp
void Count::deposit(double
ammount)
{
sold += ammount;
}

double Count::balance()
{
return sold;
}

. . .

Count::Count(char
*s)
{
owner =
new string(s);
sold = 0;
assignCountNo();
}

Count::~Count()
{
delete owner;
releaseCountNo();
}

creare obiect nou
distrugere obiect
D. Lucanu POO Proiectarea de clase
Demo.cpp
void main()
{
Count count("Ionescu");
count.deposit(2000);
}
error C2248: 'sold' : cannot access private member
cont.sold += 5000;
main() joaca rol de client pentru Cont
D. Lucanu POO Proiectarea de clase
Tipuri de date abstracte si obiecte

tip de data abstract = o descriere a unui tip de data
independent de reprezentarea datelor si
implementarea operatiilor

O clasa este o implementare a unui tip de date
abstract. Ea defineste atribute si metode care
implementeaza structura de date respectiv operatiile
tipului de date abstract.


D. Lucanu POO Proiectarea de clase
Stiva
tipul de data abstract Stiva
entitati de tip data: liste LIFO
operatii
push()
pop()
top()
is_empty()
Stack
arr[0..MAX-1]
top_index
push()
pop()
top()
is_empty()
D. Lucanu POO Proiectarea de clase
Stiva.h
class Stack
{
public:
Stack();
~Stack();
void push(char);
void pop();
char top();
bool is_empty();
private:
char arr[MAX_STACK];
int top_index;
};
D. Lucanu POO Proiectarea de clase
Stiva.cpp
void Stack::push(char c)
{
if (top_index == MAX_STACK-1)
throw "Depasire superioara.";
arr[++top_index] = c;
}

char Stack::top()
{
if (top_index < 0)
throw "Depasire inferioara.";
return arr[top_index];
}
D. Lucanu POO Proiectarea de clase
Stiva_demo
Stack s;
char c = 'a';

try {
while (true) {
s.push(c++);
cout << s.top() << endl;
}
}
catch (char *mes_err) {
cout << mes_err << endl;
}
a
b
c
d
e
f
g
h
i
j
Depasire superioara.
Press any key to ...
D. Lucanu POO Proiectarea de clase
Utilizarea de clase
exista multe bibloteci de clase
STL
MFC
etc
pentru utilizare, trebuie cunoscuta doar interfata
(elementele publice)
nu intereseaza implementarea
programul care utlizeaza clasa este independent de
implementarea clasei
Exemplu: string
my-string.h
STL
Cum construim o aplicatie OO?
constructia unei aplicatii OO este similara cu cea a unei
case: daca nu are o structura solida se darama usor
ca si in cazul proiectarii cladirilor (urbanisticii), patternurile
(sablaonele) sunt aplicate cu succes
patternurile pentru POO sunt similare structurilor de
control (programarea structurata) pentru pogramarea
imperativa
noi vom studia
un pattern arhitectural (MVC)
cateva patternuri de proiectare
mai mult la cursul de IP din anul II
D. Lucanu POO Proiectarea de clase
Patternul model-view-controller (MVC)
isi are radacinile in Smalltalk
maparea intrarilor, iesirilor si procesarii intr-un GUI
model
model reprezinta datele si regulile care guverneaza
actualizarile
este o aproximare software a sist. din lumea reala
view interpreteaza continutul modelului
are responsabilitateaa de a mentine consistenta dintre
schimbarile in model si reprezentare
controller translateaza interactiunili cu view-ul in
actiuni asupra modelului
actiunile utilizatorului pot fi selectii de meniu, clickuri
de butoane sau mouse
in functie de interactiunea cu utliz. si informatiile de la
model, poate alege view-ul potrivit

D. Lucanu POO Proiectarea de clase
MVC
D. Lucanu POO Proiectarea de clase
Model
incapsuleaza starea aplicatiei
raspunde la interogari despre stare
expune functionalitatea modelului
notifica schimbarea starii
View
vizualizeaza modelul
cere actualizari de la model
trimite evenimentele utilizator la
controller
permite controllerului sa schimbe
modul de vizualizare
Controller
defineste comportarea aplicatiei
mapeaza actiunile utilizator pe
actulizare model
selecteaza vizulizarea
raspunsului
unul pentru fiecare functionalitate
n
o
t
i
f
.

s
c
h
.
i
n
t
e
r
o
g
.

s
t
a
r
e

actiuni utilizator
selectie vizualizare
s
c
h
i
m
b
a
r
e

s
t
a
r
e

MVC studiu de caz
D. Lucanu POO Proiectarea de clase
MVC poate fi aplicat si pentru interactiune utilizator in
mod text
un studiu de caz simplu:
model = clasa Cont
view = afisare sold (interogare stare) si un meniu de
actiuni (similar bancomat)
controller = transpune optiunile meniu in actualizare
cont
(deocamdata) fara notificari ale modelului
View
class View
{
private:
Controller *controller;
Count *model;
public:
View(Controller *newController,
Count *newCount);
void display();
int getUserAction();
};
D. Lucanu POO Proiectarea de clase
View::display
void View::display()
{
cout << endl << "New window" << endl;
cout << "Balanta: "
<< model->balance() << endl;
cout << "Commands:" << endl;
cout << "1. Depune 50" << endl;
cout << "2. Depune 100" << endl;
cout << "3. Extrage 50" << endl;
cout << "4. Extrage 100" << endl;
cout << "0. Exit" << endl;
}
D. Lucanu POO Proiectarea de clase
View::getUserAction
int View::getUserAction()
{
int option;
cout << "Option: ";
cin >> option;
return option;
}

D. Lucanu POO Proiectarea de clase
Controller
class Controller
{
private:
Count *model;
View *view;
public:
Controller(Count *newModel); public:
void setView(View *newView);
void listen();
void finish();
};
D. Lucanu POO Proiectarea de clase
Controller::listen
void Controller::listen()
{
int option = view->getUserAction();
switch (option)
{
case 0:
finish();
break;
case 1:
model->deposit(50);
break;
...
default: exit(1);
}
}

D. Lucanu POO Proiectarea de clase
Demo
int main(){
Count *model = new Count("Ionescu");
Controller *controller = new Controller(model);
View *view = new View(controller, model);
controller->setView(view);
try {
while (true) {
view->display();
controller->listen();
}
}
catch (char *mes_err) {
cout << mes_err << endl;
}
return 0;
}
D. Lucanu POO Proiectarea de clase
Programare orientata-
obiect (POO)
utilizand C++
Dorel Lucanu
Gheorghe Grigoras
D. Lucanu POO Proiectarea de clase
Curs 2
proiectul Agenda
prezentare
dezvoltarea aplicatiei utilizand MVC
elemente interfata utilizator in mod text
display box
edit box
meniu
principii POO (continuare)
mostenire
polimorfism
Agenda
Domeniul problemei
O agend telefonic este o colecie de contacte
Un contact este format dintr-un numar telefonic si
informaii asociate (nume, prenume, adresa )
Cerinte program:
adugarea unui nou contact n agend;
editarea unui contact existent n agend;
tergerea unui contact din agend;
afiarea tuturor informaiilor existente n agend
despre un contact;
crearea unei noi agende;
salvarea unei agende ntr-un fiier;
ncrcarea unei agende dintr-un fiier;
nchiderea unei agende;

D. Lucanu POO Proiectarea de clase
Agenda cu MVC - v1
vom considera un model simplificat al agendei
un singur contact
doar doua functionalitati
vizualizare informatii generale + meniu actiuni
agenda
vizualizare + meniu actiuni contact (doar
modificare)
pentru fiecare functionalitate o instanta MVC
D. Lucanu POO Proiectarea de clase
MVC
D. Lucanu POO Proiectarea de clase
Model
incapsuleaza starea aplicatiei
raspunde la interogari despre stare
expune functionalitatea modelului
notifica schimbarea starii
View
vizualizeaza modelul
cere actualizari de la model
trimite evenimentele utilizator la
controller
permite controllerului sa schimbe
modul de vizualizare
Controller
defineste comportarea aplicatiei
mapeaza actiunile utilizator pe
actulizare model
selecteaza vizualizarea
raspunsului
unul pentru fiecare functionalitate
n
o
t
i
f
.

s
c
h
.
i
n
t
e
r
o
g
.

s
t
a
r
e

actiuni utilizator
selectie vizualizare
s
c
h
i
m
b
a
r
e

s
t
a
r
e

not quite
an UML
diagram
MVC functionalitate agenda
D. Lucanu POO Proiectarea de clase
*** Agenda view ***
Proprietar: Ionescu

Menu:
1. Afiseaza
0. Exit
Option:
view
model
controller
not quite
an UML
diagram
MVC functionalitate contact
D. Lucanu POO Proiectarea de clase
*** Contact view ***
Contact: no contact
Menu:
1. Modifica
0. Exit
Option:
aceasta actiune
poate modelata
cu MVC
view
model
controller
not quite
an UML
diagram
D. Lucanu POO Proiectarea de clase
Analiza solutiei
solutia descrisa are cateva defecte
cod care se repeta (getUserAction)
functii cu actiuni similare cu sectiuni care difera putin
o slaba separare a functionalitatilor date de interfata
grafica
toate acestea pot fi eliminate daca facem o clasificare a
elementelor de interfata
display box
edit box
menu

D. Lucanu POO Proiectarea de clase
Display box
exemplu

Proprietar: Ionescu

afiseaza o eticheta si o valoare (de tip sir)
valoarea poate fi schimbata

D. Lucanu POO Proiectarea de clase
eticheta
valoare
Display box & MVC
D. Lucanu POO Proiectarea de clase
view
model
dbOwner.setValue(model.getOwner)
not quite
an UML
diagram
Editbox
exemplu

Nume: _ _ _ _

afiseaza o eticheta si preia o valoare (de tip sir)

D. Lucanu POO Proiectarea de clase
eticheta
valoare introdusa de utilizator
Edit box & MVC
D. Lucanu POO Proiectarea de clase
not quite
an UML
diagram
model
view
controller
editBox.setLabel(string("Nume"));
model->setName(editBox.getValue());
editBox.setLabel(string("Nr telefon"));
model->setPhoneNo(editBox.getValue());
getValue()
setLabel()
s
e
t
N
a
m
e
(
)

Menu
afiseaza o lista de optiuni si preia valoarea optiunii
introduse de utilizator
exemplu
D. Lucanu POO Proiectarea de clase
Menu:
1. Afiseaza
0. Exit
Option:
Menu & MVC
D. Lucanu POO Proiectarea de clase
getOption()
display()
d
i
s
p
l
a
y
(
)

model
controller
not quite
an UML
diagram
view
menu.addOption("1. Afiseaza");
menu.addOption("0. Exit");
case 1:
model->display();
D. Lucanu POO Proiectarea de clase
Generalizare specializare
un contact poate fi
o cunostinta
un prieten
un coleg

apare asadar necesitatea clasificarii contactelor
orice contact are un nume, numar telefon si o operatie
de serializare toString
o cunostinta are in plus o ocupatie,
iar un prieten o zi de nastere
iar un coleg o functie in cadrul institutiei/companiei
rezulta o ierarhie a claselor ce descriu contactele,
cunostintele, prietenii, colegii
D. Lucanu POO Proiectarea de clase
Ierarhia Contact
Contact este o generalizare (abstractizare) pentru
Acquiantance, Colleague, Friend
Acquiantance, Colleague, Friend sunt specializari
(particularizari) ale clasei Contact
D. Lucanu POO Proiectarea de clase
relatie de
mostenire
Mostenire
mostenirea = mecanismul prin care elementele specifice
(specializate) ncorporeaz structura i comportarea
elementelor generale (reutilizare).
principiul substituirii (B. Liskov, 1987): obiectele clasei
specializate (copil) pot fi utilizate oriunde apar obiecte ale
clasei generale (printe) fara a altera proprietatile dorite
(dar nu i reciproc);
mostenirea este sinonima cu relatia de subtip
Let q(x) be a property provable about objects x of type T.
Then q(y) should be true for objects y of type S where
S is a subtype of T.
relatia de mostenire este tranzitiva
D. Lucanu POO Proiectarea de clase
Mostenirea in C++ 1/2
se realizeaza prin derivare publica
class Contact
{ ...
public:
string toString()
protected:
string name;
protected:
string phoneNo;
};
D. Lucanu POO Proiectarea de clase
un nou limitator de
acces; elementele
protejate sunt
vizibile si in clasele
derivate
Mostenirea in C++ 2/2

class Acquiantance : public Contact
{
...
public:
string toString() {
return Contact::toString() +
string("Occupation: ") +
occupation + string("\n");
}
protected:
string occupation;
};

D. Lucanu POO Proiectarea de clase
operatia din
clasa de baza
declaratie inline a
metodei toString
suprascrierea metodei
toString
relatia de
derivare publica
D. Lucanu POO Proiectarea de clase
Acquiantance myAcq("Ionescu", "1212121", "afacerist");
cout << myAcq.toString();
Friend myFriend("Popescu", "7676767", "12-12-1999");
cout << myFriend.toString();
Un client al ierarhiei Contact
un view simplu care afiseaza continutul unui contact

D. Lucanu POO Proiectarea de clase
void displayContact()
{
cout << contact->toString();
}
D. Lucanu POO Proiectarea de clase
View view(&myAcq);
view.displayContact();
view.setContact(&myFriend);
view.displayContact();
ups! avem o problema
Sursa problemei
class View
{
public:
void displayContact()
{
cout << contact->toString();
}
private:
Contact *contact;
};
D. Lucanu POO Proiectarea de clase
legarea numelui la definitia sa
se face la momentul compilarii:

toString Contact::toString { ... }
Solutia: legarea dinamica
cunoscuta si sub numele de legare tarzie (late binding)
legarea numelui (aici de metoda) este legat de
semnificatia/definitia sa (aici codul) la momentul executiei
in C++ se realizeaza prin intermediul metodelor virtuale
class Contact
{ ...
public:
virtual string toString()
{
...
}
};
D. Lucanu POO Proiectarea de clase
este suficient sa declaram virtuala numai metoda
din clasa de baza; toate suprascrierile din clasele
derivate vor fi considerate automat virtuale
D. Lucanu POO Proiectarea de clase
View view(&myAcq);
view.displayContact();
view.setContact(&myFriend);
view.displayContact();
Magic!
Mecanismul metodelor virtuale
Tabela functiilor virtuale (VFT)
D. Lucanu POO Proiectarea de clase
myCntct Contact
Contact::toString()
{
...
}
myAcq Acquiantance
Acquiantance::
toString()
{
...
}
myFriend Friend
Friend::toString()
{
...
}
Tbela functiilor virtuale (VFT)
class Contact{
. . .
void toString();
};
class Contact{
. . .
virtual void toString();
};
demo
cout << sizeof(Contact) 64
demo cout << sizeof(Contact) 68
D. Lucanu POO Principii 30
Principiul substituirii - contraexemplu
Dreptunghi
Patrat
clasa Patrat are invariantul lungimea =
latimea
o operatie maresteLungimea() a clasei
Dreptunghi nu pstreaza acest invariant
deci un patrat nu poate fi utilizat in locul unui
dreptunghi totdeauna
D. Lucanu POO Principii 31
Atentie la clasificare
PasareNezburatoare
Pinguin
Pasare
zboara()
PasareZburatoare
zboara()
Pasare
Pinguin
Pinguini care
zboara?
Conceptul de clas - Plan
Membri, controlul accesului, constructori,
membri statici, funcii membru constante, funcii
inline.
Setul de operaii pentru definirea unui tip
utilizator: constructori, accesori, manipulatori,
operatori, copiere, asignare, excepii
Obiecte: construire i distrugere, copiere,
new/delete, obiecte ca date membru, iniializarea
obiectelor, membri constani, tablouri de obiecte,
obiecte locale, obiecte nelocale, obiecte
temporare.
POO(C++) Gh GRIGORAS 1
Obiecte membru, ordinea de apel a constructorilor
Date membru calificate const, membri referin,
iniializare
Metode ce ntorc referine la membri din seciunea
private
Spaiu de nume, domeniu de vizibilitate
Pointeri la membri
Prieteni
Suprancrcare operatori
Operatorii +=, +,++
Operatorii <<, >>
Operatorii *+ i ()
Conversii
POO(C++) Gh GRIGORAS 2
CLASE
O clas n C++ se caracterizeaz prin:
Un nume - identificator
O colecie de date membru prin aceste date
este reprezentat un obiect. Datele nestatice sunt
create pentru fiecare obiect (instan a clasei)
O colecie de funcii membru tratamente
(metode) ce se aplic obiectelor. Un tratament se
execut de ctre un obiect ca rspuns la primirea
unui mesaj
Eventual, o colecie de prieteni: funcii i/sau
clase prieten
POO(C++) Gh GRIGORAS 3
CLASE
Specificarea unei clase se face prin numele
rezervat class sau struct
Specificarea este cuprins, n general, ntr-un
fiier header ce va fi partajat de fiierele ce
implementeaz clasa i de cele ce utilizeaz clasa
Numele clasei este numele unui tip utilizator: se
pot declara variabile care au acest tip
Componentele unei clase sunt repartizate n trei
domenii de protecie: public, protected, private
POO(C++) Gh GRIGORAS 4
CLASE - Declaraie
Declaraie cu class:
class <Nume_clasa> {Corp_clasa};
class <Nume_clasa> {
//Declaraii membri privai (nerecomandat)
public:
// Declaraii funcii (metode) (eventual date)
protected:
// Declaraii date (eventual metode)
private:
// Declaraii date (eventual metode)
};
POO(C++) Gh GRIGORAS 5
CLASE - Declaraie
Declaraie clas cu struct:
struct <Nume_clasa> {Corp_clasa};
struct <Nume_clasa> {
// Declaraii membri public (nerecomandat)
public:
// Declaraii funcii (eventual date)
protected:
// Declaraii date (eventual metode)
private:
// Declaraii date (eventual metode)
};
POO(C++) Gh GRIGORAS 6
CLASE - Declaraie
Fiecare domeniu de protecie poate fi, fizic, mprit
n mai multe regiuni. Ordinea regiunilor poate fi
arbitrar
Domeniul public:
Componenta este vizibil oriunde
Variabilele ce definesc starea unui obiect nu trebuie s fie
publice (principiul ncapsulrii)
n general, metodele sunt n domeniul public
Domeniul protected:
Componenta este vizibil n funciile clasei, n funciile i
clasele prieten i n clasele derivate
Domeniul private:
Componenta este vizibil doar n funciile clasei i n
funciile i clasele prieten
POO(C++) Gh GRIGORAS 7
Exemplu
#define MAX_STACK 10
class Stack
{
public:
Stack(int = MAX_STACK);
~Stack();
void push(char);
void pop();
char top();
bool is_empty();
void display();
private:
char *arr;
int top_index, nMax;
};
POO(C++) Gh GRIGORAS 8
Exemplu
//data.h
#include <iostream>
using std::ostream;
//using namespace std;
class Data {
public:
Data(int oZi = ziCurenta(), int oLuna = lunaCurenta(),
int unAn = anCurent());
~Data();
void pesteNZile(int n);
void pesteNLuni(int n);
void pesteNAni(int n);
Data operator ++(int); // postfix
Data& operator ++(); // prefix
void setZi(int zi_noua);
void setLuna(int );
void setAn(int an_nou);
POO(C++) Gh GRIGORAS 9
Exemplu continuare
int getZi() const;
int getLuna() const;
int getAn() const;
friend ostream& operator << (ostream&, const Data&);
static Data azi();
private:
int zi, luna, an;
static int ziCurenta();
static int lunaCurenta();
static int anCurent();
bool esteAnBisect();
int NrZileLuna();
int NrZileAn();
};
POO(C++) Gh GRIGORAS 10
OBIECTE - Declaraie
Declaraie obiecte:
<Nume_clasa> <Nume_Obiect>, ;
<Nume_clasa> <Nume_Obiect>(<Parametri_actuali>);
La declararea unui obiect:
Se aloc memorie pentru datele membru
Se execut o metod constructor
La ieirea dintr-un bloc
Se apeleaz destructorul (este unic) pentru fiecare din
obiectele locale, ce nceteaz s mai existe
POO(C++) Gh GRIGORAS 11
OBIECTE - Declaraie
Data d1; // Apel constructor d1.Data()
Data d2(26,4,2010);
// Apel constr. Data(int,int,int)
Data d3[5];// Apel constructor Data() de 5 ori
Obiecte dinamice:
Data *pd = new Data; // apel constructor pd->Data()
Data *t = new Data[5];// apel de 5 ori t->Data()
delete pd; // se apeleaza pd->~Data()
delete [] t; // se apeleaza t ->~Data() de 5 ori
POO(C++) Gh GRIGORAS 12
Exemplu
#include <iostream>
using namespace std;
class C
{
public:
C(){cout << "C() ";}
~C(){cout << "~C() ";}
private:
int i;
};
int main(){
C c1;
C* p1= new C;
{
C c[2];
C* p2 = new C;
delete p2;
}
C c[2];
delete p1;
return 0;
}
//C() C() C() C() C() ~C() ~C() ~C() C() C() ~C() ~C() ~C() ~C()
POO(C++) Gh GRIGORAS 13
CLASE - Implementare
Funcii membru(Metode) - Implementare:
n cadrul clasei implementarea se face, n general,
inline (sistemul decide acest lucru)
n afara clasei (precedat de inline pentru
implementare inline):
<tip> <Nume_clasa>::<Nume_funcie>(<Lista_parametri>)
{
// Corp funcie
}
POO(C++) Gh GRIGORAS 14
CLASE - Implementare
void Data::pesteNLuni(int n)
{
int ll = luna + n;
if (ll > 12)
{
luna = ll % 12;
if (luna == 0) luna = 12;
an += (ll - luna)/12;
}
else
luna = ll;
}
inline void Data::setAn(int an_nou){an = an_nou;}
POO(C++) Gh GRIGORAS 15
CLASE - Mesaje
Apel(Invocare) funcie membru (Mesaj ctre
obiect):
<Nume_obiect>. <Nume_functie>(Lista_par_act)
<Nume_point_obiect> -> <Nume_functie>(Lista_par_act)
(*<Nume_point_obiect>). <Nume_functie>(Lista_par_act)
Data* pd, azi;
azi.setAn(2010);
azi.setLuna(4);
azi.setZi(26);
pd = &azi;
pd->get_zi();
(*pd).get_zi();
POO(C++) Gh GRIGORAS 16
CLASE Funcii membru
Funcii manager: constructori, destructor
Data(int, int, int), Data(int, int),
Data(int), Data(), Data(const char*)
~Data()
Funcii de acces (examinare obiect); aceste
funcii nu trebuie s modifice starea obiectului
Data::getZi(), Data::setAn()
Implementori:
void Data::adunaZi()
Operatori :
Data& Data::operator++()
POO(C++) Gh GRIGORAS 17
CLASE Funcii membru
Funcii ajuttoare:
bool Data::esteAnBisect(){
return (an%400==0)||((an%4==0)&&(an%100!=0));
}
Funcii membru const (nu modific starea
obiectului):
inline int Data::getZi() const {return zi;}
int Data::getAn() const {return an++;}//Eroare!
POO(C++) Gh GRIGORAS 18
CLASE Metode const
O funcie membru const poate fi apelat att pentru
obiecte const ct i pentru obiecte non - const;
O funcie membru non - const nu poate fi apelat pentru
obiecte const!
Exemplu
void f(Data& d, const Data& cd){
int i = d.getAn();
d.adunaAn(2);
int j = cd.getAn();
cd.adunaAn(1); // Eroare: cd este obiect const!
//
}
const face parte din tipul metodei, la implementarea n
afara clasei trebuie precizat acest lucru:
inline int Data::getAnn() const{
return an;
}
POO(C++) Gh GRIGORAS 19
CLASE Membri static
O variabil membru dar nu este parte a obiectelor
(instane ale clasei) se numete variabil membru
static
O singur copie a unei variabile membru static este
partajat de toate obiectele; exist cte o copie din
variabilele membru nonstatic pentru fiecare
instan(obiect) a clasei
static Data default_date;
static int nr_instante;
Definiia unui membru static trebuie s apar, o singur
dat, undeva n afara clasei dar n acelai fiier:
int Data::nr_instante = 0;
Data Data::default_date(10,1,1906)
POO(C++) Gh GRIGORAS 20
Numrarea instanelor create
class A {
public:
A() { nr_instante++; // ... }
~A();
int get_nr_inst() { return nr_instante; }
//...
private:
static int nr_instante;
double x;
};
int A::nr_instante = 0;
void main(){
A a;
A b;
cout << a.get_nr_inst();// afiseaza 2
cout << b.get_nr_inst();// afiseaza 2
}
POO(C++) Gh GRIGORAS 21
CLASE Membri static
O funcie ce trebuie s acceseze membrii clasei dar nu e
nevoie s fie invocat pentru un anume obiect este numit
funcie membru static
funcie asociat clasei: se poate apela prin X::f()
o funcie calificat static poate fi apelat i ca mesaj ctre obiect; nu
este indicat
poate accesa doar membrii statici ai clasei
static void set_default(int, int, int);
O funcie static trebuie definit undeva:
void Data::set_default(int dd, int mm, int yy)
{
default_date = Data(dd,mm,yy);
}
POO(C++) Gh GRIGORAS 22
CLASE membri static
class X {
public:
X(int ii = 0) : i(ii) {
j = i; // j poate fi accesat de metode nestatice
}
int val() const { return i; }
static int incr() {
i++; // Eroare: incr() este static, i nu este static
return ++j; // OK, j este static
}
static int f() {
val(); // Eroare: f() este static iar val() nu
return incr(); // OK, incr() este static
}
private:
int i;
static int j;
};
POO(C++) Gh GRIGORAS 23
O clas cu obiect unic (singleton)
class Unic {
public:
static Unic* instanta() { return &e; }
int get_i() const { return i; }
private:
static Unic e;
int i;
Unic(int ii) : i(ii) {}// anuleaza crearea de ob
Unic(const Unic&); // anuleaza copierea
};
Unic Unic::e(99);
int main() {
Unic x(1); // Eroare nu se pot crea alte obiecte
// Se poate accesa unicul obiect:
cout << Unic::instanta()->get_i() << endl;
return 0;
}
POO(C++) Gh GRIGORAS 24
(Auto)referine
Pentru modificarea unei date prin adugare de
ani, luni, zile s-au folosit funciile:
void pesteNZile(int n);

Uneori este mai util s returneze referine la


Data:
Data& pesteNZile(int n);
Data& pesteNLuni(int n);
Data& pesteNAni(int n);
pentru a putea scrie ceva de genul:
azi.pesteNAni(5).pesteNLuni(3).pesteNZile(20).
POO(C++) Gh GRIGORAS 25
CLASE - Pointerul implicit this
Pentru fiecare funcie membru exist o singur instan
care este accesibil fiecrui obiect
Pointerul this pointer implicit accesibil doar n
funciile membru nonstatic ale unei clase (structuri);
pointeaz la obiectul pentru care este apelat funcia
int getLuna() const {return this->luna;}
int getLuna(Data* d )const {return d->luna;}
Data azi(26,4,2010);
cout << azi.getLuna() << endl;
cout << azi.getLuna(&azi) << endl;
(*this) pentru (returnarea) obiectul(ui) curent ntr-o funcie membru
POO(C++) Gh GRIGORAS 26
CLASE - Pointerul implicit this
Exemple:
void Data::setLuna( int m ) {
luna = m;
//this->luna = m;
//(*this).luna = m;
}
Data& Data::pesteNAni(int n) {
if(zi==29 && luna==2 && !esteAnBisect(an+n){
zi = 1; luna = 3;
}
an += n;
return (*this);
}
POO(C++) Gh GRIGORAS 27
Exemplu: Pointerul implicit this
#include <iostream>
using namespace std;
class ExThis{
public:
ExThis() :Y(0.0){
cout << "Obiect " << X++ ;
cout << " : this = " << this << "\n";
}
~ExThis(){
cout << "Se distruge:" << --X << " this = " << this << "\n";
}
private:
static int X;
double Y;
};
int ExThis::X = 0;
void main(){
cout << main: Se declara tabloul Tab[5] de tip ExThis:\n" ;
ExThis Tab[5];
cout << Sfarsit main: Se distrug obiectele din tablou:\n";
}
POO(C++) Gh GRIGORAS 28
Exemplu- Pointerul implicit this
/*
main: Se declara tabloul Tab[5] de tip ExThis:
Obiect 0 : this = 0x0012FF4C
Obiect 1 : this = 0x0012FF54
Obiect 2 : this = 0x0012FF5C
Obiect 3 : this = 0x0012FF64
Obiect 4 : this = 0x0012FF6C
Sfarsit main: Se distrug obiectele din tablou:
Se distruge:4 this = 0x0012FF6C
Se distruge:3 this = 0x0012FF64
Se distruge:2 this = 0x0012FF5C
Se distruge:1 this = 0x0012FF54
Se distruge:0 this = 0x0012FF4C
*/
POO(C++) Gh GRIGORAS 29
Constructorii unei clase
Aa cum a fost proiectat clasa Data se poate declara:
Data d(45,17,21);
Constructorul ar trebui s fie responsabil de validarea datelor:
class Data
{
public:
enum Luna{ian = 1, feb, mar, apr, mai, iun, iul, aug, sep, oct, nov,
dec};
class Data_gresita { };
Data(int zz=0, Luna ll =Luna(0), int aa=0); // 0 = data implicita
int getZi() const;
Luna getLuna() const;
int getAn() const;
static void set_default(int, Luna, int);
//..
private:
int zi, luna, an;
static Data default_date;
};
Data Data::default_date(10,1,1906);
POO(C++) Gh GRIGORAS 30
CONSTRUCTORUL
Data::Data(int zz, Luna ll, int aa)
{
if(aa == 0) aa = default_date.getAn();
if(ll == 0) ll = default_date.getLuna();
if(zz == 0) zz = default_date.getZi();
int max;
switch(ll)
{
case feb:
max = 28 + anBisect(aa);
break;
case apr:case iun:case sep:case nov:
max = 30;
break;
case ian:case mar:case mai:case iul:case aug:case dec:
max = 31;
break;
default:
throw Data_gresita();
}
if (zz < 1 || max < zz) throw Data_gresita();
an = aa;
luna = ll;
zi = zz;
}
POO(C++) Gh GRIGORAS 31
CONSTRUCTORI
Constructor implicit: poate fi apelat fr parametri
Data(int z = 0, int l = Luna(0), int a = 0);
Dac o clas nu are constructori, se apeleaz unul implicit
(furnizat de sistemul C++);
Dac o clas are constructori, ar trebui s aib i unul implicit ;
O clas ce are membri const sau referine trebuie s aib
constructori
class X{const int a; const int& b;};
X x; // Eroare, constructorul implicit nu poate
// initializa a si b
POO(C++) Gh GRIGORAS 32
CONSTRUCTORI
Constructor i operatorul new:
Data* d = new Data(26, 4, 2010);// d obiect dinamic
class Tablou{
public:
Tablou(int n=10){p = new char[sz = n];}
~Tablou(){delete[] p;}
private:
const char* p; int sz;
};
Dac o clas are membri pointeri(este necesar alocare
dinamic) trebuie definit explicit un constructor i destructorul
clasei.
Obiectele membru ntr-o clas trebuiesc construite la crearea
obiectului compus: alegerea constructorului se face n lista de
iniializare a constructorului clasei compuse
POO(C++) Gh GRIGORAS 33
CONSTRUCTORI
class Y{
public:
Y(){y = 0;};
Y(int n){y = n;};
private:
int y;
};
class X{
public:
//X(int n):y1(Y::Y()), y2(Y::Y(n)),x(n){}
X(int n):y1(), y2(n),x(n){}
private:
int x;
Y y1,y2;
};
void main(){
X x(2);
}
POO(C++) Gh GRIGORAS 34
DESTRUCTOR
Distruge un obiect n maniera n care a fost construit
Are sintaxa: ~<Nume_clasa>(){ }
Apelat implicit pentru o variabil(obiect) din clasa automatic la
prsirea domeniului de vizibilitate
Apelat implicit cnd un obiect din memoria heap, creat cu
operatorul new, este ters cu operatorul delete
int main(){
Tablou* p = new Tablou;
Tablou* q = new Tablou;
//
delete p;
delete q;//delete p;
}
POO(C++) Gh GRIGORAS 35
Creare / distrugere obiecte
Obiect din clasa automatic (obiect local): este creat
de fiecare dat cnd declararea sa este ntlnit la
execuia programului i distrus cnd programul
prsete blocul n care este declarat
Obiect n memoria heap: este creat cu operatorul
new i distrus cu operatorul delete;
Obiect membru nestatic (ca dat membru a altei
clase): este creat/distrus cnd un obiect al crui
membru este, este creat/distrus
Obiect element al unui tablou: este creat/distrus
cnd tabloul a crui element este, este creat/distrus
POO(C++) Gh GRIGORAS 36
Creare / distrugere obiecte
Obiect local static: este creat cnd se ntlnete
prima dat declaraia sa la execuia programului
i este distrus la terminarea programului;
Obiect global, obiect n namespace, obiect
membru static: este creat o singur dat la
nceputul execuiei programului i distrus la
terminarea programului
Obiect temporar: este creat ca parte a evalurii
unei expresii i distrus la sfritul evalurii n
ntregime a expresiei n care apare
POO(C++) Gh GRIGORAS 37
CLASE: Copiere i atribuire
Pentru orice clas, se pot iniializa obiecte la
declarare i se poate folosi operatorul de atribuire
Iniializarea i atribuirea implicit nseamn copiere
membru cu membru a unui obiect n cellalt:
Punct p1; //apel constructor implicit
Punct p2 = p1;//initializare prin copiere:
//p2 nu exista, se construeste
Punct p3;
p3 = p2; //atribuire prin copiere:
//p3 exista si se modifica
POO(C++) Gh GRIGORAS 38
CLASE: Copiere i atribuire
Cazul n care nu avem alocare dinamic:
Data d1(26,4,2010);
Data d2 = d1; //echiv. cu Data d2(d1);
La o declaraie cu iniializare X x1(x2) este
apelat automat un constructor, numit constructor
de copiere: X::X(const X&)
Pentru clasa Data acest constructor este echivalent
cu:
Data::Data(const Data& d)
{
zi = d.zi;
luna = d.luna
an = d.an
}
POO(C++) Gh GRIGORAS 39
CLASE: Copiere i atribuire
Atenie la clasele ce conin pointeri! Folosirea
constructorului de copiere implicit poate conduce la
erori. Soluia: implementarea unui constructor de
copiere utilizator
Constructor de copiere:
X::X(const X& x){
// Implementare copiere
}
Suprancrcare operator de atribuire:
X::X& operator=(const X& x){
// Implementare atribuire
}
POO(C++) Gh GRIGORAS 40
// constructorul de copiere pentru Data
// datele membru zi, luna, an sunt dinamice
Data::Data(const Data& oData)
{
zi = new int(*oData.zi);
luna = new int(*oData.luna);
an = new int(*oData.an);
}
// operatorul de atribuire
Data& Data::operator=(const Data &oData)
{
if(this != &oData) // evitare atribuire x = x
{ delete zi;
delete luna;
delete an;
zi = new int(*oData.zi);
luna = new int(*oData.luna);
an = new int(*oData.an);
}
return *this;
}
POO(C++) Gh GRIGORAS 41
CLASE: Copiere i atribuire
Constructorul de copiere se apeleaz(implicit):
La declararea unui obiect cu iniializare
La evaluarea expresiilor pentru crearea de obiecte
temporare
La transmiterea parametrilor prin valoare
La returnarea din funcii prin valoare
POO(C++) Gh GRIGORAS 42
CLASE Obiecte membru
Argumentele pentru constructorii membrilor sunt
date n lista de iniializare:
Clasa::Clasa(par) : Obiect1(par1), Obiect2(par2),-
class Club{
public:
Club(const string& n, Data df);
private:
string nume;
Tablou membri;
Tablou membri_fondatori;
Data data_fond;
};
Club::Club(const string& n, Data df)
:nume(n), data_fond(df), membri_fond(), membri()
{
// Implementare constructor
} // apelurile fara parametri pot lipsi
Ordinea de apel a constructorilor : ordinea declaraiilor n
clas
POO(C++) Gh GRIGORAS 43
Lista de
iniializare
CLASE membri const, membri referin
Iniializarea membrilor: obiecte ale claselor fr constructor
implicit, membri calificai const sau membri referin, se face
numai prin liste de iniializare:
class X{
public:
X(int ii, const string& n, Data d, Club& c)
:i(ii), c(n, d), pc(c) {}
private:
const int i; Club c; Club& pc;
};
class Punct{
public:
Punct(int vx = 0, int vy = 0):x(vx), y(vy) {};
private:
int x; int y;
};
POO(C++) Gh GRIGORAS 44
Metode ce ntorc referine la membri private
Atenie la astfel de metode!!
class A{
public:
A(int x = 0): el(x){}
int& get_elem() {return elem;} // referinta la elem
private:
int elem;
};
main(){
A a(5); int& b = a.get_elem(); // b alias pentru a.elem
cout << (a.get_elem())<< ;
b= b + 5; // se modifica a.elem prin intermediul lui b
cout << a.get_elem() << endl;
}
// 5 11
POO(C++) Gh GRIGORAS 45
CLASE Spaiul de nume
class, struct, enum, union creeaz un spaiu distinct
spaiu de nume cruia aparin toate numele folosite acolo;
Clasele definite n alte clase pot conine membri statici:
class C{class B{static int i;};};
int C::B::i=99;
Clasele locale (clase definite n funcii) nu pot conine membri statici:
void f(){
class Local{
public :
static int i; // Eroare: nu se poate defini i!
} x;
}
POO(C++) Gh GRIGORAS 46
CLASE Spaiul de nume (cont)
Numele funciilor globale, variabilele globale, numele
claselor fac parte dintr-un spaiu de nume global ; apar
probleme grave uneori. Soluii:
Crearea de nume lungi, complicate
Divizarea spaiului global prin crearea de namespace
Creare : namespace <Nume_Namesp>{
<Declaratii>
}
Diferenele fa de class, struct, union,
enum:
Se poate defini doar global, dar se pot defini namespace imbricate
Definiia namespace nu se termin prin ;
O definiie namespace poate continua pe mai multe fiiere header
POO(C++) Gh GRIGORAS 47
CLASE Spaiul de nume (cont)
Un namespace poate fi redenumit:
namespace BibliotecaDeProgramePersonaleAleLuiIon{}
namespace Ion =
BibliotecaDeProgramePersonaleAleLuiIon
Nu pot fi create instane ale unui namespace
Utilizare namespace-urilor deja declarate:
Folosirea operatorului de rezoluie:
class <NumeSp>::C{};
Folosirea directivei using:
using namespace <NumeSp>;
Folosirea declaraiei using:
using <NumeSp>::<Nume_membru>;
POO(C++) Gh GRIGORAS 48
CLASE Spaiul de nume (Exemple)
namespace U {inline void f() {} inline void g() {}}
namespace V {inline void f() {} inline void g() {}}
void h() {
using namespace U; // Directiva using
using V::f; // Declaratia using
f(); // Apel V::f();
U::f();
}
namespace Q {using U::f;using V::g;}
void m() {
using namespace Q;
f(); // Apel U::f();
g(); // Apel V::g();
}
int main() {
h();
V::f();
m();
}
POO(C++) Gh GRIGORAS 49
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 50
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, cnd se instaniaz,
trebuie s se potriveasc cu funcia respectiv n trei
elemente:
numrul i tipurile argumentelor
tipul valorii returnate
tipul clasei a crei membru este
POO(C++) Gh GRIGORAS 51
Exemplu
//Pointeri la functii membru
class C{
public:
void f(int n=5) const {cout << "apel C::f(" << n <<")" << endl;}
void g(int n) const {cout << "apel C::g(" << n <<")" << endl;}
void h(int n) const {cout << "apel C::h(" << n <<")" << endl;}
void i(int n) const {cout << "apel C::i(" << n <<")" << endl;}
};
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();
}
// apel C::h(7) apel C::h(0) apel C::f(8) apel C::f(0) apel C::f(5)
POO(C++) Gh GRIGORAS 52
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 53
PRIETENII UNEI CLASE
O declaraie de funcie membru nseamn:
Funcia poate accesa partea privat a clasei;
Funcia este n domeniul de vizibilitate al clasei;
Funcia poate fi invocat de un obiect (are acces la pointerul this)
Declararea unei funcii friend, i confer doar prima
proprietate
Se declar atunci cnd este necesar accesul la membrii
privai
Class Vector{}; class Matrice{}
Vector operator*(constMatrice& m, const Vector& v){
Vector r;
// Implementare r = m*v, Trebuie sa aiba acces la
// reprezentarile claselor Vector si Matrice
return r;
}
POO(C++) Gh GRIGORAS 54
PRIETENII UNEI CLASE
O clas poate avea prieteni:
Alte clase (structuri)
Funcii
Operatori
Adesea operatorii << i >> sunt declarai friend
class Data {
/
friend ostream& operator <<(ostream&, const Data&);
//
};
ostream& operator << (ostream& o, const Data& d) {
o << d.zi << ' ' << d.luna << ' ' << d.an;
return o;
}
POO(C++) Gh GRIGORAS 55
Exemplu
// Functii si clase friend
struct X;
// Declaratie necesara pentru definitia lui Y
struct Y {
void f(X*);
};
struct X { // Definitia clasei X
public:
void init();
friend void g(X*, int); // Functie globala friend
friend void Y::f(X*); // Functie din Y friend
friend struct Z; // Structura(clasa) friend
friend void h(); // Functie globala friend
private:
int i;
};
POO(C++) Gh GRIGORAS 56
Suprancrcare operatori: operator@
Nu se pot suprancrca operatorii:
:: scope resolution
. acces la membru
.* derefereniere membru
?: sizeof() typeid
Nu pot fi introdui noi operatori
Operatorii binari se definesc fie ca funcii membru
nestatic cu un argument sau ca funcii nemembru cu
2 argumente
Interpretarea expresiei a@b:
a.operator@(b) respectiv operator@(a,b)
POO(C++) Gh GRIGORAS 57
Suprancrcare operatori: operator@
Operatorii unari se definesc fie ca funcii membru
nestatic fr argumente (cu un argument int
pentru operator postfix) sau ca funcii nemembru cu
1 argument (2 argumente pentru operator postfix);
@a nseamn a.operator@() respectiv
operator@(a)
a@ nseamn a.operator@(int) respectiv
operator@(a, int)
operator=, operator[], operator() i
operator-> trebuie definii ca funcii membru
nestatic; asta asigur c primul operand este lvalue
POO(C++) Gh GRIGORAS 58
Recomandare: 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 59
Exemplul: + suprancrcat
struct X{
void operator+(int);
void operator+(double);
X(int);
int n;
...
};
void operator+(X, X);
void operator+(double, X);
void f(X a){
a+99; // a.operator+(99)
a+5.55; // a.operator+(5.55)
33 + a; // ::operator+(X(33), a)
1.1 + a; // ::operator+(1.1, a)
a + a // :: operator+(a, a)
}
POO(C++) Gh GRIGORAS 60
Exemplu: &
struct Y{
public:
Y* operator&();
// adresa, operator unar
Y operator&(Y);
// operatorul logic &, binar
Y operator++(int); // ++ postfix, unar
Y operator&(Y, Y);
// Eroare, prea multe argumente
Y operator/();
// Eroare, prea putine argumente
};
POO(C++) Gh GRIGORAS 61
Exemplu: ++
struct Clock{
Clock tic_tac();
Clock operator++();
Clock operator++(int);
int ora, min, ap; // ap=0 pentru AM, 1 pentru PM
};
Clock Clock::tic_tac(){
++min;
if(min == 60){
ora++;
min = 0;
}
if(ora == 13)
ora = 1;
if(ora == 12 && min == 0)
ap = !ap;
return *this;
}
POO(C++) Gh GRIGORAS 62
Exemplu: ++ (cont)
Clock Clock::operator++(){
return tic_tac();
}
Clock Clock::operator++(int n){
Clock c = *this;
tic_tac();
return c;
}
POO(C++) Gh GRIGORAS 63
operator<< i operator>>
#include<iostream>
using namespace std;
class Punct{
public :
Punct(int xx=0, int yy=0): x(xx), y(yy) { }
int getx() const{return x;}
int gety() const{return y;}
private:
int x, y;
};
ostream& operator<<( ostream& os,const Punct& p){
return os <<(<<p.getx()<<","<<p.gety()<<)<< endl;
}
istream& operator>>(istream& in, Punct& p){
int x,y;
in >> x >> y;
p = Punct(x,y);
return in;
}
POO(C++) Gh GRIGORAS 64
Suprancrcare 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 65
Suprancrcare 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 66
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 67
Suprancrcare 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 68
Suprancrcare operator()
/*
0 1 2 3
2 3 4 5
4 5 6 7
4
Al doilea indice gresit
*/
POO(C++) Gh GRIGORAS 69
neles predefinit pentru operatori
=, & (adresa) i , au neles predefinit pentru orice
clas
Acest neles poate fi anulat prin plasarea lor n
seciunea private
class X {
private:
void operator=(const X&);
void operator&();
void operator,(const X&);
//
};
Poate fi stabilit alt neles prin suprancrcare
POO(C++) Gh GRIGORAS 70
POO(C++) Gh GRIGORAS 71
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 72
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
Constructor explicit
Un constructor cu un singur argument
definete o conversie implicit; uneori acest
lucru poate produce erori:
complex z = 2 // ok
String s = a ; // nu-i ok daca exista
//constructorul String(int n)
Conversia implicit poate fi stopat dac se
declar constructorul explicit
class String{
//
explicit String(int n);
String(const char* p);
//
};
POO(C++) Gh GRIGORAS 73
Constructor explicit
class An{
int y;
public:
explicit An(int i):y(i){}
operator int() const {return y;}
};
class Data{
public:
Data(int d, Luna m, An y);
//
};
Data d10(7, mar, 1977);// eroare
Data d11(7, mar, An(1977));//ok
POO(C++) Gh GRIGORAS 74
POO(C++) Gh GRIGORAS 75
CLASE: Operatorul de conversie
este o funcie membru care definete o conversie de
la tipul X la tipul T:
X::operator T()const;
Exemplu:
class Clock{
public:
Clock(int = 12, int = 0, int = 0);
Clock tic_tac();
Clock operator++();
Clock operator++(int);
operator int()const; // 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 76
CLASE: Operatorul de conversie
class fractie{
public:
fractie(int n=0, int m=1):numarator(n),
numitor(m) { }
operator int(){
return numarator/numitor;
} //conversie fracie -> int
operator double(){
return double(numarator)/numitor;
} //conversie fracie -> double
private:
int numarator, numitor;
};
fractie x(1,2);
double u = x;
int i = int(x);
POO(C++) Gh GRIGORAS 77
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 78
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 ???
}
1
POO
Modelare I
D. Lucanu POO Principii 2
Cuprins
fazele dezvoltarii unui produs soft
modelare
UML
diagrame use case
diagrame de clase
cum modelam in UML
cum implementam in C++
D. Lucanu POO Principii 3
Cum dezvoltam un produs soft?
Relatia client dezvoltator software
D. Lucanu POO Modelare 4
Dezvoltarea in cascada
D. Lucanu POO Principii 5
Dezvoltarea in iteratii (RUP)
D. Lucanu POO Principii 6
Dezvoltarea agila (extreme programming)
D. Lucanu POO Principii 7
Important de tinut minte
pentru proiectele realizate in timpul studiilor
clientul este profesorul
dezvoltatorul
studentul (proiecte individuale)
echipa de studenti (proiecte in echipa)

mai multe despre metodologiile de dezvoltare a
produselor soft la cursurile de IP
D. Lucanu POO Principii 8
Ce este un model
modelarea este esentiala in dezvoltarea eficienta de
produse soft, indiferent de metodogia aleasa
in principiu, rezultatele fazelor initiale si de elaborare
sunt specificatii scrise ca modele
un model este o simplificare a realitatii, fara insa a
pierde legatura cu aceasta
principalul motiv pentru care se construieste un
model: necesitatea de a intelege sistemul ce
urmeaza a fi dezvoltat
cu cat sistemul este mai complex, cu atat importanta
modelului creste
alegerea modelului influienteaza atat modul in care
problema este abordata cat si solutia proiectata
in general, un singur model nu este suficient
D. Lucanu POO Principii 9
UML limbaj de modelare
pentru a scrie un model, e nevoie de un limbaj de
modelare
UML (Unified Modeling Language) este un limbaj si
o tehnica de modelare potrivite pentru programarea
orientata-obiect
UML este utilizat pentru a vizualiza, specifica,
construi si documenta sisteme orientate-obiect
la acest curs vom utiliza elemente UML pentru a
explica conceptele si legile POO
instrumente soft free: Argouml (open source), Visual
Paradigm UML (Community edition)
D. Lucanu POO Principii 10
Ce include UML 2.0
diagrame de modelare structurala
definesc arhitectura statica a unui model
diagrame de clase
diagrame de obiecte
diagrame de pachete
diagrame de structuri compuse
diagrame de componente
diagrame de desfasurare (deployment)
D. Lucanu POO Principii 11
Ce include UML
diagrame de modelare comportamentala
definesc interactiunile si starile care pot sa apara la
executia unui model
diagrame de utilizare (use case)
diagrame de activitati
diagrame de stari (state Machine diagrams)
diagrame de comunicare
diagrame de secvente (sequence diagrams)
diagrame de timp (fuzioneaza diagrame de stari
cu cele de secvente)
diagrame de interactiune globala (interaction
overview diagrams) (fuzioneaza diagrame de
activitati cu cele de secvente)
D. Lucanu POO Principii 12
Cum sunt utilizate modelele UML
pot fi utilizate in toate fazele de dezvoltare a
produselor soft
analiza cerintelor, e.g.,
diagramele cazurilor de utilizare
proiectare, e.g.,
diagramele de clase
diagrame de comunicare/secvente
diagrame de activitate
implementare,
diagramele constituie specificatii pentru cod
exploatare, e.g.,
diagrame de desfasurare
D. Lucanu POO Principii 13
La acest curs vom insista
... doar pe
analiza cerintelor
diagramele cazurilor de utilizare
proiectare
diagramele de clase
diagrame de obiecte
diagrame de comunicare
diagrame de secvente
implementare
cum scriem cod C++ din specificatiile date de
diagrame
mai mult la cursurile de IP
D. Lucanu POO Principii 14
Ce este analiza OO
analiza este focalizata mai mult pe intelegerea
domeniului problemei si mai putin pe gasirea de
solutii
este orientata mai mult spre
ce ( trebuie, inseamna, relatii exista, )
formulare si specificare cerinte
investigarea domeniului
intelegerea problemei
descrie obiectele (conceptele) din domeniul
problemei
D. Lucanu POO Principii 15
Diagramele cazurilor de utilizare
modelul cazurilor de utilizare captureaza cerintele
un caz de utilizare (use case) este un mijloc de a
comunica utilizatorului ce intentioneaza sistemul sa
faca

D. Lucanu POO Principii 16
caz de
utilizare
actor
relatia de
utilizare
multiplicitate
Relatia de includere intre cazuri de ut.
D. Lucanu POO Principii 17
Relatia de extindere intre cazuri de ut.
D. Lucanu POO Principii 18
Proiectare OO (design)
proiectarea se bazeaza pe solutia logica, cum
sistemul realizeaza cerintele
este orientata spre
cum
solutia logica
intelegerea si descrierea solutiei
descrie obiectele (conceptele) ca avand atribute si
metode
descrie solutiam prin modul in care colaboreaza
obiectele
relatiile dintre concepte sunt descrise ca relatii intre
clase
D. Lucanu POO Principii 19
Diagrama de clase
include
clase
interfete
relatii intre clase
de generalizare/specializare
de asociere
de compozitie
de dependenta
D. Lucanu POO Principii 20
Clasa
D. Lucanu POO Principii 21
nume clasa
atribute (date membre)
operatii (metode)
D. Lucanu POO Principii 22
Relatia de generalizare/specializare
depune()
extrage()
titular
sold
Cont
ContDebit ContCredit
Relatia de generalizare/specializare
D. Lucanu POO Principii 23
Relatia de generalizare/specializare
D. Lucanu POO Principii 24
Relatia de generalizare/specializare in C++
class Figure
{
...
};

class Circle
: public Figure
{
...
};

class Ellipse
: public Circle
{
...
};

class Polygon
: public Figure
{

};
D. Lucanu POO Principii 25
in C++ gen/spec se realizeaza
prin relatie de derivare
in C++ gen/spec se realizeaza
prin relatie de derivare
in C++ gen/spec se realizeaza
prin relatie de derivare
Relatia de generalizare/specializare in C++
operatiile perimeter() si surface() se calculeaza
diferit de la figura la figura
class Figure {
public:
virtual void perimeter() { return 0; }
};
class Circle : public Figure {
public:
virtual void perimeter()
{ return 2 * 3.1415 * radius; }
};

D. Lucanu POO Principii 26
polimorfism prin suprascriere si
legare dinamica
polimorfism prin suprascriere si
legare dinamica
D. Lucanu POO Principii 27
Interfata
obiecte de tip Figura nu exista la acest nivel de
abstractizare
clasa Figura este mai degraba o interfata pentru
figurile concrete (cerc, poligon, elipsa )
interfata = o colectie de operatii care
caracterizeaza comportarea unui obiect
D. Lucanu POO Principii 28
Interfata in UML
D. Lucanu POO Principii 29
relatia de
implementare
a unei interfete
Interfata in C++
interfetele in C++ sunt descrise cu ajutorul claselor
abstracte
o clasa abstracta nu poate fi instantiata, i.e., nu are
obiecte
de notat totusi ca interfata si clasa abstracta sunt
concepte diferite
o clasa abstracta poate avea date membre si
metode implementate
in C++ o clasa este abstracta daca include metode
virtuale pure (neimplementate)
D. Lucanu POO Principii 30
Clase abstracte in C++
class Figure {
public:
...
virtual void perimeter() = 0;
virtual void surface() = 0;
...
};

D. Lucanu POO Principii 31
metode virtuale pure
Diagrame cu clase abstracte
D. Lucanu POO Principii 32
clasa abstracta
daca interfata este
descrisa printr-o
clasa abstracta,
implementarea
interfetei se
realizeaza prin
mostenire si
suprascriere virtuala
Abstractizare prin parametrizare
D. Lucanu POO Principii 33
void setValue(string newValue)
{
value = newValue;
}
void setValue(double newValue)
{
value = newValue;
}
poate fi parametrizat?
Clase parametrizate
D. Lucanu POO Principii 34
parametru parametru
Clase parametrizate in C++
template <class T>
class DisplayBox
{
private: string label;
private: T value;
public: DisplayBox(char *newLabel = "");
public: void setValue(T newValue);
};

template <class T>
void DisplayBox<T>::setValue(T newValue)
{
value = newValue;
}
D. Lucanu POO Principii 35
definitii
parametrizate
definitii
parametrizate
declaratie
parametri
declaratie
parametri
utilizare
parametri
utilizare
parametri
D. Lucanu POO Principii 36
Dorel Lucanu Programarea calculatoarelor
(C++)
37
Ex. de ierarhie de clase param.: fluxuri STL
ios_base
ios<>
istream<>
ostream<>
ofstream<> ifstream<> iostream<>
ostringstream<>
istringstream<>
fstream<>
stringstream<>
relatii de
mostenire
C++ intermezzo
declarare obiect fisier
fstream f;
scrierea intr-un fisier
f.open("test.txt", ios::out);
cout << "Umplere fisier\n";
while (ok)
{
cin.getline(buffer, 80, '#');
f << buffer;
cout << "Continui?[y/n]: ";
cin >> ans;
ok = (ans == 'y');
}
f.close();
D. Lucanu POO Principii 38
C++ intermezzo
citirea dintr-un fisier
f.open("test.txt", ios::in);
cout << "Afisare fisier\n";
while (!f.eof())
{
f.getline(buffer, 80);
cout << buffer << endl;
}
f.close();
D. Lucanu POO Principii 39
Relatii de asociere
D. Lucanu POO Principii 40
relatie de asociere
unidirectionala
multiplicitate
rol
model model
controller view
relatie de asociere
bidirectionala
Relatii de asociere mai simplificat
D. Lucanu POO Principii 41
relatie de asociere
unidirectionala
multiplicitate
rol
model model
controller view
relatie de asociere
bidirectionala
Relatii de asociere in C++
class ControllerAgenda
{
private:
Agenda *model;
ViewAgenda *view;
public:
void setView(ViewAgenda *newView);
};
class ViewAgenda
{
private:
ControllerAgenda *controller;
Agenda *model;
DisplayBoxString dbOwner;
Menu menu;
};
D. Lucanu POO Principii 42
referinta la obiectul
Agenda asociat
referinta la obiectul
ViewAgenda asociat
referinta la obiectul
Agenda asociat
Asociere agenda - fisier
D. Lucanu POO Principii 43
Derivare, Ierarhii- plan
Relaia de derivare
Sintaxa
Tipuri de derivare
Constructori, Destructori
Conversii standard
Copiere
Conflicte
Derivare virtual
POO(C++) Gh GRIGORAS 1
Introducere
C++ a mprumutat de la Simula conceptul de clas
(ca tip utilizator) i cel de ierarhie de clase
Clasele ar trebui utilizate pentru a modela
concepte att din domeniul aplicaiilor ct i din
cel al programrii
Un concept nu exist izolat, el coexist cu alte
concepte cu care relaioneaz
Automobil
roi, motor, oferi, pietoni, camion, ambulan, osea,
ulei, combustibil, parcare, motel, service, etc.
Exprimarea prilor comune, a relaiilor ierarhice
dintre clase se realizeaz prin noiunea de derivare
POO(C++) Gh GRIGORAS 2
struct Angajat{
string nume, prenume;
char initiala;
Data data_angajarii;
short departament;
//
}
struct Manager{
Angajat ang; // datele managerului
list<Angajat*> grup;//echipa condusa
//
}
POO(C++) Gh GRIGORAS 3
Un manager este un angajat; compilatorul nu
poate nelege acest lucru din codul scris
Mai mult, un Manager* nu este un Angajat*
deci nu pot pune un Manager ntr-o list de
Angajai dect dac scriem o conversie
explicit
Soluia corect: specificarea(i pentru
compilator) c un Manager este un Angajat
struct Manager:public Angajat{
list<Angajat*> grup;//echipa condusa
//
}
POO(C++) Gh GRIGORAS 4
Se spune c Manager este derivat din Angajat, c
Angajat este clas de baz pentru Manager
Clasa Manager are ca membri, membrii clasei
Angajat i n plus, membrii declarai acolo
Clasa derivat motenete de la clasa de baz,
relaia se mai numete motenire.
Clasa de baz este numit uneori o superclas iar
clasa derivat o subclas
Confuzie uneori: clasa derivat este mai mare dect
clasa de baz n sensul c ea poate conine date i funcii
n plus
POO(C++) Gh GRIGORAS 5
Relaia de motenire Clase derivate
Tipul D este un subtip al (o specializare a) tipului B:
toate obiectele de tip D sunt i de tip B. (Manager este
subtip al tipului Angajat)
Specializarea se poate face prin:
Restricionarea domeniului de valori a obiectelor de
tip D
Adugarea de noi operaii la cele definite pe tipul B
n anume condiii, printr-o nou definire a
membrilor
POO(C++) Gh GRIGORAS 6
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
POO(C++) Gh GRIGORAS 7
Relaia de motenire Clase derivate
n C++ : clas de baz (superclas), clas
derivat (subclas)
Motenire simpl, motenire multipl
POO(C++) Gh GRIGORAS 8
B B1 B2
D
D
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 9
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: membrii 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 10
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 membri : 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
de rezoluie ::
POO(C++) Gh GRIGORAS 11
Clase derivate
Constructori, Destructori
Constructorii i destructorul 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 12
class Angajat{
public:
Angajat(const string& n, int d);
//...
private:
string nume, prenume;
short departament;
//..
};
class Manager:public Angajat{
public:
Manager(const string& n, int d, int niv);
//...
private:
list<angajat*> grup;
short nivel;
//...
};
POO(C++) Gh GRIGORAS 13
Angajat::Angajat(const string& n, int d)
:nume(n), departament(d)
{
//...
}
Manager::Manager(const string& n, int d, int niv)
:Angajat(n,d), // initializarea bazei
nivel=niv // initializare membri
{
//..
}
Constructorul clasei derivate poate iniializa membrii
clasei de baz prin invocarea constructorului acesteia
n lista de iniializare
POO(C++) Gh GRIGORAS 14
Clase derivate - Conversii standard
Un obiect al clasei derivat poate fi convertit implicit la unul din
clasa de baz
Un Manager poate fi folosit oriunde este acceptabil un Angajat
O adres a unui obiect derivat poate fi convertit implicit la o
adres de obiect din clasa de baz
Un Manager& poate fi folosit ca un Angajat&
Un pointer la un obiect derivat poate fi convertit implicit la un
pointer la obiect din clasa de baz
Un Manager* poate fi folosit ca un Angajat*
Conversia reciproc poate fi definit cu un constructor n clasa
derivat
POO(C++) Gh GRIGORAS 15
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 implicit clasa baza, clasa derivat
explicit implicit clasa baza, clasa derivat
implicit explicit constructorul clasei derivate
explicit explicit constructorul clasei derivate
trebuie sa apeleze constructorul
clasei de baz
POO(C++) Gh GRIGORAS 16
Copiere
class Angajat{
public:
//...
Angajat&operator=(const Angajat&);
Angajat(const Angajat&);
//...
};
void f(const Manager& m){
Angajat e = m;
// se construieste e din partea Angajat a lui m
e = m;
// se atribuie lui e partea Angajat a lui m
}
Copierea, atribuirea nu se motenesc
POO(C++) Gh GRIGORAS 17
Ierarhii de clase
class Angajat{/*...*/);
class Manager::public Angajat{/*...*/);
class Director::public Manager{/*...*/);
class Secretar::public Angajat{/*...*/);
class AngajatTemporar{/*...*/);
class SecretarTemporar::public AngajatTemporar, public Angajat{/*...*/);
class Consultant::public AngajatTemporar, public Manager{/*...*/);
POO(C++) Gh GRIGORAS 18
AngajatTemporar
SecretarTemporar
Angajat
Secretar Manager
Director Consultant
Utilizarea claselor derivate presupune rezolvarea
problemei: dat un pointer la clasa de baz, crui tip
derivat aparine obiectul pointat?
Soluii:
1. Asigurarea ca sunt pointate doar obiecte de un singur tip
2. Folosirea unui cmp tip n clasa de baz
3. Utilizarea operatorului dynamic_cast
4. Utilizarea funciilor virtuale
Pointerii la clase de baz sunt folosii la proiectarea
containerelor(mulimi, vectori, liste)
Soluia 1 conduce la folosirea containerelor omogene (obiecte
de acelai tip)
Soluiile 2-4 permit construirea de containere eterogene
Soluia 3 este varianta implementat de sistem a soluiei 2
Soluia 4 este o variant sigur a soluiei 2
POO(C++) Gh GRIGORAS 19
Cmp tip n clasa de baz
struct Angajat{
enum Ang_type{M, A};
Ang_type tip;
string nume, prenume;
char initiala;
Data data_angajarii;
short departament;
//
}
POO(C++) Gh GRIGORAS 20
struct Manager{
Manager() {tip = M;}
Angajat ang;
list<Angajat*> grup
short nivel;
//
}
void print_angajat(const Angajat* a){
switch Angajat(a->tip){
case Angajat::A:
cout << a -> nume << \t << a->departament << \n;
//
break
case Angajat::M:
cout << a -> nume << \t << a->departament << \n;
//
const Manager* p = static_cast<const Manager*>(a);
cout << nivel << p->nivel<< \n;
//..
}
Cmp tip n clasa de baz
POO(C++) Gh GRIGORAS 21
void print_list(const list<Angajat*>& alist){
for(list<Angajat*>::const_iterator p=alist.begin();
p!=alist.end(); ++p)
print_angajat(*p);
}
Varianta care ine cont de partea comun:
void print_angajat(const Angajat* a){
cout << a -> nume << \t << a->departament << \n;
//..
if(a->type == Angajat::M){
const Manager* p = static_cast<const Manager*>(a);
cout << nivel << p->nivel<< \n;
//..
}
Funcii virtuale
class Angajat{
public:
Angajat(const string& n, int d);
virtual void print() const//...
private:
string nume, prenume;
short departament;
//..
};
Cuvntul cheie virtual indic faptul c print() poate aciona ca
o interfa pentru funcia print() din aceast clas i print()
definite n clasele derivate
Compilatorul va ti s invoce funcia potrivit atunci cnd
print() este transmis unui obiect Angajat
Tipul argumentelor funciei virtuale n clasele derivate trebuie
s fie aceleai
POO(C++) Gh GRIGORAS 22
O funcie virtual trebuie definit pentru clasa n care a fost
prima dat declarat (cu excepia cazului funcie virtual pur)
void Angajat::print() const{
cout << nume << \t << departament << \n;
}
class Manager:public Angajat{
public:
Manager(const string& n, int d, int niv);
void print() const; // nu mai e nevoie de cuvantul virtual
//...
private:
list<angajat*> grup;
short nivel;
//...
};
void Manager::print() const{
Angajat::print();
cout << \tnivel << nivel << \n;
}
POO(C++) Gh GRIGORAS 23
Funcii virtuale
O funcie din clasa derivat cu acelai nume i
acelai set de tipuri de argumente cu o funcie
virtual din clasa de baz se zice c extinde
(override) versiunea din clasa de baz
Programatorul poate indica verisiunea ce
trebuie apelat
Angajat::print();
Altfel, compilatorul alege versiunea potrivit,
n funcie de obiectul pentru care este
invocat
POO(C++) Gh GRIGORAS 24
void print_list(const list<Angajat*>& alist){
for(list<Angajat*>::const_iterator p=alist.begin();
p!=alist.end(); ++p)
(*p)->print();
}
int main()
{
Angajat a("Ionescu", 1234);
Manager m("Popescu", 1234, 2);
list<Angajat*> ang;
ang.push_front(&a);
ang.push_front(&m);
print_list(ang);
return 0;
Rezultatul execuiei:
Popescu 1234
nivel 2
Ionescu 1234
POO(C++) Gh GRIGORAS 25
Ierarhia RxR
POO(C++) Gh GRIGORAS 26
PctSpatiu
mutaLa()
transl()
RxRxR
z : float
setZ()
getZ()
RxR
x : float
y : float
setX()
setY()
getX()
getY()
modul()
PctPlan
transl()
mutaLa()
PlanComplex
phi()
rho()
Complex
conj()
operator+()
operator*()
operator-()
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 27
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 28
POO(C++) 2005-2006 Gh GRIGORAS 29
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 acestea sunt derivate din B:
B este accesibil pe dou ci din D
POO(C++) 2005-2006 Gh GRIGORAS 30
Clase derivate Conflicte
Conflict de clas: clasa PlanComplex derivat din
PctPlan i Complex iar acestea sunt derivate din RxR
POO(C++) 2005-2006 Gh GRIGORAS 31
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 PlanComplex : public PctPlan, public Complex{
public:
PlanComplex(double = 0, double = 0);
~PlanComplex(){};
};
POO(C++) 2005-2006 Gh GRIGORAS 32
Ierarhia RxR
PlanComplex::PlanComplex(double un_x, double un_y) : PctPlan(un_x, un_y),
Complex(un_x, un_y)
{}
PlanComplex::~PlanComplex()
{
// nimic
}
void main(void) {
PlanComplex pc(5, 5);
cout << pc.modul() << endl;
PlanComplex pc2;
pc2.setX(5);
pc2.setY(5);
cout << pc2.modul() << endl;
}
// 'PlanComplex::modul' is ambiguous
//could be the 'modul' in base 'RxR' of base 'PctPlan' of class 'PlanComplex
//or the 'modul' in base 'RxR' of base 'Complex' of class 'PlanComplex'
POO(C++) 2005-2006 Gh GRIGORAS 33
Motenire fr partajare
Fiecare clas derivat are cte un exemplar din
datele i metodele clasei de baz
PctPlan::x
PctPlan::y
Complex::x
Complex ::y
PctPlan::modul()
Complex ::modul()
Soluia (cazul derivrii multiple):
Clasa de baz virtual poate fi clas de baz
indirect de mai multe ori fr a duplica membrii
POO(C++) 2005-2006 Gh GRIGORAS 34
Partajare: clase derivate virtuale
Derivare virtual:
class A1:virtual public B{};
class A2:public virtual B{};
class D: public A1, public A2{};
class PctPlan : virtual public RxR ...
class Complex : virtual public RxR ...
POO(C++) 2005-2006 Gh GRIGORAS 35
Partajare: clase derivate virtuale
void main(void) {
PlanComplex pc(5, 5);
cout << pc.modul() << endl; //0 ???
PlanComplex pc2;
pc2.setX(5);
pc2.setY(5);
cout << pc2.modul() << endl; //7.07107
}
Care este explicaia acestei diferene?
POO(C++) 2005-2006 Gh GRIGORAS 36
Clase derivate virtuale
Dac n loc de:
PlanComplex::PlanComplex(double un_x, double un_y) :
PctPlan(un_x, un_y), Complex(un_x, un_y){}
implementm astfel:
PlanComplex::PlanComplex(double un_x, double un_y) :
RxR(un_x, un_y){}
rezultatul va fi:
7.07107
7.07107
POO(C++) 2005-2006 Gh GRIGORAS 37
Clase derivate virtuale
n cazul derivrii virtuale, constructorul fiecrei clase derivate este
responsabil de iniializarea clasei virtuale de baz:
class Baza{ class m1:public D1, public D2{
public: public:
Baza(int){} m1():Baza(2){}
// //
}; };
class D1 : virtual public Baza{ class m2:public D1, public D2{
public: public:
D1():Baza(1){} m2():Baza(3){}
// //
}; };
class D2 : virtual public Baza{
public:
D2():Baza(6){}//
};
Un constructor implicit n clasa de baz virtual, simplific lucrurile (dar le
poate i complica!)
Parametrizare (Programare generic) - plan
Clase parametrizate
Declaraie template
Definirea membrilor
Instaniere (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,
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 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 aceluiai nume pentru mai multe
nelesuri(polimorfism).
nelesul este dedus din tipul parametrilor
(parametric).
POO(C++) Gh GRIGORAS 4
Template-uri
Funcie 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);
POO(C++) Gh GRIGORAS 5
Template-uri
Funcie generic de sortare:
template <class T>
void naiveSort(T a[], int n)
{
for (int i=0; i<n-1; i++)
for(int j=i+1; j<n; j++)
if (a[i] > a[j])
swap<T>(a[i], a[j]);
};
Parametrii generici pot fi i tipuri de baz
template <class T, int n>
void naivSort2(T a[])
{
for (int i=0; i<n-1; i++)
for(int j=i+1; j<n; j++)
if (a[i] > a[j])
swap<T>(a[i], a[j]);
};
POO(C++) Gh GRIGORAS 6
Template-uri
La apel, pentru n trebuie transmis o constant:
int i;
double x[5] = {2,1,3,5,4};
naivSort<double>(x, 5);
for (i=0; i<5; i++)
cout << x[i] << ", ";
cout << endl;
double y[5] = {2,1,3,5,4};
naivSort2<double, 5>(y);
for (i=0; i<5; i++)
cout << x[i] << ", ";
cout << endl;
int n = 5;
double z[5] = {2,1,3,5,4};
naivSort2<double, n>(z); // eroare
POO(C++) Gh GRIGORAS 7
Abstractizare prin parametrizare
D. Lucanu POO Principii 8
void setValue(string newValue)
{
value = newValue;
}
void setValue(double newValue)
{
value = newValue;
}
poate fi
parametrizat?
Clase parametrizate
D. Lucanu POO Principii 9
parametru parametru
Clase parametrizate in C++
template <class T>
class DisplayBox
{
private: string label;
private: T value;
public: DisplayBox(char *newLabel = "");
public: void setValue(T newValue);
};
template <class T>
void DisplayBox<T>::setValue(T newValue)
{
value = newValue;
}
D. Lucanu POO Principii 10
definitii
parametriza
te
definitii
parametriza
te
declaratie
parametri
declaratie
parametri
utilizare
parametri
utilizare
parametri
Clase template (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 11
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 12
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 13
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 14
Clase parametrizate Exemplul 1
POO(C++) Gh GRIGORAS 15
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;
}
Exemplul 1 - cont
POO(C++) Gh GRIGORAS 16
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;
}
Exemplul 1 - cont
POO(C++) Gh GRIGORAS 17
#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;
};
Exemplul 1 - cont
POO(C++) Gh GRIGORAS 18
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();
};
Exemplul 1 - cont
POO(C++) Gh GRIGORAS 19
Template: Suprancrcare operatori
template <class Elt>
Cell<Elt>& Array<Elt>::operator[](int i)
{
if((i<0)||(i>=nOfComp)) throw "Index gresit.";
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();
}
Exemplul 1 - cont
POO(C++) Gh GRIGORAS 20
// 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;
Clase parametrizate - Exemplul 2
POO(C++) Gh GRIGORAS 21
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;
};
Exemplul 2
POO(C++) Gh GRIGORAS 22
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;
Specializri
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 23
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;
};
Specializri:
Vector<int> vi;
Vector<Punct*> vpp;
Vector<string> vs;
Vector<char*> vpc;
POO(C++) Gh GRIGORAS 24
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 25
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(tab, a.tab);
swap(n, a.n);
}
POO(C++) Gh GRIGORAS 26
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 27
Clase parametrizate relaia 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 28
Clase parametrizate relaia 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 29
Membri statici n template uri
Fiecare specializare a unei clase template
are copia proprie a membrilor 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 30
Derivare - 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 obinuit
Se poate defini o clas obinuit prin
derivare de la o instan a unei clase
parametrizate
POO(C++) 2005-2006 Gh GRIGORAS 31
Derivare - parametrizare
template <class T>
class Fisier: protected fstream {};
template <class T>
class FisierCitire: public virtual Fisier<T> {};
template <class T>
class FisierScriere: public virtual Fisier<T> {};
template <class T>
class FisierCitireScriere: public FisierCitire<T>,
public FisierScriere<T>
{};
POO(C++) 2005-2006 Gh GRIGORAS 32
Derivare i parametrizare - Exemplu
template <class TYPE>
class stack {
public:
explicit stack(int size = 100) // doar explicit
: max_len(size), top(EMPTY)
{s = new TYPE[size]; assert (s != 0);}
~stack() { delete []s; }
void reset() { top = EMPTY; }
void push(TYPE c) { s[++top] = c; }
TYPE pop() { return s[top--]; }
TYPE top_of()const { return s[top]; }
bool empty()const { return top == EMPTY;}
bool full()const { return top == max_len - 1;}
private:
enum { EMPTY = -1 };
TYPE* s;
int max_len;
int top;
};
POO(C++) 2005-2006 Gh GRIGORAS 33
Derivare i parametrizare - Exemplu
class safe_char_stack : public stack<char> {
public:
// push, pop sigure
void push(char c)
{ assert (!full()); stack<char>::push(c); }
char pop()
{assert (!empty()); return (stack<char>::pop());}
};
template <class Type>
class safe_stack : public stack<Type> {
public:
// push, pop sigure
void push(Type c)
{ assert (!full()); stack<Type>::push(c); }
char pop()
{assert (!empty()); return (stack<Type>::pop());}
};
POO(C++) 2005-2006 Gh GRIGORAS 34
POO(C++) 2005-2006 Gh GRIGORAS 35
Ierarhia de clase STL:: IOS
ios<>
istream<>
ostream<>
iostream<>
istringstream<>
ifstream<> ofstream<>
ostringstream<>
fstream<> stringstream<>
ios_base
Mostenire virtuala
POO(C++) 2005-2006 Gh GRIGORAS 36
Ierarhia de clase iostream
Clasele cu sufixul <> sunt template - uri parametrizate cu un tip
caracter iar numele lor au prefixul basic_ :
template <class E, class T = char_traits<E> >
class basic_ios : public ios_base {
//
};
char_traits<E> conine informaii pentru
manipularea elementelor de tip E
template <class E, class T = char_traits<E> >
class basic_istream : virtual public basic_ios<E, T>
{
//
};
POO(C++) 2005-2006 Gh GRIGORAS 37
Ierarhia de clase streambuf
streambuf<>
filebuf<> stringbuf<>
POO(C++) 2005-2006 Gh GRIGORAS 38
Clasa basic_iostream
template <class E, class T = char_traits<E>>
class basic_iostream :
public basic_istream<E, T>,
public basic_ostream<E, T> {
public:
explicit basic_iostream(basic_streambuf<E, T>* sb);
virtual ~basic_iostream();
};
POO(C++) 2005-2006 Gh GRIGORAS 39
Fisierul header <iosfwd>
typedef basic_ios<char, char_traits<char> > ios;
typedef basic_istream<char, char_traits<char> > istream;
typedef basic_ostream<char, char_traits<char> > ostream;
typedef basic_iostream<char, char_traits<char> > iostream;
typedef basic_ifstream<char, char_traits<char> > ifstream;
typedef basic_ofstream<char, char_traits<char> > ofstream;
typedef basic_fstream<char, char_traits<char> > fstream;
POO(C++) 2005-2006 Gh GRIGORAS 40
Clasa ostream
Un obiect din ostream(flux de ieire) este un
mecanism pentru conversia valorilor de diverse
tipuri n secvene de caractere
n <iostream>:
ostream cout; //fluxul standard de iesire
ostream cerr; // mesaje eroare,fara buffer
ostream clog; // mesaje eroare,cu buffer
POO(C++) 2005-2006 Gh GRIGORAS 41
operator<< (n ostream)
basic_ostream& operator<< (const char *s);
basic_ostream& operator<< (char c);
basic_ostream& operator<< (bool n);
basic_ostream& operator<< (short n);
basic_ostream& operator<< (unsigned short n);
basic_ostream& operator<< (int n);
basic_ostream& operator<< (unsigned int n);
basic_ostream& operator<< (long n);
basic_ostream& operator<< (unsigned long n);
basic_ostream& operator<< (float n);
basic_ostream& operator<< (double n);
basic_ostream& operator<< (long double n);
basic_ostream& operator<< (void * n);
basic_ostream& put(E c); // scrie c
basic_ostream& write(E *p, streamsize n); // scrie p[0],,p[n-1]
basic_ostream& flush(); // goleste bufferul
pos_type tellp(); // pozitia curenta
basic_ostream& seekp(pos_type pos); // noua positie pos
basic_ostream& seekp(off_type off, ios_base::seek_dir way);
// pozitia way (= beg, cur, end) + off
POO(C++) 2005-2006 Gh GRIGORAS 42
Formatare, fiierul <iomanip>
void main()
{
int i = 10, j = 16, k = 24;
cout << i << '\t' << j << '\t' << k << endl;
cout << oct << i << '\t' << j << '\t' << k << endl;
cout << hex << i << '\t' << j << '\t' << k << endl;
cout << "Introdu 3 intregi: " << endl;
cin >> i >> hex >> j >> k;
cout << dec << 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 43
Manipulatori
MANIPULATOR EFECTUL FISIERUL
endl
Scrie newline iostream
ends
Scrie NULL in string iostream
flush
Goleste iostream
dec
Baza 10 iostream
hex
Baza 16 iostream
oct
Baza 8 iostream
ws
Ignor spaiile la intrare iostream
skipws
Ignor spaiile iostream
noskipws
Nu ignor spaiile iostream
showpoint
Se scrie punctul zecimal i zerourile iostream
noshowpoint
Nu se scriu zerourile, nici punctul iostream
showpos
Scrie + la numerele nenegative iostream
noshowpos
Nu scrie + la numerele nenegative iostream
boolalpha
Scrie true si false pentru bool iostream
noboolalpha
Scrie 1 si 0 pentru bool iostream
POO(C++) 2005-2006 Gh GRIGORAS 44
Manipulatori
MANIPULATOR EFECTUL FISIERUL
scientific
Notaia tiinific pentru numere reale iostream
fixed
Notaia punct fix pentru numere reale iostream
left
Aliniere stnga iostream
right
Aliniere dreapta iostream
internal
Caract. de umplere intre semn si valoare iostream
setw(int)
Seteaza dimensiunea cmpului iomanip
setfill(char c)
Caracterul c nlocuete blancurile iomanip
setbase(int)
Setarea bazei iomanip
setprecision(int)
Seteaza precizia in flotant iomanip
setiosflags(long)
Seteaza bitii pentru format iomanip
resetiosflags(long)
Reseteaza bitii pentru format iomanip
POO(C++) 2005-2006 Gh GRIGORAS 45
double a = 12.05, b = 11.25, c = -200.89;
cout << a << ',' << b << ',' << c << endl;
cout << setfill('*') << setprecision(3);
cout << setw(10) << a << endl;
cout << setw(10) << b << endl;
cout << setw(10) << c << endl;
cout << setw(10) << showpoint << c << endl;
cout << setfill(' ') << right << showpoint;
cout << setw(15) << setprecision(5)
<< c << endl;
cout << scientific << c << endl;
char d;
cin >> noskipws;
while(cin >>d)
cout << d;
12.05,11.25,-200.89
******12.1
******11.3
******-201
*****-201.
-200.89
-2.00890e+002
text pentru test
text pentru test
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; //fluxul standard de intrare
n basic_istream este definit operator>>
pentru tipurile fundamentale
POO(C++) 2005-2006 Gh GRIGORAS 47
Funcii utile n istream
streamsize gcount() const;
int_type get();
basic_istream& get(E& c);
basic_istream& get(E *s, streamsize n);
basic_istream& get(E *s, streamsize n, E delim);
basic_istream& get(basic_streambuf<E, T> *sb);
basic_istream& get(basic_streambuf<E, T> *sb, E delim);
basic_istream& getline(E *s, streamsize n);
basic_istream& getline(E *s, streamsize n, E delim);
basic_istream& ignore(streamsize n = 1,
int_type delim = T::eof());
int_type peek(); // citeste fara a-l extrage
basic_istream& read(E *s, streamsize n);
streamsize readsome(E *s, streamsize n); // peek cel mult n
basic_istream& putback(E c); // pune c in buferul de intrare
basic_istream& unget(); // pune inapoi ultimul citit
pos_type tellg();
basic_istream& seekg(pos_type pos);
basic_istream& seekg(off_type off, ios_base::seek_dir way);
int sync(); // flush input
POO(C++) 2005-2006 Gh GRIGORAS 48
Fiiere
ntr-un program C++ fluxurile standard cin,
cout, cerr, clog sunt disponibile;
corespondena lor cu dispozitivele (fiierele )
standard este fcut de sistem
Programatorul poate crea fluxuri proprii
obiecte ale clasei fstream (ifstream,
ofstream). Ataarea fluxului creat unui fiier
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 49
Fiiere
Constructorii clasei fstream:
explicit basic_fstream();
explicit basic_fstream(const char *s,
ios_base::openmode mode =
ios_base::in | ios_base::out);
Metode:
bool is_open() const;
void open(const char *s,
ios_base::openmode mode =
ios_base::in | ios_base::out);
void close();
POO(C++) 2005-2006 Gh GRIGORAS 50
Fiiere de intrare
Constructorii clasei ifstream:
explicit basic_ifstream();
explicit basic_ifstream(const char *s,
ios_base::openmode mode = ios_base::in);
Metode:
bool is_open() const;
void open(const char *s,
ios_base::openmode mode = ios_base::in);
void close();
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("file.cpp");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}else
cout << "Unable to open file";
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 51
POO(C++) 2005-2006 Gh GRIGORAS 52
Fiiere de ieire
Constructorii clasei ofstream:
explicit basic_ofstream();
explicit basic_ofstream(const char *s,
ios_base::openmode which =
ios_base::out | ios_base::trunc);
Metode:
bool is_open() const;
void open(const char *s,
ios_base::openmode mode =
ios_base::out | ios_base::trunc);
void close();
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile ("example.txt");
if (myfile.is_open()){
myfile << "This is a line.\n";
myfile << "This is another line.\n";
myfile.close();
}
else
cout << "Unable to open file";
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 53
POO(C++) 2005-2006 Gh GRIGORAS 54
ios_base::openmode
app, poziionare la sfrit nainte de fiecare
inserie
ate, poziionare la sfrit la deschiderea
fiierului
binary, citirea fiierului n mod binar i nu n
mod text
in, permite extragerea (fiier de intrare)
out, permite inseria (fiier de ieire)
trunc, trunchiaz un fiier existent la prima
creare a fluxului ce-l controleaz
POO(C++) 2005-2006 Gh GRIGORAS 55
Clasa stringstream
Permite ca stringurile s fie tratate ca fiiere:
explicit basic_stringstream(ios_base::openmode mode
= ios_base::in | ios_base::out);
explicit basic_stringstream(const
basic_string<E,T,A>& x, ios_base::openmode mode =
ios_base::in | ios_base::out);
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream s("This is initial string.");
// get string
string str = s.str();
cout << str << endl;
// output to string stream
s << "Numbers: " << 10 << " " << 123.2;
int i;
double d;
s >> str >> i >> d;
cout << str << " " << i << " " << d;
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 56
1
POO
Modelare II
D. Lucanu POO Principii 2
Cuprins
UML
diagrame de clase (continuare)
cum modelam in UML
cum implementam in C++
diagrame de secventa (comunicare)
diagrame de activitate
Ce am facut cursul trecut (Modelare I)
clase




ierarhii


relatii de asociere
D. Lucanu POO Principii 3
Relatia de agregare (compunere)
arata cum obiectele mai mari sunt compuse din
obiecte mai mici
poate fi privita si ca o relatie de asociere speciala
exista doua tipuri de agregare
agregare slaba (romb neumplut), cand o
componenta poate apartine la mai multe agregate
(obiecte compuse)
agregare tare (romb umplut cu negru), cand o
componenta poate apartine la cel mult un agregat
(obiect compus)
D. Lucanu POO Principii 4
Relatia de agregare tare
D. Lucanu POO Principii 5
relatia de agregare
tare (compunere)
un contact apartine la
o singura agenda;
stergere agenda =>
stergere contact
o agenda poate avea
zero sau mai multe
contacte
Relatia de agregare (slaba)
D. Lucanu POO Principii 6
relatia de agregare
(slaba)
un contact apartine la
una sau mai multe
agende; un contact
poate exista si dupa
stergere agendei
o agenda poate avea
zero sau mai multe
contacte
Relatia de agregare in C++
agregare tare (compunere)
class Agenda {
private:
Contact contacts[MAX];
};


agregare (slaba)
class Agenda {
private:
Contact *contacts[MAX];
};



D. Lucanu POO Principii 7
container de obiecte
Contact (aici tablou)
container de referinte la
obiecte Contact (aici
tablou de pointeri)
Containere STL
sunt cele mai potrivite pentru implementarea relatiei
de agregare
aici vom exemplifica numai utilizarea listelor in
proiectul Agenda
mai multe despre STL se vor face in partea a doua
cursului
D. Lucanu POO Principii 8
D. Lucanu STL Partea 1 9
Containere STL
container = un obiect care contine alte obiecte
(componentele) si are metode de accesare a
componentelor
fiecare container are asociat un tip iterator cu ajutorul
caruia se "merge" prin container
Container
Componenta
Iterator
1
*
1 0..*
D. Lucanu STL Partea 1 10
Contactele ca liste STL in Agenda
agregare tare (compunere)
#include <list>
...
class Agenda {
private:
list<Contact> contacts;
};
agregare (slaba)
#include <list>
...
class Agenda {
private:
list<Contact*> contacts;
};
header pt. listele STL
liste in care componentele
sunt pointeri la obiecte
Contact
liste in care componentele
sunt obiecte Contact
Operatii asupra agendei - declaratie
class Agenda
{
private:
list<Contact*> contacts;
public:
void AddContact(Contact *newContact);
public:
void display();
public:
list<Contact*>::iterator findName(char *newName);
...
};
D. Lucanu POO Principii 11
adauga un contact
afiseaza agenda
cauta un contact dupa un criteriu
acest exemplu arata
numai cum sunt
utilizate listele STL
Adaugarea unui contact si afisare ag.
void Agenda::AddContact(Contact *newContact)
{
contacts.push_back(newContact);
}


void Agenda::display()
{
list<Contact*>::iterator i;
for (i = contacts.begin(); i != contacts.end(); ++i)
cout << (*i)->toString() << endl;
}

D. Lucanu POO Principii 12
insereaza un element
la sfarsitul listei
declarare iterator cu care se
refera componentele listei;
utilizarea lor e similara cu
cea a pointerilor
schema de parcurgere a
unei liste
referirea unei componente a
listei cu ajutorul iteratorului
Cautarea in agenda
ar trebui sa permita cautarea dupa mai multe criterii
... ihm, cam complicat ...
mai bine cautam prin documentatia STL sa vedem
daca gasim ceva
D. Lucanu POO Principii 13
Din documentatia STL
find_if
Category: algorithms
Prototype
template<class InputIterator, class Predicate>
InputIterator find_if(InputIterator first,
InputIterator last,
Predicate pred);
Description
Returns the first iterator i in the range [first, last) such
that pred(*i) is true.
Returns last if no such iterator exists.
Definition Defined in the standard header algorithm
D. Lucanu POO Principii 14
aha!
Cautarea dupa nume
class Agenda {
...
private: static string buffer;
private:
static bool eqName(Contact *contact) {
return contact->getName() == buffer;
}
};
list<Contact*>::iterator
Agenda::findName(char *newName) {
buffer = string(newName);
return find_if(contacts.begin(),
contacts.end(), Agenda::eqName);
}
D. Lucanu POO Principii 15
declarare data
membra statica declarare functie
membra statica
(criteriul de cautare)
apel functie
statica
functia de cautare
intoarce un iterator
D. Lucanu POO Principii 16
C++ intermezzo
membri statici
pot fi date (variabile) sau functii
variabilele statice sunt numite variabile de clasa
deoarece au valoare unica pentru toate obiectele
clasei; au un rol asemantor cu cel al vriabilelor
globale, dar se bucura doar de domeniul de
vizibilitate al clasei
functiile statice pot, eventual, accesa numai
variabile statice (nu pot avea acces la starea
particulara a unui obiect)
D. Lucanu POO Principii 17
C++ intermezzo
membri statici - exemplu
o variabila care memoreaza numarul de obiecte
create trebuie sa fie unica pentru toate obiectele
clasei => variabila statica



D. Lucanu POO Principii 18
class Bare
{
private:
static int n;
public:
Bare () { n++; };
~Bare () { n--; };
static int getN()
{ return n; }
};

int Bare::n=0;
int main () {
Bare a;
Bare b[5];
Bare * c = new Bare;
cout << a.getN() << endl;
delete c;
cout << Bare::getN()
<< endl;
return 0;
}
7
6
notatii
echivalente
notatii
echivalente
variabila unica pt
toate ob. clasei
initializare variabila
statica
Componente si relatii de dependenta
D. Lucanu POO Principii 19
componenta
relatie de
dependenta
D. Lucanu POO Proiectarea de clase 20
Principiul de inversare a dependentelor
A. Modulele de nivel inalt nu trebuie sa depinda de
modulele de nivel jos. Amandoua trebuie sa depinda
de abstractii.

B. Abstractiile nu trebuie sa depinda de detalii.
Detaliile trebuie sa depinda de abstractii.

programele OO bine proiectate inverseaza
dependenta structurala de la metoda procedurala
traditionala
metoda procedurala: o procedura de nivel inalt
apeleaza o procedura de nivel jos, deci depinde
de ea
Principiul de inversare a dependentelor
D. Lucanu POO Principii 21
Agenda nu trebuie sa depinda de
modul particular de definire a
contactelor (prieteni, colegi, amici ...);
toate depind de abstractia Contact
Princip. de inversare a dependentelor si MVC
D. Lucanu POO Principii 22
Elimina dilema oul sau gaina
pentru view si controller
Elimina dilema oul sau gaina
pentru view si controller
Princip. de inversare a dependentelor si MVC
Ce include clasa abstracta View?
orice fereastra are display-boxuri, edit-boxuri,
meniuri ... => o metoda create() (virtuala pura)
elementele display-box pot fi actualizate => o
metoda update() (vida - de ce?)
elementele ferestrei trebuie afisate => o metoda
display() (virtuala pura), care va fi resp. si cu
treansmiterea evenimentelor catre controller
Ce va inlcude clasa abstracta Controller?
doar implementarea relatiei de asociere
D. Lucanu POO Principii 23
Clasele View si Controller revizuite
class View
{
public:
virtual void create() = 0; // pure virtual method
virtual void update() {}; // empty method
virtual bool display() = 0; // pure virtual method
};
class Controller
{
protected:
View *view;
public:
void setView(View *newView);
};
D. Lucanu POO Principii 24
doar implementarea
relatiei de asociere
Clasa ViewAgenda revizuita
class ViewAgenda : public View
{
private:
Agenda *model;
ControllerAgenda *controller;
DisplayBox<string> dbOwner;
Menu menu;
public:
ViewAgenda(ControllerAgenda *newController,
Agenda *newModel);
void create();
void update();
bool display();
};
D. Lucanu POO Principii 25
noile relatii de asociere
continut fereastra
implementarea operatiilor
din clasa abstracta
Metodele create() si update()
void ViewAgenda::create()
{
menu.addOption("1. Afiseaza");
menu.addOption("0. Exit");
dbOwner.setLabel("Proprietar");
}

void ViewAgenda:: update()
{
dbOwner.setValue(model->getOwner());
}
D. Lucanu POO Principii 26
construire meniu
display-box
actualizarea singurului display-box
Metoda display() revizuita
bool display()
{
cout << "*** Agenda view ***" << endl;
update();
dbOwner.display();
menu.display();
if ((option = menu.getOption()) != 0)
{
controller->listen(option);
return true;
}
else
return false;
}
D. Lucanu POO Principii 27
transmitere eveniment
preluat de la utilizator
catre controller
indica sfarsitul rolului acestui
view
Clasa ControllerAgenda revizuita
class ControllerAgenda : public Controller
{
private:
Agenda *model;
public:
ControllerAgenda(Agenda *newModel);
void listen(int option);
void finish();
};
D. Lucanu POO Principii 28
acum are ca parametru mesajul
primit de la viewer
intermezz0
Inainte de a vedea implementarea revizuita a
metodei listen(), aruncam o privire asupra altei
instante MVC (functionalitatea Contact)
celelalte instante vor fi implementate asemanator
D. Lucanu POO Principii 29
Functionalitatea pt. un contact
D. Lucanu POO Principii 30
Depoarece toate instantele sunt similare,
de ce sa nu definim o clasa MVC?
Clasa MVC
template <class M, class V, class C>
class Mvc
{
private:
C *c; V *v; M *m;
public:
Mvc(M *newM = 0)
{
m = newM;
c = new C(m);
v = new V(c, m);
c->setView(v);
}
D. Lucanu POO Principii 31
public:
~Mvc()
{
delete c;
delete v;
}

void run()
{
while (v->display())
{
//nothing
}
}
};
Modelul, View-ul si
Controllerul sunt parametri
Crearea
componetelor
si a relatiilor
eliberare
memorie
metoda
responsabila cu
executia
controllerului
afisarea viewerului este
suficient pentru a declansa
comunic. intre obiecte
Metoda ControllerAgenda::listen()
void ControllerAgenda::listen(int option)
{
Mvc<Contact, ViewContact, ControllerContact>
mvcContact(model->getContact());
switch (option)
{
...
case 1:
mvcContact.run();
break;
...
}
}
D. Lucanu POO Principii 32
creare instanta MVC
pentru functionalitatea
ce refera un contact
executie instanta MVC
D. Lucanu POO Principii 33
Diagrame de comunicare
la inceput au fost numite diagrame de colaborare
se focalizeaza pe interactiunea dintre obiecte
pot fi utilizate pentru a descrie cum sunt
implementate digramele cazurilor de utilizare
din pacate ArgoUML are suport slab pentru
diagramele de counicare si de aceea ne vom ocupa
de diagramele de secventa
o diagrama de comunicare poate fi generata
automat dintr-o diagrama de secenta si reciproc
... asa ca nu pierdem foarte mult daca facem numai
digramele de secventa
D. Lucanu POO Principii 34
Diagrame de secventa
arata interactiunea dintre obiecte
obiectele sunt reprezentate ca linii ale vietii care
merg de sus catre josul paginii
interactiunile sunt reprezentate ca mesaje trasate
sub forma de sageti de la linia vietii sursa la linia
vietii destinatie
arata cum obiectele comunica unele cu altele,
punand in evidenta mesajele presupuse de aceste
comunicari
nu sunt recomandate pentru reprezentarea unor
logici procedurale complexe
D. Lucanu POO Principii 35
Diagrame de secventa
D. Lucanu POO Principii 36
D. Lucanu POO Principii 37
Diagrame de activitate
afiseaza secvente de activitati
o diagrama de activitate arata fluxul de lucru de la un
punct de start la unul final, evidentiind caile
decizionale luate in functie de evenimentele si
activitatile in progres
sunt utile in modelarea domeniului problemei
(business modeling)
D. Lucanu POO Principii 38
Diagrama de activitate
D. Lucanu POO Principii 39
activitate
stare de start
punct de decizie
punct de combinare
stare de
sfarsit (finala)
conditie
Diagrama de activitate
D. Lucanu POO Principii 40
activitati
concurente
activitati
concurente
start activitati
concurente (fork)
sfarsit activitati
concurente (joint)
Plan
Polimorfism
suprascriere -> legare static
exemplu
funcii virtuale -> legare dinamic
exemplu
static_cast, dinamic_cast
Operatorul typeid
POO(C++) 2005-2006 Gh GRIGORAS 1
Polimorfism - suprascriere
Legare static: asocierea apel funcie --
corp(implementare) funcie se face nainte de execuia
programului (early binding) la compilare
POO(C++) 2005-2006 Gh GRIGORAS 2
Polimorfism - suprascriere
persoanele, studenii, profesorii au abilitatea de a semna:
class Persoana {
public:
//
string getNume() const;
void semneaza();
protected:
string id;
string nume;
};
class Student:public Persoana {
//
void semneaza();
}
class Profesor:public Persoana {
//
void semneaza();
}
POO(C++) 2005-2006 Gh GRIGORAS 3
Polimorfism - suprascriere
fiecare semneaz in felul su:
void Persoana::semneaza()
{
cout << getNume() << endl;
}
void Student::semneaza()
{
cout << "Student " << getNume() << endl;
}
void Profesor::semneaza()
{
cout << "Profesor " << getNume() << endl;
}
POO(C++) 2005-2006 Gh GRIGORAS 4
Polimorfism - suprascriere
Exemplu:
Persoana pers("1001","Popescu Ion");
Student stud("1002", "Angelescu Sorin");
Profesor prof("1003","Marinescu Pavel");
pers.semneaza();
stud.semneaza();
prof.semneaza();
Popescu Ion
Student Angelescu Sorin
Profesor Marinescu Pavel
POO(C++) 2005-2006 Gh GRIGORAS 5
Polimorfism - suprascriere
Exemplu:
// studentul poate semna ca persoana
stud.Persoana::semneaza();
// ... si profesorul poate semna ca persoana
prof.Persoana::semneaza();
Angelescu Sorin
Marinescu Pavel
POO(C++) 2005-2006 Gh GRIGORAS 6
Polimorfism - suprascriere
Suprascriere -> legare static ( asocierea apel
funcie implementare se face la compilare):
void semneaza(Persoana& p)
{
p.semneaza();
};
semneaza(pers);
semneaza(stud);// &stud poate inlocui &p
semneaza(prof);// &prof poate inlocui &p
Popescu Ion
Angelescu Sorin
Marinescu Pavel
POO(C++) 2005-2006 Gh GRIGORAS 7
Polimorfism - Funcii virtuale
Legare dinamic: asocierea apel funcie --
corp(implementare) funcie se face la
execuia programului (late binding, run-
time binding), pe baza tipului obiectului
cruia i se transmite funcia ca mesaj. n
acest caz, funcia se zice polimorf
POO(C++) 2005-2006 Gh GRIGORAS 8
Implementare polimorfism n C++:
Declaraia funciei n clasa de baz precedat de
cuvntul virtual
class Persoana {
public:
//
virtual void semneaza();
//
};
O funcie virtual pentru clasa de baz rmne
virtual pentru clasele derivate. La redefinirea
unei funcii virtuale n clasa derivat (overriding)
nu e nevoie din nou de specificarea virtual
POO(C++) 2005-2006 Gh GRIGORAS 9
Polimorfism funcii virtuale
Polimorfism funcii virtuale-> legare dinamic:
Persoana pers("1001","Popescu Ion");
Student stud("1002", "Angelescu Sorin");
Profesor prof("1003","Marinescu Pavel");
pers.semneaza();
stud.semneaza();
prof.semneaza();
semneaza(pers);
semneaza(stud);
semneaza(prof);
Popescu Ion
Student Angelescu Sorin
Profesor Marinescu Pavel
Popescu Ion
Student Angelescu Sorin
Profesor Marinescu Pavel
POO(C++) 2005-2006 Gh GRIGORAS 10
Implementare polimorfism n C++:
Compilatorul creeaz o tabel - VTABLE - pentru
fiecare clas care conine funcii virtuale; adresele
tuturor funciilor virtuale sunt plasate n aceast
tabel. Sistemul creeaz un pointer VPTR n
fiecare clas cu funcii virtuale; el pointeaz la
aceast tabel i alege funcia corect la un apel
polimorfic
std::cout << sizeof(pers);
Se obine:
32 dac funcia semneaza() nu este virtual
36 dac funcia semneaza() este virtual
POO(C++) 2005-2006 Gh GRIGORAS 11
Implementare polimorfism n C++:
POO(C++) 2005-2006 Gh GRIGORAS 12
Implementare polimorfism n C++:
Un constructor nu poate fi virtual
Un destructor poate fi virtual; destructorii
claselor derivate ar trebui s fie virtuali;
asta asigur apelul lor la distrugerea cu
delete a pointerilor la clasa de baz
POO(C++) 2005-2006 Gh GRIGORAS 13
Destructor virtual
class A{
public:
A(){p = new char[5];}
~A(){delete [] p;}
protected:
char* p;
};
class D:public A{
public:
D(){q = new char[500];}
~D(){delete [] q;}
protected
char* q;
};
void f(){
A* pA;
pA = new D();
//
delete pA;// doar apel ~A()
}
void main(){
for(int i = 0; i<9; i++)
f();
}
// pentru a se apela si ~D()
// se declara virtual ~A(){}
POO(C++) 2005-2006 Gh GRIGORAS 14
Clase abstracte
Reprezentarea unor concepte abstracte: figur (geometric),
form, etc.
class Shape{
public:
virtual void rotate(int) {error(Shape::rotate);}
virtual void draw() {error(Shape::drow);}
//
};
Nu pot fi instaniate astfel de clase; nu pot exista obiecte
abstracte
Alternativa: declararea funciilor virtuale ca funcii virtuale
pure:
class Shape{
public:
virtual void rotate(int) = 0;
virtual void draw() = 0;
//
};
O clas abstract este o interfa
POO(C++) 2005-2006 Gh GRIGORAS 15
Operator virtual
class Q
{
protected:
int p,q;
public:
Q (int m=0, int n=1) { p=m;q=n; }
virtual Q operator* (Q& r) {
return Q(p*r.p,q*r.q);
}
Q& operator*= (Q& r) {
return *this=*this *r;
}
void write(char* s) {
cout << s << p << "/" << q;
}
};
POO(C++) 2005-2006 Gh GRIGORAS 16
Operator virtual
class F : public Q
{
public:
F (int m=0, int n=1) : Q (m,n) { }
Q operator* (Q& r)
{
Q f = Q(*this) * r;
this->write("");
r.write(" *");
f.write(" = ");
cout << endl;
return f;
}
};
POO(C++) 2005-2006 Gh GRIGORAS 17
Operator virtual
void main (void)
{
F a(2,3), b(4,5);
Q d;
a.write(" a = ");
cout << endl;
b.write(" b = ");
cout << endl;
d=a*b;
d.write(" d = ");
cout << endl;
d= a *= b ;
d.write(" d = ");
cout << endl;
}
POO(C++) 2005-2006 Gh GRIGORAS 18
Clase de baz abstracte
Clas de baz abstract: o clas ce are cel
puin o funcie virtual pur ( = 0):
class ABC{
public:
virtual void m1() = 0;
//
};
Iniializarea unei metode virtuale cu zero
este o convenie sintactic: specificarea
unei clasei abstracte ce nu poate fi
instaniat
POO(C++) 2005-2006 Gh GRIGORAS 19
Clase de baz abstracte
Clasele derivate din clase abstracte trebuie s
defineasc toate metodele virtuale pure - override
- altfel devin ele nsele abstracte
O clas abstract poate s aib i ali membri (ce
se motenesc)
Numai o metod virtual poate fi pur
O clas abstract poate fi folosit n sisteme mari
pentru a specifica cerinele de proiectare.
POO(C++) 2005-2006 Gh GRIGORAS 20
Clase de baz abstracte - Exemplu
class figura{
public:
virtual void read_figure ()=0;
virtual void compute_area ();
virtual void compute_perim ();
virtual void display_fig ();
protected:
double area;
double perimeter;
};
class cerc : public figura //cercul este o figura
{
public:
void read_figure ();
void compute_area ();
void compute_perim ();
void display_fig ();
private:
double radius;
};
POO(C++) 2005-2006 Gh GRIGORAS 21
Clase de baz abstracte - Exemplu
// FILE: figura.cpp
#include figura.h"
//
void figura::compute_perim()
{perimeter = 0.0;}
void figura::compute_area()
{area = 0.0;}
void figura::display_fig (){
cout << "Aria este " << area << endl;
cout << "Perimetrul este " << perimeter << endl;
}
POO(C++) 2005-2006 Gh GRIGORAS 22
Clase de baz abstracte - Exemplu
// FILE: cerc.cpp
// IMPLEMENTAREA CLASEI cerc
#include "cerc.h
//
const double pi = 3.1415927;
void cerc::read_figure (){
cout << Raza > ";
cin >> radius;
}
void cerc::compute_perim (){
perimeter= 2.0 * pi * radius;
}
void cerc::compute_area (){
area = pi * radius * radius;
}
void cerc::display_fig (){
cout << "Figura este cerc" << endl;
cout << "Raza cercului este" << radius << endl;
figura::display_fig ();
}
POO(C++) 2005-2006 Gh GRIGORAS 23
Clase de baz abstracte - Exemplu
void main(){
figura* get_figure ();//Alegerea unei figuri
void process_figure(figura&);
figura* my_fig; // pointer la o figura
// Se proceseaza figurile alese
for (my_fig = get_figure (); my_fig != 0; my_fig =
get_figure ()) {
process_figure (*my_fig);
delete my_fig; // se elibereaza memoria
}
}
// PROCESAREA UNEI FIGURI
void process_figure(figura& fig){
fig.read_figure ();
fig.compute_area ();
fig.compute_perim ();
fig.display_fig ();
}
POO(C++) 2005-2006 Gh GRIGORAS 24
Type Casting
Conversia unei expresii de tip dat ntr-un alt tip
Conversie implicit: existena unui constructor
de conversie
class A {};
class B { public: B (A a) {} };
A a; B b=a;
Conversie explicit
b = (int) a;
CDummy d; CAddition * padd;
padd = (CAddition*) &d;
POO(C++) 2005-2006 Gh GRIGORAS 25
Type Casting
Conversia explicit permite conversia de la un pointer al
unei clase la un pointer al altei clase(chiar fr legtur
ntre ele) dar utilizarea sub aceast form poate
conduce la erori la execuie sau la rezultate imprevizibile
Pentru controlul acestor conversii ntre clase s-au
introdus operatorii:
dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)
POO(C++) 2005-2006 Gh GRIGORAS 26
dynamic_cast
Se poate folosi doar cu pointeri i referine
Asigur faptul c rezultatul conversiei este un obiect
valid, complet, al clasei cerute
Este ok conversia de la pointer al clasei derivate la
pointer al clasei de baz
Conversia de la pointer al clasei de baz la pointer al
clasei derivate este permis doar n prezena
polimorfismului
class CBase { };
class CDerived: public CBase { };
CBase b; CBase* pb;
CDerived d; CDerived* pd;
pb = dynamic_cast<CBase*>(&d);
// ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);
// wrong: base-to-derived
POO(C++) 2005-2006 Gh GRIGORAS 27
dynamic_cast
n cazul polimorfismului dynamic_cast produce o verificare la
momentul execuiei pentru a se asigura c expresia conduce la
un obiect valid; altfel se returneaz pointerul nul
class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };
int main () {
try {
CBase * pba = new CDerived;
CBase * pbb = new CBase;
CDerived * pd;
pd = dynamic_cast<CDerived*>(pba);
if (pd==0) cout << "Null pointer on first type-cast" << endl;
pd = dynamic_cast<CDerived*>(pbb);
if (pd==0) cout << "Null pointer on second type-cast" << endl;
} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 28
dynamic_cast
Deosebirea ntre pointerii(la clasa de baz) pba i pbb
Dac nu se poate face conversia, se returneaz
pointerul nul
(cazul pd = dynamic_cast<CDerived*>(pbb);)
Dac dynamic_cast este folosit pentru conversia la
un tip referin i conversia nu este posibil, este
aruncat o excepie de tip bad_cast.
POO(C++) 2005-2006 Gh GRIGORAS 29
POO(C++) 2005-2006 Gh GRIGORAS 30
dynamic_cast
std::vector<Figura*> v[20];
//
int nrCercuri = 0;
int nrDrept = 0;
for (i=0; i< v.size(); i++)
{
if (dynamic_cast<Cerc*>(v[i])){
v[i]->arie();
nrCercuri++;
}
if (dynamic_cast<Dreptunghi*>(v[i])){
v[i]->arie();
nrDrept++;
}
}
static_cast
static_cast poate face conversii ntre pointeri dar
nu se face verificarea dac conversia este corect,
programatorul trebuie s se asigure de acest lucru, altfel
rezultatele pot fi imprevizibile (dac nu se obin erori la
dereferenierea pointerilor rezultai)
class CBase {};
class CDerived: public CBase {};
CBase *a = new CBase;
CDerived *b = static_cast<CDerived*>(a);
static_cast poate fi folosit pentru orice alt fel de conversie
inclusiv pentru tipurile fundamentale:
double d=3.14159265;
int i = static_cast<int>(d);
POO(C++) 2005-2006 Gh GRIGORAS 31
reinterpret_cast
reinterpret_cast convertete un pointer la
un tip la un pointer la alt tip chiar dac clasele
sunt incompatibile. Conversia se face prin simpla
copiere a valorii binare; nu se face nici o verificare
asupra coninutului pointat
Se poate face i conversie de la pointer (la un tip)
la tipul ntreg, cu singura garanie c acesta, dac
a fost memorat n ntregime, poate fi reconvertit
la pointer
POO(C++) 2005-2006 Gh GRIGORAS 32
const_cast
Este legat de atributul const al obiectelor; poate fi folosit
pentru a transmite un argument const la o funcie ce nu are
parametru const:
// const_cast
#include <iostream>
using namespace std;
void print (char * str)
{
cout << str << endl;
}
int main () {
const char * c = exemplu ";
print ( const_cast<char *> (c) );
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 33
POO(C++) 2005-2006 Gh GRIGORAS 34
Operatorul typeid
Operatorul typeid permite determinarea tipului unui obiect
la momentul execuiei
Syntaxa
typeid( type-id )
typeid( expresie )
Rezultatul este referin la un obiect al clasei type_info
(fiierul <typeinfo> )
Dac se aplic la un type-id atunci returneaz o referin la
type_info ce reprezint numele tipului(type-id)
Dac se aplic la o expresie atunci rezultatul este referin la
type_info ce reprezint tipul obiectului denotat de
expresie
POO(C++) 2005-2006 Gh GRIGORAS 35
Operatorul typeid
Clasa type_info descrie informaii relative
la tip; acestea sunt generate de compilator.
Obiectele clasei conin un pointer la char -
numele tipului:
class type_info {
public:
virtual ~type_info();
int operator==(const type_info& rhs) const;
int operator!=(const type_info& rhs) const;
const char* name() const;
//..
private:
//...
};
Exemplu
// typeid
#include <iostream>
#include <typeinfo>
using namespace std;
int main () {
int *a,b;
a=0; b=0;
if (typeid(a) != typeid(b))
{
cout << "a and b are of different types:\n";
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
}
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 36
// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;
class CBase { virtual void f(){} };
class CDerived : public CBase {};
int main () {
try {
CBase* a = new CBase;
CBase* b = new CDerived;
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
cout << "*a is: " << typeid(*a).name() << '\n';
cout << "*b is: " << typeid(*b).name() << '\n';
} catch (exception& e) { cout << "Exception: " <<
e.what() << endl; }
return 0;
}
POO(C++) 2005-2006 Gh GRIGORAS 37
POO(C++) 2005-2006 Gh GRIGORAS 38
Operatorul typeid
#include <typeinfo>
// utilizarea metodei type_info::typeid()
//si static_cast<T>(exp) in loc de virtual
double f(RxR *pa)
{
if (typeid(*pa) == typeid(RxR))
return static_cast<RxR *>(pa)->modul();
if (typeid(*pa) == typeid(RxRxR))
return static_cast<RxRxR *>(pa)->modul();
return 0.0;
}
STL - plan
Coninutul STL
Containere clasificare
Iteratori clasificare
Operaii de baz
vector: declarare, acces, iteratori, inserri,
tergeri, comparri
deque
list
map, multimap
set, multiset
bitset
Coninutul STL
Containere: obiecte ce conin alte obiecte
Iteratori: pointeri pentru parcurgerea
containerelor
Algoritmi generici: funcii ce se aplic
diverselor tipuri de containere
Clase adaptor: clase ce adapteaz alte clase
(variaii ale altor containere)
Alocatori: obiecte responsabile cu alocarea
spaiului
Toate componentele stl sunt template-uri
Containere secvene
clase template ce implementeaz structuri de
date n care memoria este organizat secvenial
suport accesul secvenial la componente
n unele cazuri acces aleator
vector<T> : fiierul header <vector>
suport acces aleator la elemente
timp constant pentru inserie i eliminarea
componentelor de la sfrit
timp liniar pentru inserarea i eliminarea
elementelor de la nceput i interior
lungime variabil
Containere secvene
deque<T>: fiierul header <deque>
suport acces (inserare i eliminare) la ambele
capete
lungime variabil
list<T> : fiierul header <deque>
suport parcurgerea n ambele sensuri
timp constant (amortizat) pentru inserie i
eliminare la nceput, la sfrit sau n interior
lungime variabil
Clase adaptor
sunt simple variaii ale containerelor secvene
clase care nu suport iteratori
stack<T> <stack>
LIFO (last in, first out)
queue<T> <queue>
FIFO (first in, first out)
priority_queue<T> <queue>
obiectul cu valoare maxim este totdeauna primul
n coad
Containere asociative
map<T> : <map>
componentele sunt perechi <cheie, dat> cu cheie
unic (nu exist dou date cu aceeai cheie)
multimap<T>: <map>
componentele sunt perechi <cheie, dat> cu cheie
multipl(pot exista mai multe date cu aceeai cheie)
set<T>: <set>
componentele sunt doar de tip cheie i NU pot exista
n duplicat
multiset<T>: <set>
componentele sunt doar de tip cheie i POT exista n
duplicat
Tipuri asociate containerului X
X::value_type
tipul obiectului memorat in container
X::allocator_type
tipul managerului de memorie
X::size_type
tip pentru indici, numr de elemente etc.
X::iterator
tip pentru iterator cu care se parcurge containerul
Accesul la elementele containerului
c.front()
primul element
c.back()
ultimul element
c[i] //(nu pentru liste)
al i-lea element din secven (NU se valideaz
valoarea lui i)
c.at(i) //(nu pentru liste)
al i-lea element din secvent (SE valideaz valoarea
lui i)
Operaii de tip list
c.insert(p, x)
insereaz x inaintea lui p
c.insert(p, n, x)
insereaz n copii ale lui x naintea lui p
c.insert(p, first, last)
adaug elementele din *first, last) naintea lui p
c.erase(p)
elimin de la p
c.erase(first, last)
elimin elementele din *first, last)
c.clear()
elimin toate elementele
Operaii de tip stiv i coad
c.push_back(x)
insereaz x la sfrit
c.pop_back()
elimin de la sfrit
c.push_front(x)
insereaz x la nceput
c.pop_front()
elimin de la nceput
Funcii utile
c.size() // numrul de elemente
c.empty() // este c vid?
c.capacity() // (numai pentru vector) spaiul alocat
c.reserve(n) // (numai pentru vector) aloc spaiu
c.resize() // (numai pentru vector) adaug elemente la
// sfrit
max_size() // (numai pentru vector) dimcelui mai mare
// vector posibil
swap(c1, c2) // intershimb coninuturile a 2 containere
== // testul de egalitate
!= // testul diferit
< // relaia de ordine lexicografic
Iteratori
Iterator: abstracie a noiunii de pointer la un element din
secven
obiect ce poate naviga printr-un container
operatorii de derefereniere * i -> permit accesul la obiectul
curent
operatorul ++ (--) permite accesul la obiectul urmtor
(precedent)
operatorul ==
Un iterator se declar n asociaie cu un tip anume de
container, este implementat relativ la acel tip dar acest
lucru nu este relevant pentru utilizator
Fiecare container include funciile membru begin(),
end() pentru specificarea valorilor iterator
corespunztoare primului, respectiv primului dup ultimul
obiect din container
n mod analog pentru explorare reverse: rbegin(),
rend()
Clasificarea iteratorilor
Categoria Output Input Forward Bidirectional Random
Abreviere Out In For Bi Ran
Citire =*p =*p =*p =*p
Acces -> -> -> -> [ ]
Scriere *p= *p= *p= *p=
Iteraie ++ ++ ++ ++ -- ++ -- + - += -+
Comparare == !== == !== == !== == !== < > < = >=
Exist 5 categorii de iteratori iar pentru fiecare
categorie sunt definii operatori specifici pentru citire
(atribuirea obiect = *iterator), scriere(atribuirea
*iterator= obiect), acces, iteraie, comparare.
Containerul vector
se comport ca un tablou alocat dinamic,
suport realocare dinamic la execuie
Constructori:
vector<T> V; //empty vector
vector<T> V(n,value); //n copii din value
vector<T> V(n); //n copii din default pt. T
clasa are definii constructorul de copiere i
operatorul de atribuire
Containerul vector
Declarare: vector<int> iVector;
vector<int> jVector(100);
cin >> Size;
vector<int> kVector(Size);
vector<int> v = vector<int>(100);
vector<int> vv = v;
Acces la elemente: jVector[23] = 71;
int temp = jVector[41];
cout << jVector.at(23) << endl;
int jFront = jVector.front();
int jBack = jVector.back();
Informaii: cout << jVector.size();
cout << jVector.capacity();
cout << jVector.max_capacity();
if ( jVector.empty() ) //. . .
[ ] vs. at()
int MaxCount = 100;
vector<int> iVector(MaxCount);
for (int Count = 0; Count < 2*MaxCount; Count++) {
cout << iVector[Count];
}
int MaxCount = 100;
vector<int> iVector(MaxCount);
for (int Count = 0; Count < 2*MaxCount; Count++) {
cout << iVector.at(Count);
}
Utilizare iteratori
string DigitString = "45658228458720501289";
vector<int> BigInt;
for (int i = 0; i < DigitString.length(); i++) {
BigInt.push_back(DigitString.at(i) - '0');
// push_back asigura redimensionarea vectorului
}
vector<int> Copy;
vector<int>::iterator It = BigInt.begin();
while ( It != BigInt.end() ) {
Copy.push_back(*It);
It++;
}
Utilizare iteratori
vector<int>::iterator It;
It = BigInt.begin(); // primul element
int FirstElement = *It; // copiere primul element
It++; // al doilea element
It = BigInt.end();
// It pointeaz n afara vectorului
// dereferenierea !!
It--; // inapoi, la ultimul element
int LastElement = *It; // ok
Utilizare iteratori
// vector::rbegin/rend
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector<int> myvector;
for (int i=1; i<=5; i++) myvector.push_back(i);
cout << "myvector:";
vector<int>::reverse_iterator rit;
for ( rit=myvector.rbegin() ; rit < myvector.rend(); ++rit )
cout << " " << *rit;
cout << endl;
return 0;
}
//myvector: 5 4 3 2 1
Inserare n vector
Se poate seta dimensiunea minim n a
vectorului v prin v.reserve(n)
Inserarea la sfrit folosind push_back()
este eficient
dac inseria se face cnd vectorul este plin, se
realoc spaiu
pop_back() elimin ultimul element
Inserarea ntr-o poziie intermediar necesit
iftarea elementelor urmtoare
Inserare la o anume poziie
vector<int> Y;
for (int m = 0; m < 20; m++) {
Y.insert(Y.begin(), m);
cout << setw(3) << m
<< setw(5) << Y.capacity()
<< endl;
}
Y.insert(Y.begin()+4, 40);
Y.insert(Y.end()-3, 30);
for (int m = 0; m < 20; m++) {
cout << setw(3) << m
<< setw(5) << Y.at(m)
<< endl;
}
0 1
1 2
2 3
3 4
4 6
5 6
6 9
7 9
8 9
9 13
10 13
11 13
12 13
13 19
14 19
15 19
16 19
17 19
18 19
19 28
Se utilizeaz un iterator i funcia
insert()
0 19
1 18
2 17
3 16
4 40
5 15
6 14
7 13
8 12
9 11
10 10
11 9
12 8
13 7
14 6
15 5
16 4
17 3
18 30
19 2
20 1
21 2
Eliminarea elementelor
de la sfrit: V.pop_back()
de la o poziie It (cu iftare): V.erase(It)
Iteratorii care refer elemente ce urmeaz punctului n
care s-a eliminat sunt invalidai:
vector<int> V=Y;
vector<int>::iterator j;
j = V.begin();
while (j != V.end())
V.erase(j++);
Expression: vector iterator incompatible
vector<int>::iterator j=V.begin();
V.erase(j+10);
V.erase(j+2,j+5);
Alte funcii
==
doi vectori v1 i v2 sunt egali dac v1.size() =
v2.size() i v1[k] = v2[k] pentru orice index valid k.
<
v1<v2 dac
primul element v1[i] care nu este egal cu v2[i] este mai
mic dect v2[i], sau
v1[size] < v2[size] i fiecare v1[i] este egal cu v2[i]
analog sunt definii operatorii !=, <=, >, >=
v1.swap(v2)
Containerul Deque
coad cu dou capete
suport inserare/tergere eficient la ambele
capete
permite inserare/tergere la orice poziie via
iterator
Sunt implementate metodele push_front()
i pop_front() mpreun cu cele de la vector
(push_back(), pop_back())
Majoritatea metodelor de la vectori sunt valide i
aici.
Constructori asemntori cu cei de la vector
Exemplu
int main ()
{
deque<int> first;
deque<int> second;
deque<int> third;
first.assign (7,100); // de 7 ori 100
deque<int>::iterator it;
it=first.begin()+1;
second.assign (it,first.end()-1); // 5 valori din first
int myints[] = {1776,7,4};
third.assign (myints,myints+3); // assign din tablou
cout << "Size of first: " << int (first.size()) << endl; //7
cout << "Size of second: " << int (second.size()) << endl; //5
cout << "Size of third: " << int (third.size()) << endl; //3
return 0;
}
Containerul List
List dublu nlnuit.
Nu este permis acces aleatoriu; inserarea i
tergerea la poziia curent a iteratorului se
face n timp constant
Suport iteratori bidirecionali
Nu este definit operatorul [ ], nici metodele
reserve(), capacity()
Inserarea i tergerea nu invalideaz iteratorii
ca la vectori
Containerul List
Metode specifice listelor:
splice(pos, x) : mut toate elementele din lista x
nainte de pos n aceeai list
splice(pos, x, p): mut *p din lista x nainte de pos
splice(pos, x, first,last)
merge(list&) : interclasare liste sortate
template<class Cmp> merge(list&, Cmp)
sort()
template <class Cmp> sort(Cmp)
front(): referin la primul element din list
Stiva <stack>
Stiva (ca i coada) este definit ca un container
diferit dar ca adaptor al containerelor de baz
secveniale (vector, list, deque)
un adaptor al unui container furnizeaz o interfa
restrictiv la un container
adaptorii nu furnizeaz iteratori
Stiva este o interfa la un container de tip
generic transmis ca argument template
Stiva <stack>
template<class T,class C = deque<T> > class stack{
public:
typedef C container_type;
typedef typename C::value_type value_type;
typedef typename C::size_type size_type;
typedef typename C::reference reference;
typedef typename C::const_reference const_reference;
stack() : c() {}
explicit stack(const C& _Cont) : c(_Cont){}
bool empty() const{return (c.empty());}
size_type size() const{ return (c.size());}
reference top(){ return (c.back());}
const_reference top() const { return (c.back());}
void push(const value_type& _Val){c.push_back(_Val);}
void pop() {c.pop_back();}
protected:
C c;
};
Stiva <stack>
stack<char> s1;
// se foloseste o coada deque<char> pentru a stoca
// elemente de tip char
stack<int, vector<int>>s2;
// se foloseste un vector<int> pentru
// reprezentarea stivei
Stiva, ca i celelalte containere adaptate, nu are parametru
template de tip allocator. Pentru alocarea spaiului se bazeaz
pe alocatorul pe care-l folosete containerul ce
implementeaz stiva
Coada <queue>
template<class T,class C = deque<T> > class queue {
//
};
Interfa la un container ce permite inserarea
la sfrit back() i extragerea la nceput front()
este folosit implicit deque pentru a pstra
elementele cozii, dar se poate folosi orice
secven ce furnizeaz operaiile front(),
back(), push_back(), pop_front()
aadar nu vector ( nu are pop_front())
Coada cu prioritate
template<class T,class C = vector<T>, class Cmp =
less<Typename C::value_type>> class priority_queue {
//
};
fiecare element are ataat o prioritate care controleaz
ordinea n care elementele ajung n capul cozii
declaraia se afl n fiierul <queue>
n mod implicit se folosete < pentru comparare
ca alternativ se poate da n argumentul template alt relaie
implicit se folosete un vector pentru stocarea elementelor,
dar orice secven ce are front(), push_back(), pop_back() i
iteratori random poate fi folosit
este implementat folosind un heap
Containere asociative <map>
map sau dicionar
perechi de valori (cheie, dat) astfel c, pentru fiecare
cheie exist cel mult o singur pereche cu acea cheie
implementai cu arbori speciali
template <class Key, class T,class Cmp = less<Key>,
class A = allocator<pair<const Key,T>>>class std::map {
public:
typedef Key key_type;
typedef T maped_type;
typedef pair<const Key, T> value_type;
//. . .
};
un obiect ntr-un container map este o valoare de tip
pair<const Key, T>
odat introdus un obiect n container se poate modifica
doar componenta a doua, cheia este constant
Perechi
template<class T, class U>
struct pair
{
typedef T first_type;
typedef U second_type
T first;
U second;
pair():first(T()), second(U()){};
pair(const T& x, const U& y):first(x), second(y) {};
template<class V, class W>
pair(const pair<V, W>& pr)
:first(pr.first), second(pr.second) {};
};
Accesul la elemente
Iteratori:
begin(), end(), rbegin(), rend()
variante const
un iterator la un container map prezint elementele n
ordinea cresctparea cheilor
operatorul []: x_map[key]
se caut key n x_map
se returneaz valoarea corespunztoare cheii gsite
dac nu exist un element cu cheia dat, este creat unul care
are ca valoare, valoarea implicit a tipului mapped_type
nu exist varianta const a operatorului []
Metoda find() permite localizarea unei chei fr a
modifica containerul
Comparri
gsirea unui element n map se face
comparnd chei
implicit se face compararea cu < (less n
template) dar se poate specifica i alt mod
exist 2 funcii membru care fac posibil
interogarea unui map pentru modul n care se
face compararea(pentru chei i valori):
key_compare key_comp() const;
value_compare value_comp() const;
nserare
Angajat ion(Ion", Popescu", "000-00-0000");
Angajat vasile(Vasile", Manea", "111-11-1111");
Angajat dan(Dan", Barbu", "888-88-8888");
map<const string, Angajat*> S;
S.insert(pair<const string, Angajat*> (ion.getID(), &ion));
S.insert(pair<const string, Angajat*> (dan.getID(), &dan));
S.insert(pair<const string, Angajat*> (vasile.getID(), &vasile));
mapPrint(S, cout);
map<const string, Angajat>::const_iterator It;
It = S.find("111-11-1111");
cout << (*It).second.getName() << endl;
000-00-0000 Ion Popescu
111-11-1111 Vasile Manea
888-88-8888 Dan Barbu
Vasile Manea
<multimap>
container asociativ (ca i map) n care pot
exist obiecte cu aceeai cheie
nu suport operatorul * +
argumentul funciei insert() este inserat
ntotdeauna
pentru map m.insert(val) returneaz o valoare
pair<iterator, bool>
pentru multimap mm.insert(val) ntoarce doar
un iterator
Operaii specializate
iterator find(const key_type& k);
caut elementul cu cheia k
size_type count(const key_type& k) const;
numrul elementelor cu cheia k
iterator lower_bound(const key_type& k);
primul element cu cheia k
iterator upper_bound(const key_type& k);
primul element cu cheia mai mare dect k
pair<iterator,iterator> equal_range(const
key_type& k);
nceputul i sfritul secvenei cu cheia k
Exemplu
int main (){
multimap<char,int> mymm;
multimap<char,int>::iterator it;
pair<multimap<char,int>::iterator,multimap<char
,int>::iterator> ret;
mymm.insert(pair<char,int>('a',10));
mymm.insert(pair<char,int>('b',20));
mymm.insert(pair<char,int>('b',30));
mymm.insert(pair<char,int>('b',40));
mymm.insert(pair<char,int>('c',50));
mymm.insert(pair<char,int>('c',60));
mymm.insert(pair<char,int>('d',60));
cout << "mymm contains:\n";
for (char ch='a'; ch<='d'; ch++)
{
cout << ch << " =>";
ret = mymm.equal_range(ch);
for (it=ret.first; it!=ret.second; ++it)
cout << " " << (*it).second;
cout << endl;
}
return 0;
}
mymm contains:
a => 10
b => 20 30 40
c => 50 60
d => 60
set, multiset
set: un container map n care valorile nu sunt
relevante, se pstreaz doar cheile
elementele n set se pstreaz ordonate
sunt definii operatorii ==, !=, <, >, <=, >=, swap()
multiset: un container multimap n care
valorile nu sunt relevante, se pstreaz doar
cheile
accesarea cheilor se face cu equal_range(),
lower_bound(), upper_bound()
Operaii
insert , erase
prin valoare:
S.insert(k), S.erase(k);
M. insert(k), M.erase(k); (terge toate intrrile k)
prin iteratori:
S.insert(i), S.erase(i);
M.insert(i), M.erase(i); (se terge doar *i)
find
S.find(k), M.find(k) ( returneaz end() dac nu-i
gsit)
Exemplu
multiset<int> mymultiset;
multiset<int>::iterator it;
// insert some values:
mymultiset.insert (40); // 40
for (int i=1; i<7; i++) mymultiset.insert(i*10); // 10 20 30 40 40 50 60
it=mymultiset.begin();
it++;
mymultiset.erase (it); // 10 30 40 40 50 60
mymultiset.erase (40); // 10 30 50 60
it=mymultiset.find (50);
mymultiset.erase ( it, mymultiset.end() ); // 10 30
bitset
<bitset> definit n std
un obiect de tipul bitset<n> este un tablou de
n bii
difer de:
un vector<bool> prin faptul c are dimensiune fix
un set prin faptul c biii sunt indexai de un ntreg
i nu de o valoare
are operaii specifice pentru bii
constructori
bitset<10> b1; // 10 biti 0
bitset<16> b2 = 0xaaaa; //1010101010101010
bitset<32> b3 = 0xaaaa;
//10101010101010101010101010101010
bitset<10> b4(string(1010101010));
bitset<10> b5(string(10110111011110, 4));
bitset<10> b6(string(10110111011110, 2, 8));
bitset<10> b7(string(badstring));
//se genereaza exceptia invalid_argument
Operaii
Operatorii: [], &=, |=, ^=, <<=, >>=, ~, <<, >>, ==, !=
Metode
set() : seteaz biii la 1
set(pos, val): seteaz bitul de pe pos la val(implicit 1)
reset(): seteaz biii la 0
reset(pos)
flip()
flip(pos)
count(): numr biii 1
size(): numrul de bii
test(pos): true dac la pos este 1
any(): true dac este mcar un bit 1
none(): true dac nu este nici un bit 1
to_ulong(), to_string(): operaii inverse constructorilor
Exemplu
bitset<4> first (string("1001"));
bitset<4> second (string("0011"));
cout << (first^=second) << endl; // 1010 (XOR,assign)
cout << (first&=second) << endl; // 0010 (AND,assign)
cout << (first|=second) << endl; // 0011 (OR,assign)
cout << (first<<=2) << endl; // 1100 (SHL,assign)
cout << (first>>=1) << endl; // 0110 (SHR,assign)
cout << (~second) << endl; // 1100 (NOT)
cout << (second<<1) << endl; // 0110 (SHL)
cout << (second>>1) << endl; // 0001 (SHR)
cout << (first==second) << endl; // false (0110==0011)
cout << (first!=second) << endl; // true (0110!=0011)
cout << (first&second) << endl; // 0010
cout << (first|second) << endl; // 0111
cout << (first^second) << endl; // 0101
POO
Proiectare I
D. Lucanu POO Proiectarea de clase 2
Cuprins
mai mult despre proiectarea unei clase
clasa Data
pointerul this
constructori
impliciti
cu parametri
copiere
conversie
operatorul de atribuire
supraincarcare operatori
sabloane de proiectare (software design patterns)
clase cu o singura instanta (Singleton)
Clasa Data
Sa se proiecteze o clasa Data cu urmatoarele
responsabilitati
sa poata spune data curenta
sa spuna ce data este maine
sa spuna ce data este peste n zile/luni/ani
nu e trivial
sa afiseze o anumita
...
Se stie ca o data este formata din
zi
luna
an
D. Lucanu POO Proiectarea de clase 3
atribute
operatii
Clasa Data: o prima incercare
D. Lucanu POO Proiectarea de clase 4
. . .
Constructori
constructorul implicit (fara parametri)
constructori cu parametri
constructori de copiere
constructori de conversie
D. Lucanu POO Proiectarea de clase 5
Constructorul implicit 1/2
ce data implicita consideram?
o posibila solutie: cea curenta
data curenta este formata din
zi curenta
luna curenta
an curent
ups! acestea nu depind de atributele zi, luna, an
exista o singura data curenta pentru toata clasa!
solutia:
functii statice!
D. Lucanu POO Proiectarea de clase 6
Constructorul implicit 2/2
class Data
{
...
static int ziCurenta();
...
}
Data(int oZi = ziCurenta(),
int oLuna = lunaCurenta(),
int unAn = anCurent())
{
zi = oZi;
luna = oLuna;
an = unAn;
}
D. Lucanu POO Proiectarea de clase 7
sunt functii statice,
asa ca pot fi
folosite pentru
valoarea implicita a
parametrilor
public sau privat?
intermezzo c: time.h
cum aflam data ziua/luna/anul curent(a)?
ne uitam la ce contine time.h

int Data::ziCurenta()
{
struct tm *tp; // struct tm este
// definit in <time.h>
time_t acum; // time_t este definit
// in <time.h>
acum = time(NULL);
tp = localtime(&acum);
return tp->tm_mday;
}
D. Lucanu POO Proiectarea de clase 8
Constructorul de copiere X::X(const X&) 1/4
Data d2 = d1;
echiv. cu
Data d2(d1);
este apelat automat constructorul de copiere
Data::Data(const Data&)
acesta este echivalent cu:
Data::Data(const Data &d)
{
zi = d.zi;
luna = d.luna;
an = d.luna;
}
D. Lucanu POO Proiectarea de clase 9
apel prin referinta (vezi
slide-ul urmator)
D. Lucanu POO Proiectarea de clase 10
intermezzo C++: apel prin referinta
void swap (int &x, int &y)
{
int aux = x;
x = y;
y = aux;
}
swap(a, b);
int x int y
int a int b
apel prin referinta apel prin referinta
Constructorul de copiere X::X(const X&) 2/4
Ce se intampla daca avem date membre dinamice?
class Data {
...
private:
int *zi, *luna, *an;
}
Data::Data(int oZi, int oLuna, int unAn)
{
zi = new int(oZi);
luna = new int(oLuna);
an = new int(unAn);
}
D. Lucanu POO Proiectarea de clase 12
alocare
dinamica
pointeri
aceasta este
doar o solutie
demonstrativa!
Constructorul de copiere X::X(const X&) 3/4
Data::~Data()
{
delete zi;
delete luna;
delete an;
}
D. Lucanu POO Proiectarea de clase 13
un destructor este
responsabil cu
eliberarea memoriei
alocate de un
constructor
Constructorul de copiere X::X(const X&) 4/4
Data::Data(const Data& oData)
{
zi = new int(*oData.zi);
luna = new int(*oData.luna);
an = new int(*oData.an);
}
D. Lucanu POO Proiectarea de clase 14
constructor de
copiere explicit;
aloca memorie
dinamica pentru
noul obiect
Constructor de conversie
putem construi o data avand la intrare un numar intreg
reprezentand numarul de zile de la nasterea lui Christos
acest constructor poate fi privit ca o functie de conversie
de la int la Data
Data::Data(int nrZile)
{
zi = ...;
luna = ...;
an = ...;
}
D. Lucanu POO Proiectarea de clase 15
Pointerul implicit this 1/2
despre implementare: exista o singura instanta pt fiecare
functie membru:
Data::getZi()
este implementat ca
getZi_Data (Data& *this) {
return this->zi;
}
apelul
azi.getZi();
este echivalent cu
getZi_Data(&azi);
adica se va executa
return (&azi)->zi;
azi Data
dar exista o copie a
datelor membre pentru
firecarea instanta a
clasei (starea)
&azi
Pointerul implicit this 2/2
apelul
altaZi.getZi();
este echivalent cu
getZi_Data(&altaZi);
adica se va executa
return (&altaZi)->zi;
altaZi Data
&altaZi
Operatorul de atribuire X::operator=(const X&)
Data startSem(22,2,2010);
Data oZi;
oZi = startSem;
este apelata o instanta a operatorului
Data& Data::operator=(const Data&)
care este echivalent cu
Data& Data::operator=(const Data& d)
{
zi = d.zi;
luna = d.luna;
an = d.an;
return *this;
}
date membre nedinamice
(agregare tare)
Operatorul de atribuire X::operator=(const X&)
cazul cand datele membre sunt dinamice
Data& Data::operator=(const Data& oData)
{
delete zi;
delete luna;
delete an;
zi = new int(*oData.zi);
luna = new int(*oData.luna);
an = new int(*oData.an);
return *this;
}
D. Lucanu POO Proiectarea de clase 19
eliberarea spatiului de memorie
dinamica ocupat de starea curenta
(numai daca e agregare tare)
alocare memorie
pentru noua stare
D. Lucanu POO Proiectarea de clase 20
Supraincarcarea operatorului <<
afisarea se poate face cu operatorul <<!
class Data {
...
public:
friend ostream& operator << (ostream&,
const Data&);
}
ostream& operator << (ostream& o,
const Data& d)
{
o << d.zi << ' ' << d.luna << ' ' << d.an;
return o;
}
D. Lucanu POO Proiectarea de clase 21
o clasa C++ poate avea prieteni (clase,
functii, operatori ...)
prietenii au acces la membrii privati
... deci atentie cum alegeti prietenii
Supraincarcarea op. de incrementare 1/2
data de maine poate fi obtinuta cu operatorul de
incrementare
class Data {
//...
public:
Data operator ++(int); // postfix
public:
Data& operator ++(); // prefix
//...
};
D. Lucanu POO Proiectarea de clase 22
Supraincarcarea op. de incrementare 2/2
postfixat
Data Data::operator ++(int) {
Data oldValue = *this;
zi++;
if ...
...
return oldValue;
}
prefixat
Data& Data::operator ++(int) {
zi++;
if ...
...
return *this;
}
D. Lucanu POO Proiectarea de clase 23
Sabloane de proiectare (Design Patterns)
intai aplicate in proiectare urbanistica:
C. Alexander. A Pattern Language. 1977
prima contributie in software: 1987, Kent Beck (creatorul
lui Extreme Programming) & Ward Cunningham (a scris
primul wicki)
contributia majora: Design Patterns:
Gamma et al. Elements of Reusable Object-Oriented
Software was published, 1994
cunoscuta ca GoF (Gang of Four)
in functie de scop, clasifica patternurile in
creationale
structurale
comportamentale
pot fi aplicate la nivel de clasa sau obiect
D. Lucanu POO Proiectarea de clase 24
Ce este un sablon de proiectare?
definitia originala a lui Alexander: "Each pattern describes
a problem which occurs over and over again in our
environment, and then describes the core of the solution
to that problem, in such a way that you can use this
solution a million times over, without ever doing it the
same way twice
Elementele esentiale ale unui pattern (GoF):
nume
problema (si context)
solutie
consecinte
GoF include 23 de sabloane
D. Lucanu POO Proiectarea de clase 25
Formatul (template) unui sablon
nume si clasificare
intentie
cunoscut de asemenea ca
motivatie
aplicabilitate
structura
participanti
colaborari
consecinte
implementare
cod
utilizari cunoscute
sabloane cu care are legatura
D. Lucanu POO Proiectarea de clase 26
Clase cu o singura instanta (Singleton)
Intentia
proiectarea unei clase cu un singur obiect (o singura
instanta)
Motivatie
intr-un sistem de operare:
exista un sistem de fisiere
exista un singur manager de ferestre
Aplicabilitate
cand trebuie sa existe exact o instanta
clientii clasei trebuie sa aiba acces la instanta din
orice punct bine definit
D. Lucanu POO Proiectarea de clase 27
Clase cu o singura instanta (Singleton)
structura
participant: Singleton
colaborari: clientii clasei
D. Lucanu POO Proiectarea de clase 28
-uniqueInstance
-data
+getValue()
+setValue()
+instance()
Singleton
Clase cu o singura instanta (Singleton)
Consecinte
acces controlat la instanta unica
reducerea spatiului de nume (eliminarea variab.
globale)
permite rafinarea operatiilor si reprezentarii
permite un numar variabil de instante
Doubleton
Tripleton
...
mai flexibila decat operatiile la nivelde clasa (statice)
Implementare
D. Lucanu POO Proiectarea de clase 29
D. Lucanu POO Proiectarea de clase 30
Clase cu o singura instanta
class Singleton
{
public:
static Singleton& instance()
{return uniqueInstance;}
int getValue() { return i; }
void setValue(int x) { i = x; }
private:
static Singleton uniqueInstance;
int i;
Singleton(int x) : i(x) { }
void operator=(Singleton&);
Singleton(const Singleton&);
};
manerul cu care se are acces
la instanta
constructor
operator atribuire
constructor de copiere
D. Lucanu POO Proiectarea de clase 31
Clase cu o singura instanta
Singleton Singleton::uniqueInstance(47);
int main()
{
Singleton& s1 = Singleton::instance();
cout << s1.getValue() << endl;
Singleton& s2 = Singleton::instance();
s2.setValue(9);
cout << s1.getValue() << endl;
return 0;
}
initializare
refera aceeasi instanta
(pe cea unica)
refera aceeasi instanta
(pe cea unica)
D. Lucanu POO Proiectarea de clase 32
Agenda unica!
este normal ca un utilizator sa aiba o singura agenda
aceasta poate fi implementata utilizand sablonul
Singleton
de exersat la laborator
D. Lucanu POO Proiectarea de clase 33
1
POO
Proiectare II
Cuprins
patternul Iterator
comparatie cu iteratorii din STL
patternul Observer
cum poate fi aplicat in contextul MVC
D. Lucanu POO Iterator Pattern 2
D. Lucanu POO Principii 3
D. Lucanu POO Iterator Pattern (GoF) 4
Iterator::intentie
furnizeaza o modalitate de a accesa componentele
unui obiect agregat fara a le expune reprezentarea
D. Lucanu POO Iterator Pattern (GoF) 5
Iterator::motivatie
returneaza
elementul
curent din lista
initializeaza
elementul
curent la primul
element din lista
testeaza daca
am trecut
dincolo de
ultimul element
al listei
Iterator::motivatie
Inainte de a instantia ListIterator, trebuie precizat
obiectul agregat List care urmeaza a fi traversat
odata ce avem o instanta ListIterator, putem accesa
elementele listei secvential
separand mecanismul de traversare de obiectele
listei, avem libertatatea de a defini iteratori pentru
diferite politici de traversare
de exemplu, am putea defini FilteringListIterator care
sa acceseze (viziteze) numai acele elemente care
satisfac un anumit criteriu de filtrare
D. Lucanu POO Iterator Pattern 6
D. Lucanu POO Iterator Pattern (GoF) 7
Iterator polimorfic::motivatie
vom discuta
mai mult la
ObjectFactory
intermezzo structuri de date skip list
D. Lucanu POO Iterator Pattern 8
structuri de date aleatoare simple si eficiente pentru cautare
structura pe 2 nivele (cost operatie de cautare: 2 sqrt(n))
structura pe 4 nivele (similara unui arbore binar
D. Lucanu POO Iterator Pattern (GoF) 9
Iterator::structura
D. Lucanu POO Iterator Pattern (GoF) 10
Iterator::participanti
Iterator
defineste interfata de accesare si traversare a
componentelor
ConcreteIterator
implementeaza interfata Iterator.
memoreaza pozitia curenta in traversarea agregatului
Aggregate
defineste interfata pentru crearea unui obiect Iterator
ConcreteAggregate
implementeaza interfata de creare a unui Iterator
pentru a intoarce o instanta proprie ConcreteIterator.
D. Lucanu POO Iterator Pattern (GoF) 11
Iterator::consecinte
suporta diferite moduri de traversare a unui agregat
simplifica interfata Aggregate
pot fi executate concurent mai multe traversari (pot
exista mai multe traversari in progres la un moment
dat); un iterator pastreaza urma numai a propriei
sale stari de travesare
D. Lucanu POO Iterator Pattern (GoF) 12
Iterator::implementare
cine controleaza iteratia? clientul (iterator extern)
sau iteratorul (iterator intern)?
cine defineste algoritmul de traversare?
agregatul (iterator = cursor)
iteratorul (mai flexibil)
s-ar putea sa necesite violarea incapsularii
cat de robust este iteratorul?
operatiile de inserare/eliminare nu ar trebui sa
interefereze cu cele de traversare
operatii aditionale cu iteratori
operatii aditionale peste iteratori
D. Lucanu POO Iterator Pattern (GoF) 13
Iterator::implementare
iteratori polimorfici
trebuie utilizati cu grija
clientul trebuie sa-i stearga ( ihm ... )
iteratorii pot avea acces privilegiat (C++ permite)
iteratori pentru componente compuse recursiv (a se
vedea patternul Composite)
external versus internal
iteratori nuli
pot usura traversarea obiectelor agregate cu
structuri mai complexe (de ex. arborescente)
prin definitie, un isDone() intoarce totdeauna true
pentru un iterator nul
D. Lucanu POO Iterator Pattern (GoF) 14
Iterator::cod::interfete
un agregat concret - lista (parametrizata)
template <class Item>
class List {
public:
List(long size = DEFAULT_LIST_CAPACITY);
long count() const;
Item& get(long index) const;
// ...
};
constanta ce reprezinta
valoarea implicita a
capacitatii unei liste
marimea listei
intoarce elementul de la o
anumita pozititie
D. Lucanu POO Iterator Pattern (GoF) 15
Iterator::cod::interfete
interfata Iterator
template <class Item>
class Iterator {
public:
virtual void first() = 0;
virtual void next() = 0;
virtual bool isDone() const = 0;
virtual Item currentItem() const = 0;
protected:
Iterator();
};
metode
abstracte
Constructorul implicit este
ascuns (de ce?)
D. Lucanu POO Iterator Pattern (GoF) 16
Iterator::cod::implementare subclasa
iterator concret pentru liste
template <class Item>
class ListIterator : public Iterator<Item> {
public:
ListIterator(const List<Item>* aList);
virtual void first();
virtual void next();
virtual bool isDone() const;
virtual Item currentItem() const;
private:
const List<Item>* _list;
long _current;
};
implementarea
operatiilor din
interfata
referinta la agregatul asociat
elementul curent
constructorul are intotdeauna
parametru (agregatul asociat)
D. Lucanu POO Iterator Pattern (GoF) 17
Iterator::cod::implementare subclasa
template <class Item>
ListIterator<Item>::ListIterator
( const List<Item>* aList)
: _list(aList), _current(0) {
//nothing
}
template <class Item>
Item ListIterator<Item>::currentItem () const {
if (isDone()) {
throw IteratorOutOfBounds;
}
return _list->get(_current);
}
agregatul asociat
ietratorul curent in
afara marginilor
initializare
D. Lucanu POO Iterator Pattern (GoF) 18
Iterator::cod::implementare subclasa
template <class Item>
void ListIterator<Item>::First () {
_current = 0;
}
template <class Item>
void ListIterator<Item>::next () {
_current++;
}
template <class Item>
bool ListIterator<Item>::isDone () const {
return _current >= _list->count();
}
pozitionarea pe
primul
trecerea la
urmatorul
complet?
D. Lucanu POO Iterator Pattern (GoF) 19
Iterator::cod::utilizare
void PrintEmployees (Iterator<Employee*>& i) {
for (i.first(); !i.isDone(); i.next()) {
i.currentItem()->print();
}
}
List<Employee*>* employees;
// ...
ListIterator<Employee*> forward(employees);
ReverseListIterator<Employee*> backward(employees);
printEmployees(forward);
printEmployees(backward);
schema de
parcurgere a unei
liste cu iteratori
Iterator care parcurge lista invers;
Este asemanator cu ListIterator cu
exceptia lui first() si next()
Iteratorii in STL
nu respecta intocmai patternul Iterator
fiecare tip container isi are asociatul propriul tip de
iterator
D. Lucanu POO Iterator Pattern 20
Iteratorii in STL
Functii membre in Container care se refera la iteratori
iterator begin()
intoarce un iterator ca refera prima componenta
iterator end()
intoarce un iterator ca refera sfarsitul containerului
(dincolo de ultima componenta)
iterator insert(iterator pos, const T& x)
insereaza x inaintea lui pos
iterator erase(iterator pos)
elimina componenta de la pozitia pos
D. Lucanu POO Iterator Pattern 21
numai pentru containere de tip secventa
Iteratorii in STL
Exista mai multe tipuri de iteratori
reverse_iterator
reverse_bidirectional_iterator
insert_iterator
front_insert_iterator
back_insert_iterator
input_iterator
output_iterator
forward_iterator
bidirectional_iterator
random_access_iterator
...
D. Lucanu POO Iterator Pattern 22
Iteratorii in STL
exemplu de utilizare a unui iterator de inserare
list<int> L;
L.push_front(3);
insert_iterator<list<int> > ii(L, L.begin());
*ii++ = 0;
*ii++ = 1;
*ii++ = 2;
copy(L.begin(), L.end(),
ostream_iterator<int>(cout, " "));
D. Lucanu POO Iterator Pattern 23
declarare
insereaza pe o si apoi avanseaza
copierea listei in fluxul cout
este echivalenta cu afisarea
0 1 2 3
Iteratorii in STL versus patternul Iterator
Iterator
ListIterator<Item> i(list);
i.first()
i.isDone()
i.next()
i.currentItem()
for (i.first();
!i.isDone();
i.next()) {...}
D. Lucanu POO Iterator Pattern 24
STL
List<Item>::Iterator<Item> i;
List<Item>::Iterator<Item>
i(list.begin());
i = list.begin()
i == list.end()
++i (i++)
*i
for (i = list.begin();
i != list.end();
++i) {...}
D. Lucanu POO Principii 25
Mai mult despre iteratori
Iterator::cod::iteratori polimorfici
motivatie
sa presupunem ca utilizam mai multe tipuri de liste
SkipList<Employee*>* employees;
// ...
SkipListIterator<Employee*> iterator(employees);
PrintEmployees(iterator);
cateodata e mai flexibil sa consideram o clasa
abstracta pentru a standardiza accesul la diferite
tipuri de lista
D. Lucanu POO Iterator Pattern 26
D. Lucanu POO Iterator Pattern (GoF) 27
Iterator::cod::iteratori polimorfici
template <class Item>
class AbstractList
{
public:
virtual Iterator<Item>* CreateIterator()
const = 0;
// ...
};
template <class Item>
Iterator<Item>* List<Item>::CreateIterator ()const
{
return new ListIterator<Item>(this);
}
interfata la lista
lista concreta
implementeaza
met. din interfata
D. Lucanu POO Iterator Pattern (GoF) 28
Iterator::cod::iteratori polimorfici
// cunoastem numai AbstractList
AbstractList<Employee*>* employees;
// ...
Iterator<Employee*>* iterator =
employees->CreateIterator();
PrintEmployees(*iterator);
delete iterator; // noi suntem resp. pt. stergere!
pentru a ne usura munca, cream o clasa
IteratorPtr care joaca rol de proxy pentru
iterator
pointer
iteratorul este asociat
la o lista concreta
D. Lucanu POO Iterator Pattern (GoF) 29
Iterator::cod::stergere it. polim.
template <class Item>
class IteratorPtr {
public:
IteratorPtr(Iterator<Item>* i): _i(i) { }
~IteratorPtr() { delete _i; }
Iterator<Item>* operator->() { return _i; }
Iterator<Item>& operator*() { return *_i; }
private:
IteratorPtr(const IteratorPtr&);
IteratorPtr& operator=(const IteratorPtr&);
private:
Iterator<Item>* _i;
};
destructorul este
apelat automat
implemen
tare inline
supraincarcare operatori de tip pointer
ascunde copierea si atribuirea
pentru a nu permite stergeri multiple
ale lui _i
D. Lucanu POO Iterator Pattern (GoF) 30
Iterator::cod::stergere it. polim.
proxy-ul ne usureaza munca
AbstractList<Employee*>* employees;
// ...
IteratorPtr<Employee*>
iterator(employees->CreateIterator());
PrintEmployees(*iterator);
Iterator::cod::iterator intern
mai este numit si iterator pasiv
cum parametrizam un iterator cu operatia pe care
dorim sa o executam peste fiecare element?
o problema: C++ nu suporta functii anonime
solutii posibile:
un parametru pointer la o functie
subclase care suprascriu functia cu copmportarea
dorita
ambele au avantaje si dezavantaje
optam pentru a doua
D. Lucanu POO Iterator Pattern 31
D. Lucanu POO Iterator Pattern (GoF) 32
Iterator::cod::iterator intern
template <class Item>
class ListTraverser {
public:
ListTraverser(List<Item>* aList);
bool Traverse();
protected:
virtual bool ProcessItem(const Item&) = 0;
private:
ListIterator<Item> _iterator;
};
urmeaza a fi implementata cu
fuctii care proceseaza fiecare
element in parte
D. Lucanu POO Iterator Pattern (GoF) 33
Iterator::cod::iterator intern
template <class Item>
ListTraverser<Item>::ListTraverser
( List<Item>* aList ) : _iterator(aList) { }
template <class Item>
bool ListTraverser<Item>::Traverse () {
bool result = false;
for ( _iterator.First();!_iterator.IsDone();
_iterator.Next() ) {
result = ProcessItem(_iterator.CurrentItem());
if (result == false) {
break;
}
}
return result;
}
D. Lucanu POO Iterator Pattern (GoF) 34
Iterator::cod::iterator intern
class PrintNEmployees
: public ListTraverser<Employee*> {
public:
PrintNEmployees(List<Employee*>* aList, int n) :
ListTraverser<Employee*>(aList),
_total(n), _count(0)
{ /* nothing /* }
protected:
bool ProcessItem(Employee* const&);
private:
int _total;
int _count;
};
D. Lucanu POO Iterator Pattern (GoF) 35
Iterator::cod::iterator intern
bool PrintNEmployees::ProcessItem
(Employee* const& e) {
_count++;
e->Print();
return _count < _total;
}
utilizare
List<Employee*>* employees;
// ...
PrintNEmployees pa(employees, 10);
pa.Traverse();
D. Lucanu POO Iterator Pattern (GoF) 36
Iterator::cod::iterator intern
diferenta fata de iteratori externi
ListIterator<Employee*> i(employees);
int count = 0;
for (i.First(); !i.IsDone(); i.Next()) {
count++;
i.CurrentItem()->Print();
if (count >= 10) {
break;
}
}
D. Lucanu POO Iterator Pattern (GoF) 37
Iterator::cod::iterator intern
incapsularea diferitelor iteratii
template <class Item>
class FilteringListTraverser {
public:
FilteringListTraverser(List<Item>* aList);
bool Traverse();
protected:
virtual bool ProcessItem(const Item&) = 0;
virtual bool TestItem(const Item&) = 0;
private:
ListIterator<Item> _iterator;
};
D. Lucanu POO Iterator Pattern (GoF) 38
Iterator::cod::iterator intern
template <class Item>
void FilteringListTraverser<Item>::Traverse () {
bool result = false;
for ( _iterator.First(); !_iterator.IsDone();
_iterator.Next() ) {
if (TestItem(_iterator.CurrentItem())) {
result = ProcessItem(_iterator.CurrentItem());
if (result == false) {
break;
}
}
}
return result;
}
D. Lucanu POO Principii 39
D. Lucanu POO Principii 40
Observator: :intentie
Defineste o relatie de dependenta 1..* intre obiecte
astfel incat cand un obiect isi schimba starea, toti
dependentii lui sunt notificati si actualizati automat
Observator :: motivatie
D. Lucanu POO Principii 41
Observator :: aplicabilitate
cand o abstractie are doua aspecte, unul depinzand
de celalalt. Incapsuland aceste aspecte in obiecte
separate, permitem reutilizarea lor in mod
independent
cand obiect necesita schimbarea altor obiecte si nu
stie cat de multe trebuie schimbate
cand un obiect ar trebui sa notifice pe altele, fara sa
stie cine sunt acestea
in alte cuvinte, nu dorim ca aceste obiecte sa fie
cuplate strans (a se compara cu relatia de asociere)
D. Lucanu POO Principii 42
Observator :: structura
D. Lucanu POO Principii 43
Observator :: participanti
Subject
cunoaste observatorii (numar arbitrar)
Observer
defineste o interfata de actualizare a obiectelor ce
trebuie notificate de schimbarea subiectelor
ConcreteSubject
memoreaza starea de interes pentru observatori
trimite notificari observatorilor privind o schimbare
ConcreteObserver
mentine o referinta la un obiect ConcreteSubject
memoreaza starea care ar trebui sa fie
consistenta cu subiectii
D. Lucanu POO Principii 44
D. Lucanu POO Principii 45
Observator :: colaborari
diagrama de secventa
Observator :: consecinte
abstractizeaza cuplarea dintre subiect si observator
suporta o comunicare de tip broadcast
notificarea ca un subiect si-a schimbat starea nu
necesita cunoasterea destinatarului
schimbari neasteptate
o schimbare la prima vedere inocenta poate
provoca schimbarea in cascada a starilor
obiectelor
D. Lucanu POO Principii 46
Observator :: implementare
maparea subiectilor la observatori
memorarea de referinte la observatori
observarea mai multor subiecti
cine declanseaza o actualizare
1. subiectul apeleaza o metoda Notify() dupa fiecare
schimbare
2. clientii sunt responsabili de apela Notify()
fiecare solutie are avantaje si dezavantaje (care?)
evitarea de referinte la subiecti stersi
subiectii ar trebui sa notifice despre stergerea lor (?)
ce se intampla cu un observator la primirea vestii?
D. Lucanu POO Principii 47
Observator :: implementare
fii sigur ca starea subiectului este consistenta inainte
de notificare
void MySubject::Operation (int newValue) {
BaseClassSubject::Operation(newValue);
// trigger notification
_myInstVar += newValue;
// update subclass state (too late!)
}
evita protocoale de actualizare specifice
observatorilor
modelul push: subiectul trimite notificari detaliate
tot timpul, chiar si cand observatorul nu doreste
modelul pop: subiectul trimite notificari minimale
si observatorul cere detalii atunci cand are nevoie
D. Lucanu POO Principii 48
Observator :: implementare
specificarea explicita a modificarilor de interes
void Subject::attach(Observer*, Aspect& interest);
void Observer::update(Subject*, Aspect& interest);
incapsularea actualizarilor complexe
relatia dintre subiect si observator este gestionata
de un obiect de tip ChangeManager
este o situatie frecventa ca o relatie de asociere sa
fie implementata prin intermediul unei clase
D. Lucanu POO Principii 49
Observator :: implementare
D. Lucanu POO Principii 50
Observator :: cod
clasa abstracta Observer
class Subject;
class Observer {
public:
virtual ~Observer();
virtual void update(Subject* theChangedSubject)
= 0;
protected:
Observer();
};
D. Lucanu POO Principii 51
constructor ascuns (de ce?)
metoda abstracta
Observator :: cod
clasa abstracta Subject
class Subject {
public:
virtual ~Subject();
virtual void attach(Observer*);
virtual void detach(Observer*);
virtual void notify();
protected:
Subject();
private:
List<Observer*> *_observers;
};
D. Lucanu POO Principii 52
constructor ascuns (de ce?)
Relatia de asociere cu Observer
Observator :: cod
metodele clasei Subject
void Subject::attach(Observer* o) {
_observers->append(o);
}
void Subject::detach(Observer* o) {
_observers->remove(o);
}
void Subject::notify() {
ListIterator<Observer*> i(_observers);
for (i.first(); !i.isDone(); i.next()) {
i.currentItem()->update(this);
}
}
D. Lucanu POO Principii 53
Observator :: cod
un subiect concret
class ClockTimer : public Subject {
public:
ClockTimer();
virtual int getHour();
virtual int getMinute();
virtual int getSecond();
void tick();
};
void ClockTimer::tick() {
// update internal time-keeping state
// ...
notify();
}
D. Lucanu POO Principii 54
Observator :: cod
un observator concret care mosteneste in plus o interfata grafica
class DigitalClock: public Widget, public Observer
{
public:
DigitalClock(ClockTimer*);
virtual ~DigitalClock();
virtual void update(Subject*);
// overrides Observer operation
virtual void draw();
// overrides Widget operation;
// defines how to draw the digital clock
private:
ClockTimer* _subject;
};
D. Lucanu POO Principii 55
relatia de asociere cu
ConcreteSubject
mostenire multipla (mai
mult in partea a doua)
Observator :: cod
constructorul si destructorul observatorului concret
DigitalClock::DigitalClock (ClockTimer* s) {
_subject = s;
_subject->attach(this);
}
DigitalClock::~DigitalClock () {
_subject->detach(this);
}
D. Lucanu POO Principii 56
deoarece isi cunoaste
subiectul, un
observator concret se
poate atsa/detasa
singur
deoarece isi cunoaste
subiectul, un
observator concret se
poate atsa/detasa
singur
Observator :: cod
operatia de actualizare
void DigitalClock::update
(Subject* theChangedSubject) {
if (theChangedSubject == _subject) {
draw();
}
}
void DigitalClock::draw () {
// get the new values from the subject
int hour = _subject->getHour();
int minute = _subject->getMinute();
// etc.
// draw the digital clock
}
D. Lucanu POO Principii 57
de ce se face
aceasta verificare?
Observator :: cod
un alt observator
class AnalogClock : public Widget, public Observer {
public:
AnalogClock(ClockTimer*);
virtual void update(Subject*);
virtual void draw();
// ...
};
crearea unui AnalogClock si unui DigitalClock care arata acelasi
timp:
ClockTimer* timer = new ClockTimer;
AnalogClock* analogClock = new AnalogClock(timer);
DigitalClock* digitalClock = new DigitalClock(timer);
D. Lucanu POO Principii 58
MVC cu Observer
D. Lucanu POO Principii 59
MVC
D. Lucanu POO Proiectarea de clase
Model
incapsuleaza starea aplicatiei
raspunde la interogari despre stare
expune functionalitatea modelului
notifica schimbarea starii
View
vizualizeaza modelul
cere actualizari de la model
trimite evenimentele utilizator la
controller
permite controllerului sa schimbe
modul de vizualizare
Controller
defineste comportarea aplicatiei
mapeaza actiunile utilizator pe
actulizare model
selecteaza vizulizarea
raspunsului
unul pentru fiecare functionalitate
n
o
t
i
f
.

s
c
h
.
i
n
t
e
r
o
g
.

s
t
a
r
e
actiuni utilizator
selectie vizualizare
s
c
h
i
m
b
a
r
e

s
t
a
r
e
not quite
UML
diagram
View Controller modelat cu Observer
un Controller observa un View
un View notifica Controllerul asociat despre actiunile
utilizator
View joaca rolul de subiect
Controller joaca rolul de observator
D. Lucanu POO Iterator Pattern 61
View Controller modelat cu Observer
D. Lucanu POO Principii 62
deobicei un
singur observer
(controller)
Pentru exemplul cu
Agenda inlocuieste
metoda listen()
mostenire
multipla
Model View cu Observer
un View observa un Model
un Model notifica View-urile asociate despre
schimbarea starii
Model joaca rolul de subiect
View joaca rolul de observator
D. Lucanu POO Iterator Pattern 63
Model View cu Observer
D. Lucanu POO Principii 64
mostenire
multipla
Oops, View = subiect + observator
D. Lucanu POO Principii 65
O fi
corect?
Diagrama cu toate clasele nu ajuta prea mult
D. Lucanu POO Principii 66
O diagrama de secventa ma poate lamuri
D. Lucanu POO Principii 67
1
POO
Proiectare III
Cuprins
Composite pattern
(prezentare bazata pe GoF)
studii de caz:
expresii
D. Lucanu POO Composite Pattern 2
Composite::intentie
este un pattern structural
Compune obiectele intr-o structura arborescenta
pentru a reprezenta o ierarhie parte-intreg.
Lasa clientii (structurii) sa trateze obiectele
individuale si compuse intr-un mod uniform
D. Lucanu POO Composite Pattern (GoF) 3
D. Lucanu POO Composite Pattern (GoF) 4
Composite:: motivatie
Composite::aplicabilitate
pentru a reprezenta ierarhii parte-intreg
clientii (structurii) sa poata ignora diferentele dintre
obiectele individuale si cele compuse
obiectele structurii sunt tratate uniform
D. Lucanu POO Composite Pattern (GoF) 5
Composite::structura
D. Lucanu POO Composite Pattern (GoF) 6
Composite::participanti
Component (Graphic)
declara interfata pentru obiectele din compozitie
implementeaza comportarea implicita pentru
interfata comuna a tuturor claselor
declara o interfata pentru accesarea si
managementul componentelor-copii
(optional) defineste o interfata pentru accesarea
componentelor-parinte in structura recursiva
Leaf (Rectangle, Line, Text, etc.)
reprezinta obiectele primitive; o frunza nu are
copii
defineste comportarea obiectelor primitive
D. Lucanu POO Composite Pattern (GoF) 7
Composite::participanti
Composite (Picture)
defineste comportarea componentelor cu copii
memoreaza componentele-copil
implementeaza operatiile relative la copii din
interfata Component
Client
manipuleaza obiectele din compozitie prin
intermediul interfetei Component
D. Lucanu POO Composite Pattern (GoF) 8
Composite::colaborari
clientii utilizeaza clasa de interfata Component
pentru a interactiona cu obiectele din structura
daca recipientul este o instanta Leaf, atunci cererea
este rezolvata direct
daca recipientul este o instanta Composite, atunci
cererea este transmisa mai departe componentelor-
copil; alte operatii aditionale sunt posibile inainte sau
dupa transmitere
D. Lucanu POO Composite Pattern (GoF) 9
Composite::consecinte
defineste o ierarhie de clase constand din obiecte
primitive si compuse
obiectele primitive pot fi compuse in obiecte mai
complexe, care la randul lor pot fi compuse in alte
obiecte mai complexe samd (recursie)
ori de cate ori un client asteapta un obiect primitiv, el
poate lua de asemnea si un obiect compus
clientul e foarte simplu; el trateaza obiectele primitive
si compuse in mod uniform
clientului nu-i pasa daca are de-a face cu un obiect
primitiv sau compus (evitarea utilizarii structurilor de
tip switch-case)
D. Lucanu POO Composite Pattern (GoF) 10
Composite:: consecinte
este usor de adaugat noi tipuri de componente Leaf
sau Composite; noile subclase functioneaza automat
cu structura existenta si codul clientului. Clientul nu
schimba nimic.
face designul foarte general
dezavantaj: e dificil de restrictionat ce componente
pot sa apara intr-un obiect compus (o solutie ar
putea fi verificarea in timpul executiei)
D. Lucanu POO Composite Pattern (GoF) 11
Composite::implementare
Referinte explicite la parinte.
simplifica traversarea si managementul structurii
arborescente
permite travesarea bottom-up si stergerea unei
componente
referinta parinte se pune in clasa Component
usureaza mentinerea urmatorului invariant:
parintele unui copil este un obiect compus si-l are
pe acesta ca si copil (metodele add() si remove()
sunt scrise o singura data si apoi mostenite)
D. Lucanu POO Composite Pattern (GoF) 12
Composite::implementare
Componente partajate.
cateodata este util sa partajam componente
dar daca o componenta are mai mult decat un
parinte, atunci managementul devine dificil
o solutie posibila: parinti multipli (?)
exista alte patternuri care se ocupa de astfel de
probleme (Flyweigth)
D. Lucanu POO Composite Pattern (GoF) 13
Composite::implementare
Maximizarea interfetei Component
Component ar trebui sa implementeze cat mai
multe operatii comune (pt Leaf si Composite)
aceste op vor descrie comportarea implicita si pot
fi rescrise de Leaf si Composite (sau subclasele
lor)
totusi aceasta incalca principiul o clasa trebuie
sa implementeze numai ce are sens pentru
subclase ; unele op. pt. Composite nu au sens
pt. Leaf (sau invers)
de ex. getChild()
solutie: comportarea default = nu intoarce
niciodata vreun copil
D. Lucanu POO Composite Pattern (GoF) 14
Composite:: implementare
Operatiile de management a copiilor (cele mai
dificile)
unde le declaram?
daca le declaram in Component, atunci avem
transparenta (datorita uniformitatii) dare ne costa
la siguranta (safety) deoarece clientii pot incerca
op fara sens (ex. eliminarea copiilor unei frunze)
daca le declaram in Composite, atunci avem
siguranta dar nu mai avem transparenta (avem
interfete diferite pt comp. primitive si compuse)
patternul opteaza pentru transparenta
D. Lucanu POO Composite Pattern (GoF) 15
Composite:: implementare
ce se intampla daca optam pentru siguranta?
se pierde informatia despre tip si trebuie
convertita o instanta Component intr-o instanta
Composite
cum se poate face?
o posibila solutie: declara o operatie
Composite* getComposite()
in clasa Component
Component furnizeaza comportarea implicita
intorcand un pointer NULL
Composite rafineaza operatia intorcandu-se pe
sine insasi prin itermediul pointerului this
D. Lucanu POO Composite Pattern (GoF) 16
Implementarea metodei getComposite()
class Composite;
class Component {
public:
//...
virtual Composite* getComposite() { return 0; }
};
class Composite : public Component {
public:
void Add(Component*);
// ...
virtual Composite* getComposite() { return this; }
};
class Leaf : public Component {
// ...
};
D. Lucanu POO Composite Pattern (GoF) 17
problema de tip oul sau gaina
implementarea implicita
implementarea pt. un compus
Exemplu utilizare a metodei getComposite()
Composite* aComposite = new Composite;
Leaf* aLeaf = new Leaf;
Component* aComponent;
Composite* test;
aComponent = aComposite;
if (test = aComponent->getComposite()) {
test->Add(new Leaf);
}
aComponent = aLeaf;
if (test = aComponent->getComposite()) {
test->Add(new Leaf);
}
D. Lucanu POO Composite Pattern (GoF) 18
adauga pentru ca test
va fi didferit de zero
adauga pentru ca test
va fi didferit de zero
crearea unui obiect
compus si a unei
frunze
Composite:: implementare
evident, componentele nu sunt tratate uniform
singura posibilitate de a avea transparenta este
includerea operatiile relativ la copii in Component
este imposibil de a implementa Component:add()
fara a intoarce o exceptie (esec)
ar fi ok sa nu intoarca nimic?
ce se poate spune despre Component:remove() ?
D. Lucanu POO Composite Pattern (GoF) 19
Composite:: implementare
Ar trebui implementata o lista de fii in Component?
ar fi tentant
dar
ar fi irosire de spatiu
Ordinea copiilor
sunt aplicatii in care conteaza
daca da, atunci accesul si managementul copiilor
trebuie facut cu grija
Cine sterge componentele?
fara GC, responsabilitatea este a lui Composite
atentie la componentele partajate
Care structura e cea mai potrivita pentru lista copiilor?
D. Lucanu POO Composite Pattern (GoF) 20
D. Lucanu POO Composite Pattern 21
D. Lucanu POO Proiectarea de clase 22
Problema
expresii
orice numar intreg este o expresie
daca e1, e2, e3, sunt expresii atunci suma lor
e1 + e2 + e3 + este expresie
daca e1, e2, e3, sunt expresii atunci produsul lor
e1 * e2 * e3 * este expresie
Expresii : : structura
D. Lucanu POO Proiectarea de clase 23
Interfata
class Expression
{
public:
virtual int getVal() = 0;
virtual void add(Expression* exp) = 0;
virtual void remove() = 0;
};
D. Lucanu POO Proiectarea de clase 24
Constant (Leaf)
class Constant : public Expression
{
public:
Constant(int x = 0) { val = x; }
int getVal() { return val;}
void add(Expression*) {}
void remove() {}
private:
int val;
};
D. Lucanu POO Proiectarea de clase 25
implementare vida
Expresie compusa
class CompoundExpression : public Expression
{
public:
void add(Expression* exp)
{
members.push_back(exp);
}
void remove()
{
members.erase(members.end());
}
protected:
list<Expression*> members;
};
D. Lucanu POO Proiectarea de clase 26
indicele/referinta componentei care se
sterge ar putea fi data ca parametru
listele din STL
Expresie de tip suma
class SumExpression : public CompoundExpression
{
public:
SumExpression() {}
int getVal()
{
list<Expression*>::iterator i;
int valTemp = 0;
for ( i = members.begin();
i != members.end(); ++i)
valTemp += (*i)->getVal();
return valTemp;
}
};
D. Lucanu POO Proiectarea de clase 27
valoarea unei expresii suma este
suma valorilor componentelor
declarare iterator pentru
parcurgere componente
Expresie de tip produs
D. Lucanu POO Composite Pattern 28
Demo 1/2
D. Lucanu POO Proiectarea de clase 29
e2
2
e1
1
2
+
*
Demo 1/2
Constant* one = new Constant(1);
Constant* two = new Constant(2);
ProdExpression* e1 = new ProdExpression();
e1->add(one);
e1->add(two);
cout << e1->getVal() << endl;
SumExpression* e2 = new SumExpression();
e2->add(e1);
e2->add(two);
cout << e2->getVal() << endl;
D. Lucanu POO Proiectarea de clase 30
creare doua
constante
creare expresie
compusa
produs
creare expresie
compusa suma
1
POO
Proiectare IV
Cuprins
principiul inchis-deschis
fabrica de obiecte (Abstract Object Factory)
(prezentare bazata pe GoF)
studii de caz:
pizza factory
D. Lucanu POO Composite Pattern 2
D. Lucanu POO Proiectarea de clase 3
Principiul inchis-deschis
Entitatile software (module, clase, functii etc.)
trebuie sa fie deschise la extensii si inchise la
modificare (Bertrand Meyer, 1988)
deschis la extensii = comportarea modulului poate
fi extinsa pentru a satisface noile cerinte
inchis la modificare = nu este permisa modificarea
codului sursa
Principiul inchis-deschis : exemplu
D. Lucanu POO Proiectarea de clase 4
D. Lucanu POO Proiectarea de clase 5
Principiul inchis-deschis: neconformare
void FigureContainer::load(std::ifstream& inp)
{
while (inp)
{
int tag;
Figura* pfig;
inp >> tag;
switch (tag)
{
case SQUAREID:
...
case CIRCLEID:
...
}
}
}
adaugarea
unui nou tip de
figura
presupune
modificarea
acestui cod
eticheta figura
pfig = new Square;
pfig.read(inp);
pfig = new Circle;
pfig.read(inp);
citeste tipul figurii ce
urmeaza a fi incarcate
Square::read()
Circle::read()
Principiul inchis-deschis
D. Lucanu POO Composite Pattern 6
Fabrica de obiecte (Abstract Factory)
intentie
de a furniza o interfata pentru crearea unei familii de
obiecte intercorelate sau dependente fara a specifica
clasa lor concreta
aplicabilitate
un sistem ar trebui sa fie independent de modul in
care sunt create produsele, compuse sau
reprezentate
un sistem ar urma sa fie configurat cu familii multiple
de produse
o familie de obiecte intercorelate este proiectata
pentru astfel ca obiectele sa fie utilizate impreuna
vrei sa furniziei o biblioteca de produse ai vrei sa
accesibila numai interfata, nu si implementarea
D. Lucanu POO Proiectarea de clase 7
D. Lucanu POO Proiectarea de clase 8
Fabrica de obiecte:: motivatie
typedef enum {FRIEND = 1, COLLEAGUE} ContTag;
atasarea unei etichete fiecarui tip
de contact
D. Lucanu POO Proiectarea de clase 9
Fabrica de obiecte:: motivatie
void Agenda::load(std::ifstream& inp)
{
while (inp)
{
// citeste tipul contactului
int tag; inp >> tag;
// creeaza un obiect vid
Contact* pfig;
switch (tag)
{
case FRIEND:
pfig = new Friend;
break;
case COLLEAGUE:
pfig = new Colleague;
break; //...
}
pfig->read(inp);
}
}
adaugarea unui
nou tip de
contact
presupune
modificarea
acestui cod
se incalca principiul
inchis-deschis
Fabrica de obiecte:: structura
D. Lucanu POO Proiectarea de clase 10
Fabrica de obiecte
colaborari
normal se creeaza o singura instanta
Consecinte
izoleaza clasele concrete
simplifica schimbul familiei de produse
promoveaza consistenta printre produse
suporta noi timpul noi familii de produse usor
respecta principiul deschis/inchis
implementare
se face pe baza studiului de caz pizza factory
D. Lucanu POO Proiectarea de clase 11
D. Lucanu POO Proiectarea de clase 12
Pizza factory: Problema
Un restaurant poate oferi mai multe feluri de mancare
pizza
pasta
etc
Exista mai multe tipuri de pizza
Margueritta
Quatro Fromaggi
etc
Numarul de feluri de mancare oferite de un restaurant este
dinamic
un client poate ordona mai multe portii de acelasi fel sau de
feluri diferite
diferite modele sunt descrise in Wikipedia:
http://en.wikipedia.org/wiki/Factory_method_pattern
Corespondenta cu modelul standard
AbstractProductA = Pizza
AbstractProductB = Pasta
AbstractFactory = Restaurant
D. Lucanu POO Proiectarea de clase 13
D. Lucanu POO Proiectarea de clase 14
Fabrica abstracta
este o clasa care sa gestioneze tipurile de pizza
inregistreaza un nou tip de pizza (apelata ori de
cate ori se defineste o noua clasa derivata)
eliminarea unui tip de pizza inregistrat (stergerea
unei clase derivate)
crearea de obiecte pizza
la nivel de implementare utilizam perechi
(pizzaId, createPizzaFn)
... si functii delegat (vezi slide-ul urmator)
se utilizeaza sablonul Singleton pentru a avea o
singura fabrica
D. Lucanu POO Proiectarea de clase 15
Functii delegat (callback)
o functie delegat (callback) este o functie care nu
este invocata explicit de programator;
responsabilitatea apelarii este delegata altei functii
care primeste ca parametru adresa functiei delegat
Fabrica de obiecte utilizeaza functii delegat pentru
crearea de obiecte: pentru fiecare tip este delegata
functia carea creeaza obiecte de acel tip
pentru pizza factory declaram un alias pentru tipul
functiilor de creare a obiectelor Pizza
typedef AbstractPizza* ( *CreatePizzaFn )();
Fabrica abstracta pentru pizza
D. Lucanu POO Composite Pattern 16
Nu va asteptati ca
Pizza factory sa
fabrice chiar pizza!
AbstractPizzaRestaurant 1/3
class AbstractPizzaRestaurant
{
public:
bool registerPizza( int pizzaId,
CreatePizzaFn createPizzaFn )
{
return pizzaMenu.insert
(
map<int, CreatePizzaFn>::
value_type (pizzaId, createPizzaFn)
).second;
}
D. Lucanu POO Proiectarea de clase 17
metoda responsabila cu inregistrarea
unui nou tip de obiecte Pizza
tablourile asociative (maps) sunt definite in STL
inserarea in tablou
a doua componenta a valorii
intoarse de insert (inserare cu
succes sau fara succes)
AbstractPizzaRestaurant 2/3
void unregisterPizza( int pizzaId )
{
pizzaMenu.erase(pizzaId);
}
AbstractPizza* createPizza( int pizzaId )
{
map<int, CreatePizzaFn>::iterator i;
i = pizzaMenu.find(pizzaId);
if ( i == pizzaMenu.end() )
throw string( "Unknown pizza ID" );
return (i->second)();
}
D. Lucanu POO Proiectarea de clase 18
metoda responsabila cu
elimnarea unui tip Pizza
metoda
responsabila cu
crearea de
obiecte Pizza
de fapt deleaga aceasta
responsabilitate metodei care
corespunde tipului dat ca parametru
AbstractPizzaRestaurant 3/3
virtual void printMenu() = 0;
protected:
AbstractPizzaRestaurant() {}
map<int, CreatePizzaFn> pizzaMenu;
};
D. Lucanu POO Proiectarea de clase 19
metoda abstracta
constructorul este declarat
protejat (vezi sablonul
Singleton)
meniul unui restaurant (= tipurile
de pizza inregistrate la fabrica)
Fabrica concreta
class FunnyPizza : public AbstractPizzaRestaurant
{
public:
static FunnyPizza* getInstance()
{
return pInstance;
}
void printMenu();
private:
FunnyPizza() { }
static FunnyPizza* pInstance;
};
D. Lucanu POO Composite Pattern 20
implementare interfata (vezi
slide-ul urmator)
constructor privat
(sablonul Singleton)
instanta unica
intermezzo STL: implementare printMenu
void printMenu()
{
map<int, CreatePizzaFn>::iterator i;
cout << endl;
for ( i = pizzaMenu.begin();
i != pizzaMenu.end();
++i)
{
cout << i->second()->name() << endl;
i->second()->printIngredients();
cout << "=======" << endl;
}
}
D. Lucanu POO Composite Pattern 21
iterator utilizat pentru a parcurge
tabloul asociativ
se creeaza un obiect
anonim utilizand
pointerul la functia de
creare
D. Lucanu POO Proiectarea de clase 22
+name()
+price()
+isVegetable()
AbstractPizza
+name()
+price()
+isVegetable()
Margueritta
+name()
+price()
+isVegetable()
QuatroFromaggi
Visual Paradigm for UML Community Edition [not for commercial use]
Produsele din familia Pizza
D. Lucanu POO Proiectarea de clase 23
Crearea produselor
definim mai intai clasa de baza ca si clasa abstracta
class AbstractPizza
{
public:
virtual int price() = 0;
virtual string name() = 0;
void printIngredients();
virtual bool isVegetable() = 0;
protected:
vector<string> ingredients;
private:
static void printString(string s)
{
cout << s << endl;
}
};
metode abstracte
ajuta la scrierea
ingredientelor
Intermezzo STL
void AbstractPizza::printIngredients()
{
for_each(ingredients.begin(),
ingredients.end(),
printString);
}
D. Lucanu POO Composite Pattern 24
algoritm care parcurge vectorul
de ingrediente si apeleaza
metoda (privata) printString
pentru fiecare ingredient
Crearea obiecte derivate: Margueritta 1/2
class Margueritta : public AbstractPizza
{
public:
Margueritta()
{
ingredients.push_back("Bread");
ingredients.push_back("Cheese");
ingredients.push_back("Tommato");
}
bool isVegetable() {return true ;}
string name() { return string("Margueritta"); }
int price() { return 12; }
};
D. Lucanu POO Proiectarea de clase 25
Adaugarea de
ingredinete
implementare
interfata
Crearea obiecte derivate: Margueritta 2/2
#define MARGUERITTA 1
AbstractPizza* CreateMargueritta()
{
return new Margueritta;
}
D. Lucanu POO Proiectarea de clase 26
declarare tag pentru
tipul Margueritta
functia de creare a
unui obiect
Margueritta
Customer
D. Lucanu POO Proiectarea de clase 27
-rest
-order
+chooseRest()
+orderPizza()
+askMenu()
+printOrder()
Customer
+name()
+price()
+isVegetable()
AbstractPizza
+registerPizza()
+unregisterPizza()
+createPizza()
+printMenu()
AbstractPizzaRestaurant
Visual Paradigm for UML Community Edition [not for commercial use]
un client este asociat atat cu
fabrica (= restaurantul in care
intra) cat si cu produsele (=
pizzele pe care le va comanda)
Customer 1/2
class Customer
{
public:
Customer() {}
void chooseRest( AbstractPizzaRestaurant* aRest )
{
rest = aRest;
}
void orderPizza(int pizzaId)
{
order.push_back(rest->createPizza(pizzaId));
}
D. Lucanu POO Proiectarea de clase 28
metoda alegere restaurant
metoda comanda pizza
Customer 2/2
void askMenu() {
rest->printMenu();
}
void printOrder() {
vector<AbstractPizza*>::iterator i;
for ( i = order.begin(); i != order.end(); ++i)
cout << (*i)->name() << endl;
}
private:
AbstractPizzaRestaurant* rest;
vector<AbstractPizza*> order;
};
D. Lucanu POO Proiectarea de clase 29
implementarea
relatiilor de
asociere
Creare profil restaurant
FunnyPizza::
getInstance()->registerPizza( MARGUERITTA,
CreateMargueritta );
FunnyPizza::
getInstance()->registerPizza( QUATROFROMAGGI,
CreateQuatroFromaggi );
D. Lucanu POO Proiectarea de clase 30
+name()
+price()
+isVegetable()
Margueritta
+name()
+price()
+isVegetable()
QuatroFromaggi
+printMenu()
+registerPizza()
+unregisterPizza()
+createPizza()
+printMenu()
FunnyPizza
Visual Paradigm for UML Community Edition [not for commercial use]
relatii de dependenta
Demo
Customer ionescu;
ionescu.chooseRest(FunnyPizza::getInstance());
cout << "Menu:" << endl;
ionescu.askMenu();
ionescu.orderPizza(MARGUERITTA);
cout << "Order: " << endl;
ionescu.printOrder();
D. Lucanu POO Proiectarea de clase 31
un client alege restaurantul FunnyPizza,
cere meniul si comanda o Margueritta
Slavarea in si incarcarea din fisier
presupunem ca toatele pizzele vandute (intr-o zi) de
FunnyPiza se doresc a fi salvate intr-un fisier
trebuie sa adaugam la FunnyPizza
un container (vector) pizzas, care sa memoreze
pizzele
metode de scriere in fisier (save) si de citire din
fisier (load)
trebuie sa adaugam la AbstractPizza si clasele
derivate metode de scriere (print) si citire (read) din
fisier
D. Lucanu POO Composite Pattern 32
Adaugarea metodei save() la fabrica
void FunnyPizza::save( ofstream&
outFile ) const
{
for ( unsigned int i = 0;
i < pizzas.size();
i++
)
pizzas[i]->print( outFile );
}
D. Lucanu POO Proiectarea de clase 33
Adaugarea unei metode load() la fabrica
void AbstractPizza::load( ifstream& inFile )
{
int pizzaId;
while ( inFile >> pizzaId)
{
AbstractPizza *pNewPizza;
pNewPizza = FunnyPizza::getInstance()->
createPizza( pizzaId );
pNewPizza->read( inFile );
pizzas.add( pNewPizza );
}
}
D. Lucanu POO Proiectarea de clase 34
Excepii - plan
Tratarea erorilor
Excepii
Componentele mecanismului
Ierarhii
Excepii n constructori
Excepii n destructor
Specificarea excepiilor
Excepii standard
1
Tratarea erorilor
Program = module separate, modulele pot
proveni din diverse biblioteci
Tratarea erorilor trebuie s fie separat n 2
pri distincte:
Raportarea erorilor ce nu pot fi tratate local
Tratarea erorilor detectate undeva, oriunde
Mecanismul exception-handling pune la
dispoziie o alternativ la tehnicile tradiionale
de tratare a erorilor (insuficiente, neelegante,
predispuse la erori)
2
Politici de tratare a erorilor n C
Terminarea programului
abort() (termin imediat programul)
exit() (golete memoriile buffer , nchide
fiierele deschise i termin programul)
Returnarea unei valori ce reprezint eroare
utilizat rar deoarece de fiecare dat trebuie un
test pentru aceast valoare
Returnarea unei valori legale i trecerea
programului ntr-o stare ilegal
n header-ul <errno.h>, se definete o variabil
global errno i funcia perror()
Apelul unei funcii desemnat a fi invocat n
cazul apariiei unei erori
3
Excepii
Mecanismul de tratare a excepiilor n C++
este proiectat pentru:
a fi suport pentru tratarea erorilor
a fi suport pentru tratarea altor condiii
excepionale ce pot apare
Se pot trata doar excepiile sincrone (erori I/O,
domenii tablouri, etc.). Evenimentele
asincrone(ntreruperi, erori aritmetice etc. )
necesit alte mecanisme
4
Excepii
O excepie este un obiect al unei clase ce
reprezint evenimente excepionale
Codul care detecteaz o eroare arunc un astfel
de obiect (cu expresia throw)
Codul care dorete s trateze o excepie trebuie
s conin o clauz catch
Efectul unei expresii throw este de a desfura
stiva (to unwind the stack) pn se gsete o
clauz catch corespunztoare, ntr-o funcie care,
direct sau indirect, a invocat funcia ce a aruncat
excepia
cutarea produce distrugerea obiectelor locale
5
Componentele mecanismului
Blocul try conine o secven de cod ce poate genera excepii:
try{
// cod ce poate genera exceptii
}
Blocul try este urmat de una sau mai multe secvene handler care
gestioneaz excepiile:
try{
//cod care poate genera excepii
}
catch(tip1 id){
//tratarea unei excepii de tipul tip1
}
catch(tip2& id){
// tratarea unei excepii de tipul tip2&
}
catch(tip3* id){
// tratarea unei excepii de tipul tip3*
}
6
Componentele mecanismului
Handler-ul catch se comport ca o funcie ce
prinde un obiect excepie fie prin valoare fie
prin referin
O list catch seamn ntr-un fel cu o
instruciune switch; nu este nevoie de
break
Tipul excepiei generat n try determin
handler-ul ce o va trata; celelalte sunt inactive
Exist un handler ce prinde orice excepie (i
care asigur desfurarea stivei):
catch(){/**/}
7
Structurarea excepiilor n ierarhii
class Matherror{};
class Overflow:public Matherror{};
class Underflow:public Matherror{};
class Zerodivide:public Matherror{};
void f()
{
try{
//
}
catch(Overflow){
// tratare Overflow
}
catch(Matherror){
//tratare orice exceptie care nu este Overflow
}
8
Structurarea excepiilor n ierarhii
class Matherror{
public:
virtual void debug_print()const{cerr<< "Math error" ;}
};
class Int_overflow:public Matherror{
public:
Int_overflow(const char* p, int a, int b) {
op = p; a1 = a; a2 = b;
}
virtual void debug_print()const{
cerr<< "Depasire superioara: " << op << '(' << a1 <<
',' << a2 <<')' ;
}
private:
const char* op;
int a1, a2;
};
9
Structurarea excepiilor n ierarhii
int add(int x, int y)
{
if( (x>0 && y>0 && x>INT_MAX-y)|| (x<0 && y<0 && x<INT_MIN-y))
throw Int_overflow("+", x, y);
return x+y;
}
void f()
{
try{
int i1 = add (100,200);
int i2 = add(INT_MAX, -2);
int i3 = add(INT_MAX, 2);
}
catch (Matherror& m){ //catch(Matherror m)
m.debug_print();
}
}
10
Tratarea excepiilor
void f(){
try{
throw E();
}
catch(H){
//
}
}
Handler-ul catch este invocat dac:
1. H este acelai tip cu E
2. H este baz public neambigu a lui E
3. H i E sunt tipuri pointeri i are loc 1 sau 2 pentru
tipurile la care se refer
4. H este referin i 1 sau 2 are loc pentru tipul la care
se refer
11
Tratarea excepiilor
n general, o excepie este copiat cnd este
aruncat nct handler-ul trateaz o copie a
excepiei
O excepie este copiat de mai multe ori pn este
tratat
Nu se pot arunca excepii ce nu pot fi copiate
Dac o excepie nu poate fi tratat complet de
ctre un handler, acesta poate decide aruncarea
sa din nou (dup ce a executat operaiile pe care
le poate face)
throw fr operand
12
Tratarea excepiilor
catch(Matherror){
if(/**/){
// tratare completa
return;
}
else{
//tratare partiala
throw; // re-throw
}
}
Dac este re-aruncat o excepie care nu exist atunci
se lanseaz funcia std::terminate()
13
Tratarea excepiilor
Ordinea n care este ncercat potrivirea unui
handler catch este cea n care acestea sunt scrise
n cod
Este important aceast ordine n cazul unei ierarhii
de excepii
O funcie care aloc resurse (deschide fiiere,
aloc memorie, etc. ) este esenial s elibereze
resursele n ordinea invers alocrii lor
Asta asigur comportarea acestora ca i modul de
creare i distrugere a obiectelor locale ceea ce confer
robustee aplicaiei
14
Excepii n constructori
Gestionarea resurselor folosind obiecte locale este
cunoscut sub numele de resource acquisition is
initialization
Se bazeaz pe proprietile constructorilor i destructorilor
i interaciunea lor cu tratarea excepiilor
Dac un constructor nu poate s completeze sarcina de
a construi n ntregime un obiect (datorit unor
excepii), destructorul nu este apelat i astfel se ajunge
la fenomenul memory leaks
Constructorul trebuie s fie proiectat astfel ca toate
excepiile s fie tratate corect, (execuia unei secvene
de cod pentru eliberarea resurselor i repropagarea
excepiei)
15
Excepii n constructori
class X{
int* p; void init();
public:
X(int s) {p = new int[s]; init();}
~X() {delete []p;}
//
}
Dac init arunc o excepie, constructorul nu-i termin
treaba i destructorul nu se va invoca. O soluie:
class Y{
vector<int> p; void init();
public:
Y(int s) :p(s) {init();}
//
};
16
Excepii n constructori
Biblioteca standard pune la dispoziie clasa template
auto_ptr care ofer suport pentru tehnica resource
acquisition is initialization
n loc de pointer la un tip, T* p, se declar n clas
auto_ptr<T> p, el poate fi derefereniat ca i pointerul la T
iar obiectele pointate vor fi implicit terse la ieirea din bloc
auto_ptr este definit n fiierul memory
class X{
auto_ptr<int> p; void init();
public:
X(int s) {p = new int[s]; init();}
~X() {delete []p;}
//
}
17
Excepii n destructor
Un destructor este invocat:
Apel normal: la ieirea din blocul unde a fost definit
obiectul, delete
Apel la tratarea unei excepii: la desfurarea stivei
Dac n al doilea caz destructorul ar genera o excepie
se consider c mecanismul eueaz i se apeleaz
terminate()
Dac destructorul apeleaz funcii ce genereaz
excepii, se poate proteja prin includerea acestora ntr-
un bloc try i adugarea unui handler catch(){}
Se poate folosi funcia uncauth_exception()
din <stdexcept> pentru a verifica dac o anume
excepie a fost tratat sau nu
18
Excepii care nu sunt erori
#include <iostream>
#include <math.h>
using namespace std;
void main(){
int nr;
cout << "Numar> ";
cin >> nr;
cout << endl;
try{
if (nr == 0) throw "zero";
if (nr == 1) throw "unu";
if (nr % 2 == 0) throw "par";
for (int i = 3; i < sqrt(nr); i++)
if (nr % i == 0) throw "neprim";
throw "prim";
}
catch (char *concluzie) {
cout << " Numarul introdus este " << concluzie;
cout << endl;
}
}
19
Specificarea excepiilor
O funcie poate specifica n declaraia sa
mulimea de excepii pe care o genereaz:
tip nume_functie(param) throw(lista tipuri);
void f(int a) throw(t1, t2);
Funcia f poate genera doar excepii de tip t1, t2 i
excepii derivate din aceste tipuri
Prin specificarea excepiilor funcia ofer garanii
apelantului su
n cazul n care la execuie se ajunge la o violare a
acestei specificaii, se apeleaz std::unexpected()
care de fapt pointeaz ctre std::terminate()
20
Specificarea excepiilor
void f() throw (t1, t2)
{
//stuff
}
este echivalent cu:
void f()
try
{
//stuff
}
catch(t1) {trow;} // retrow
catch(t2) {trow;} // retrow
catch () { std::unexpected(); }
21
Specificarea excepiilor
O funcie virtual poate fi extins doar de o funcie care are
specificaia de excepii cel puin cu restricia celei din baz
class B{
public:
virtual void f();
virtual void g() throw(X, Y);
virtual void h throw(X);
}
class D: public B{
public:
void f()throw(X);
voi g() throw(X); // OK
void h() throw(X, Y); // error
}
22
Excepii standard
exception
logic_error
length_error
domain_error
aut_of_range
invalid_argument
runtime_error
range_error
overflow_error
underflow_error
bad_alloc
bad_exception
bad_cast
bad_typeid
ios_base::failure
23
Clasa de baz interfaa
class exception {
public:
exception() throw();
exception(const exception&) throw();
exception& operator=(const exception&) throw();
virtual ~exception() throw();
virtual const char* what() const throw();
};
what() returneaz o descriere a excepiei sub forma unui ir de
caractere
24
Excepii generate de limbaj
bad_alloc
generat de new (eec de alocare de memorie)
bad_cast
generat de dynamic_cast (expresie invalid)
bad_typeid
generat de typeid ( returnare pointer nul)
bad_exception
generat de exception specification
25
class X { };
class Y { };
void f() throw (X, std::bad_exception)
{
//
throw Y(); // throw bad exception
}
26
Excepii generate de std
aut_of_range
generat de bitset, deque, string, vector.
invalid_argument
generat de bitset, fstream
length_error
generat de string, vector (numr de elemente din
container mai mare dect dimensiunea sa)
overflow_error
generat de bitset<>::to_ulong()
ios_base::failure
generat de ios_base::clear()
27
Excepii netratate
funcia std::terminate() se va apela dac:
o excepie este generat cu throw dar nu este tratat;
mecanismul de tratare a excepiilor constat c stiva este
corupt
un destructor apelat n procesul desfurrii stivei cauzat de o
excepie ncearc s nceteze execuia folosindu-se de o
excepie
Comportamentul lui terminate() se poate modifica prin
std::set_terminate() care are ca argument o funcie de tip
void fr parametri
Prin apelul lui set_terminate() pot fi eliberate resursele
(apelul explicit al destructorilor ) nainte de apela abort()
28
Sfaturi (Stroustrup)
Folosii excepii pentru tratarea erorilor
Acolo unde sunt suficiente informaii pentru a gestiona
erorile, renunai la excepii
Minimizai utilizarea blocurilor try
Generai excepii pentru a pune n eviden eurile n
constructori
Evitai generarea de excepii n destructori
Proiectai main() nct s prind i s raporteze toate
excepiile
separai codul ordinar de cel ce trateaz erorile
Folosii specificaii de excepie n interfa
Dezvolt o strategie de tratarea erorilor la proiectarea
aplicaiei
29
STL2 - plan
Algoritmi n STL
Operaii ce nu modific secvena
Operaii ce modific secvena
Sortare
Cutare binar
Merge
Heap
Min/max
Exemple
http://www.cplusplus.com/reference/algorithm/
Standard Template Library: Algorithms
Header-ul <algorithm> definete o colecie de funcii
proiectate pentru a fi aplicate unui domeniu de
elemente ale unui container
Domeniul (range) este orice secven de obiecte, dintr-
un tablou sau container, ce pot fi accesate via pointer
sau iterator
Algoritmii implementai de aceste funcii opereaz
direct pe valorile pointate, nu sunt afectate n nici un
fel structura containerului (dimensiune, memoria
alocat) .
Operaii ce nu modific secvena
for_each Apply function to range
find Find value in range
find_if Find element in range
find_end Find last subsequence in range
find_first_of Find element from set in range
adjacent_find Find equal adjacent elements in range
count Count appearances of value in range
count_if Return number of elements in range
satisfying condition
mismatch Return first position where two ranges differ
equal Test whether the elements in two ranges are
equal
search Find subsequence in range
search_n Find succession of equal values in range
Exemple
void myfunction (int i) {
cout << " " << i;
}
struct myclass {
void operator() (int i) {cout << " " << i;}
} myobject;
int main () {
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), myfunction);
// or:
cout << "\nmyvector contains:";
for_each (myvector.begin(), myvector.end(), myobject);
cout << endl;
return 0;
}
Exemple
vector<int> myvector;
for (int i=1; i<10; i++) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
mycount = (int) count_if (myvector.begin(), myvector.end(), IsOdd);
cout << "myvector contains " << mycount << " odd values.\n";
int myints[]={10,20,30,30,20,10,10,20};
vector<int> myvector (myints,myints+8);
vector<int>::iterator it;
it = search_n (myvector.begin(), myvector.end(), 2, 30); // 2 (== 30)
it = search_n (myvector.begin(), myvector.end(), 2, 10, mypredicate);
Operaii ce modific secvena(1)
copy Copy range of elements
copy_backward Copy range of elements backwards
swap Exchange values of two objects
swap_ranges Exchange values of two ranges
iter_swap Exchange values of objects pointed by two iterators
transform Apply function to range
replace Replace value in range
replace_if Replace values in range
replace_copy Copy range replacing value
replace_copy_if Copy range replacing value
fill Fill range with value
fill_n Fill sequence with value
generate Generate values for range with function
generate_n Generate values for sequence with function
Exemple
int myints[]={10,20,30,40,50,60,70};
vector<int> myvector;
vector<int>::iterator it;
myvector.resize(7);
copy ( myints, myints+7, myvector.begin() );
int RandomNumber () { return (rand()%100); }
struct c_unique {
int current; c_unique() {current=0;}
int operator()() {return ++current;}
} UniqueNumber
vector<int> myvector (8);
vector<int>::iterator it;
generate (myvector.begin(), myvector.end(), RandomNumber);
// functie generator
cout << "myvector contains:";
for (it=myvector.begin(); it!=myvector.end(); ++it)
cout << " " << *it;
generate (myvector.begin(), myvector.end(), UniqueNumber);
// obiect dintr-o clasa cu operator()
Exemple
int myints[]={10,20,30,40,50 }; // myints: 10 20 30 40 50
vector<int> myvector (4,99); // myvector: 99 99 99 99
iter_swap(myints,myvector.begin()); // myints: [99] 20 30 40 50
// myvector: [10] 99 99 99
iter_swap(myints+3,myvector.begin()+2); // myints: 99 20 30 [99]
// myvector: 10 99 [40] 99
vector<int> myvector (8); // myvector: 0 0 0 0 0 0 0 0
fill (myvector.begin(),myvector.begin()+4,5);// myvector: 5 5 5 5 0 0 0 0
fill (myvector.begin()+3,myvector.end()-2,8);// myvector: 5 5 5 8 8 8 0 0
Operaii ce modific secvena(2)
remove Remove value from range
remove_if Remove elements from range
remove_copy Copy range removing value
remove_copy_if Copy range removing values
unique Remove consecutive duplicates in range
unique_copy Copy range removing duplicates
reverse Reverse range
reverse_copy Copy range reversed
rotate Rotate elements in range
rotate_copy Copy rotated range
random_shuffle Rearrange elements in range randomly
partition Partition range in two
stable_partition Partition range in two - stable ordering
Exemple
template <class ForwardIterator> void rotate ( ForwardIterator first,
ForwardIterator middle, ForwardIterator last );
for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
rotate(myvector.begin(),myvector.begin()+3,myvector.end());
// 4 5 6 7 8 9 1 2 3
vector<int> myvector;
for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
reverse(myvector.begin(),myvector.end()); // 9 8 7 6 5 4 3 2 1
for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
bound = partition (myvector.begin(), myvector.end(), IsOdd);
// se rearanjeaza elementele vectorului
// bound = adresa de inceput a partii a doua
// 1 9 3 7 5 6 4 8 2
Sortare
sort Sort elements in range
stable_sort Sort elements preserving order of
equivalents
partial_sort Partially Sort elements in range
partial_sort_copy Copy and partially sort
range
nth_element Sort element in range
Exemple
template <class RandomAccessIterator>
void sort ( RandomAccessIterator first, RandomAccessIterator last );
template <class RandomAccessIterator, class Compare>
void sort ( RandomAccessIterator first, RandomAccessIterator last,
Compare comp );
vector<int> myvector (myints, myints+8); // 32 71 12 45 26 80 53 33
vector<int>::iterator it;
// using default comparison (operator <):
sort (myvector.begin(), myvector.begin()+4); //(12 32 45 71)26 80 53 33
// using function as comp
sort (myvector.begin()+4, myvector.end(), myfunction);
// 12 32 45 71(26 33 53 80)
// using object as comp
sort (myvector.begin(), myvector.end(), myobject);
//(12 26 32 33 45 53 71 80)
Exemple
double mydoubles[] = {3.14, 1.41, 2.72, 4.67, 1.73, 1.32, 1.62, 2.58};
vector<double> myvector;
vector<double>::iterator it;
bool compare_as_ints (double i,double j)
{
return (int(i)<int(j));
}
myvector.assign(mydoubles,mydoubles+8);
stable_sort (myvector.begin(), myvector.end());
// 1.32 1.41 1.62 1.73 2.58 2.72 3.14 4.67
myvector.assign(mydoubles,mydoubles+8);
stable_sort (myvector.begin(), myvector.end(), compare_as_ints);
// elementele cu aceeasi valoare raman in aceeasi ordine
// 1.41 1.73 1.32 1.62 2.72 2.58 3.14 4.67
Exemple
int myints[] = {9,8,7,6,5,4,3,2,1};
vector<int> myvector (myints, myints+9);
vector<int>::iterator it;
// using default comparison (operator <):
partial_sort (myvector.begin(), myvector.begin()+5, myvector.end());
// using function as comp
partial_sort (myvector.begin(), myvector.begin()+5,
myvector.end(),myfunction);
//1 2 3 4 5 9 8 7 6
vector<int> myvector(15);
generate (myvector.begin(), myvector.end(), RandomNumber);
//41 67 34 0 69 24 78 58 62 64 5 45 81 27 61
partial_sort (myvector.begin(), myvector.begin()+5, myvector.end());
//0 5 24 27 34 69 78 67 62 64 58 45 81 41 61
Cutare binar (pe secvene sortate):
lower_bound Return iterator to lower bound
upper_bound Return iterator to upper bound
equal_range Get subrange of equal elements
binary_search Test if value exists in sorted array
Exemple
int myints[] = {10,20,30,30,20,10,10,20};
vector<int> v(myints,myints+8); // 10 20 30 30 20 10 10 20
vector<int>::iterator low,up;
sort (v.begin(), v.end()); // 10 10 10 20 20 20 30 30
low=lower_bound (v.begin(), v.end(), 20); // 3
up= upper_bound (v.begin(), v.end(), 20); // 6
bounds=equal_range (v.begin(), v.end(), 20); // 3 6
template <class ForwardIterator, class T>
bool binary_search ( ForwardIterator first, ForwardIterator last,
const T& value );
template <class ForwardIterator, class T, class Compare>
bool binary_search ( ForwardIterator first, ForwardIterator last,
const T& value, Compare comp );
if (binary_search (v.begin(), v.end(), 3)) //
if (binary_search (v.begin(), v.end(), 6, myfunction)) //
Merge (pe secvene sortate)
merge Merge sorted ranges
inplace_merge Merge consecutive sorted ranges
includes Test whether sorted range
includes another sorted range
set_union Union of two sorted ranges
set_intersection Intersection of two sorted
ranges
set_difference Difference of two sorted ranges
set_symmetric_difference Symmetric difference
of two sorted ranges
Exemple
template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator merge ( InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
OutputIterator result );
template <class InputIterator1, class InputIterator2,
class OutputIterator, class Compare>
OutputIterator merge ( InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
OutputIterator result, Compare comp );
int first[] = {5,10,15,20,25};
int second[] = {50,40,30,20,10};
vector<int> v(10);
sort (first,first+5); // 5,10,15,20,25
sort (second,second+5); // 10,20,30,40,50
merge (first,first+5,second,second+5,v.begin());
//5 10 10 15 20 20 25 30 40 50
Heap
push_heap Push element into heap range
pop_heap Pop element fromheap range
make_heap Make heap fromrange
sort_heap Sort elements of heap
Exemple
template <class RandomAccessIterator>
void make_heap ( RandomAccessIterator first, RandomAccessIterator last );
template <class RandomAccessIterator, class Compare>
void make_heap ( RandomAccessIterator first, RandomAccessIterator last,
Compare comp );
int myints[] = {10,20,30,5,15};
vector<int> v(myints,myints+5);
make_heap (v.begin(),v.end());
cout << "initial max heap : " << v.front() << endl; // 30
pop_heap (v.begin(),v.end()); v.pop_back();
cout << "max heap after pop : " << v.front() << endl; // 20
v.push_back(99); push_heap (v.begin(),v.end());
cout << "max heap after push: " << v.front() << endl; // 99
sort_heap (v.begin(),v.end());
cout << "final sorted range :";
for (unsigned i=0; i<v.size(); i++) cout << " " << v[i]; // 5 10 15 20 99
Min/max
min Return the lesser of two arguments
max Return the greater of two arguments
min_element Return smallest element in range
max_element Return largest element in range
lexicographical_compare Lexicographical less-
than comparison
next_permutation Transform range to
next permutation
prev_permutation Transform range to
previous permutation
Exemple
template <class ForwardIterator>
ForwardIterator min_element ( ForwardIterator first, ForwardIterator last );
template <class ForwardIterator, class Compare>
ForwardIterator min_element ( ForwardIterator first, ForwardIterator last,
Compare comp );
int myints[] = {3,7,2,5,6,4,9};
// using default comparison:
cout << *min_element(myints,myints+7) << endl; // 2
cout << *max_element(myints,myints+7) << endl; // 9
char first[]="Apple"; // 5 letters
char second[]="apartment"; // 9 letters
cout << "Using default comparison (operator<): ";
if (lexicographical_compare(first,first+5,second,second+9))
cout << first << " is less than " << second << endl;
else
if (lexicographical_compare(second,second+9,first,first+5))
cout << first << " is greater than " << second << endl;
else
cout << first << " and " << second << " are equivalent\n";
Exemple
template <class BidirectionalIterator>
bool next_permutation (BidirectionalIterator first,
BidirectionalIterator last );
template <class BidirectionalIterator, class Compare>
bool next_permutation (BidirectionalIterator first,
BidirectionalIterator last, Compare comp);
int myints[] = {1,2,3};
cout << "The 3! possible permutations with 3 elements:\n;
sort (myints,myints+3);
do {
cout << myints[0] << " " << myints[1] << " " << myints[2] << endl;
} while ( next_permutation (myints,myints+3) );