🚀 Moștenirea în C++

Tutorial complet cu exemple practice și explicații detaliate

📚 Introducere în Moștenire

Moștenirea este unul dintre cei patru piloni ai programării orientate pe obiecte (POO), alături de încapsulare, abstractizare și polimorfism.

Permite unei clase (clasa derivată) să preia proprietățile și metodele unei alte clase (clasa de bază).

De ce folosim moștenirea?

  • Reutilizarea codului - Evităm duplicarea codului
  • Ierarhizare logică - Organizăm clasele într-o structură naturală
  • Extensibilitate - Adăugăm funcționalități noi fără să modificăm codul existent
  • Polimorfism - Tratăm obiecte diferite într-un mod uniform
Clasă de Bază (Părinte)
Clasă Derivată (Copil)

Sintaxa de bază:

Sintaxă Generală
class ClasaDeBaza {
    // membri ai clasei de bază
};

class ClasaDerivata : public ClasaDeBaza {
    // membri ai clasei derivate
};

1️⃣ Moștenire Simplă

În moștenirea simplă, o clasă derivată moștenește de la o singură clasă de bază.

Exemplul 1: Vehicul și Mașină

Moștenire Simplă - Vehicul
#include <iostream>
#include <string>
using namespace std;

// Clasa de bază
class Vehicul {
protected:
    string marca;
    int anFabricatie;
    
public:
    Vehicul(string m, int an) : marca(m), anFabricatie(an) {
        cout << "Constructor Vehicul apelat" << endl;
    }
    
    void afiseazaInfo() {
        cout << "Marca: " << marca << ", An: " << anFabricatie << endl;
    }
    
    void porneste() {
        cout << "Vehiculul pornește" << endl;
    }
};

// Clasa derivată
class Masina : public Vehicul {
private:
    int numarUsi;
    
public:
    Masina(string m, int an, int usi) : Vehicul(m, an), numarUsi(usi) {
        cout << "Constructor Masina apelat" << endl;
    }
    
    void afiseazaDetalii() {
        afiseazaInfo(); // apelăm metoda din clasa de bază
        cout << "Număr uși: " << numarUsi << endl;
    }
    
    void claxoneaza() {
        cout << "Beep beep! 🚗" << endl;
    }
};

int main() {
    Masina mea("Toyota", 2020, 4);
    
    mea.porneste();        // metodă moștenită
    mea.afiseazaDetalii(); // metodă proprie
    mea.claxoneaza();      // metodă proprie
    
    return 0;
}

Exemplul 2: Persoană și Student

Moștenire Simplă - Student
class Persoana {
protected:
    string nume;
    int varsta;
    
public:
    Persoana(string n, int v) : nume(n), varsta(v) {}
    
    void prezentare() {
        cout << "Numele meu este " << nume;
        cout << " și am " << varsta << " ani." << endl;
    }
};

class Student : public Persoana {
private:
    string universitate;
    double medie;
    
public:
    Student(string n, int v, string uni, double m) 
        : Persoana(n, v), universitate(uni), medie(m) {}
    
    void afiseazaDetaliiStudent() {
        prezentare(); // apelăm metoda moștenită
        cout << "Studiez la " << universitate;
        cout << " cu media " << medie << endl;
    }
    
    bool esteBursier() {
        return medie >= 8.5;
    }
};

2️⃣ Moștenire Multiplă

C++ permite unei clase să moștenească de la mai multe clase de bază simultan.

⚠️ Atenție: Moștenirea multiplă poate duce la "problema diamantului". Folosiți cu grijă!

Exemplu: Smartphone (Telefon + Computer)

Moștenire Multiplă
class Telefon {
protected:
    string numarTelefon;
    
public:
    Telefon(string nr) : numarTelefon(nr) {}
    
    void apeleaza(string destinatar) {
        cout << "Apel către " << destinatar;
        cout << " de la " << numarTelefon << endl;
    }
    
    void trimiteSmS(string mesaj) {
        cout << "SMS trimis: " << mesaj << endl;
    }
};

class Computer {
protected:
    int memorieRAM;
    int stocare;
    
public:
    Computer(int ram, int storage) 
        : memorieRAM(ram), stocare(storage) {}
    
    void ruleazaAplicatie(string app) {
        cout << "Rulează aplicația: " << app << endl;
    }
    
