Академический Документы
Профессиональный Документы
Культура Документы
CALCULATOARELOR 2
Modul 2, partea I
Curs 4
1
CUPRINS
2
1. CONCEPTE ALE PROGRAMĂRII OBIECTUALE
DE CE POO (PROGRAMARE ORIENTATĂ PE OBIECTE)?
Orice program este compus din 2 părți distincte:
- date (de intrare și/sau iesire) → tipuri de date
- operații → funcții
Tipuri de date utilizate în programare:
- tipuri predefinite
- tipuri de date utilizator (în C/C++ prin utilizarea struct,
union, enum și typedef); operațiile acționează tot asupra
unor tipuri predefinite de date, elementele componente nu
sunt protejate → programarea structurată
- clasa: tip abstract, reunește date și operații în cadrul
aceluiași tip de dată → Programarea ADT (Abstract Data
Type – abstractizare a datelor) 3
CONCEPTE ALE PROGRAMĂRII OBIECTUALE
4
POO a apărut pentru a elimina dezavantajele
programării structurate, în ceea ce privește tratarea
separată a algoritmilor și a structurilor de date ce se
prelucrează, posibilitatea reutilizării programelor,
scalabilității unor module de program.
5
Proiectarea de programe utilizând clase se numește
programare prin abstractizarea datelor ADT, iar dacă se
consideră și mecanismul moștenirii avem programare
orientată pe obiecte (POO).
Date + Metode = Clasa
6
Primul limbaj orientat pe obiecte este Simula 67,
dezvoltat în cadrul Norwegian Computing Centre. (anii
‘60)
Alan Kay este considerat promotorul programării
orientate pe obiecte
Simula a rămas un instrument în dezvoltarea de noi
limbaje, cele mai importante în anii 70-80 fiind Smalltalk,
Eiffel și C++.
În acest moment cele mai folosite limbaje obiectuale sunt
derivate din C++, și anume C#, Java, Python, PhP, etc.
7
OBIECTELE
Ce este un obiect? Un obiect modelează o entitate din
lumea reală sau imaginară.
9
Clasa = un șablon pentru generarea unor obiecte având
structura și comportamentul identice
10
Mesajele fac apel la serviciile pe care obiectul le poate
oferi. Obiectele comunică prin intermediul mesajelor
(emițătoare și receptoare). Mesajul - obiect, numele
metodei și parametrii care rafinează mesajul.
Abstractizarea datelor:
− identifică proprietățile generale și esențiale, omițând
unele detalii neesențiale (Ex. – carnet șofer)
un obiect este caracterizat complet de specificaţiile
metodelor sale, detaliile de implementare fiind
transparente pentru utilizator (principiul lui Parnas)
modificarea structurii datelor membre are efect numai
asupra metodelor, iar dacă se păstrează specificaţiile
metodelor, nu afectează utilizarea obiectului 12
Pot exista la un moment dat mai multe obiecte de acelaşi
tip, adică instanţe ale aceleiaşi clase:
instanţele obiectului vor avea date diferite, dar vor
partaja acelaşi cod corespunzător metodelor clasei din
care provin
13
Moștenirea
Clasa originală se numește clasa de bază sau
superclasă, iar noua clasă - clasa derivată sau sub-clasă.
Polimorfism
15
POO :
definire de tipuri abstracte (ADT) +
derivarea tipurilor +
[polimorfism (inclus de obicei în ADT și
derivare)]
18
Declararea unei clase
Membrii pot fi :
date membre -> specifică reprezentarea obiectelor
clasei:
sintactic acestea se declară ca şi variabilele obişnuite
19
Specificator de acces
Antet clasa class <nume_clasa>
{
[private:]
[declaratii de date] Sectiune
[declaratii de functii]
[protected:]
Corp clasa [declaratii de date] Sectiune
[declaratii de functii]
[public:]
[declaratii de date] Sectiune
[declaratii de functii]
} [lista de obiecte];
20
Membrii unei clase pot aparţine unor secţiuni delimitate de
etichete de acces sau specificatori de acces:
public, private şi protected
Specificatorii de acces:
permit ascunderea datelor şi metodelor
ordinea în care apar este nerelevantă
dacă nu este prezent nici un specificator de acces toate
datele membre şi toate metodele membre se consideră
că sunt private
21
Un membru care este public poate fi utilizat de orice altă
funcţie (din clasă sau din afara clasei)
Exemplu:
class Rectangle
{
int x, y;
public:
void setVal(int, int);
int aria(void) {
return x*y; }
}; 23
Criterii de calitate ale unei clase (Bjarne Stroustrup)
O clasă trebuie să ofere un set mic, dar suficient și bine
definit de operații publice
O clasă trebuie să poată fi privită ca și o cutie neagră,
manevrabilă prin setul de operații
O clasă trebuie să aibă un set restrâns de date publice, pe
cât posibil, niciuna
O clasă trebuie să fie ușor modificabilă, fără ca acest lucru
să se răsfrângă asupra interfeței publice (cu excepția
extinderii acesteia)
24
Accesul la membri
Obiectul: o instanţă a unei clase
25
Un obiect poate fi privit ca o generalizare a noțiunii de
variabilă, astfel încât toate aspectele referitoare la
variabile sunt păstrate:
- din punct de vedere al accesului avem obiecte
locale și globale
- din punct de vedere al alocării avem obiecte statice,
automatice și dinamice
26
Accesul din exterior la membrul public al unui obiect (dată
sau funcţie/metodă) se face cu operatorul punct(.) :
nume_obiect.data_membra
nume_obiect.metoda_membra(lista_param_actuali)
28
Definirea metodelor
Dacă definirea metodei este realizată în interiorul clasei,
sintaxa definiţiei este identică cu cea a oricărei funcţii
întâlnite în programarea non-obiectuală
În acest caz avem aşa numitele metode inline pentru care
compilatorul va încerca o implementare inline:
class nume_clasa{
…
// metoda inline
tip_returnat nume_metoda (lista_parametri_formali)
{
// corp metoda
}
…
29
} [lista_de_obiecte];
O altă metodă de descriere a unei clase este de a declara
doar prototipul metodelor membre în interiorul clasei şi de a
le defini funcţionalitatea lor în exteriorul zonei de cod
alocate acesteia
În această situaţie, în momentul implementării corpului
metodei respective, trebuie să specificăm numele clasei
căreia îi aparţine metoda al cărei conţinut urmează să fie
scris
Pentru aceasta se foloseşte operatorul de rezoluţie sau
scop, simbolizat prin ::
31
int main (void){
Rectangle dr1, dr2; // declarare obiecte
dr1.setVal(4,5); // apel metoda
dr2.setVal(3,4); // apel metoda
cout<< “Aria obiectului 1: “ << dr1.aria( ); // apel metoda
cout<< “\nAria obiectului 2: “ << dr2.aria( ); // apel metoda
}
Operatorul de rezoluţie mai poate fi folosit pentru a distinge
între datele membre şi variabile locale cu acelaşi nume
dintr-un bloc (funcţie sau instrucţiune compusă) :
class Point
{
private:
int x, y;
public:
void setVal(int x, int y)
{
Point::x = x;
Point::y = y;
}
}; 33
class Access {
int nA;
int getA( ) { return nA; }
private: // redundant
int nB;
int getB( ) { return nB; }
protected:
int nC;
int getC( ) { return nC; }
public:
int nD;
int getD( ) { return nD; }
};
34
int main( )
{
Access cAccess;
cAccess.nD = 5; // corect
std::cout << cAccess.getD( ); // corect
35
Pentru accesul la date putem utiliza funcții de tip accesor
(care returnează valoarea unei date membre – getter)
sau funcţii de tip mutator (care setează valoarea unei
date membre – setter)
class Date{
private:
int nMonth;
int nDay;
int nYear;
public:
// Getters
int getMonth( ) { return nMonth; }
int getDay( ) { return nDay; }
int getYear( ) { return nYear; }
// Setters
void setMonth(int Month) { nMonth = Month; }
void setDay(int Day) { nDay = Day; } 36
void setYear(int Year) { nYear = Year; }
};
Avantaje:
Dacă se doreşte modificarea datelor membre, se
modifică funcţiile accesor și/sau mutator şi, atât timp cât
nu se modifică specificaţiile acestora, utilizarea acestor
metode nu se modifică
37
• Se simplifică depanarea programului, deoarece
modificarea datelor membre se face controlat, prin
intermediul unei singure funcţii
38
STRUCTURI ÎN C++
În limbajul C structurile au doar date membre
În limbajul C++, o structură e asimilată unei clase, toți
membrii fiind implicit public:
o structură în C++ poate include metode
42
Utilizări ale autoreferinţei :
în cazul în care avem de-a face în interiorul unei funcţii
dintr-o clasă cu alte instanţe ale clasei:
this ajută la diferenţierea variabilelor din clasă în ceea ce
priveşte obiectele de care aparţin
pointerul în discuţie va indica întotdeauna obiectul curent
43
Utilizări ale autoreferinţei :
în metode ce supraîncarcă operatorul de atribuire -
asignare ( = ), când se returnează obiectul curent
în clase în care parametrul unei metode are același
nume cu un atribut al clasei :
class X{
int a;
public:
X(int a){
this->a=a; // X::a = a;
}
…};
44
EX. POINTERUL THIS
#include <iostream>
using namespace std;
class TimeClass {
int hours, minutes;
public:
TimeClass ( int new_hours, int new_minutes) // constructor
{ hours = new_hours; minutes = new_minutes; }
void setTime ( int new_hours, int new_minutes )
{ hours = new_hours; minutes = new_minutes; }
void getTime ( int ¤t_hours, int ¤t_minutes){
current_hours = hours; current_minutes = minutes; }
void copyTime( TimeClass &Time2);
};//TimeClass
45
void TimeClass::copyTime (TimeClass &Time2){
this->hours=Time2.hours;
this->minutes=Time2.minutes;};
int main(void){
TimeClass Time1 (11,25), Time2 (12,12),Time3(1,1); // instantieri
int hrs, mins;
Time1.getTime(hrs, mins);
cout<<"time1 is: " <<hrs<< ":" <<mins<<endl;
Time2.getTime(hrs, mins);
cout<<"time2 is: " <<hrs<< ":" <<mins<<endl;
Time3.copyTime(Time2);
Time3.getTime(hrs, mins);
cout<<"\nAfter copying Time2 to Time3, the time is :
"<<hrs<<":"<<mins<<endl;
cout<<"\npress Enter to continue."; cin.get();
46
}//main
Constructori şi destructori
47
Teoretic constructorii și destructorii pot fi publici sau
privaţi, dar uzual se folosesc ca membri publici
48
TIPURI DE OBIECTE
Automatice, sunt create de fiecare dată când apare o
definiție a unui obiect la execuție și sunt distruse când se
părăsește blocul unde au fost create
Statice (globale, locale), sunt create o singură dată,
când programul e pornit (în cadrul blocului pentru cele
locale) și sunt distruse la sfârșitul programului.
Dinamice, sunt create de programator în heap-ul
dinamic cu operatorul new și sunt distruse cu delete.
Derivate, aparțin claselor derivate, dar înainte se
apelează constructorul clasei de bază și apoi
constructorul din clasa derivată, dacă e necesar
Anonime, au o existență temporară, fiind necesare în
evaluarea expresiilor sau la transferul parametrilor pe
49
stivă
Caracteristici comune constructori/destructori :
definirea obiectelor
Caracteristici specifice destructorilor :
52
Observații constructori:
class Rectangle {
int x,y;
public:
//constructor explicit cu parametri impliciți
Rectangle(int a=0, int b=0) {
x = a; y = b;
}
void setX(int);
void setY(int);
int aria(void) {
return x*y;
} 56
};
void Rectangle::setX(int a) {
if (a>0) x=a;
else x = 0;
}
void Rectangle::setY(int b) {
if (b>0) y=b;
else y = 0;
}
public:
Stiva( void );
Stiva( int );
~Stiva( void );
int push( char c );
int pop( char &c );
int isEmpty( void );
int isFull( void );
58
};
// constructori
Stiva :: Stiva(void) {
next = -1;
dim = 256;
stack = new char [dim];
}
// destructor
Stiva :: ~Stiva(void) {
delete [ ] stack;
} 59
// test stiva goala
int Stiva :: isEmpty(void) {
if (next < 0)
return 1;
else
return 0;
}
buf[0] = ‘\0’;
i=0;
while(!mesaj.isEmpty( ))
mesaj.pop(buf[i++]);
cout << endl << buf << endl;
cin.get();
62
}
Constructorul de copiere
class Stiva {
private:
int dim;
char *stack;
int next;
public:
Stiva(int dim_i);
~Stiva(void);
// …
};
63
Stiva :: Stiva(int dim_i)
{
next = -1;
dim = dim_i;
stack = new char [dim];
}
int main(void)
{
Stiva ob1(10);
Stiva ob2(ob1); // copiază obiectul 1 in obiectul 2
// …
}
64
Compilatorul generează automat un constructor de
copiere (implicit):
acesta face copierea element cu element
66
class Stiva {
…
public:
Stiva(int dim_i=256);
~Stiva(void);
Stiva(const Stiva &);
…
};
int main(void)
{
Stiva ob1(10);
Stiva ob2(ob1);
// Stiva ob2=ob1;
// …
}
68
Constructori cu conversie de tip
Sunt constructori care au primul parametru de tipul unui
atribut al clasei și dacă există alți parametri, aceștia
trebuie să aibă valori implicite.
class Student{
private: char nume[30];
int anul;
int nr_matricol;
public: Student(const char *n, int an=1, int nr=1234);
…
};
69
Student::Student(const char *n, int an, int nr) {
strcpy(nume, n);
anul=an;
nr_matricol=nr;
}
int main() {
Student s=“Popescu”;
…
}
Obs. Constructorul convertește un char * într-un obiect de
tip Student
70
Concluzie: în funcție de tipul argumentelor pasate
constructorilor aceștia pot fi:
71
Alte observații legate de constructori:
73
EXEMPLE: CONSTRUCTORI EXPLICITI
#include <iostream>
using namespace std;
class C{
int x,y;
public: C(){
cout<<"\nCons. explicit fara param. Atributele x si y nedefinite \n";
cout <<"x = "<< x <<'\n';
cout <<"y= "<< y <<'\n'; }
C(int a){ x=a;
cout<<"\nCons. cu un param explicit; Atributul y nedefinit \n";
cout << "x = "<<x <<'\n';
cout << "y= "<<y << '\n'; }
C(int a, int b){ x=a;
y=b;
cout<<"\nCons. cu doi param. expliciti. Atribute definite \n";
cout <<"x = "<<x <<'\n'; 74
cout <<"y= "<< y <<'\n';
}
void setX(int a) { x=a; }
void setY(int b) { y=b; }
void afis(){
cout<<"Afis. metoda"<<endl;
cout <<"x = "<< x <<'\n';
cout <<"y= "<< y <<'\n'; }
};//C class
int main(){
C ob1(10,20);
ob1.setX(7); ob1.setY(7);
ob1.afis();
C ob2(10);
ob2.afis();
C ob3; //val nedefinita, constr. explicit fara param.
ob3.afis();
ob3.setX(1); ob3.setY(1);
ob3.afis(); cin.get(); 75
}//main
76
CONSTRUCTORI PENTRU ALOCAREA DINAMICA A MEMORIEI
#include<string.h>
#include <iostream>
using namespace std;
const int MaxBufferSize=1023;
class CFieldEdit{
private:
char *buffer;
int bufferSize;
public:
CFieldEdit(int FieldSize);
~CFieldEdit();
int getBufferSize() { return bufferSize; }
char *getBuffer() { return buffer; }
}; //CFieldEdit Class
77
//begin constructor
CFieldEdit::CFieldEdit(int fieldSize){
if (fieldSize>MaxBufferSize)
fieldSize=MaxBufferSize;
//lungimea introdusa poate fi mai mare decat cea maxima prestabilita
//in acest caz se reduce la cea maxima prestabilita
buffer=new char[fieldSize];
bufferSize=fieldSize;
printf("\nAm construit un obiect de tip CFieldEdit");
} //CFieldEdit constr
//begin destructor
CFieldEdit::~CFieldEdit(){
delete [ ] buffer;
printf("\nAm distrus un obiect de tip CFieldEdit");
78
} //~CfieldEdit destructor
int main(){
CFieldEdit *aField;
char *str, c;
aField=new CFieldEdit(500);
str=aField->getBuffer();
79
80
COPY-CONSTRUCTOR
#include <iostream>
using namespace std;
class ObiectSimplu {
public:
int valoare;
ObiectSimplu() {
valoare = 0;
}
ObiectSimplu(int v) {
valoare = v;
}
ObiectSimplu(const ObiectSimplu &o) {
valoare = o.valoare;
} //nu e necesar – oferit implicit 81
};//ObiectSimplu Class
class ObiectPointer {
public:
int * valoare;
ObiectPointer() {
valoare=new int;
*valoare = 0;
}
ObiectPointer(int v) {
valoare=new int;
*valoare = v;
}
};// ObiectPointer Class
82
class ObiectPointerCC {
public:
int * valoare;
ObiectPointerCC() {
valoare=new int;
*valoare = 0;
}
ObiectPointerCC(int v) {
valoare=new int;
*valoare = v;
}
ObiectPointerCC(const ObiectPointerCC & o) {
valoare=new int;
*valoare = *o.valoare;
}
83
};// ObiectPointerCC
int main() {
cout<<"Se creaza un obiect simplu a cu valoarea 2.\n";
ObiectSimplu a(2);
cout<<"Se copiaza a in b.\n";
ObiectSimplu b = a;
cout<<"Valoarea lui b este "<< b.valoare<< endl;
cout<<"Se modifica valoarea lui a la 3.\n";
a.valoare = 3;
cout<<"Valoarea lui a este " << a.valoare << endl;
cout<<"Valoarea lui b este « << b.valoare <<endl;
cout<<"\nSe creaza un obiect cu pointer c cu valoarea 10.\n";
ObiectPointer c(10);
cout<<"Se copiaza c in d.\n";
ObiectPointer d = c;
cout<<"Valoarea lui d este " <<*d.valoare <<endl;
84
cout<<"Se modifica valoarea lui c la 13.\n");
*c.valoare = 13;
cout<<"Valoarea lui d este " << *d.valoare << endl;
cout<<"Valoarea lui c este " << *c.valoare << endl;