Sunteți pe pagina 1din 8

Cuprins

1. Clase. Încapsularea sau abstractizarea datelor................................................................................. 1


2. Obiecte instanţiate din aceeaşi clasă ................................................................................................ 4
3. Referinţe ............................................................................................................................................ 5
4. Exerciţii.............................................................................................................................................. 6

1. Clase. Încapsularea sau abstractizarea datelor

O clasă este o extindere a conceptului de structură din C standard. O primă extindere a


structurii a fost realizată în C++. Dacă structura din C standard poate conţine doar date, structura din
C++ poate conţine atât date cât şi funcţii, accesul la ele nefiind restricţionat. Pasul următor în
extinderea structurii a fost restricţionarea accesului la o parte din membrii acesteia. În mod implicit însă,
toţi membrii unei structuri din C++ sunt publici, deci cu acces nerestricţionat. Extinderea structurii din
C++, adică clasa, are în mod implicit toţi membrii privaţi.
De regulă, într-o clasă se grupează şi se protejează datele şi funcţiile care prelucrează aceste
date, în scopul rezolvării unei anumite probleme. Deci clasa poate fi considerată un model de
organizare şi prelucrare a datelor, numit şi tip abstract de date (Abstract Data Types). Rezervând
memorie pentru un set de date al unei clase, grupându-le sub un nume şi eventual iniţializându-le cu
valori concrete, vom obţine o instanţiere a clasei, numită obiect sau instanţă. Numele obiectului este o
variabilă. Datele şi funcţiile declarate în interiorul clasei se numesc membrii clasei. Datele membre ale
unei clase se mai numesc şi câmpuri. Funcţiile membre se mai numesc şi metode. Clasele sunt declarate
cu ajutorul cuvântului cheie class, folosind următoarea sintaxă:

class NumeClasa {
private:
[tip1] membruPrivat1;
[tip2] membruPrivat2;
...

public:
[tip1] membruPublic1;
[tip2] membruPublic2;
...
};

Obiectele sunt declarate ca orice fel de variabile:


NumeClasa numeObiect1, numeObiect2, ...;

Modul de acces poate fi definit prin unul din cuvintele cheie public, private sau
protected. Acesta indică dreptul de acces la membrii definiţi după el.
Membrii declaraţi cu private sunt accesibili doar membrilor din cadrul aceleiaşi clase. Membrii
declaraţi cu public sunt accesibili atât membrilor din cadrul aceleiaşi clase cât şi membrilor altor clase,
de oriunde, din interiorul sau din afara acelor clase. Membrii declaraţi cu protected sunt accesibili
atât membrilor aceleiaşi clase cât şi membrilor claselor derivate din ea.
În mod implicit, toţi membrii unei clase au modul de acces private.
De exemplu:
class Dreptunghi {
int lungime, latime;

public:
void setLungime (int);
void setLatime (int);
int arie (void);
};

Exemplul declară o clasă (adică un tip de dată abstractă) numită Dreptunghi. Aceasta conţine
cinci membri: două câmpuri de tip int (lungime şi latime) cu modul de acces privat şi trei metode cu
modul de acces public: setLungime(int), setLatime(int) şi arie(). Pentru moment am inclus
doar declaraţia acestor metode, nu şi definiţia lor.
Pentru a declara un obiect (o variabilă) cu numele dr, vom folosi următoarea instrucţiune:
Dreptunghi dr;

unde Dreptunghi reprezintă numele clasei, iar dr obiectul instanţiat. Prin această instrucţiune,
se alocă obiectului dr o zonă de memorie corespunzătoare membrilor de tip dată (câmpuri) de lungime
2 * sizeof(int) = 8 octeţi, câmpurile nefiind iniţializate.
În afara clasei, cu ajutorul acestui obiect putem accesa membrii publici, folosind următoarea
sintaxă:
numeObiect.numeMembru;

Accesul la membrii unei clase este foarte asemănător cu accesul datelor dintr-o structură. De
exemplu:
dr.setLatime(10);
dr.setLungime(20);
valArie = dr.arie();

Singurii membri ai obiectului dr pe care nu-i putem accesa în corpul programului nostru, din
afara clasei, sunt lungime şi latime, deoarece au accesul privat.
În continuare, vom completa clasa Dreptunghi cu definiţia metodelor membre:
// exemplu de clasa
#include <conio.h>
#include <iostream>
using namespace std;

class Dreptunghi {
int lungime, latime;
public:
// metode definite in corpului clasei
void setLungime (int L)
{
lungime = L;
}

void setLatime (int l)


{
latime = l;
}
int arie (void);
};

/* metoda care urmeaza este definita in afara corpului clasei */


int Dreptunghi::arie (void)
{
return lungime * latime;
}

int main()
{
Dreptunghi dr;
dr.setLatime(10);
dr.setLungime(20);
cout << "arie: " << dr.arie() << endl;
_getch();
return 0;
}
Ieşire
arie: 200

