Documente Academic
Documente Profesional
Documente Cultură
Abstractizarea datelor
Vom face n cursul de Programarea calculatoarelor i limbaje de programare II
o introducere n programarea orientat pe obiecte, cu aplicaii n limbajul de
programare C++. Cursul de Programarea calculatoarelor i limbaje de programare I a
realizat o prezentare a elementelor de programare structurat pe care le vom folosi
acum pentru a crea aplicaii care folosesc obiecte. Am introdus, totui, i cteva
concepte de programare obiectual.
Am vzut c programarea orientat pe obiecte (object oriented programming
OOP) ncapsuleaz date (atribute) i funcii (comportamente) n pachete numite
clase. O clas poate fi asemnat cu un proiect, un ablon, o descriere. Avnd la
dispoziie o clas, un programator poate s creeze obiecte din acea clas. Clasele
au proprietatea de ascundere a informaiei (information hiding). Aceasta nseamn
c, dei obiectele pot s comunice unele cu altele prin intermediul unor interfee,
claselor nu le este permis s acceseze detaliile de implementare ale altor clase. Se
spune c detaliile de implementare sunt ascunse n interiorul claselor. Vom vedea de
ce este att de important ascunderea informaiei n ingineria software.
n programarea procedural aplicaiile tind s fie orientate pe aciuni, n timp ce
n programarea obiectual ele sunt, n mod ideal, orientate pe obiecte. n limbajul de
programare C care este unul procedural, unitatea de program este funcia. n C++, n
schimb, unitatea de program este clasa din care pot fi instaniate sau create obiecte.
Programatorii de aplicaii scrise n limbajul C se concentreaz pe scrierea de
funcii. Grupurile de aciuni care realizeaz o operaie formeaz o funcie, iar funciile
sunt grupate pentru a forma un program. Datele sunt importante pentru o aplicaie C,
dar ele sunt privite ca un suport pentru aciunile pe care le realizeaz funciile.
Verbele din setul de specificaii ale unei aplicaii ajut programatorul C s determine
care sunt funciile necesare implementrii sistemului.
Programatorii C++ se concentreaz pe crearea propriilor tipuri de date (userdefined types) numite clase. Clasele se mai numesc si tipuri de dat definite de
programator (programmer-defined types). Fiecare clas conine datele i setul de
funcii care le manipuleaz. Datele care intr n componena unei clase se numesc
date membre. Funciile care intr n alctuirea unei clase se numesc funcii membre.
n alte limbaje de programare, datele membre se numesc proprieti, iar funciile
menbre se numesc metode. O instan a unui tip de dat predefinit (built-in type), de
exemplu int, se numete variabil, n timp ce o instan a unui tip de dat definit de
utilizator, adic a unei clase, se numete obiect. Putem folosi termenul de obiect
poate fi folosit i pentru a ne referi la variabile. n proiectarea unei aplicaii orientate
pe obiecte ne focalizm atenia n principal asupra claselor i mai puin asupra
funciilor. Substantivele din specificaiile unui sistem software ne ajut s identificm
setul de clase care urmeaz a fi folosite pentru crearea obiectelor care, lucrnd
mpreun, implementeaz aplicaia.
Clasele n C++ pot fi privite ca o evoluie de la noiunea de structur din
limbajul C. Vom implementa mai nti un tip de dat folosind o structur. Vom trece
apoi la implementarea aceluiai tip de dat folosind o clas.
Exemplu
struct Time
{
int hour;
int minute;
int second;
};
Cuvntul rezervat struct se folosete pentru a defini o nou structur.
Identificatorul Time este numele ales de noi n exemplu pentru a denumi noul tip de
dat definit prin aceast structur. ntre acolade se gsesc membrii structurii.
Membrii aceleiai structuri trebuie s aib nume unice, ns dou structuri diferite pot
conine membri cu aceleai nume. Definiia unei structuri se ncheie cu ;.
O structur nu poate conine un membru al crui tip s fie chiar cel definit de
ea. n exemplul anterior, structura Time nu poate conine un membru de tip Time.
Poate, ns, s conin un membru care este pointer la tipul Time, fiind vorba, n
acest caz, de o structur autorefernial. Aceste structuri sunt utile, e exemplu, atunci
cnd se definesc structuri de date precum listele nlnuite, stivele sau arborii.
Aceast observaie este valabil i pentru clase.
Definiia unei structuri nu implic rezervarea de spaiu de memorie. n schimb,
declaraiile de obiecte dintr-un tip definit printr-o structur presupun alocari de
memorie. Declaraia
Time timeObject, timeArray[10],
*timePtr, &timeRef = timeObject;
declar timeObject ca un obiect de tip Time, timeArray ca tablou de 10
elemente de tip Time, timePtr ca pointer la un obiect de tip Time i timeRef ca
referin la un obiect de tip Time iniializat cu timeObject.
Exemplu
#include <iostream>
using std::cout;
using std::endl;
struct Time //definitia structurii
{
int hour;
//0-23
int minute; //0-59
int second; //0-59
};
void printShort(const Time&);
void printLong (const Time&);
int main()
{
Time dinnerTime; //obiect de tip Time
//asignarea unor valori valide membrilor obiectului
dinnerTime.hour = 18;
dinnerTime.minute = 30;
dinnerTime.second = 0;
cout << "Cina va avea loc la ora ";
printShort(dinnerTime);
cout << " (format scurt), \nadica la ora ";
printLong(dinnerTime);
cout << " (format lung).\n" << endl;
//asignarea unor valori invalide membrilor obiectului
dinnerTime.hour = 29;
dinnerTime.minute = 73;
cout << "Obiect de tip Time cu valori invalide: ";
printShort(dinnerTime);
cout << endl;
return 0;
}
void printShort(const Time &t)
{
cout << (t.hour < 10 ? "0" : "") << t.hour << ":"
<< (t.minute < 10 ? "0" : "") << t.minute;
}
void printLong(const Time &t)
{
cout << ((t.hour == 0 || t.hour == 12) ?
12 : t.hour % 12)
<< ":" << (t.minute < 10 ? "0" : "") << t.minute
3
Funciile membre
Definiia clasei Time din exemplul de mai sus conine prototipurile celor patru
funcii membre. Acestea sunt aezate dup specificatorul public (n seciunea
public a clasei) i se numesc Time, setTime, printShort i printLong.
Acestea se numesc funcii membre publice sau servicii publice sau comportamente
publice sau interfaa clasei. Aceste funcii pot fi folosite de clienii clasei pentru a
manipula datele clasei. Clienii clasei sunt poriunile de program care folosesc
obiecte ale clasei. Datele membre ale clasei reprezint suportul pentru serviciile
oferite de clas clienilor si prin intermediul funciilor membre. Serviciile permit
codului client s interacioneze cu un obiect al casei.
n lista de funcii membre se gsete una care are acelai nume cu cel al clasei.
Ea este o funcie special care se numete constructor al clasei i care are rolul de a
iniializa membrii unui obiect al clasei. Constructorul clasei este apelat automat atunci
cnd se creeaz n memoria calculatorului un obiect al clasei. O clas poate avea
mai muli constructori, acest lucru fiind posibil prin mecanismul suprancrcrii
funciilor. Pentru funciile constructor nu se specific niciun tip al valorii returnate,
deci ele nu ntorc valori.
Datele membre
n definiia clase Time, cele trei date membre, hour, minute i second, apar
dup specificatorul de acces private. Acesta indic faptul c cei trei membri sunt
accesibili doar funciilor membre sau, aa cum vom vedea ntr-unul dintre capitolele
urmtoare, prietenilor clasei. Datele membre poti fi accesate doar de cele patru
5
funcii membre care apar n definiia clasei. Se obinuiete ca datele membre s fie
listate n seciunea private a unei clase i funciile membre n seciunea public a
clasei. Vom vedea c putem avea i funcii private i date membre publice. Cu toate
acestea, este considerat o greeal de proiectare a unei aplicaii orientate pe
obiecte folosirea datelor membre publice.
Obiectele
Un obiect const dintr-o copie a setului de date membre declarate n clas.
Funciile membre sunt partajate ntre toate obiectele unei clase, neexistnd copii ale
funciilor pentru fiecare obiect n parte.
Odat definit o clas, aceasta poate fi folosit ca tip de dat pentru declararea
obiectelor, tablourilor, pointerilor sau referinelor. Tipul de dat introdus printr-o clas
poate fi utilizat n acelai fel ca i tipurile predefinite. Putem avea ntr-un program mai
multe obiecte dintr-o clas, aa cum putem avea mai multe variabile de tip int.
Programatorul poate s creeze oricte tipuri de dat are nevoie ntr-un program. Din
acest motiv, limbajul C++ se spune c este un limbaj extensibil.
Exemplu
Time sunset,
//obiect de tip Time
arrayOfTimes[5],
//tablou de obiecte Time
*pointerToTime,
//pointer la un obiect de tip Time
&dinnerTime = sunset; //referinta la un obiect Time
n programul urmtor vom folosi clasa Time pentru a nlocui tipul de dat definit
prin structura Time. Vom vedea cum se definesc funciile membre, cum se declar
(instaniaz) obiecte ale clasei Time i cum se apeleaz funciile membre.
Exemplu
#include <iostream>
using std::cout;
using std::endl;
//Declaratia tipului abstract de
class Time
{
public:
Time();
void setTime(int, int, int);
void printShort();
void printLong ();
private:
int hour;
//0-23
int minute; //0-59
int second; //0-59
};
data Time
//constructor
//asignarea valorilor
//tiparire in format scurt
//tiparire in format lung
return 0;
}
Rulnd programul, vom obine urmtorul rezultat:
Valoarea initialia in format scurt este 00:00
Valoarea initialia in format lung este 12:00:00 AM
Ora in format scurt dupa setTime este 13:27
Ora in format lung dupa setTime este 1:27:06 PM
Dupa asignarea valorilor invalide:
Ora in format scurt: 00:00
Ora in format lung: 12:00:00 AM
Programul instaniaz obiectul t de tip Time. Atunci cnd este instaniat acest
obiect, constructorul clasei Time este apelat automat. Conform definiiei acestei
funcii, datele membre private hour, minute i second sunt iniializate cu valoarea
0. Funcia membr setTime asigneaz valori noi celor trei date membre, iar funciile
printShort i printLong tipresc ora n format scurt i n format lung.
Datele membre ale clasei Time sunt private, nefiind accesibile din afara clasei.
Conform principiilor programrii orientate pe obiecte, reprezentarea datelor din
interiorul clasei este n afara zonei de interes a clientului clasei. De exemplu, o alt
reprezentare a orei ar putea fi sub forma numrului de secunde scurs de la miezul
nopii. Clienii ar putea folosi aceleai funcii membre publice, obinnd aceleai
rezultate fr s cunoasc aceste detalii. Astfel, implementarea unei clase se spune
c este ascuns clienilor. Ascunderea informaiei reprezint imposibilitatea de a
accesa detaliile de implementare ale unei clase prin metode din afara sa.
Ascunderea informaiei promoveaz posibilitatea de a modifica programele i de a
simplifica percepia clienilor asupra unei clase. Dac implementarea unei clase se
schimb, de exemplu pentru a i mbunti performanele, interfaa clasei rmnnd
neschimbat, programul client nu trebuie modificat. Acest avantaj face ca
modificarea unui sistem s fie mult mai uoar.
n programul de mai sus, constructorul clasei Time iniializeaz datele membre
cu valori 0. Acest lucru asigur faptul c obiectele sunt ntr-o stare consistent atunci
cnd sunt create. Obiectele de tip Time nu pot conine valori iniiate aleatoare
invalide deoarece constructorul este apelat automat, conform mecanismelor
implementate de orice limbaj de programare orientat pe obiecte. Nici operaiile
ulterioare nu pot introduce valori incorecte n datele membre ale obiectelor Time
pentru c funcia setTime a fost scris n aa fel nct verific ncadrarea n
domeniile dorite a ntregilor care se vor stoca.
Diagrama UML a clasei Time este urmtoarea:
Time
-hour : int = 0
-minute : int = 0
-second : int = 0
+setTime(h : int, m : int, s : int):
+printShort() : void
+printLong() : void
8
void
Membrii private sunt marcai prin semnul -, iar cei public prin +. Valorile
iniiale are datelor membre sunt specificate n dreptul fiecreia dintre ele dup
semnul =. Datele membre nu pot fi iniializate atunci cnd sunt declarate n corpul
claselor. O astfel de operaie produce o eroare de compilare. Datele membre trebuie
iniializate de constructorii claselor sau li se pot asigna valori prin funcii de tip set.
O funcie care are acelai nume cu cel al clasei dar este precedat de
caracterul tilda (~) se numete destructor al clasei. Cu ajutorul lor, programatorul
poate implementa operaiile care consider c trebuie realizate nainte de eliberarea
memoriei care a fost alocat obiectului. Destructorii sunt funcii care nu pot avea
argumente, deci nu pot fi suprancrcai.
Adeseori, clasele nu trebuie create de la zero, ci pot fi derivate din alte clase
care ofer atribute i comportamente care pot fi refolosite. O alt posibilitate este
posibilitatea de a include n noile clase obiecte altor clase ca membri. Reutilizarea
codului n aceast manier poate crete semnificativ productivitatea n dezvoltarea
software. Derivarea noilor clase din clase existente se numete motenire, iar
includerea obiectelor unei clase ca membri n alte clase se numete compunere sau
agregare.
Operatorii folosii pentru a accesa membrii unei clase sunt identici cu cei folosii
pentru accesul membrilor unei structuri. Operatorul punct . se folosete n
combinaie cu numele unui obiect sau cu cel al unei referine la un obiect pentru a
accesa membrii obiectului. Operatorul sgeat -> se folosete n combinaie cu un
pointer la un obiect pentru a accesa membrii obiectului.
time.cpp
#include <iostream>
using std::cout;
#include "time.h"
//Constructorul clasei Time initializeaza
//toate datele membre cu valoarea 0.
//Ne asiguram astfel ca orice obiect de tip
//Time porneste dintr-o stare consistenta.
Time::Time()
{
hour = minute = second = 0;
}
//Asignarea unor noi valori datelor membre din Time
//Este verificata validitatea datelor
//Valorile invalide sunt inlocuite cu 0
void Time::setTime(int h, int m, int s)
{
hour = (h >= 0 && h < 24) ? h : 0;
minute = (m >= 0 && m < 60) ? m : 0;
second = (s >= 0 && s < 60) ? s : 0;
}
void Time::printShort()
{
cout << (hour < 10 ? "0" : "") << hour << ":"
<< (minute < 10 ? "0" : "") << minute;
}
void Time::printLong()
{
cout << ((hour == 0 ||
12 : hour % 12)
<< ":" << (minute
<< ":" << (second
<< (hour < 12 ? "
}
test_time.cpp
#include <iostream>
using std::cout;
using std::endl;
hour == 12) ?
< 10 ? "0" : "") << minute
< 10 ? "0" : "") << second
AM" : " PM");
#include "time.h"
int main()
{
Time t; //instantiaza obiectul t de tip Time
cout << "Valoarea initialia in format scurt este ";
11
t.printShort();
cout << "\nValoarea initialia in format lung este ";
t.printLong();
t.setTime(13, 27, 6);
cout << "\n\nOra in format scurt dupa setTime este ";
t.printShort();
cout << "\nOra in format lung dupa setTime este ";
t.printLong();
//asignarea unor valori invalide membrilor obiectului
t.setTime(99, 99, 99);
cout << "\n\nDupa asignarea valorilor invalide:"
<< "\nOra in format scurt: ";
t.printShort();
cout << "\nOra in format lung: ";
t.printLong();
cout << endl;
return 0;
}
Definiia clasei este inserat n interiorul urmtorului cod destinat
preprocesorului:
//Previne includerile multiple ale fisierului header
#ifndef TIME_H
#define TIME_H
...
#endif
n programele de dimensiuni mari, cu multe fiiere header care la rndul lor includ
alte fiiere header, pot aprea situaii n care unul dintre ele ar putea fi inclus de mai
multe ori. Aceste directive de preprocesare se folosesc pentru a preveni includerea
multipl care conduce la erori de compilare.
Exemplu
test_private.cpp
#include <iostream>
using std::cout;
#include "time.h"
int main()
{
Time t;
//Eroare: Time::hour nu este accesibil
t.hour = 7;
//Eroare: Time::minute nu este accesibil
cout << "minute=" << t.minute;
return 0;
}
La compilare, apar urmtoarele erori:
C:\Dev-Cpp\Project\PCLPII\C1\Ex4\/time.h:
main()':
In
C:\Dev-Cpp\Project\PCLPII\C1\Ex4\/time.h:13:
Time::hour' is private
function
`int
error:
`int
C:\Dev-Cpp\Project\PCLPII\C1\Ex4\test_private.cpp:11:
within this context
C:\Dev-Cpp\Project\PCLPII\C1\Ex4\/time.h:14:
Time::minute' is private
error:
C:\Dev-Cpp\Project\PCLPII\C1\Ex4\test_private.cpp:14:
within this context
13
error:
`int
error: