Sunteți pe pagina 1din 12

5.

Motenirea claselor
Obiective
- nelegerea modului n care se pot crea clase noi prin motenirea din clasele
existente
- nelegerea modului n care motenirea promoveaz reutilizarea codului
- nelegerea noiunilor de clas de baz i clas derivat

- Introducere
n acest capitol vom studia una dintre cele mai importante faciliti pe care le
ofer programarea orientat pe obiecte: motenirea claselor. Motenirea este o
form de reutilizare a codului n care noile clase sunt create din clase existente prin
absorbirea atributelor i comportamentelor lor, prin nlocuirea unor comportamente i
prin adgarea unor atribute i comportmante noi. Reutilizarea codului economisete
timp preios n dezvoltarea software. Este ncurajat reutilizarea secvenelor de cod
testate i de calitate pentru reducerea problemelor care ar putea aprea dup ce
sistemul ar deveni funcional.
Atunci cnd creeaz o nou clas, n loc s rescrie complet noile date membre
i funcii membre, programatorul poate arta c noua clas va moteni datele
membre i funciile membre dintr-o clas de baz definit anterior. Noua clas este o
clas derivat. Fiecare clas derivat poate deveni, mai departe, un candidat pentru
derivri ulterioare. Atunci cnd folosim motenirea simpl, o clas este derivat dintro singur clas de baz. Motenirea multipl presupune posibilitatea ca o clas s
fie derivat din mai multe clase de baz. Motenirea simpl este uor de folosit i o
vom ilustra prin cteva exemple. Motenirea multipl este mai complex i vom
studia doar un exemplu simplu.
O clas derivat poate aduga noi date membre i funcii membre, astfel nct
poate fi mai cuprinztoare dect clasa ei de baz. O clas derivat este mai
particular dect clasa ei de baz i reprezint un grup mai mic de obiecte. Fora
mecanismului motenirii vine din posibilitatea de a defini n clasele derivate adugiri,
nlocuiri sau rafinri ale elementelor motenite din clasa de baz.
Limbajul C++ ofer trei tipuri de moteniri: public, protected i private. n
acest capitol ne vom concentra pe motenirea public i le vom explica pe scurt pe
celelalte dou. Motenirea private poate fi folosit ca o modalitate alternativ de
compunere a claselor iar motenirea protected este folosit rar. Cnd derivarea
este public, fiecare obiect al unei clase derivate poate fi folosit oriunde se folosete
un obiect al clasei de baz din care a fost derivat acea clas. Operaia invers nu
este posibil, deci obiectele clasei de baz nu sunt i obiecte ale clasei derivate.
Avantajul acestei relaii rezumat prin expresia un obiect din clasa derivat este i
obiect al clasei de baz va fi ilustrat n capitolul n care vom introduce o alt facilitate
fundamental a programrii orientate pe obiecte, polimorfismul. Acesta permite
procesarea generic a obiectelor care fac parte din clase derivate din aceeai clas
de baz.
Experiena dezvoltrii aplicaiilor software arat c adeseori segmente
semnificative de cod sunt dedicate tratrii cazurilor speciale. Devine dificil
proiectarea acestor sisteme pentru c proiectantul i programatorul devin preocupai
de ele. Programarea orientat pe obiecte prin procesul numit abstractizare este o
soluie la aceste situaii. Dac programul este suprancrcat de cazuri speciale, o

Programarea calculatoarelor i limbaje de programare II

soluie la ndemn este utilizarea secvenelor switch care pot oferi posibilitatea de
a scrie secvene logice de procesare pentru a trata fiecare caz individual. Vom vedea
ntr-unul dintre capitolele urmtoare c motenirea i polimorfismul sunt alternative
mai simple ale logicii switch.
Trebuie s facem distincia ntre relaiile tip este un sau este o (is a) i are
un sau are o (has a). Aa cum am vzut deja, o relaie has a nseamn
compunere de clase, adic un obiect al unei clase are ca membri unul sau mai multe
obiecte ale altor clase. O relaie is a este o motenire. Acesta este tipul de relaie n
care obiectele unei clase derivate pot fi tratate i ca obiecte ale clasei de baz.
n acest capitol discutm specificatorul de acces la membri numit protected.
O clas derivat nu poate accesa membrii private ai clasei sale de baz pentru c
n caz contrar s-ar nclca ideea de ncapsulare a clasei de baz. O clas derivat
poate, ns, s acceseze membrii public i protected ai clasei de baz. O clas
derivat poate accesa membrii private ai clasei sale de baz doar dac aceasta a
implementat funcii de acces public sau protected pentru ei.
O problem a motenirii este c o clas derivat motenete i implementri
ale funciilor membre public din clasa de baz de care nu are nevoie. Cnd
implementarea unui membru din clasa de baz nu este potrivit clasei derivate, acest
membru poate fi suprascris n clasa derivat cu o implementare corespunztoare.

