Încapsularea este unul dintre cei patru piloni fundamentali ai programării orientate pe obiecte (POO), alături de abstractizare, moștenire și polimorfism. Reprezintă mecanismul prin care datele (variabilele) și metodele care operează asupra acestor date sunt grupate împreună într-o singură unitate numită clasă, restricționând accesul direct la unele componente ale obiectului.
Principiul fundamental: "Ascunde implementarea, expune interfața."
Protejează datele interne ale obiectului de modificări neautorizate
Facilitează modificarea implementării fără a afecta codul client
Permite validarea datelor înainte de modificare
Ascunde complexitatea implementării
Permite schimbarea implementării interne fără a afecta utilizatorii
Facilitează identificarea și rezolvarea erorilor
| Specificator | În Clasă | În Clasă Derivată | În Afara Clasei | Utilizare Tipică |
|---|---|---|---|---|
private |
✅ Da | ❌ Nu | ❌ Nu | Date interne, metode auxiliare |
protected |
✅ Da | ✅ Da | ❌ Nu | Date pentru moștenire |
public |
✅ Da | ✅ Da | ✅ Da | Interfața publică |
// Student.h - Fișier header (declarații) #ifndef STUDENT_H #define STUDENT_H #include <string> #include <vector> #include <memory> class Student { private: // Date membre private - ascunse de utilizator std::string nume; std::string prenume; int varsta; std::string matricol; std::vector<double> note; static int numarTotalStudenti; // Metode private pentru uz intern bool valideazaMatricol(const std::string& mat) const; void actualizeazaMedie(); // Date pentru implementare internă struct Impl; std::unique_ptr<Impl> pImpl; protected: // Date accesibile claselor derivate double medie; bool esteActiv; public: // Constructori Student(); Student(const std::string& nume, const std::string& prenume, int varsta); Student(const Student& other); // Copy constructor Student(Student&& other) noexcept; // Move constructor // Destructor ~Student(); // Operatori Student& operator=(const Student& other); Student& operator=(Student&& other) noexcept; // Getters (metode const) std::string getNume() const; std::string getPrenume() const; std::string getNumeComplet() const; int getVarsta() const; double getMedie() const; std::string getMatricol() const; // Setters cu validare void setNume(const std::string& nume); void setPrenume(const std::string& prenume); bool setVarsta(int varsta); bool setMatricol(const std::string& matricol); // Metode pentru gestionare note bool adaugaNota(double nota); bool stergeUltimaNota(); std::vector<double> getNote() const; // Metode utilitare void afiseaza() const; bool estePromovat() const; std::string getStatus() const; // Metode statice static int getNumarTotalStudenti(); static void resetCounter(); // Friend functions friend std::ostream& operator<<(std::ostream& os, const Student& s); friend bool operator<(const Student& s1, const Student& s2); }; #endif // STUDENT_H
// Student.cpp - Fișier sursă (implementări) #include "Student.h" #include <iostream> #include <iomanip> #include <algorithm> #include <numeric> #include <regex> // Implementare structură internă (ascunsă în .cpp) struct Student::Impl { std::string adresa; std::string telefon; std::string email; std::chrono::system_clock::time_point dataInregistrare; Impl() : dataInregistrare(std::chrono::system_clock::now()) {} }; // Inițializare membru static int Student::numarTotalStudenti = 0; // Constructor implicit Student::Student() : nume("Necunoscut"), prenume("Necunoscut"), varsta(18), medie(0.0), esteActiv(true), pImpl(std::make_unique<Impl>()) { numarTotalStudenti++; matricol = "STD" + std::to_string(numarTotalStudenti); std::cout << "Constructor implicit apelat pentru " << matricol << std::endl; } // Constructor parametrizat Student::Student(const std::string& n, const std::string& p, int v) : nume(n), prenume(p), varsta(v), medie(0.0), esteActiv(true), pImpl(std::make_unique<Impl>()) { if (varsta < 16 || varsta > 100) { throw std::invalid_argument("Vârsta trebuie să fie între 16 și 100 ani"); } numarTotalStudenti++; matricol = "STD" + std::to_string(numarTotalStudenti); std::cout << "Constructor parametrizat pentru " << getNumeComplet() << std::endl; } // Copy constructor Student::Student(const Student& other) : nume(other.nume), prenume(other.prenume), varsta(other.varsta), matricol(other.matricol + "_COPY"), note(other.note), medie(other.medie), esteActiv(other.esteActiv), pImpl(std::make_unique<Impl>(*other.pImpl)) { numarTotalStudenti++; std::cout << "Copy constructor pentru " << getNumeComplet() << std::endl; } // Move constructor Student::Student(Student&& other) noexcept : nume(std::move(other.nume)), prenume(std::move(other.prenume)), varsta(other.varsta), matricol(std::move(other.matricol)), note(std::move(other.note)), medie(other.medie), esteActiv(other.esteActiv), pImpl(std::move(other.pImpl)) { std::cout << "Move constructor pentru " << getNumeComplet() << std::endl; other.varsta = 0; other.medie = 0.0; other.esteActiv = false; } // Destructor Student::~Student() { numarTotalStudenti--; std::cout << "Destructor pentru " << getNumeComplet() << " (Rămân " << numarTotalStudenti << " studenți)" << std::endl; } // Copy assignment operator Student& Student::operator=(const Student& other) { if (this != &other) { nume = other.nume; prenume = other.prenume; varsta = other.varsta; matricol = other.matricol + "_ASSIGN"; note = other.note; medie = other.medie; esteActiv = other.esteActiv; pImpl = std::make_unique<Impl>(*other.pImpl); } return *this; } // Move assignment operator Student& Student::operator=(Student&& other) noexcept { if (this != &other) { nume = std::move(other.nume); prenume = std::move(other.prenume); varsta = other.varsta; matricol = std::move(other.matricol); note = std::move(other.note); medie = other.medie; esteActiv = other.esteActiv; pImpl = std::move(other.pImpl); other.varsta = 0; other.medie = 0.0; other.esteActiv = false; } return *this; } // Implementare metode private bool Student::valideazaMatricol(const std::string& mat) const { std::regex pattern("^STD[0-9]+(_COPY|_ASSIGN)?$"); return std::regex_match(mat, pattern); } void Student::actualizeazaMedie() { if (note.empty()) { medie = 0.0; } else { double suma = std::accumulate(note.begin(), note.end(), 0.0); medie = suma / note.size(); } } // Implementare getters std::string Student::getNume() const { return nume; } std::string Student::getPrenume() const { return prenume; } std::string Student::getNumeComplet() const { return nume + " " + prenume; } int Student::getVarsta() const { return varsta; } double Student::getMedie() const { return medie; } std::string Student::getMatricol() const { return matricol; } // Implementare setters cu validare void Student::setNume(const std::string& n) { if (n.empty()) { throw std::invalid_argument("Numele nu poate fi gol"); } nume = n; } void Student::setPrenume(const std::string& p) { if (p.empty()) { throw std::invalid_argument("Prenumele nu poate fi gol"); } prenume = p; } bool Student::setVarsta(int v) { if (v < 16 || v > 100) { return false; } varsta = v; return true; } bool Student::setMatricol(const std::string& m) { if (!valideazaMatricol(m)) { return false; } matricol = m; return true; } // Implementare metode pentru note bool Student::adaugaNota(double nota) { if (nota < 1.0 || nota > 10.0) { return false; } note.push_back(nota); actualizeazaMedie(); return true; } bool Student::stergeUltimaNota() { if (note.empty()) { return false; } note.pop_back(); actualizeazaMedie(); return true; } std::vector<double> Student::getNote() const { return note; // Returnează copie, nu referință } // Metode utilitare void Student::afiseaza() const { std::cout << "\n=== Date Student ===" << std::endl; std::cout << "Matricol: " << matricol << std::endl; std::cout << "Nume: " << getNumeComplet() << std::endl; std::cout << "Vârsta: " << varsta << " ani" << std::endl; std::cout << "Media: " << std::fixed << std::setprecision(2) << medie << std::endl; std::cout << "Status: " << getStatus() << std::endl; } bool Student::estePromovat() const { return medie >= 5.0 && esteActiv; } std::string Student::getStatus() const { if (!esteActiv) return "Inactiv"; if (note.empty()) return "Fără note"; if (medie >= 9.0) return "Excelent"; if (medie >= 7.0) return "Foarte bine"; if (medie >= 5.0) return "Promovat"; return "Restanțier"; } // Metode statice int Student::getNumarTotalStudenti() { return numarTotalStudenti; } void Student::resetCounter() { numarTotalStudenti = 0; } // Friend functions std::ostream& operator<<(std::ostream& os, const Student& s) { os << "[" << s.matricol << "] " << s.getNumeComplet() << " - Media: " << std::fixed << std::setprecision(2) << s.medie; return os; } bool operator<(const Student& s1, const Student& s2) { return s1.medie < s2.medie; }
// main.cpp - Program principal #include "Student.h" #include <iostream> #include <vector> #include <algorithm> int main() { try { // Test constructor implicit Student s1; s1.setNume("Popescu"); s1.setPrenume("Ion"); s1.adaugaNota(8.5); s1.adaugaNota(9.0); s1.adaugaNota(7.5); // Test constructor parametrizat Student s2("Ionescu", "Maria", 20); s2.adaugaNota(10.0); s2.adaugaNota(9.5); // Test copy constructor Student s3 = s2; // Test move constructor Student s4 = std::move(Student("Georgescu", "Ana", 19)); // Afișare date std::cout << "\n=== Lista Studenți ===" << std::endl; std::cout << s1 << std::endl; std::cout << s2 << std::endl; std::cout << s3 << std::endl; std::cout << s4 << std::endl; // Vector de studenți std::vector<Student> catalog; catalog.push_back(s1); catalog.push_back(s2); catalog.push_back(s3); // Sortare după medie std::sort(catalog.begin(), catalog.end()); std::cout << "\n=== Catalog Sortat după Medie ===" << std::endl; for (const auto& student : catalog) { std::cout << student << std::endl; } std::cout << "\nTotal studenți creați: " << Student::getNumarTotalStudenti() << std::endl; } catch (const std::exception& e) { std::cerr << "Eroare: " << e.what() << std::endl; } std::cout << "\n=== Destructori apelați automat ===" << std::endl; return 0; }
#ifndef LOGGER_H #define LOGGER_H #include <string> #include <fstream> #include <memory> #include <mutex> #include <chrono> class Logger { private: std::ofstream logFile; std::string filename; std::mutex logMutex; size_t linesWritten; std::chrono::steady_clock::time_point startTime; bool isOpen; // Singleton pattern - instanță unică static std::unique_ptr<Logger> instance; static std::mutex instanceMutex; // Constructor privat pentru Singleton explicit Logger(const std::string& file); // Metodă privată pentru formatare timestamp std::string getCurrentTimestamp() const; public: // Destructor - FOARTE IMPORTANT pentru cleanup ~Logger(); // Ștergem constructorii de copiere (Singleton) Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; // Metode statice pentru acces static Logger& getInstance(const std::string& filename = "app.log"); static void destroyInstance(); // Metode publice pentru logging void log(const std::string& message); void logError(const std::string& error); void logWarning(const std::string& warning); void flush(); // Getters size_t getLinesWritten() const; std::string getFilename() const; double getUptime() const; }; #endif
#include "Logger.h" #include <iostream> #include <iomanip> #include <sstream> #include <ctime> // Inițializare membri statici std::unique_ptr<Logger> Logger::instance = nullptr; std::mutex Logger::instanceMutex; // Constructor privat Logger::Logger(const std::string& file) : filename(file), linesWritten(0), isOpen(false) { logFile.open(filename, std::ios::app); if (logFile.is_open()) { isOpen = true; startTime = std::chrono::steady_clock::now(); // Scrie header la deschidere logFile << "\n===== Logger Started =====" << std::endl; logFile << "Time: " << getCurrentTimestamp() << std::endl; logFile << "=========================" << std::endl; std::cout << "[Logger] Fișier deschis: " << filename << std::endl; } else { std::cerr << "[Logger] Eroare la deschiderea fișierului: " << filename << std::endl; } } // DESTRUCTOR - Foarte important pentru cleanup Logger::~Logger() { std::cout << "[Logger] Destructor apelat" << std::endl; if (isOpen && logFile.is_open()) { // Calculează timpul total de funcționare auto endTime = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::seconds>(endTime - startTime); // Scrie footer înainte de închidere logFile << "\n===== Logger Stopped =====" << std::endl; logFile << "Total lines: " << linesWritten << std::endl; logFile << "Uptime: " << duration.count() << " seconds" << std::endl; logFile << "Time: " << getCurrentTimestamp() << std::endl; logFile << "=========================" << std::endl; // Flush și închide fișierul logFile.flush(); logFile.close(); std::cout << "[Logger] Fișier închis. Total " << linesWritten << " linii scrise în " << duration.count() << " secunde." << std::endl; } isOpen = false; } // Singleton getInstance Logger& Logger::getInstance(const std::string& filename) { std::lock_guard<std::mutex> lock(instanceMutex); if (!instance) { instance = std::unique_ptr<Logger>(new Logger(filename)); } return *instance; } // Distruge instanța Singleton void Logger::destroyInstance() { std::lock_guard<std::mutex> lock(instanceMutex); instance.reset(); // Apelează destructorul } // Metodă privată pentru timestamp std::string Logger::getCurrentTimestamp() const { auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); std::stringstream ss; ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S"); return ss.str(); } // Metode de logging void Logger::log(const std::string& message) { std::lock_guard<std::mutex> lock(logMutex); if (isOpen && logFile.is_open()) { logFile << "[INFO][" << getCurrentTimestamp() << "] " << message << std::endl; linesWritten++; } } void Logger::logError(const std::string& error) { std::lock_guard<std::mutex> lock(logMutex); if (isOpen && logFile.is_open()) { logFile << "[ERROR][" << getCurrentTimestamp() << "] " << error << std::endl; linesWritten++; logFile.flush(); // Flush imediat pentru erori } } void Logger::logWarning(const std::string& warning) { std::lock_guard<std::mutex> lock(logMutex); if (isOpen && logFile.is_open()) { logFile << "[WARN][" << getCurrentTimestamp() << "] " << warning << std::endl; linesWritten++; } } void Logger::flush() { std::lock_guard<std::mutex> lock(logMutex); if (isOpen && logFile.is_open()) { logFile.flush(); } } // Getters size_t Logger::getLinesWritten() const { return linesWritten; } std::string Logger::getFilename() const { return filename; } double Logger::getUptime() const { auto now = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - startTime); return duration.count(); }
#ifndef RESOURCE_MANAGER_H #define RESOURCE_MANAGER_H #include <memory> #include <vector> #include <string> // Clasă pentru gestiunea memoriei dinamice template<typename T> class DynamicArray { private: T* data; size_t size; size_t capacity; // Statistici de utilizare mutable size_t accessCount; static size_t totalAllocations; static size_t totalDeallocations; // Metodă privată pentru realocare void resize(size_t newCapacity); public: // Constructor implicit DynamicArray(size_t initialCapacity = 10); // Constructor de copiere DynamicArray(const DynamicArray& other); // Constructor de mutare DynamicArray(DynamicArray&& other) noexcept; // DESTRUCTOR - eliberează memoria ~DynamicArray(); // Operatori de atribuire DynamicArray& operator=(const DynamicArray& other); DynamicArray& operator=(DynamicArray&& other) noexcept; // Metode publice void push_back(const T& value); void pop_back(); T& operator[](size_t index); const T& operator[](size_t index) const; // Getters size_t getSize() const { return size; } size_t getCapacity() const { return capacity; } bool isEmpty() const { return size == 0; } // Statistici static void printStatistics(); }; // Clasă pentru gestiunea conexiunilor de rețea class NetworkConnection { private: int socketFd; std::string address; int port; bool isConnected; static int activeConnections; public: NetworkConnection(const std::string& addr, int p); ~NetworkConnection(); // Închide conexiunea automat // Dezactivăm copierea (resursa unică) NetworkConnection(const NetworkConnection&) = delete; NetworkConnection& operator=(const NetworkConnection&) = delete; // Permitem mutarea NetworkConnection(NetworkConnection&& other) noexcept; NetworkConnection& operator=(NetworkConnection&& other) noexcept; bool send(const std::string& data); std::string receive(size_t maxBytes); void disconnect(); static int getActiveConnections() { return activeConnections; } }; #endif
#include "ResourceManager.h" #include <iostream> #include <cstring> #include <stdexcept> // Implementare DynamicArray template<typename T> size_t DynamicArray<T>::totalAllocations = 0; template<typename T> size_t DynamicArray<T>::totalDeallocations = 0; template<typename T> DynamicArray<T>::DynamicArray(size_t initialCapacity) : size(0), capacity(initialCapacity), accessCount(0) { data = new T[capacity]; totalAllocations++; std::cout << "[DynamicArray] Alocat: " << capacity << " elemente (" << capacity * sizeof(T) << " bytes)" << std::endl; } template<typename T> DynamicArray<T>::DynamicArray(const DynamicArray& other) : size(other.size), capacity(other.capacity), accessCount(0) { data = new T[capacity]; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } totalAllocations++; std::cout << "[DynamicArray] Copy constructor: " << size << " elemente" << std::endl; } template<typename T> DynamicArray<T>::DynamicArray(DynamicArray&& other) noexcept : data(other.data), size(other.size), capacity(other.capacity), accessCount(other.accessCount) { other.data = nullptr; other.size = 0; other.capacity = 0; std::cout << "[DynamicArray] Move constructor" << std::endl; } // DESTRUCTOR - curățare automată template<typename T> DynamicArray<T>::~DynamicArray() { if (data != nullptr) { std::cout << "[DynamicArray] Destructor: eliberez " << capacity << " elemente (" << capacity * sizeof(T) << " bytes)" << std::endl; std::cout << " Total accesări: " << accessCount << std::endl; delete[] data; totalDeallocations++; } } template<typename T> void DynamicArray<T>::resize(size_t newCapacity) { T* newData = new T[newCapacity]; size_t elementsToCopy = (size < newCapacity) ? size : newCapacity; for (size_t i = 0; i < elementsToCopy; i++) { newData[i] = std::move(data[i]); } delete[] data; data = newData; capacity = newCapacity; std::cout << "[DynamicArray] Redimensionat la: " << capacity << std::endl; } template<typename T> void DynamicArray<T>::push_back(const T& value) { if (size >= capacity) { resize(capacity * 2); } data[size++] = value; } template<typename T> T& DynamicArray<T>::operator[](size_t index) { if (index >= size) { throw std::out_of_range("Index în afara limitelor"); } accessCount++; return data[index]; } template<typename T> void DynamicArray<T>::printStatistics() { std::cout << "\n=== Statistici DynamicArray ===" << std::endl; std::cout << "Total alocări: " << totalAllocations << std::endl; std::cout << "Total dealocări: " << totalDeallocations << std::endl; std::cout << "Scurgeri de memorie: " << (totalAllocations - totalDeallocations) << std::endl; } // Implementare NetworkConnection int NetworkConnection::activeConnections = 0; NetworkConnection::NetworkConnection(const std::string& addr, int p) : address(addr), port(p), isConnected(false), socketFd(-1) { // Simulare creare socket static int nextSocket = 100; socketFd = nextSocket++; isConnected = true; activeConnections++; std::cout << "[Network] Conexiune creată: " << address << ":" << port << " (Socket: " << socketFd << ")" << std::endl; } // DESTRUCTOR - închide conexiunea automat NetworkConnection::~NetworkConnection() { if (isConnected) { std::cout << "[Network] Destructor: închid conexiunea " << address << ":" << port << std::endl; disconnect(); } } NetworkConnection::NetworkConnection(NetworkConnection&& other) noexcept : socketFd(other.socketFd), address(std::move(other.address)), port(other.port), isConnected(other.isConnected) { other.socketFd = -1; other.isConnected = false; std::cout << "[Network] Move constructor" << std::endl; } void NetworkConnection::disconnect() { if (isConnected) { std::cout << "[Network] Închid socket: " << socketFd << std::endl; // Simulare închidere socket socketFd = -1; isConnected = false; activeConnections--; } } bool NetworkConnection::send(const std::string& data) { if (!isConnected) return false; std::cout << "[Network] Trimit: " << data.size() << " bytes" << std::endl; return true; } // Instanțieri template explicite template class DynamicArray<int>; template class DynamicArray<double>; template class DynamicArray<std::string>;
#include "Student.h" #include "Logger.h" #include "ResourceManager.h" #include <iostream> #include <memory> #include <thread> // Funcție de test cu scope limitat void testResourceManagement() { std::cout << "\n=== Test Resource Management ===" << std::endl; { // Scope pentru DynamicArray std::cout << "\n-- Test DynamicArray --" << std::endl; DynamicArray<int> arr(5); for (int i = 0; i < 10; i++) { arr.push_back(i * i); } std::cout << "Array size: " << arr.getSize() << std::endl; std::cout << "Array capacity: " << arr.getCapacity() << std::endl; // Destructor automat la ieșirea din scope } { // Scope pentru NetworkConnection std::cout << "\n-- Test NetworkConnection --" << std::endl; NetworkConnection conn1("192.168.1.1", 8080); conn1.send("Hello Server!"); { NetworkConnection conn2("10.0.0.1", 443); std::cout << "Conexiuni active: " << NetworkConnection::getActiveConnections() << std::endl; // conn2 distrugă aici } std::cout << "Conexiuni active după scope intern: " << NetworkConnection::getActiveConnections() << std::endl; // conn1 distrugă aici } DynamicArray<int>::printStatistics(); } // Funcție pentru test cu excepții void testExceptionSafety() { std::cout << "\n=== Test Exception Safety ===" << std::endl; try { DynamicArray<double> numbers(3); numbers.push_back(3.14); numbers.push_back(2.71); // Forțăm o excepție std::cout << "Încerc acces invalid..." << std::endl; double