În afara corpului clasei, în definirea metodei arie(), se observă utilizarea unui operator nou,
numit operator de rezoluţie, fiind simbolizat prin două perechi de două puncte ( :: ). Acest operator
arată domeniul (în cazul de faţă clasa), căruia îi aparţine metoda. Menţionăm că este obligatorie
utilizarea operatorului de rezoluţie pentru definirea unei metode în afara clasei. Declaraţia (prototipul)
metodei definite în afara clasei, trebuie să fie în mod obligatoriu în corpul clasei.
Remarcăm definiţiile metodelor setLungime(int) şi setLatime(int)care au fost incluse
direct în corpul clasei Dreptunghi, datorită faptului că acestea sunt foarte simple.
Membrii lungime şi latime au modul de acces privat. Declarandu-i privaţi, interzicem
accesarea lor directă de către orice funcţie din afara clasei. Iniţializarea câmpurilor din interiorul
obiectului este posibilă, deoarece am definit metodele membru setLungime(int) şi
setLatime(int), care setează valorile câmpurilor lungime şi latime. Datorită lor, în restul
programului, nu este necesar (dar nici posibil) să se acceseze direct câmpurile clasei.

Observaţie
În cadrul exerciţiilor ce vor fi rezolvate la laboratorul de POO, toate declaraţiile de clase se vor
face în fişierele antet (header), la fel ca şi declaraţiile de alte tipuri. Tot aici vom declara şi eventualele
funcţii globale. Definiţia metodelor se va face în fişierul (fişierele) .cpp asociate antetului.
Posibilitatea de a ascunde utilizatorului unei clase detaliile ei de realizare, se numeşte
încapsulare sau abstractizare a datelor. Utilizatorului îi este oferit doar un set de membri publici,
suficienţi pentru a utiliza clasa. Aceşti membri publici constituie interfaţa clasei. Membrii inaccesibili din
exterior sunt declaraţi privaţi sau protejaţi şi realizează implementarea clasei.
Încapsularea sau abstractizarea datelor este unul dintre cele trei principii de bază ale
programării orientate pe obiecte. Celelalte două principii: moştenirea şi polimorfismul, le vom studia în
laboratoarele următoare (6 şi 7).

2. Obiecte instanţiate din aceeaşi clasă

Putem avea mai multe obiecte instanţiate din aceeaşi clasă. Dezvoltând exemplul anterior,
putem declara al doilea obiect drept de tip Dreptunghi:
// exemplu: o clasa, doua obiecte
#include <conio.h>
#include <iostream>
using namespace std;

class Dreptunghi {
int lungime, latime;
public:
void setLungime (int L) {lungime = L;}
void setLatime (int l){ latime = l;}
int arie (void);
};

int Dreptunghi::arie (void)


{
return lungime * latime;
}

int main()
{
Dreptunghi dr;
dr.setLatime(10); dr.setLungime(20);
Dreptunghi drept;
drept.setLatime(5); drept.setLungime(6);
cout <<"arie obiect dr: "
<< dr.arie() << endl;
cout <<"arie obiect drept: "
<< drept.arie() << endl;
_getch();
return 0;
}
Ieşire
arie obiect dr: 200
arie obiect drept: 30

În acest caz, avem două instanţe de tip Dreptunghi: dr şi drept. Fiecare obiect are propriile
valori pentru câmpuri şi poate accesa metodele clasei. Se explică astfel de ce rezultatele sunt diferite,
deşi este apelată aceeaşi metodă: arie().
3. Referinţe

În C++ o funcţie poate primi parametri în două feluri – prin valoare sau prin referinţă.
Transmiterea parametrilor prin valoare este cea obişnuită, cunoscută până acum din limbajul C. Un
parametru transmis prin valoare, dacă este modificat în funcţie, nu îşi va păstra valoarea modificată în
funcţia apelantă. De exemplu, în programul de mai jos, funcţia schimba() este greşită şi nu va avea nici
un efect asupra parametrilor primiţi:

/*exemplu eronat cu transmiterea parametrilor prin valoare */


#include<conio.h>
#include<iostream>
using namespace std;

void schimba(int a, int b) {


int aux = a;
a = b;
b = aux;
}

int main() {
int a = 2, b = 3;
cout << a << " " << b << endl;
schimba(a,b);//a si b raman neschimbate
cout << a << " " << b << endl;
_getch();
return 0;
}
Ieşire:
2 3
2 3

Însă în limbajul C++, putem să transmitem parametrii prin referinţă. În acest caz, modificările
efectuate în funcţie, asupra parametrilor, vor rămâne şi în funcţia apelantă. Pentru a transmite un
parametru prin referinţă, în declaraţia funcţiei vom pune operatorul & în faţa numelui parametrului. De
exemplu, funcţia schimba() cu parametri referinţă va fi declarată astfel:
void schimba(int &a, int &b);