- Motenirea: clase de baz i clase derivate


Adeseori, un obiect al unei clase este un obiect al altei clase n acelai timp. Un
dreptunghi este un patrulater, la fel ca i un ptrat, un paralelogram sau un trapez.
Astfel, clasa Dreptunghi se poate spune c motenete clasa Patrulater. n
acest context, clasa Patrulater se numete clas de baz i clasa Dreptunghi
se numete clas derivat. Un dreptunghi este un tip particular de patrulater, dar
este incorect s afirmm c un patrulater este un dreptunghi. Iat cteva exemple de
motenire:
Clasa de baz
Forma
Credit
Cont

Clase derivate
Cerc
Triunghi
Dreptunghi
CreditAuto
CreditImobiliar
ContCurent
ContDepozit
ContPlati

Motenirea conduce la structuri ierarhice arborescente. O clas de baz se afl


ntr-o relaie ierarhic cu clasele derivate din ea. Bineneles c o clas poate s
existe n mod individual. Atunci cnd clasa este folosit mpreun cu mecanismul
motenirii, ea poate deveni clas de baz care ofer atribute i comportamente altor
clase, sau clas derivat i motenete atribute i comportamente.
O ierarhie simpl de motenire este ierarhia Forma din figura de mai jos.

Programarea calculatoarelor i limbaje de programare II

Forma
FormaBidimensionala
Cerc

Triunghi

FormaTridimensionala
Patrat

Sfera

Cub

Formele sunt mprite n aceast ierarhie n forme unidimensionale si


bidimensionale. Cerc, Triunghi i Patrat sunt clase derivate din
FormaBidimensionala. Un obiect al clasei Cerc este n acelai timp i o
FormaBidimensionala, dar i o Forma.
n limbajul C++, sintaxa prin care clasa FormaBidimensionala este definit
ca o clas derivat din Forma este urmtoarea:
class FormaBidimensionala : public Forma
{
...
};
Aceasta este o derivare public i este cel mai folosit tip de derivare. n
aceast situaie, membrii public i protected din clasa de baz sunt motenii ca
membri public, respectiv protected ai clasei derivate. Membrii private ai clasei
de baz nu sunt accesibili din clasele derivate. Funcile friend nu se motenesc.

- Membrii protected
Membrii public ai unei clase de baz pot fi accesai de orice funcie din
program. Membrii private al unei clase de baz sunt accesibili doar funciilor
membre sau prietenilor clasei.
Nivelul de acces protected este un nivel intermediar ntre accesul public i
cel private. Membrii protected ai unei clase de baz pot fi accesai doar de
membrii i de prietenii clasei de baz i de membrii i prietenii claselor derivate.
Membrii claselor derivate pot referi membrii public i protected ai clasei de baz
folosind numele acestor membri. Datele protected depesc ideea de ncapsulare
pentru c o schimbare a membrilor protected din clasa de baz poate influena
toate clasele derivate. n general, se recomand ca datele membre s fie declarate
private, iar protected trebuie folosit numai atunci cnd este strict necesar.

- Cast ntre pointerii la clasa de baz i pointerii la clasa


derivat
Un obiect al unei clase derivate public poate fi tratat ca obiect al clasei ei de
baz. Aceasta face posibil o serie ntreag de operaii.
Pe de alt parte, programatorul trebuie s foloseasc un cast explicit pentru a
converti un pointer la clasa de baz ntr-un pointer la o clas derivata deoarece
compilatorul consider c aceast operaie este una periculoas. Acest proces se
numete downcasting a pointer. Trebuie, ns, acordat atenie dereferenierii unui
astfel de pointer, programatorul asigurndu-se c tipul pointerului se potrivete cu
tipul obiectului ctre care pointeaz. Standardele recente C++ au introdus metode
mai elaborate pentru acest tip de conversie prin run-time type identification (RTTI),
dynamic_cast i typeid.

Programarea calculatoarelor i limbaje de programare II

Operaia invers, prin care un pointer al clasei derivate este convertit la un


