Invatare Atomica

Introducere in Programarea Orientata pe Obiecte

Progres lectie:
0%
🎯

Obiectivul lectiei

Vei intelege paradigma programarii orientate pe obiecte (POO) si vei sti sa definesti clase proprii, sa instantiezi obiecte si sa lucrezi cu membrii acestora (date + metode) in Python si C++ (intensiv).

Dupa aceasta lectie vei putea:

  • Sa explici diferenta dintre clasa (sablon/tip) si obiect (instanta concreta)
  • Sa definesti o clasa cu date (atribute) si metode in Python
  • Sa scrii si sa folosesti constructorul __init__ in Python
  • Sa instantiezi obiecte si sa accesezi membrii lor cu operatorul punct
  • Sa aplici encapsularea prin atribute private
  • Sa distingi membrii de instanta de membrii de clasa (statici)
  • Sa definesti o clasa echivalenta in C++ cu constructor si acces public/privat EXCLUSIV INTENSIV

Incearca singur!

Provocare:

Gandeste-te la un Elev. Ce informatii (date) are un elev? Ce actiuni (metode) poate face sau i se pot aplica? Scrie 3 date si 3 metode posibile.

💡 Ai nevoie de un indiciu?

In POO, datele descriu starea (ce ESTE obiectul) si metodele descriu comportamentul (ce FACE obiectul). Clasa Elev ar putea avea:

  • Date: nume, clasa, note (lista privata)
  • Metode: adauga_nota(), media(), __str__()

Exact asta construim in atomii acestei lectii!

1

1. Ce este POO? Clasa vs Obiect

Programarea Orientata pe Obiecte (POO) este o paradigma de programare care organizeaza codul in jurul obiectelor — entitati care combina date (stare) si comportament (operatii) intr-o singura unitate coerenta.
Analogia arhitecturala:

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.

Un obiect are doi feluri de membri:
  • Date (atribute / campuri) — valorile care descriu starea obiectului: marca, viteza, sold
  • Metode — functii definite in interiorul clasei care opereaza pe datele obiectului: accelereaza(), depune()
Terminologie cheie:
  • 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

2. Prima clasa in Python: class si self

In Python, o clasa se defineste cu cuvantul cheie 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)}")
Output real (rulat cu Python 3.13):
Masina: Dacia, viteza: 60 km/h
Masina: BMW, viteza: 120 km/h
Clasa lui m1: Masina
m1 este Masina? True
Observatii cheie:
  • m1 si m2 sunt obiecte independente: modificarea m1.viteza nu afecteaza m2.viteza
  • Operatorul punct (.) acceseaza membrii: obiect.atribut si obiect.metoda()
  • isinstance(m1, Masina) verifica tipul la runtime: returneaza True
3

3. Constructorul __init__ si encapsularea in Python

Constructorul este o metoda speciala apelata automat la crearea unui obiect. In Python se numeste __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())
Output real (rulat cu Python 3.13):
Dacia Logan (alb): 80 km/h
Dacia Logan (alb): 50 km/h
Viteza: 50
De ce encapsulare?

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

4. Membrii de clasa vs membrii de instanta

  • Atribut de instanta (self.x in __init__): fiecare obiect are propria copie, independenta
  • Atribut de clasa (definit direct in corpul clasei, fara self): partajat de TOATE instantele; accesat prin Clasa.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}")
Output real (rulat cu Python 3.13):
Cont#1 [Popescu Ion]: 1050 RON
Cont#2 [Ionescu Ana]: 800 RON
Total conturi deschise: 2
Complexitate O:

Creare obiect: O(1). Operatii depune/retrage: O(1). Accesul la atribut de clasa: O(1).

5

5. Clasa completa — exemplu educativ: Elev

Construim clasa 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}")
Output real (rulat cu Python 3.13):
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
Nota de design: 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

6. Clase in C++: constructor, public/private, static EXCLUSIV INTENSIV

⚡ Sectiune exclusiva pentru 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;
}
Output real (compilat g++ -std=c++17, rulat pe Windows 11):
Dacia Logan (alb): 50 km/h
BMW X5 (negru): 120 km/h
Viteza m1: 50 km/h
Masini create: 2
C++ vs Python:
  • Python: __init__; C++: constructor cu acelasi nume
  • Python: __x conventie; C++: private: blocare compilator
  • Python: tipuri dinamice; C++: tipuri explicite (int, string)
  • C++: const la sfarsitul metodei = nu modifica obiectul

Exercitii practice

Exercitiul 1 (Nivel minim) — Clasa Cerc

Defineste o clasa Cerc in Python cu raza initializata prin constructor, PI = 3.14159 ca atribut de clasa, metodele aria() si perimetru(). Instantiaza doua cercuri si afiseaza rezultatele.

Exercitiul 2 (Nivel standard) — Clasa Stiva

Implementeaza o clasa Stiva in Python cu metodele: push(x), pop() (returneaza None daca e goala), top(), este_goala(). Date private. Complexitate: O(1).

Exercitiul 3 (Nivel performanta) — Clasa Matrice in C++ EXCLUSIV INTENSIV

Implementeaza Matrice(n,m) in C++ cu vector<vector<int>>. Metode: set(i,j,v), get(i,j) const (returneaza -1 pt indici invalizi), afiseaza() const. Identifica complexitatea O.

Ce ai invatat astazi

  • Paradigma POO: clasa = sablon/tip, obiect = instanta concreta
  • Membrii: date (atribute) + metode
  • Constructorul __init__ Python / constructor cu acelasi nume in C++
  • Encapsulare: __x Python / private: C++ cu getteri publici
  • Membrii de instanta (self.x) vs de clasa (Clasa.x / static C++)
  • Instantierea si accesul la membri prin operatorul punct
  • Specificatori C++: public: si private: EXCLUSIV INTENSIV

Urmatoarea lectie

Continua cu Lucrul cu fisiere — citire/scriere date din fisiere text in Python si C++.

Continua →