Saptamana 03 / 14 Programare Orientata Obiect
Introducere in clase
De la struct la class. Cum definim o clasa cu atribute si metode, ce tipuri de metode exista, cum cream obiecte si cum protejeaza public si private starea unui obiect.
- Sa compari struct, union si class
- Sa definesti o clasa cu atribute si metode
- Sa definesti o metoda in clasa si in afara ei, cu operatorul de rezolutie `::`
- Sa deosebesti tipurile de metode (de acces, de prelucrare, auxiliare, const)
- Sa creezi obiecte si sa explici ca fiecare obiect are propriile atribute
- Sa folosesti public, private si protected si sa stii accesul implicit in struct si class
De ce nu ne ajunge un struct
In saptamana 2 am grupat date cu struct:
struct Student {
int varsta;
string nume;
int* note;
};
Student s;
s.varsta = -40; // compileaza, iar datele nu mai au sens
Oricine poate scrie orice in s.varsta sau s.note. Un struct grupeaza datele, dar nu le protejeaza. O clasa grupeaza datele si operatiile permise asupra lor si poate ascunde datele, astfel incat doar acele operatii sa le poata modifica.
struct, union, class
| Membri | Acces implicit | Folosire tipica | |
|---|---|---|---|
struct | date si functii, fiecare cu memoria lui | public | grupuri simple de date |
class | date si functii, fiecare cu memoria lui | private | tipuri cu reguli |
union | toate datele folosesc aceeasi memorie | public | o valoare dintre mai multe tipuri |
Intr-un union este valid un singur membru la un moment dat: ultimul in care ai scris.
union Valoare {
int i;
double d;
};
Valoare v;
v.i = 42; // i este membrul activ
v.d = 3.5; // acum d este activ; de aici incolo nu mai citim v.i
Citirea altui membru decat ultimul scris este comportament nedefinit (undefined behaviour) in C++. La acest curs vei folosi rar union. Il prezentam ca sa stii ce este.
Definirea unei clase
O clasa are atribute (date membre, adica starea) si metode (functii membre, adica comportamentul).
class ContBancar {
double sold = 0; // atribut (private implicit)
public:
void depune(double suma) { // metoda definita in clasa
if (suma > 0) sold += suma;
}
bool retrage(double suma); // doar declarata aici
double getSold() const { return sold; }
}; // nu uita ';'
bool ContBancar::retrage(double suma) { // definita in afara, cu ::
if (suma <= 0 || suma > sold) return false;
sold -= suma;
return true;
}
ContBancar::retrage se citeste “functia retrage care apartine clasei ContBancar”. Fara ContBancar:: ar fi o functie oarecare, care nu stie nimic despre sold.
Un bool se afiseaza ca 1 sau 0. Ce afiseaza programul?
#include <iostream>
using namespace std;
class ContBancar {
double sold = 0;
public:
void depune(double suma) { if (suma > 0) sold += suma; }
bool retrage(double suma);
double getSold() const { return sold; }
};
bool ContBancar::retrage(double suma) {
if (suma <= 0 || suma > sold) return false;
sold -= suma;
return true;
}
int main() {
ContBancar cont;
cont.depune(100);
cont.depune(-50);
bool ok1 = cont.retrage(30);
bool ok2 = cont.retrage(500);
cout << ok1 << " " << ok2 << " " << cont.getSold();
} Tipuri de metode
- Metode de acces citesc sau modifica un atribut in mod controlat:
getSold(). Un setter, daca exista, verifica valoarea primita. - Metode de prelucrare fac munca reala a obiectului:
depune,retrage. Ele sunt motivul pentru care exista clasa. - Metode auxiliare sunt
private. Le folosesc alte metode si nu fac parte din interfata publica. - Metode const promit ca nu modifica obiectul:
double getSold() const. Compilatorul verifica promisiunea. - Constructorii si destructorul sunt metode speciale. Ii discutam saptamana viitoare.
O metoda poate fi inline (definita in corpul clasei) sau definita in afara, cu ::. Comportamentul este acelasi. Metodele lungi se scriu de obicei in afara, ca sa ramana clasa usor de citit.
Obiecte
O clasa este un tip. Un obiect este o variabila de acel tip. Fiecare obiect are propria copie a atributelor. Metodele exista o singura data si lucreaza pe obiectul pentru care sunt apelate.
#include <iostream>
using namespace std;
class Contor {
int valoare = 0;
public:
void creste() { valoare++; }
int get() const { return valoare; }
};
int main() {
Contor a, b;
a.creste();
a.creste();
b.creste();
cout << a.get() << " " << b.get();
} In interiorul unei metode, this este un pointer catre obiectul curent. valoare++ din a.creste() inseamna de fapt this->valoare++, cu this == &a.
Obiectele traiesc acolo unde traieste orice variabila: obiectele locale pe stiva, cele create cu new pe heap.
Contor a, b; - doua obiecte pe stiva, fiecare cu propria valoare.
Pasul 1/4
Domenii de vizibilitate (specificatori de acces)
| Specificator | Cine poate folosi membrul |
|---|---|
public | oricine |
private | doar metodele clasei (si prietenii ei, saptamana 6) |
protected | clasa si clasele derivate din ea (saptamana 8) |
Accesul este verificat de compilator. Codul urmator este gresit intentionat:
ContBancar cont;
cont.sold = 1000000; // eroare de compilare: 'double ContBancar::sold' is private within this context
Incapsularea inseamna: atributele sunt private, iar metodele publice pastreaza obiectul valid. O regula care trebuie sa fie mereu adevarata pentru un obiect, de exemplu “soldul nu este niciodata negativ”, se numeste invariant. Daca doar metodele pot modifica starea, invariantul trebuie verificat doar in metode.
Ruleaza programul de mai jos. Apoi scoate comentariul de pe ultima linie si citeste mesajul compilatorului.
#include <iostream>
using namespace std;
struct PunctS { // struct: membrii sunt public implicit
int x = 0, y = 0;
};
class Dreptunghi { // class: membrii sunt private implicit
double latime = 1, inaltime = 1;
public:
bool setDimensiuni(double l, double h) {
if (l <= 0 || h <= 0) return false; // dreptunghiul ramane valid
latime = l;
inaltime = h;
return true;
}
double arie() const { return latime * inaltime; }
};
int main() {
PunctS p;
p.x = 3; // permis: public
cout << "punct: " << p.x << " " << p.y << endl;
Dreptunghi d;
cout << "arie: " << d.arie() << endl;
d.setDimensiuni(2, 5);
cout << "arie: " << d.arie() << endl;
cout << "acceptat: " << d.setDimensiuni(-1, 4) << endl;
cout << "arie: " << d.arie() << endl;
// d.latime = -3; // incearca: eroare de compilare, latime e private
}Intrare (stdin)
Verifica-te
Scor: 0/7