pointer al clasei de baz se numete upcasting a pointer. Ilustrm aceste operaii de
cast prin folosirea claselor Point, care este clas de baz, i Circle care este
clas derivat.
Exemplu
point.h
#ifndef POINT_H
#define POINT_H
#include <iostream>
using std::ostream;
class Point
{
friend ostream& operator<<(ostream&, const Point&);
public:
Point(int = 0, int = 0); //constructor implicit
void setPoint(int, int); //seteaza coordonatele
int getX() const { return x; } //returneaza x
int getY() const { return y; } //returneaza y
protected: //accesibil din clasele derivate
int x, y; //x si y coordonatele unui punct
};
#endif
point.cpp
#include <iostream>
#include "point.h"
//Constructor pentru clasa Point
Point::Point(int a, int b)
{ setPoint(a, b); }
//Seteaza coordonatele x si y ale unui punct
void Point::setPoint(int a, int b)
{
x = a;
y = b;
}
//Afiseaza un punct
ostream& operator<<(ostream& output, const Point& p)
{
output << '[' << p.x << ", " << p.y << ']';
return output; //pentru cascadarea apelurilor
}
circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
using std::ostream;
#include <iomanip>
using std::ios;
using std::setiosflags;
using std::setprecision;

Programarea calculatoarelor i limbaje de programare II

#include "point.h"
class Circle : public Point //Circle derivata din Point
{
friend ostream& operator<<(ostream&, const Circle&);
public:
//constructor implicit
Circle(double r = 0.0, int x = 0, int y = 0);
void setRadius(double); //seteaza radius
double getRadius() const; //intoarce radius
double area() const; //calculeaza aria
protected:
double radius;
};
#endif
circle.cpp
#include "circle.h"
//Constructorul clasei Circle apeleaza
//constructorul pentru Point si apoi
//initializeaza raza
Circle::Circle(double r, int a, int b)
: Point(a, b)
{ setRadius(r); }
//Seteaza raza cercului
void Circle::setRadius(double r)
{ radius = (r > 0 ? r : 0); }
//Returneaza raza cercului
double Circle::getRadius() const
{ return radius; }
//Calculeaza aria cercului
double Circle::area() const
{ return 3.14159 * radius * radius; }
//Afiseaza datele despre cerc in forma
//Centrul = [x, y]; Raza = #.##
ostream& operator<<(ostream& output, const Circle& c)
{
output << "Centrul = " << static_cast<Point>(c)
<< "; Raza = "
<< setiosflags(ios::fixed | ios::showpoint)
<< setprecision(2) << c.radius;
return output;
}
test_point_circle.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
#include "point.h"
#include "circle.h"
5

Programarea calculatoarelor i limbaje de programare II

int main()
{
Point *pointPtr = 0, p(30, 50);
Circle *circlePtr = 0, c(2.7, 120, 89);
cout << "Punctul p: " << p << "\nCercul c: " << c << '\n';
//Trateaza Circle ca un Point
//Este vizibila doar partea care provine din clasa de baza
pointPtr = &c; //asigneaza adresa unui Circle lui pointPtr
cout << "\nCercul c (via *pointPtr): "
<< *pointPtr << '\n';
//Trateaza un Circle ca un Circle
//cast de la pointer la clasa de baza la pointer
//la clasa derivata
circlePtr = static_cast<Circle*>(pointPtr);
cout << "\nCercul c (via *circlePtr):\n" << *circlePtr
<< "\nAria lui c (via circlePtr): "
<< circlePtr->area() << '\n';
//PERICULOS: Trateaza Point ca un Circle
pointPtr = &p; //asigneaza adresa unui Point la pointPtr
//cast al clasei de baza la clasa derivata
circlePtr = static_cast<Circle*>(pointPtr);
cout << "\nPunctul p (via *circlePtr):\n" << *circlePtr
<< "\nAria obiectului la care pointeaza circlePtr: "
<< circlePtr->area() << endl;
return 0;
}
Rulnd acest program obinem urmtorul rezultat:
Punctul p: [30, 50]
Cercul c: Centrul = [120, 89]; Raza = 2.70
Cercul c (via *pointPtr): [120, 89]
Cercul c (via *circlePtr):
Centrul = [120, 89]; Raza = 2.70
Aria lui c (via circlePtr): 22.90
Punctul p (via *circlePtr):
Centrul = [30, 50]; Raza = 0.00
Aria obiectului la care pointeaza circlePtr: 0.00
Interfaa public a clasei Point cuprinde funciile membre setPoint, getX i
getY. Datele membre x i y ale clasei Point sunt protected. Astfel, datele
membre nu pot fi accesate de clienii clasei, dar clasele derivate din Point vor putea
folosi n mod direct aceste date motenite. Dac aceste date ar fi fost private, ar fi
6