    void navigheazaInternet() {
        cout << "Navigare pe internet..." << endl;
    }
};

// Moștenire multiplă
class Smartphone : public Telefon, public Computer {
private:
    string sistemeOperare;
    double diagonalaEcran;
    
public:
    Smartphone(string nr, int ram, int storage, 
                string os, double ecran)
        : Telefon(nr), Computer(ram, storage), 
          sistemeOperare(os), diagonalaEcran(ecran) {}
    
    void afiseazaSpecificatii() {
        cout << "📱 Smartphone Specificații:" << endl;
        cout << "Număr: " << numarTelefon << endl;
        cout << "RAM: " << memorieRAM << " GB" << endl;
        cout << "Stocare: " << stocare << " GB" << endl;
        cout << "OS: " << sistemeOperare << endl;
        cout << "Ecran: " << diagonalaEcran << " inch" << endl;
    }
    
    void facePoza() {
        cout << "📸 Poză capturată!" << endl;
    }
};

int main() {
    Smartphone iPhone("0721234567", 6, 128, 
                      "iOS", 6.1);
    
    // Metode din Telefon
    iPhone.apeleaza("Maria");
    iPhone.trimiteSmS("Salut!");
    
    // Metode din Computer
    iPhone.ruleazaAplicatie("Instagram");
    iPhone.navigheazaInternet();
    
    // Metode proprii
    iPhone.facePoza();
    iPhone.afiseazaSpecificatii();
    
    return 0;
}

3️⃣ Moștenire Ierarhică

Mai multe clase derivate moștenesc de la aceeași clasă de bază.

Animal
↙ ↓ ↘
Câine
Pisică
Pasăre

Exemplu: Ierarhie de Animale

Moștenire Ierarhică
class Animal {
protected:
    string nume;
    int varsta;
    double greutate;
    
public:
    Animal(string n, int v, double g) 
        : nume(n), varsta(v), greutate(g) {}
    
    void mananca() {
        cout << nume << " mănâncă." << endl;
    }
    
    void doarme() {
        cout << nume << " doarme." << endl;
    }
    
    virtual void emiteSunet() {
        cout << nume << " emite un sunet." << endl;
    }
};

class Caine : public Animal {
private:
    string rasa;
    
public:
    Caine(string n, int v, double g, string r)
        : Animal(n, v, g), rasa(r) {}
    
    void emiteSunet() override {
        cout << nume << " latră: Ham ham! 🐕" << endl;
    }
    
    void dauDinCoada() {
        cout << nume << " dă din coadă fericit!" << endl;
    }
    
    void aduceObiect() {
        cout << nume << " aduce mingea înapoi!" << endl;
    }
};

class Pisica : public Animal {
private:
    bool arePedigree;
    
public:
    Pisica(string n, int v, double g, bool pedigree)
        : Animal(n, v, g), arePedigree(pedigree) {}
    
    void emiteSunet() override {
        cout << nume << " miaună: Miau miau! 🐱" << endl;
    }
    
    void toarce() {
        cout << nume << " toarce mulțumit." << endl;
    }
    
    void vaneazaSoareci() {
        cout << nume << " vânează șoareci!" << endl;
    }
};

class Pasare : public Animal {
private:
    double anverguraAripi;
    bool poateZbura;
    
public:
    Pasare(string n, int v, double g, double aripi, bool zboara)
        : Animal(n, v, g), anverguraAripi(aripi), poateZbura(zboara) {}
    
    void emiteSunet() override {
        cout << nume << " cântă: Cip cip! 🐦" << endl;
    }
    
    void zboara() {
        if (poateZbura) {
            cout << nume << " zboară în înaltul cerului!" << endl;
        } else {
            cout << nume << " nu poate zbura." << endl;
        }
    }
};

4️⃣ Moștenire Multinivel

O clasă derivată devine clasă de bază pentru o altă clasă.

Vehicul
Mașină
Mașină Sport

Exemplu: Vehicul → Mașină → Mașină Sport

Moștenire Multinivel
class Vehicul {
protected:
    string marca;
    string model;
    int anFabricatie;
    
public:
    Vehicul(string m, string mod, int an) 
        : marca(m), model(mod), anFabricatie(an) {
        cout << "[Nivel 1] Constructor Vehicul" << endl;
    }
    
