Clase C++: obiecte, încapsulare și supraîncărcare
O clasă grupează datele unui obiect și operațiile care au sens pentru acele date. Încapsularea controlează accesul la reprezentarea internă, iar constructorul stabilește starea inițială. Supraîncărcarea permite mai multe operații cu același nume, diferențiate prin parametri.
În acest material
O clasă grupează datele unui obiect și operațiile care au sens pentru acele date. Încapsularea controlează accesul la reprezentarea internă, iar constructorul stabilește starea inițială. Supraîncărcarea permite mai multe operații cu același nume, diferențiate prin parametri.
Vom construi un contor mic pentru a urmări exact ce aparține fiecărui obiect și ce se schimbă la un apel. Scopul nu este să transformăm orice variabilă într-o clasă, ci să înțelegem cum o interfață păstrează o reprezentare coerentă.
Cum funcționează
În class, membrii sunt implicit private; în struct sunt implicit public. Ambele pot avea funcții membre și constructori. Alegerea public/private exprimă ce poate folosi codul exterior. Un câmp privat nu este o măsură de criptare, ci o regulă a limbajului care împiedică accesul direct din cod fără permisiunea potrivită.
Constructorul are numele clasei și nu declară un tip de rezultat. Lista de inițializare setează value_ înaintea corpului constructorului. Cuvântul explicit împiedică anumite conversii implicite din int în Counter, făcând intenția apelantului mai clară. Fiecare obiect are propriul value_: schimbarea lui x nu modifică automat y.
Metoda value() const citește starea și promite că nu modifică membrii obișnuiți ai obiectului prin acel apel. Metodele add() și add(int) sunt supraîncărcări: compilatorul alege varianta după lista argumentelor. Tipul rezultatului singur nu este suficient pentru a diferenția două funcții cu același nume și aceiași parametri.
Operatorul + este definit să creeze un contor nou cu suma celor două valori. Parametrul const Counter& evită o copie inutilă și protejează operandul drept de modificări prin acea referință. Metoda este const, deci nu schimbă operandul stâng. Semnificația aleasă păstrează așteptarea obișnuită că x+y calculează un rezultat fără să modifice operanzii. Nu putem inventa operatori noi și nu putem schimba prioritatea sau numărul lor de operanzi.
Programul citește a și b între -1000000 și 1000000, astfel încât incrementările și sumele încap în int. Contorul este intenționat simplu: nu impune pozitivitate și nu oferă un setter general, deoarece operațiile expuse sunt suficiente. Dacă domeniul ar cere o limită maximă sau valori nenegative, constructorii și metodele care modifică starea ar trebui să o verifice în mod consecvent.
Exemplu urmărit pas cu pas
Pentru a=4 și b=10, obiectele x și y pornesc cu valorile 4 și 10. x.add() produce 5, iar x.add(2) produce 7. Expresia x+y construiește z cu valoarea 17.
La afișare obținem 7,10,17. y a rămas neschimbat, iar z este un obiect separat. Dacă ulterior modificăm z, aceasta nu schimbă x sau y, deoarece clasa conține un int propriu, nu un pointer către starea comună.
Implementare C++17
#include <iostream>
class Counter {
int value_;
public:
explicit Counter(int value = 0) : value_(value) {
}
int value() const {
return value_;
}
void add() {
++value_;
}
void add(int amount) {
value_ += amount;
}
Counter operator+(const Counter &other) const {
return Counter(value_ + other.value_);
}
};
int main() {
int a, b;
std::cin >> a >> b;
Counter x(a), y(b);
x.add();
x.add(2);
Counter z = x + y;
std::cout << x.value() << ' ' << y.value() << ' ' << z.value() << '\n';
}
De ce funcționează și cât costă
Constructorul inițializează fiecare obiect, iar fiecare metodă implementează transformarea declarată. Accesul privat obligă utilizatorul clasei să treacă prin aceste operații. Corectitudinea vine din contractele lor și limitele numerice, nu doar din folosirea cuvântului class.
Operațiile exemplului au timp și memorie suplimentară O(1). Clasele nu implică automat alocare dinamică sau apeluri virtuale. Costul real depinde de membrii și operațiile definite, nu de simplul fapt că programul folosește obiecte.
Greșeli frecvente
Nu confunda supraîncărcarea cu suprascrierea virtuală din moștenire. Nu expune automat un setter pentru fiecare câmp dacă asta permite stări invalide. Evită conversiile surprinzătoare și operatorii cu efecte contrare semnificației lor uzuale.
Exersează
Dacă x are valoarea 2 și y valoarea 5, ce se schimbă după Counter z=x+y?
Rezolvare explicată: Se creează z cu valoarea 7. x rămâne 2 și y rămâne 5, deoarece operatorul nu modifică operanzii.
Continuă să înveți
Funcții, parametri și structuri.
Întrebări frecvente
Care este diferența dintre clasă și obiect?
Clasa definește tipul, datele și operațiile. Obiectul este o instanță concretă a acelui tip, cu propria stare.
private protejează datele ca o parolă?
Nu. Este o regulă de acces în limbaj, utilă pentru organizarea și corectitudinea codului. Nu reprezintă criptare sau protecție față de accesul la memoria procesului.
Ce face un getter const?
Oferă citirea stării fără modificarea membrilor obișnuiți prin acel apel. const face parte din contractul metodei.
Pot supraîncărca doar schimbând tipul rezultatului?
Nu. Compilatorul trebuie să poată diferenția apelurile prin parametri și celelalte reguli ale semnăturii, nu doar prin valoarea returnată.
De ce operator+ întoarce un obiect nou?
Aceasta respectă semnificația obișnuită a adunării: produce un rezultat și păstrează operanzii. Operatorii trebuie proiectați pentru un comportament previzibil.
Un pas mai departe
Se încarcă progresul…