Programarea calculatoarelor i limbaje de programare II

fost nevoie de apeluri ale funciilor membre public din clasa Point pentru accesul
acestor date chiar i n clasele derivate.
Clasa Circle este derivat public din clasa Point. Aceast derivare este
specificat prin prima linie din definiia clasei:
class Circle : public Point //Circle mosteneste Point
Semnul : din header-ul definiiei clasei indic aceast motenire. Cuvntul
cheie public arat tipul motenirii. Toi membrii public i protected ai clasei
Point sunt motenii ca public, respectiv protected n clasa Circle. nseamn
c interfaa public a clasei Circle cuprinde membrii public ai clasei Point, dar
i membrii public ai clasei Circle care sunt area, setRadius i getRadius.
Constructorul clasei Circle trebuie s invoce constructorul clasei Point
pentru iniializarea prii din obiect care provine din clasa de baz. Aceas invocare
se face prin lista de iniializare:
Circle :: Circle(double r, int a, int b)
: Point(a, b) //apelul constructorului clasei de baza
n situaia n care constructorul clasei Circle nu ar fi invocat n mod explicit
constructorul clasei Point, atunci ar fi fost apelat automat constructorul implicit al
clasei Point pentru iniializarea datelor membre x i y. n acest caz, n lipsa
constructorului implicit compilatorul semnaleaz eroare.
Programul creeaz pointPtr ca pointer la un obiect tip Point i circlePtr
ca pointer la un obiect Circle i obiectele p i c de tip Pointer i Circle.
Afiarea obiectelor p i c se face prin apelul operatorului << suprancrcat separat
pentru fiecare dintre cele dou tipuri de date.
Operatorul << suprancrcat n clasa Point poate manipula i obiecte din clasa
Circle tiprind partea care provine din clasa Point pentru obiectele clasei
Circle. Apelul se face prin cast de la referina c de tip Circle la un Point.
Rezultatul este apelul operator<< pentru Point i tiprirea coordonatelor x i y
folosind formatarea specific celei definite n clasa Point. Prin asignarea
pointPtr = &c;
este ilustrat operaia de upcasting prin care un obiect al unei clase derivate este
tratat ca obiect al clasei de baz. Rezultatul tipririi pointerului derefereniat
*pointPtr este partea din obiectul c care provine din clasa Point deoarece
compilatorul interpreteaza apelul operator<< ca un apel pentru un obiect tip
Point. Prin pointerul la clasa se baz se vede doar partea din obiectul c care
provine din clasa Point.
Asignarea
circlePtr = static_cast<Circle*>(pointPtr);
ilustreaz operaia de downcasting prin care un pointer la un obiect din clasa de baz
este convertit la un pointer la un obiect dintr-o clas derivat. Operatorul
static_cast din Standard C++ permite implementarea acestei operaii. Pointerul
pointPtr este transformat napoi n Circle* i rezultatul operaiei este asignat
pointerului circlePtr. Acest pointer a provenit iniial din adresa obiectului c, aa
cum se poate vedea n funcia main. Rezultatul afirii este coninutul obiectului c.
n final, programul asigneaz un pointer la clasa de baz (adresa obiectului p)
lui pointPtr i apoi aplic o operaie de cast lui pointPtr pentru a l transforma n
Circle*. Rezultatul celei de-a doua operaii este pstrat n circlePtr. Astfel,
obiectul p de tip Point este tiprit folosind operator<< pentru Circle i pointerul
derefereniat *circlePtr. Valoare tiprit pentru raz este 0 fiindc ea nu exist n
7

Programarea calculatoarelor i limbaje de programare II

obiectul p, el fiind un Point. Afiarea unui Point ca un Circle poate conduce,


aadar, la afiarea unor valori nedefinite.

- Folosirea funciilor membre