    void porneste() {
        cout << "Vehiculul pornește" << endl;
    }
    
    void opreste() {
        cout << "Vehiculul se oprește" << endl;
    }
};

class Masina : public Vehicul {
protected:
    int numarUsi;
    string tipCombustibil;
    
public:
    Masina(string m, string mod, int an, int usi, string combustibil)
        : Vehicul(m, mod, an), numarUsi(usi), tipCombustibil(combustibil) {
        cout << "[Nivel 2] Constructor Masina" << endl;
    }
    
    void deschidePortbagaj() {
        cout << "Portbagajul s-a deschis" << endl;
    }
    
    void activeazaAerConditionat() {
        cout << "Aer condiționat activat ❄️" << endl;
    }
};

class MasinaSport : public Masina {
private:
    int vitezaMaxima;
    double acceleratie0_100;
    bool areNitro;
    
public:
    MasinaSport(string m, string mod, int an, int usi, 
                   string combustibil, int vMax, double acc, bool nitro)
        : Masina(m, mod, an, usi, combustibil), 
          vitezaMaxima(vMax), acceleratie0_100(acc), areNitro(nitro) {
        cout << "[Nivel 3] Constructor MasinaSport" << endl;
    }
    
    void activeazaModSport() {
        cout << "🏁 MOD SPORT ACTIVAT!" << endl;
        cout << "Suspensie rigidă, răspuns accelerație îmbunătățit!" << endl;
    }
    
    void activeazaNitro() {
        if (areNitro) {
            cout << "💨 NITRO ACTIVAT! Viteză maximă!" << endl;
        } else {
            cout << "Această mașină nu are sistem nitro." << endl;
        }
    }
    
    void afiseazaPerformante() {
        cout << "\n🏎️ Performanțe " << marca << " " << model << ":" << endl;
        cout << "Viteză maximă: " << vitezaMaxima << " km/h" << endl;
        cout << "0-100 km/h în: " << acceleratie0_100 << " secunde" << endl;
        cout << "Sistem Nitro: " << (areNitro ? "DA" : "NU") << endl;
    }
};

int main() {
    MasinaSport ferrari("Ferrari", "F8 Tributo", 2023, 
                        2, "Benzină", 340, 2.9, true);
    
    // Metode de la Vehicul (nivel 1)
    ferrari.porneste();
    
    // Metode de la Masina (nivel 2)
    ferrari.activeazaAerConditionat();
    
    // Metode proprii (nivel 3)
    ferrari.activeazaModSport();
    ferrari.activeazaNitro();
    ferrari.afiseazaPerformante();
    
    return 0;
}

🔒 Specificatori de Acces în Moștenire

Tip Moștenire public în bază protected în bază private în bază
public public protected inaccesibil
protected protected protected inaccesibil
private private private inaccesibil

Exemplu Practic:

Specificatori de Acces
class Baza {
public:
    int publicVar = 1;
protected:
    int protectedVar = 2;
private:
    int privateVar = 3;
};

// Moștenire PUBLIC
class DerivataPublic : public Baza {
public:
    void afiseaza() {
        cout << publicVar;     // OK - rămâne public
        cout << protectedVar;  // OK - rămâne protected
        // cout << privateVar; // EROARE - inaccesibil
    }
};

// Moștenire PROTECTED
class DerivataProtected : protected Baza {
public:
    void afiseaza() {
        cout << publicVar;     // OK - devine protected
        cout << protectedVar;  // OK - rămâne protected
        // cout << privateVar; // EROARE - inaccesibil
    }
};

// Moștenire PRIVATE
class DerivataPrivate : private Baza {
public:
    void afiseaza() {
        cout << publicVar;     // OK - devine private
        cout << protectedVar;  // OK - devine private
        // cout << privateVar; // EROARE - inaccesibil
    }
};

int main() {
    DerivataPublic objPublic;
    objPublic.publicVar = 10;  // OK - public
    
    DerivataProtected objProtected;
    // objProtected.publicVar = 10; // EROARE - protected acum
    
    DerivataPrivate objPrivate;
    // objPrivate.publicVar = 10; // EROARE - private acum
    
    return 0;
}

⚡ Funcții Virtuale și Polimorfism

