Documente Academic
Documente Profesional
Documente Cultură
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);
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) );