Funciile membre ale clasei derivate poate avea nevoie s acceseze anumite
date i funcii membre. O clas derivat nu poate accesa direct membri private ai
clasei de baz. Acesta este un aspect crucial de inginerie software in C++. Dac o
clas derivat ar putea accesa membrii private ai clasei de baz, ar nclca
principiul ncapsulrii pentru obiectele clasei de baz. Ascunderea membrilor
private este de mare ajutor n testarea, depanarea i modificarea corect a
sistemelor. Dac o clas derivat ar putea accesa membrii private ai clasei sale
de baz, atunci clasele care sunt derivate mai departe din clasele derivate pot
accesa i ele aceti membri i aa mai departe. Propagarea accesului la datele
private ar anula astfel beneficiile ncapsulrii datelor n cadrul unei ierarhii de
derivare.

- Suprascrierea membrilor clasei de baz n clasele


derivate
O clas derivat poate suprascrie (override) o funcie membr a clasei de baz
printr-o nou versiune a acestei funcii cu aceeai semntur. Dac semnturile sunt
diferite, atunci ar fi vorba de suprancrcare (overload), nu se suprascriere. Cnd
numele acestei funciei suprascrise este menionat n clasa derivat, este selectat
automat versiunea din clasa derivat. Poate fi folosit i veriunea din clasa de baz,
dar pentru aceasta trebuie folosit operatorul domeniu.
Exemplu
employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class Employee
{
public:
Employee(const char*, const char*);//constructor
void print() const;//tipareste numele si prenumele
~Employee();//destructor
private:
char* firstName;//string alocat dinamic
char* lastName; //string alocat dinamic
};
#endif
employee.cpp
#include <iostream>
using std::cout;
#include <cstring>
#include <cassert>
#include "employee.h"
//Constructorul aloca dinamic spatiu pentru nume si prenume

Programarea calculatoarelor i limbaje de programare II

//si foloseste strcpy pentru a copia


//numele si prenumele in obiect
Employee::Employee(const char* first, const char* last)
{
firstName = new char[strlen(first) + 1];
assert(firstName != 0);//termina programul daca nu se aloca
strcpy(firstName, first);
lastName = new char[strlen(last) + 1];
assert(lastName != 0);//termina programul daca nu se aloca
strcpy(lastName, last);
}
//Tipareste numele
void Employee::print() const
{ cout << firstName << ' ' << lastName; }
//Destructor
Employee::~Employee()
{
delete[] firstName;//eliberarea zonei de memorie
delete[] lastName; //eliberarea zonei de memorie
}
hourly.h
#ifndef HOURLY_H
#define HOURLY_H
#include "employee.h"
class HourlyWorker : public Employee
{
public:
HourlyWorker(const char*,
const char*,
double, double);//constructor
double getPay() const;//calculeaza si returneaza salariul
void print() const;//suprascrierea functiei
//din clasa de baza
private:
double wage;//salariul pe ora
double hours; //ore lucrate pe saptamana
};
#endif
hourly.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::ios;
using std::setiosflags;
using std::setprecision;

Programarea calculatoarelor i limbaje de programare II

#include "hourly.h"
//Constructorul clasei HourlyWorker
HourlyWorker::HourlyWorker(const char* first,
const char* last,
double initHours,
double initWage)
: Employee(first, last)//apel al constructorului
//clasei de baza
{
hours = initHours; //ar trebui validat
wage = initWage;
//ar trebui validat
}
//Returneaza salariul muncitorului
double HourlyWorker::getPay() const
{ return wage * hours; }
//Tipareste numele si salariul
void HourlyWorker::print() const
{
cout << "Se executa HourlyWorker::print()\n\n";
Employee::print();//Apelul functiei print din clasa de baza
cout << " este un lucrator angajat cu ora platit cu "
<< setiosflags(ios::fixed | ios::showpoint)
<< setprecision(2) << getPay() << " EUR" << endl;
}
test_hourlyworker.cpp
#include"hourly.h"
int main()
{
HourlyWorker h("Bob", "Smith", 40.0, 10.00);
h.print();
return 0;
}
Rulnd acest program obinem urmtorul rezultat:
Se executa HourlyWorker::print()
Bob Smith este un lucrator angajat cu ora platit cu
400.00 EUR
Definiia clasei Employee const din dou date membre private char*,
firstName i lastName i trei funcii membre, un constructor, un destructor i
print. Funcia constructor primete dou iruri de caractere i aloc dinamic
tablouri de char pentru stocarea lor. Folosim macro-ul assert pentru a determina
daca fost alocat memoria pentru firstName i lastName. n cazul n care
alocarea nu s-a putut realiza, programul se termin cu un mesaj de eroare. O
alternativ la folosirea lui assert este secvena try/catch tiind c operaia new
care nu se desfoar corect genereaz excepia bad_alloc. Deoarece datele
membre ale lui Employee sunt private, singura modalitate prin care pot fi accesate
este funcia membr print care afieaz numele i prenumele angajatului.