Funcțiile virtuale permit polimorfismul dinamic - capacitatea de a apela metoda corectă în funcție de tipul real al obiectului, nu de tipul pointerului.

Exemplu: Forme Geometrice cu Funcții Virtuale

Funcții Virtuale și Polimorfism
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

// Clasă abstractă de bază
class Forma {
protected:
    string culoare;
    
public:
    Forma(string c) : culoare(c) {}
    
    // Funcție virtuală pură - face clasa abstractă
    virtual double calculeazaArie() = 0;
    virtual double calculeazaPerimetru() = 0;
    
    // Funcție virtuală normală
    virtual void afiseazaInfo() {
        cout << "Formă de culoare " << culoare << endl;
    }
    
    // Destructor virtual - important pentru moștenire!
    virtual ~Forma() {}
};

class Cerc : public Forma {
private:
    double raza;
    
public:
    Cerc(string c, double r) : Forma(c), raza(r) {}
    
    double calculeazaArie() override {
        return M_PI * raza * raza;
    }
    
    double calculeazaPerimetru() override {
        return 2 * M_PI * raza;
    }
    
    void afiseazaInfo() override {
        cout << "🔵 Cerc " << culoare;
        cout << " cu raza " << raza << endl;
        cout << "   Arie: " << calculeazaArie() << endl;
        cout << "   Perimetru: " << calculeazaPerimetru() << endl;
    }
};

class Dreptunghi : public Forma {
private:
    double lungime, latime;
    
public:
    Dreptunghi(string c, double l, double lat) 
        : Forma(c), lungime(l), latime(lat) {}
    
    double calculeazaArie() override {
        return lungime * latime;
    }
    
    double calculeazaPerimetru() override {
        return 2 * (lungime + latime);
    }
    
    void afiseazaInfo() override {
        cout << "▭ Dreptunghi " << culoare;
        cout << " de " << lungime << "x" << latime << endl;
        cout << "   Arie: " << calculeazaArie() << endl;
        cout << "   Perimetru: " << calculeazaPerimetru() << endl;
    }
};

class Triunghi : public Forma {
private:
    double a, b, c; // laturile
    double baza, inaltime;
    
public:
    Triunghi(string col, double l1, double l2, double l3, 
             double bz, double h)
        : Forma(col), a(l1), b(l2), c(l3), baza(bz), inaltime(h) {}
    
    double calculeazaArie() override {
        return (baza * inaltime) / 2;
    }
    
    double calculeazaPerimetru() override {
        return a + b + c;
    }
    
    void afiseazaInfo() override {
        cout << "▲ Triunghi " << culoare << endl;
        cout << "   Arie: " << calculeazaArie() << endl;
        cout << "   Perimetru: " << calculeazaPerimetru() << endl;
    }
};

int main() {
    // Vector de pointeri către clasa de bază
    vector<Forma*> forme;
    
    // Adăugăm diferite forme
    forme.push_back(new Cerc("roșu", 5));
    forme.push_back(new Dreptunghi("albastru", 10, 7));
    forme.push_back(new Triunghi("verde", 3, 4, 5, 4, 3));
    forme.push_back(new Cerc("galben", 3));
    
    cout << "=== Polimorfism în Acțiune ===\n" << endl;
    
    // Polimorfism - aceeași interfață, comportament diferit
    for (Forma* forma : forme) {
        forma->afiseazaInfo();
        cout << endl;
    }
    
    // Calculăm aria totală
    double arieTotal = 0;
    for (Forma* forma : forme) {
        arieTotal += forma->calculeazaArie();
    }
    cout << "\n📊 Aria totală a tuturor formelor: " << arieTotal << endl;
    
    // Eliberăm memoria
    for (Forma* forma : forme) {
        delete forma;
    }
    
    return 0;
}

💡 Exemple Practice Complete

Exemplu 1: Sistem de Management Angajați

Sistem Complet de Angajați
class Angajat {
protected:
    string nume;
    string id;
    double salariuBaza;
    
public:
    Angajat(string n, string i, double s) 
        : nume(n), id(i), salariuBaza(s) {}
    
    virtual double calculeazaSalariu() {
        return salariuBaza;
    }
    
    virtual void afiseazaDetalii() {
        cout << "Angajat: " << nume << " (ID: " << id << ")" << endl;
        cout << "Salariu: " << calculeazaSalariu() << " RON" << endl;
    }
};

