📚 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
Sintaxa de bază:
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ă
#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
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.
Exemplu: Smartphone (Telefon + Computer)
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ă.
Exemplu: Ierarhie de Animale
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ă.
Exemplu: Vehicul → Mașină → Mașină Sport
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:
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
#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
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
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ă?