Dacă efectuăm această modificare în exemplul de mai sus, rezultatul va fi:


2 3
3 2

Putem utiliza o astfel de funcţie într-un algoritm de sortare, în locul funcţiei cu pointeri
cunoscute din semestrul trecut, de la Programarea Calculatoarelor:
void schimba(int *pa, int *pb) {
int aux = *pa;
*pa = *pb;
*pb = aux;
}

Referinţa se defineşte ca un nume alternativ pentru variabilă.


De asemenea, este posibil să returnăm o variabilă prin referinţă. În acest caz, nu se mai face
copierea variabilei din stiva funcţiei apelate în stiva funcţiei apelante.
De exemplu:
int& max(int& a, int& b) {
return a > b ? a : b;
}

Referinţele au un rol important în implementarea claselor. Vom reveni la ele în laboratoarele


ulterioare.

4. Exerciţii

1. Să se scrie o clasă Punct care reprezintă un punct din plan. Clasa va conţine:

• câmpurile private x, y în dublă precizie;


• metodele setX(), setY() care setează valorile celor două câmpuri;

• metodele getX(), getY();

• metoda void afis() care afişează coordonatele punctului.

În main(), să se testeze clasa Punct cu toate metodele ei


prin definirea şi afişarea coordonatelor a trei puncte.

2. Să se implementeze clasa Multime, care să păstreze o mulţime de întregi. Clasa trebuie să aibă
următoarele metode publice:
• void init() care iniţializează câmpurile private ale mulţimii;
• void adauga(int)care adaugă un element în mulţime. În cazul în care elementul deja
există, mulţimea rămâne nemodificată;
• void extrage(int) care extrage un element din mulţime. În cazul în care elementul
nu este prezent, mulţimea rămâne neschimbată;
• void afisare() care afişează mulţimea.
Folosiţi următorul program pentru a testa mulţimea:
int main() {
Multime m;
m.init();
m.adauga(4);
m.adauga(3);
m.afisare();
m.extrage(4);
m.afisare();
m.adauga(9);
m.adauga(2);
m.afisare();
_getch();
return 0;
}

Indicaţie: folosiţi un vector pentru a stoca elementele.

3. Să se scrie o clasă Data care să reprezinte o dată calendaristică. Clasa va conţine următorii membri:
• câmpurile zi, luna, an întregi, privaţi;
• metoda setValori(int z, int l, int a) care să seteze valorile celor trei câmpuri;
• metoda afisare() care afişează data la consolă.
Puteţi adăuga şi alţi membri dacă este cazul.
Pe baza clasei Data să se implementeze cerinţele de mai jos:
3.1
• Să se scrie un program care să citească şi să afişeze
un vector de n date.
3.2
• Să se adauge metoda int maiMare(Data data2),
care realizează compararea dintre două date. În această metodă sunt accesibile două obiecte de tip
Data. Unul este obiectul curent, iar celălalt parametrul data2. Metoda returnează 1 dacă data curentă
(din obiectul curent) este mai mare decât data2 şi 0, în caz contrar.
• Să se determine data cea mai mare din vector. Pentru
compararea datelor se va folosi metoda maiMare .
3.3
• Să se adauge metoda afisareLunga() care afişează
data în formatul „29 august 2008”. Să se afişeze datele citite în ambele formate: normal (zz.ll.aaaa) şi
lung.
• Să se adauge metoda ziDinSaptamana() care să
returneze ziua din săptamână pentru obiectul curent de tip Data. De exemplu, pentru luni va returna 1,
iar pentru duminică 7. Pentru simplitate, pentru orice an, să se considere zilele din săptămână la fel ca
pentru anul 2008, ştiind că acest an începe marţi.
De exemplu, pentru datele:
03.09.2008
21.10.2008

Metoda ziDinSaptamana() va returna:


3
2

• Să se adauge metoda afisareCompleta() care


afişează data în următorul format:
3 septembrie 2008, miercuri
Metoda va folosi ziDinSaptamana(). Să se afişeze datele citite în toate cele trei formate.
3.4
• Să se adauge metoda int diff(Data data2) care
returnează diferenţa în zile dintre data curentă şi data păstrată în parametrul data2. Această diferenţă
poate fi un număr negativ, 0, sau un număr pozitiv. Pentru simplitate puteţi considera toţi anii nebisecţi.
• Să se sorteze datele în ordine crescătoare şi să se
afişeze diferenţele dintre oricare două date consecutive.
De exemplu, pentru datele citite:
03.09.2007
03.09.2008
21.10.2008

Rezultatul va fi:
3 septembrie 2007, miercuri
peste 365 zile –
3 septembrie 2008, miercuri
peste 48 zile –
21 octombrie 2008, marti

S-ar putea să vă placă și