10

Programarea calculatoarelor i limbaje de programare II

Destructorul elibereaz memoria care a fost alocat dinamic pentru evitarea


fenomenului numit memory leak.
Clasa HourlyWorker este derivat din clasa Employee i motenirea este de tip
public. Noua clas i definete propria variant a funciei print care are acelai
prototip cu cea din clasa de baz Employee. Acesta este un exemplu de suprascriere
n clasa derivat a unei funcii din clasa de baz. n acest fel, clasa HourlyWorker are
acces la dou funcii print. De regul, n astfel de cazuri funcia din clasa derivat
apeleaz funcia din clasa de baz pentru a implementa o parte din operaii. n
exemplul nostru, funcia print din clasa derivat apeleaz funcia print din clasa de
baz pentru a tipri numele i prenumele angajatului, informaii care provin din clasa
de baz. Funcia print din clasa derivat adaug valorile datelor din clasa derivat,
adic informaiile legate de plata muncitorului. Din cauz c cele dou funcii print au
semnturi identice, apelul versiunii din clasa de baz se face precednd numele
funciei de numele clasei i de operatorul domeniu:
Employee::print();

- Motenirea public, protected i private


La derivarea unei clase, clasa de baz poate fi motenit public, protected sau
private. Derivarea protected sau private reprezint opiuni folosite rar. n mod obinuit
se folosete derivarea public. n tabelul de mai jos este prezentat pentru fiecare tip
de motenire modul de acces n clasa derivat al membrilor clasei de baz.
Specificatoru
l de acces al
motenire
datei membre
public
n clasa de
baz
public
public
n
clasa
derivat.
Poate
fi
accesat
direct
prin
orice
funcie
membr
nestatic,
funcie
friend sau funcie
nemembr.
protected
protected n clasa
derivat.
Poate
fi
accesat
direct
prin
orice
funcie
membr
nestatic sau funcie
friend.
private
Inaccesibil n clasa
derivat.
Poate
fi
accesat
direct
prin
orice
funcie
membr
nestatic sau funcie
friend prin funcii

Tipul motenirii
motenire
protected

motenire
private

protected n clasa
derivat.
Poate
fi
accesat
direct
prin
orice
funcie
membr
nestatic sau funcie
friend.

private n clasa
derivat.
Poate fi accesat direct
prin
orice
funcie
membr nestatic sau
funcie friend.

protected n clasa
derivat.
Poate
fi
accesat
direct
prin
orice
funcie
membr
nestatic sau funcie
friend.
Inaccesibil n clasa
derivat.
Poate
fi
accesat
direct
prin
orice
funcie
membr
nestatic sau funcie
friend prin funcii

private n clasa
derivat.
Poate fi accesat direct
prin
orice
funcie
membr nestatic sau
funcie friend.

11

Inaccesibil n clasa
derivat.
Poate fi accesat direct
prin
orice
funcie
membr nestatic sau
funcie friend prin
funcii
membre

Programarea calculatoarelor i limbaje de programare II

membre public sau membre public sau public


sau
protected din clasa protected din clasa protected din clasa
de baz.
de baz.
de baz.
La derivarea unei clase dintr-o clas de baz public, membrii public din
clasa de baz devin membri public ai clasei derivate i membrii protected ai
clasei de baz devin membri protected ai clasei derivate. Membrii private ai
clasei de baz nu pot fi accesai direct n clasele derivate, dar pot fi accesai prin
funcii membre private sau protected din clasa de baz.
La derivarea unei clase dintr-o clas de baz protected, membrii public
sau protected din clasa de baz devin membri protected n clasa derivat. La
derivarea dintr-o clas de baz private, membrii public i protected ai clasei
de baz devin membri private n clasa derivat. De exemplu, funciile devin funcii
utilitare. Derivrile private i protected nu sunt relaii de tip este un sau este
o.

- Clase de baz directe i clase de baz indirecte


O clas de baz poate fi clas de baz direct a clasei derivate sau clas de
baz indirect a clasei derivate. O clas de baz direct a unei clase derivate este
listat explicit n header-ul clasei derivate, dup semnul :. O clas de baz indirect
nu este listat explicit n header-ul clasei. Ea este motenit cu dou sau mai multe
nivele nainte n ierarhia de motenire.

12