1. Ce este POO? Clasa vs Obiect
Clasa = planul tehnic al unui model de masina (descrie atributele si comportamentul oricarei masini de acel model)
Obiect = masina concreta cu numar de inmatriculare propriu, kilometraj propriu, stare proprie
Din acelasi plan (clasa) poti construi oricate masini (obiecte), fiecare independenta cu valorile ei proprii.
- Date (atribute / campuri) — valorile care descriu starea obiectului:
marca,viteza,sold - Metode — functii definite in interiorul clasei care opereaza pe datele obiectului:
accelereaza(),depune()
- Clasa = tip de date definit de programator; plan/sablon
- Obiect / instanta = valoare concreta de tipul clasei
- Instantiere = actul de creare a unui obiect dintr-o clasa
- Membri = totalitatea datelor + metodelor definite in clasa
- Encapsulare = ascunderea datelor interne, expunerea unui API controlat
2. Prima clasa in Python: class si self
class. Fiecare metoda primeste ca prim parametru self — referinta la obiectul curent pe care se apeleaza metoda.
class Masina: # Atribute cu valori implicite marca = "Necunoscuta" viteza = 0 def accelereaza(self, delta): self.viteza += delta def info(self): return f"Masina: {self.marca}, viteza: {self.viteza} km/h" # Instantiere: creare obiecte distincte m1 = Masina() m1.marca = "Dacia" m1.accelereaza(60) m2 = Masina() m2.marca = "BMW" m2.accelereaza(120) print(m1.info()) print(m2.info()) print(f"Clasa lui m1: {type(m1).__name__}") print(f"m1 este Masina? {isinstance(m1, Masina)}")
Masina: Dacia, viteza: 60 km/h Masina: BMW, viteza: 120 km/h Clasa lui m1: Masina m1 este Masina? True
m1sim2sunt obiecte independente: modificaream1.vitezanu afecteazam2.viteza- Operatorul punct (
.) acceseaza membrii:obiect.atributsiobiect.metoda() isinstance(m1, Masina)verifica tipul la runtime: returneazaTrue
3. Constructorul __init__ si encapsularea in Python
__init__. Encapsularea ascunde datele interne folosind prefixul __ (doua underscore) pentru atributele private — accesibile numai prin metodele clasei.
class Masina: def __init__(self, marca, culoare): self.marca = marca # atribut public self.culoare = culoare # atribut public self.__viteza = 0 # atribut privat def accelereaza(self, delta): if delta > 0: self.__viteza += delta def faneaza(self, delta): self.__viteza = max(0, self.__viteza - delta) def get_viteza(self): # getter: acces controlat return self.__viteza def __str__(self): # metoda speciala pt print() return f"{self.marca} ({self.culoare}): {self.__viteza} km/h" m = Masina("Dacia Logan", "alb") m.accelereaza(80) print(m) m.faneaza(30) print(m) print("Viteza:", m.get_viteza())
Dacia Logan (alb): 80 km/h Dacia Logan (alb): 50 km/h Viteza: 50
Atributul __viteza nu poate fi modificat direct din exterior. Prin name mangling, Python il stocheaza ca _Masina__viteza, deci m.__viteza = -999 ar crea un atribut nou, nu l-ar modifica pe cel real. Controlul se face EXCLUSIV prin metodele publice care valideaza intrarea.
4. Membrii de clasa vs membrii de instanta
- Atribut de instanta (
self.xin__init__): fiecare obiect are propria copie, independenta - Atribut de clasa (definit direct in corpul clasei, fara
self): partajat de TOATE instantele; accesat prinClasa.atribut
class Cont: numar_conturi = 0 # atribut de CLASA (partajat) def __init__(self, titular, sold_initial=0): Cont.numar_conturi += 1 self.titular = titular # atribut de instanta self.__sold = sold_initial # privat de instanta self.id_cont = Cont.numar_conturi def depune(self, suma): if suma > 0: self.__sold += suma def retrage(self, suma): if 0 < suma <= self.__sold: self.__sold -= suma def __str__(self): return f"Cont#{self.id_cont} [{self.titular}]: {self.__sold} RON" c1 = Cont("Popescu Ion", 1000) c2 = Cont("Ionescu Ana", 500) c1.depune(200) c1.retrage(150) c2.depune(300) print(c1) print(c2) print(f"Total conturi deschise: {Cont.numar_conturi}")
Cont#1 [Popescu Ion]: 1050 RON Cont#2 [Ionescu Ana]: 800 RON Total conturi deschise: 2
Creare obiect: O(1). Operatii depune/retrage: O(1). Accesul la atribut de clasa: O(1).
5. Clasa completa — exemplu educativ: Elev
Elev care reuneste toate conceptele lectiei: constructor, atribute private, validare in metode, metoda __str__, copie defensiva a listei.
class Elev: def __init__(self, nume, clasa): self.nume = nume self.clasa = clasa self.__note = [] # lista privata de note def adauga_nota(self, nota): if 1 <= nota <= 10: self.__note.append(nota) return True return False def media(self): if not self.__note: return 0.0 return sum(self.__note) / len(self.__note) def note(self): return list(self.__note) # copie, nu referinta def __str__(self): return f"{self.nume} (cls. {self.clasa}) - media: {self.media():.2f}" e1 = Elev("Popescu Andrei", "12A") e1.adauga_nota(9) e1.adauga_nota(8) e1.adauga_nota(10) e2 = Elev("Ionescu Maria", "12A") e2.adauga_nota(7) e2.adauga_nota(9) print(e1) print(f" Note: {e1.note()}") print(e2) print(f" Note: {e2.note()}") print(f"Media clasei: {(e1.media() + e2.media()) / 2:.2f}")
Popescu Andrei (cls. 12A) - media: 9.00 Note: [9, 8, 10] Ionescu Maria (cls. 12A) - media: 8.00 Note: [7, 9] Media clasei: 8.50
note() returneaza list(self.__note) — o copie, nu referinta originala. Codul extern nu poate modifica lista privata direct. Acesta este un pattern de encapsulare defensiva.
6. Clase in C++: constructor, public/private, static EXCLUSIV INTENSIV
In C++ controlul accesului se face explicit prin public: si private:. Constructorul are acelasi nume ca clasa, fara tip de retur. Membrii static sunt partajati de toate instantele si se acceseaza prin Clasa::membru.
#include <iostream> #include <string> using namespace std; class Masina { public: string marca; string culoare; static int numar_masini; // membru static (partajat de toate instantele) private: int viteza; public: Masina(string m, string c) : marca(m), culoare(c), viteza(0) { numar_masini++; } void accelereaza(int d) { if(d>0) viteza+=d; } void faneaza(int d) { viteza=viteza-d>0?viteza-d:0; } int getViteza() const { return viteza; } void afiseaza() const { cout << marca << " (" << culoare << "): " << viteza << " km/h" << endl; } }; int Masina::numar_masini = 0; // initializare in afara clasei (obligatorie) int main() { Masina m1("Dacia Logan", "alb"); Masina m2("BMW X5", "negru"); m1.accelereaza(80); m2.accelereaza(120); m1.faneaza(30); m1.afiseaza(); m2.afiseaza(); cout << "Viteza m1: " << m1.getViteza() << " km/h" << endl; cout << "Masini create: " << Masina::numar_masini << endl; return 0; }
Dacia Logan (alb): 50 km/h BMW X5 (negru): 120 km/h Viteza m1: 50 km/h Masini create: 2
- Python:
__init__; C++: constructor cu acelasi nume - Python:
__xconventie; C++:private:blocare compilator - Python: tipuri dinamice; C++: tipuri explicite (
int,string) - C++:
constla sfarsitul metodei = nu modifica obiectul