Introducere
Derivarea claselor (moștenirea) este unul dintre principiile fundamentale ale programării orientate pe obiecte. Ne permite să definim o clasă pornind de la altă clasă, creată anterior, și facilitează crearea și întreținerea aplicațiilor. Tototdată permite reutilizarea codului și micșorează timpul de implementare a programelor.
La crearea unei clase, în loc să scriem date și funcții membre complet noi, putem să precizăm că noua clasă va moșteni membri unei clase existente. Se obțin astfel ierarhii de clase.
Moștenirea are sens numai când obiectele din clasa moștenită fac parte din obiectele clasei de bază – relația dintre ele este de tipul Is A (este un/o). De exemplu:
- paralelogramul este un patrulater. Clasa
Paralelogram
poate fi derivată din clasaPatrulater
. - câinele este un animal. Clasa
Caine
poate fi derivată din clasaAnimal
.
Terminologie
Fie B
o clasă care există deja, iar D
clasa care moștenește membrii clasei B
. Spunem că:
B
este clasa de bază;D
este clasa derivată;- clasa
D
s-a obținut prin derivarea claseiB
; - clasa
B
a fost derivată și s-a obținut clasaD
; - clasa
D
moștenește clasaB
; - relația de moștenire se reprezintă prin următoarea diagramă:
În C++, o clasă poate fi derivată pornind de la mai multe clase de bază. Totodată, specificatorii de acces cunoscuți (public
, private
, protected
) sunt folosiți și pentru a preciza modul în care se face derivarea. Efectul lor este legat de vizibilitatea membrilor clasei de bază în clasa derivată.
Derivarea unei clase
Cea mai simplă formă de derivarea a unei clase este prezentată mai jos:
class D: public B{ // membri noi ai clasei derivate }
Observații:
- clasa
B
este clasa de bază, care trebuie să fie deja definită; - clasa
D
este clasa derivată; - specificatorul de acces folosit în exemplu,
public
, face ca:- membrii
public
din clasa de bazăB
rămânpublic
și în clasa derivatăD
– pot fi accesați din afara claseiD
; - membrii
protected
din clasa de bazăB
rămânprotected
și în clasa derivatăD
– pot fi accesați din clasa derivataD
și vor putea fi acesați din alte clase vor moșteni clasaD
; - membrii
private
din clasa de bazăB
nu pot fi accesați din clasa derivatăD
;
- membrii
- la definiția clasei derivate, în loc de
public
putem folosiprivate
sauprotected
. Semnificația lor va fi discutată ceva mai târziu!
Exemplu
#include<iostream> using namespace std; class Animal{ private: protected: int varsta; public: Animal(){ varsta = 0; cout << "S-a nascut un animal." << endl; } ~Animal(){ cout << "Animalul a murit." << endl; } void creste() { ++ varsta; cout << "Animalul are " << varsta << (varsta == 1 ? " an":" ani") << endl; } }; class Caine: public Animal{ public: Caine(){ cout << "S-a nascut un caine." << endl; } ~Caine(){ cout << "Cainele a murit." << endl; } void latra() { for(int i = 1 ; i <= varsta ; i ++) cout << "Ham " ; cout << endl; } void creste() { ++ varsta; cout << "Cainele are " << varsta << (varsta == 1 ? " an":" ani") << endl; } }; int main(){ Caine X; X.creste(); X.Animal::creste(); X.latra(); X.creste(); X.latra(); }
S-a nascut un animal. S-a nascut un caine. Cainele are 1 an Animalul are 2 ani Ham Ham Cainele are 3 ani Ham Ham Ham Cainele a murit. Animalul a murit.
Observații
Animal
este clasa de bază, iarCaine
este clasa derivată;- din clasa derivată (metoda
latra()
) am accesat proprietateavarsta
din clasa de bază:- acest lucru a fost posibil deoarece proprietatea
varsta
a fost declaratăprotected
- dacă ar fi fost declarată
private
, nu putea fi accesată din clasa derivată
- acest lucru a fost posibil deoarece proprietatea
- din exterior – funcția
main()
, pentru obiectulX
de tipCaine
am accesat:- metoda
latra()
, disponibilă doar în clasa derivată; - metoda
creste()
, moștenită din clasa de bază; - ambele metode sunt publice în clasa derivată;
- metoda
- ambele clase sunt înzestrate cu constructori și destructori:
- în cazul constructorului, mai întâi se apeleaza cel al clasei de bază, apoi cel al clasei derivate;
- în cazul destructorului, ordinea este inversă;
- dacă în clasa de bază și în clasa derivată avem doi membri cu același nume (overriding), prioritate are cel din clasa derivată. Pentru a-l accesa pe cel din clasa de bază vom folosi operatorul de rezoluție:
X.creste(); // Cainele are 1 an
X.Animal::creste(); // Animalul are 2 ani - în exemplul de mai jos se evidențiază modul în care se poate face atribuirea între o variabilă de tipul clasei de bază și una de tipul clasei derivate:
int main(){ Caine X; X.creste(); // Cainele are 1 an X.latra(); // Ham Animal A; A = X; A.creste(); // Animalul are 2 ani // X = A; eroare de sintaxă
}
A
este de tipulAnimal
(clasa de bază), iarX
este de tipulCaine
(clasa derivată). Atunci:- atribuirea
A = X;
este corectă. ÎnA
se vor copia doar membri dinX
care fac parte din clasa de bază. - atribuirea
X = A;
nu este corectă. Clasa derivată conține și membri care nu aparțin clasei de bază, ce nu pot fi inițializați prin această atribuire!
- atribuirea
Accesul la membrii claselor derivate
Accesul la membrii (date sau funcții) clasei de bază în clasa derivată se face în funcție de regulile de acces la membrii clasei de bază și în funcție de modalitatea în care s-a făcut derivarea.
Sunt trei moduri de declarare a membrilor unei clase:
- publici –
public
– pot fi accesați din afara clasei, dar și din interiorul ei - protejati –
protected
– nu pot fi accesați din exteriorul clasei (de bază sau derivate). Pot fi accesați din interiorul clasei de bază și din interiorul claselor derivate - privați –
private
– pot fi accesați numai din interiorul clasei.
Modalitățile de derivarea ale unei clase sunt:
- derivare publică:
class D: public B{ … }
- membrii publici ai clasei
B
rămân publici și în clasaD
; - membrii protejați al clasei
B
rămân protejați în clasaD
; - membrii privați ai clasei
B
sunt inaccesibili în clasaD
;
- membrii publici ai clasei
- derivare protejată:
class D: protected B{ … }
- membrii publici ai clasei
B
devin protejați și în clasaD
; - membrii protejați al clasei
B
rămân protejați în clasaD
; - membrii privați ai clasei
B
sunt inaccesibili în clasaD
;
- membrii publici ai clasei
- derivare privată:
class D: private B{ … }
- membrii publici ai clasei
B
devin privați și în clasaD
; - membrii protejați al clasei
B
devin privați în clasaD
; - membrii privați ai clasei
B
sunt inaccesibili în clasaD
;
- membrii publici ai clasei