Documente Academic
Documente Profesional
Documente Cultură
Modul 2
Curs 8
Cuprins
1. Moştenirea
• Constructori şi destructori pentru clasa derivată
2. Clase virtuale
3. Pointeri către clasa de bază
4. Metode virtuale
5. Clase abstracte
2
1. Moştenirea
Constructori şi destructori pentru clasa derivată
• Regulile de funcţionare ale constructorilor şi destructorilor
rămân valabile pentru clasele derivate, cu unele aspecte
particulare
• Ce se întâmplă la crearea unui obiect din clasa derivată:
– se alocă spaţiu pentru întregul obiect (atât pentru datele membre
moștenite din clasa de bază cât si datele membre noi din clasa
derivată)
– se apelează constructorul clasei de bază pentru a iniţializa datele
membre moştenite din clasa de bază
– se apelează constructorul din clasa derivată pentru a iniţializa
datele membre adăugate în clasa derivată
• Exemplu:
B::B(int x, int y) : A(y) {
// corp constructor
}
5
Exemplu
// clasa de baza
class Pozitie {
protected :
int x, y;
public :
Pozitie (int=0, int=0);
void afisare( );
void deplasare(int dx, int dy);
};
8
// redefinire functie de deplasare in clasa derivata
void Punct::deplasare(int dx, int dy)
{
if(vizibil) {
cout << "Deplasare: ";
afisare( ); // apel metoda din clasa Punct
}
x += dx;
y += dy;
if(vizibil) {
cout << "la coordonatele: ";
Pozitie::afisare( ); // apel metoda din clasa Pozitie
}
}
9
// program ce utlizeaza clasa derivata
int main()
{
Punct p0(1, 1, 'V');
Punct p1(p0);
p1.arata( );
p1.deplasare(10,10);
}
10
• Constructorul de copiere al clasei derivate este
răspunzător de iniţializarea corectă a datelor moştenite
de la clasa de bază
• De aceea se recomandă utilizarea unui astfel de
constructor de copiere:
clasa_deriv ::clasa_deriv(clasa_derivata &nume_par) : clasa_baza(parametri);
11
• In cazul moştenirii multiple, ordinea în care sunt apelaţi
constructorii claselor de bază este aceiaşi cu ordinea
specificării claselor de bază în declaraţia clasei derivate
– această ordine poate diferi de ordinea specificată în lista de
iniţializare din constructorul clasei derivate
12
2. Clase virtuale
• Considerăm următoarea situaţie:
class BB {
public : int x;
…
};
class B1 : public BB {
// corp clasa
};
class B2 : public BB {
// corp clasa
};
class D : public B1, public B2 {
// corp clasa
};
• Apare o ambiguitate:
– compilatorul nu poate decide prin care din clasele B1 sau B2 să
acceseze variabila din clasa de bază
14
• Există posibilitatea includerii unui singur exemplar al clasei
de bază primare prin declararea acesteia ca şi clasă virtuală
în declaraţiile claselor B1 si B2:
class BB {
protected : int x, y;
…
};
16
• Dacă într-o ierarhie de clase, unele instanţe ale clasei de
bază sunt declarate virtuale iar altele sunt declarate non-
virtuale, atunci obiectele claselor derivate vor conţine câte
un obiect al clasei de bază pentru fiecare instanţă non-
virtuală şi un singur obiect al clasei de bază pentru toate
instanţele virtuale
17
• Constructorul clasei derivate D (ultima clasă derivată)
trebuie să precizeze transferul de date către
constructorul clasei de bază BB pentru crearea unei
copii unice a obiectului BB:
D::D(lista_param) : B1(Lista_param), B2(lista_param),
BB(lista_param) {…}
int main()
{
derived3 ob(10, 20, 30);
cout << "Product is: " << ob.product( ) << "\n";
}
20
Exemplul 2:
class Person
{
private:
string ptype;
string name;
public:
Person( const string & t, const string & n ) : ptype( t ), name( n )
{}
21
class Student : virtual public Person
{
private:
int hours;
public:
Student( const string & n, int h ) : Person( "Student", n ), hours(h)
{}
int getCreditHours( ) {
return hours;
}
};
22
class Employee : virtual public Person
{
private:
int hours;
public:
Employee( const string & n, int h ) : Person( "Employee", n), hours(h)
{}
int getVacationHours( ) {
return hours;
}
};
23
class StudentEmployee : public Student, public Employee
{
public:
StudentEmployee( const string & n, int ch, int vh ) :
Person( "StudentEmployee", n ),
Student( "ignored", ch ),
Employee( "ignored", vh )
{}
};
24
int main( )
{
StudentEmployee se( "Bitang", 120, 15 );
25
3. Pointeri către clasa de bază
• Un pointer către o clasă derivată este compatibil ca şi tip
cu un pointer la clasa de bază din care este derivată:
– pointerii către clasa de bază pot fi folosiţi pentru a accesa membrii
din clasele derivate ce sunt moşteniţi din clasa de bază
26
class Base
{
protected:
int b;
public:
Base(int k) {
b = k;
}
void show() {
cout << "Din clasa de baza: b = " << b << endl;
}
};
27
class Derived : public Base
{
protected:
int d;
public:
Derived(int j, int k) : Base(k)
{
d = j;
}
void show() {
cout << "Din clasa derivata: b = " << b << ", d = " << d << endl;
}
};
28
int main()
{
Base b(20), *bp=&b;
bp->show();
((Derived *)bp)->show();
29
30
4. Metode virtuale
• O metodă virtuală este acea metodă care este definită cu
specificatorul virtual în clasa de bază şi apoi este
redefinită în clasele derivate:
– au implementări diferite în clasele derivate
31
• Motivaţia:
– supraîncărcarea metodelor nu este posibilă dacă semnăturile
metodelor coincid
– metodele virtuale permit acest lucru şi ca urmare prototipul
funcţiilor din clasele derivate trebuie să fie exact acelaşi ca cel
al funcţiei originale (lista de parametri şi tip returnat identice)
– dacă totuşi lista de parametri diferă şi funcţia originală este
declarată că fiind şi virtuală, mecanismul de metodă virtuală
este ignorat
32
Exemplu:
class CPolygon {
protected:
int width, height;
public:
void set_w (int a) { width=a; }
void set_h (int b) { height=b; }
35
36
Exemplu:
class baza {
public:
virtual void functie( ) {
cout << endl << "Functia din clasa de baza" << endl;
}
};
38
• Alte caracteristici:
– o metodă rămâne virtuală indiferent de câte ori este moştenită
– dacă o clasă derivată nu redefineşte o metodă virtuală atunci
un obiect dintr-o clasă derivată va folosi varianta din clasa de
bază
– metodele statice nu pot fi metode virtuale
– constructorii nu pot fi metode virtuale
– destructorii pot fi metode virtuale
– metodele inline nu pot fi virtuale
39
• Incepând cu C++ 11 este posibilă împiedicarea
redefinirii unei metode virtuale, folosind specificatorul
final:
class Base
{
public:
virtual void myfunction() {//…}
};
class Derived : public Base
{
void myfunction() final { //…}
};
- Compilatorul va sancționa cu eroare orice tentativă de redefinire
într-o altă clasă derivată din clasa Derived
40
• Același specificator se poate folosi pentru a preciza că
o clasă nu mai poate fi folosită ca și clasă de bază într-
o nouă moștenire:
41
5. Clase abstracte
• Sunt clase care nu sunt utilizate direct ci furnizează un
schelet pentru alte clase ce vor fi derivate din acestea
• De obicei, toate metodele membre ale unei clase
abstracte sunt virtuale şi au implementări vide urmând să
fie redefinite în clasele derivate
43
Exemplu:
class CPolygon {
protected:
int width, height;
public:
void set_w (int a) { width=a; }
void set_h (int b) { height=b; }
44
class CRectangle: public CPolygon {
public:
int area (void) {
return (width * height);
}
};
45
int main ( )
{
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_w (4); ppoly1->set_h (5);
ppoly2->set_w (5); ppoly2->set_h (5);
cout << "Apel direct pentru functia virtuala \n";
cout << "\tArie dreptunghi: " << ppoly1->area( ) << endl;
cout << "\tArie triunghi: " << ppoly2->area( ) << endl;
cout << “\nApel indirect pentru functia virtuala \n";
cout << "\tArie dreptunghi: " ;
ppoly1->print_area( );
cout << "\tArie triunghi: " ;
ppoly2->print_area( );
}
46