class Manager : public Angajat {
private:
    double bonus;
    int numarSubordonati;
    
public:
    Manager(string n, string i, double s, double b, int sub)
        : Angajat(n, i, s), bonus(b), numarSubordonati(sub) {}
    
    double calculeazaSalariu() override {
        return salariuBaza + bonus + (numarSubordonati * 500);
    }
    
    void afiseazaDetalii() override {
        cout << "👔 Manager: " << nume << " (ID: " << id << ")" << endl;
        cout << "Subordonați: " << numarSubordonati << endl;
        cout << "Salariu total: " << calculeazaSalariu() << " RON" << endl;
    }
};

class Dezvoltator : public Angajat {
private:
    string limbajPrincipal;
    int proiecteFinalizate;
    
public:
    Dezvoltator(string n, string i, double s, string limbaj, int proiecte)
        : Angajat(n, i, s), limbajPrincipal(limbaj), proiecteFinalizate(proiecte) {}
    
    double calculeazaSalariu() override {
        double bonusProiecte = proiecteFinalizate * 1000;
        return salariuBaza + bonusProiecte;
    }
    
    void afiseazaDetalii() override {
        cout << "💻 Dezvoltator: " << nume << " (ID: " << id << ")" << endl;
        cout << "Limbaj principal: " << limbajPrincipal << endl;
        cout << "Proiecte finalizate: " << proiecteFinalizate << endl;
        cout << "Salariu total: " << calculeazaSalariu() << " RON" << endl;
    }
};

Exemplu 2: Sistem Bancar

Sistem Bancar cu Moștenire
class ContBancar {
protected:
    string numarCont;
    string titular;
    double sold;
    
public:
    ContBancar(string nr, string tit, double s = 0)
        : numarCont(nr), titular(tit), sold(s) {}
    
    virtual void depune(double suma) {
        if (suma > 0) {
            sold += suma;
            cout << "✅ Depunere: " << suma << " RON" << endl;
        }
    }
    
    virtual bool retrage(double suma) {
        if (suma > 0 && suma <= sold) {
            sold -= suma;
            cout << "💰 Retragere: " << suma << " RON" << endl;
            return true;
        }
        cout << "❌ Fonduri insuficiente!" << endl;
        return false;
    }
    
    virtual void afiseazaDetalii() {
        cout << "Cont: " << numarCont << endl;
        cout << "Titular: " << titular << endl;
        cout << "Sold: " << sold << " RON" << endl;
    }
};

class ContEconomii : public ContBancar {
private:
    double rataDobanda;
    int retrageriLunare;
    const int LIMITE_RETRAGERI = 3;
    
public:
    ContEconomii(string nr, string tit, double s, double dobanda)
        : ContBancar(nr, tit, s), rataDobanda(dobanda), retrageriLunare(0) {}
    
    void aplicaDobanda() {
        double dobanda = sold * (rataDobanda / 100);
        sold += dobanda;
        cout << "📈 Dobândă aplicată: " << dobanda << " RON" << endl;
    }
    
    bool retrage(double suma) override {
        if (retrageriLunare >= LIMITE_RETRAGERI) {
            cout << "⚠️ Limită retrageri lunare atinsă!" << endl;
            return false;
        }
        if (ContBancar::retrage(suma)) {
            retrageriLunare++;
            return true;
        }
        return false;
    }
};

class ContCurent : public ContBancar {
private:
    double limitaDescoperit;
    
public:
    ContCurent(string nr, string tit, double s, double descoperit)
        : ContBancar(nr, tit, s), limitaDescoperit(descoperit) {}
    
    bool retrage(double suma) override {
        if (suma > 0 && suma <= (sold + limitaDescoperit)) {
            sold -= suma;
            cout << "💳 Retragere: " << suma << " RON" << endl;
            if (sold < 0) {
                cout << "⚠️ Cont în descoperit: " << sold << " RON" << endl;
            }
            return true;
        }
        cout << "❌ Depășire limită descoperit!" << endl;
        return false;
    }
};

🎯 Test Rapid

Care tip de moștenire permite unei clase să moștenească de la mai multe clase de bază?

Moștenire simplă
Moștenire multiplă ✓
Moștenire ierarhică
Moștenire multinivel