Documente Academic
Documente Profesional
Documente Cultură
ALGORITMI
MODUL 2
CURS 9
CUPRINS
1. Moştenirea
• Noţiuni introductive
• Moştenirea simplă
• Moştenirea multiplă
• Constructori şi destructori pentru clasa derivată
2. Clase virtuale
3. Metode virtuale
4. Clase abstracte
5. Destructori virtuali
2
1. MOŞTENIREA
Noţiuni introductive
A) Asociere – relație între două sau mai multe clase care modelează
o interdependență între obiectele instanțiate din aceste clase;
Se folosesc: numele asocierii, săgeți de navigare, roluri, indicatori
de multiplicitate într-o reprezentare UML;
Implementarea e realizată prin: pointeri la obiecte sau tablouri de
pointeri la obiecte, sau prin asocieri abstracte în clase distincte cu
atribute și comportament propriu, printr-o implementare sub forma
unui dicționar, care e o asociere multiplicativă de tipul n ... m
4
implementată cu tablouri de hashing.
• Asocierea este o relație între 2 clase bazată pe referință.
Clasa A va conține o referință la clasa B. Asocierea poate fi
reprezentată printr-o linie între aceste clase, săgeata
indicând direcția de navigare. Dacă săgeţile sunt prezente la
ambele capete, asocierea permite navigarea în ambele
sensuri.
7
class Asset { ... };
class Player {
List assets;
public void AddAsset(Asset newlyPurchasedAsset) {
assets.Add(newlyPurchasedAssest); ... }
...
};
8
AGREGAREA COMPUSĂ
În acest caz într-o clasă se instantiază un obiect dintr-
o altă clasa. Când o clasă B este instanţiată într-o
clasă A, clasa A controlează crearea şi durata
existenţei instanţelor clasei B. Când instanţa clasei A
este distrusă, la fel va fi şi instanţa clasei B.
O astfel de relaţie se reprezintă printr-o linie ce uneşte
cele 2 clase pe care este figurat un romb plin spre
clasa care deţine responsabilitatea creării obiectelor.
O astfel de relaţie nu este implementată prin clase
imbricate. Clasa care este instanţiată în altă clasă
poate fi utilizată şi de alte părţi ale aplicaţiei.
9
public class Piece { ... };
public class Player
{
Piece piece = new Piece(); /*Player owns the
responsibility of creating the Piece*/
...
};
10
D) Moștenirea - caracterizată prin proprietatea a fi (to
be). E folosită pentru a modela similaritățile și diferențele
dintre clase. Expresia, e un fel de ( is_a_kind_of ) e
folosită la nivelul clasei și e un (is_a) la nivelul
obiectelor. Doar având moștenire considerăm că avem
POO.
Avem mai multe tipuri de moștenire, nu toate disponibile
în orice limbaj OO.
11
TIPURI DE MOȘTENIRE
-prin specializare, subclasa este o varietate specializată
a clasei de bază
-prin specificare, clasa de bază defineste doar
comportamentul (interfeţe sau clase abstracte) care este
implementat în subclase
-prin construcţie, subclasa foloseste comportamentul
clasei de bază nefiind un subtip al ei (Stiva construită cu
Vector)
-prin extindere, subclasa adaugă noi functionalităţi clasei
de bază, dar nu va modifica nici un element moştenit
-prin limitare, subclasa limitează comportamentul clasei
de bază, fiind utilizată destul de rar
-prin combinare, când de fapt avem moştenire multiplă,
bazată pe mai multe clase de bază. 12
Clasa CPolygon conţine membri ce sunt comuni
celorlalte două clase
Clasele CRectangle şi CTriangle vor conţine și membri
ce corespund unor caracteristici specifice
13
Clasa de bază nu este afectată de crearea unei clase
derivate din ea şi nu trebuie recompilată
Moştenire
Clasa de bază
public protected private
class Baza
{
protected:
int i, j;
public:
void initializare(int a, int b) {
i = a;
j = b;
}
void afiseaza( ) {
cout << i << “, “ << j << “\n”;
}
};//Baza
19
class Derivata : public Baza {
public:
int inmulteste( ) {
return i * j; // corect, i si j raman protected
}
};//Derivata
int main(void)
{
Derivata obiect_derivat;
//obiect_derivat.i = 5; // gresit, i ramane protected
obiect_derivat.initializare(12, 17); // din Baza
obiect_derivat.afiseaza( ); // din Baza
cout<< “\n Produsul este: “ <<obiect_derivat.inmulteste( );
cin.get();
}
20
Moştenirea protected
class Baza
{
int x;
protected:
int y;
public:
int z;
Baza(int x=1, int y=1 ) {
this->x=x;
this->y=y;
}
void arata( ) {
cout << "\n --------Clasa de baza------";
cout << "\n Valoarea variabilei private x: "<<x;
cout << "\n Valoarea variabilei publice y: "<<y;
} 21
};//Baza
class Derivata: protected Baza
{
public:
void do_this(void) {
//x = 5; // gresit, x este private in Baza
y = 7; // corect, y este protected in Baza, ramane protected
z = 15; // corect, z este public in Baza, devine protected
}
};
int main(void){
Baza ob1;
Derivata ob2;
ob1.arata( ); // public in Baza
ob2.do_this( );
//ob2.arata( ); // gresit, arata( ) devine protected in Derivata
cin.get(); 22
}
Moştenirea private
class Baza
{
protected: int a, b;
public:
int setA(int a){ this->a=a;}
int setB(int b){this->b=b;}
int aduna() {
return a+b;
}
int scade() {
return a-b;
}
void afis_baza( ) {
cout << a << " " << b << "\n";
} 23
};
class Derivata : private Baza
{
public:
int inmulteste() {
return a+b;
}
};
Int main(void){
Baza obiect_baza;
obiect_baza.setA(1);
obiect_baza.setB(2);
Derivata obiect_derivat;
cout<< “\nProdusul este= “<<obiect_derivat.inmulteste(); // corect
//obiect_derivat.aduna(); // eroare, devine private
cin.get();
}
24
Este posibil ca membrii clasei de bază să fie exceptaţi
individual de la modul de acces stabilit prin declaraţia
clasei derivate, astfel încât să-şi păstreze atributele din
clasa de bază:
26
Exemplul 1:
class Baza1 { class Baza2 {
protected: protected:
int x; int y;
public: public:
void afiseaza_x( ) { void afiseaza_y( ) {
cout << “valoarea lui x este: “ cout << “valoarea lui y
<< x <<”\n”; este: “ << y <<”\n”;
} }
void afis( ) { void afis( ) {
cout << “ y = “ << y <<”\n”;
cout << “ x = “ << x <<”\n”;
}
}
};//Baza2
};//Baza1
27
class Derivata: public Baza1, public Baza2 {
public:
void initializeaza(int i, int j) {
x = i;
y = j;
}
void afis( ) {
Baza1::afis( );
Baza2::afis( );
}
};
int main(void){
Derivata obiect_derivat;
obiect_derivat.initializeaza(100, 200);
obiect_derivat.afiseaza_x( ); // metoda mostenita din Baza1
obiect_derivat.afiseaza_y( ); // metoda mostenita din Baza2
obiect_derivat.afis(); // metoda din clasa Derivata
28
cin.get();
}
Observații:
29
În cazul moştenirii multiple, dacă clasele de bază conţin
membri cu acelaşi nume, referirea acestora printr-un obiect
din clasa derivată poate conduce la ambiguităţi:
pentru evitarea acestora se utilizează calificarea
completă
obiect_clasa_derivata.Nume_clasa_baza::nume_membru
Exemplu : dacă în exemplul anterior în clasa derivata nu
avem functia afis(), printr-un obiect din clasa derivată
putem apela una din metodele afis() din clasele de bază.
obiect_derivat.afis( ); // ambiguitate
…
obiect_derivat.Baza1::afis( ); //corect
30
Exemplul 2:
class CPolygon
{
protected:
int width, height;
public:
void set_values (int a, int b) {
width=a; height=b;
}
};
class COutput
{
public:
void output (float i) {
cout << i << endl;
31
}
};
class CRectangle: public CPolygon, public COutput
{
public: int area ( ) { return (width * height); }
};
int main ( ) {
CRectangle re;
CTriangle trgl;
re.set_values (4,5); // metoda mostenita din CPolygon
trgl.set_values (4,5);
re.output (re.area( )); // metoda mostenita din COutput
trgl.output (trgl.area( ));
32
cin.get();
}
Constructori şi destructori pentru clasa derivată
34
class A {
// corp clasa
};
class B : public A {
// corp clasa
};
class C : public B {
// corp clasa
};
41
Copy-constructorul în clasa derivată
42
În cazul moştenirii multiple:
ordinea în care sunt apelaţi constructorii claselor de
bază este aceeaş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
În general, ordinea operaţiilor în cazul creării obiectelor
derivate este următoarea:
se apelează constructorii claselor de bază în ordinea
precizată în declaraţia clasei derivate
se apelează constructorii altor obiecte membre din
clasa derivată, în ordinea declarării lor în clasa
derivată
se apelează constructorii clasei derivate
La distrugerea obiectelor derivate, operaţiile se
desfăşoară în ordine inversă 43
2. CLASE VIRTUALE
Considerăm următoarea situaţie:
class BB {
protected : int x;
…
};
class B1 : public BB {
// corp clasa
};
class B2 : public BB {
// corp clasa
};
class D : public B1, public B2 {
// corp clasa
};
47
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
48
Constructorul clasei derivate D 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) {…}
class Person {
private:
string ptype;
string name;
public:
Person( const string & t, const string & n ) : ptype( t ), name( n ){ }
virtual ~Person( ) { }
const string & getName( ) {
return name;}
const string getPtype( ) {
return ptype; }
};//Person class
50
class Student : virtual public Person {
private:
int hours;
public:
Student( const string& n, int h ) : Person( "Student", n ), hours(h) { }
int getCreditHours( ) {
return hours;
}
}; //Student class
int getCreditHours( ) {
return hours;
}
};
54
class Employee : virtual public Person
{
private:
int hours;
public:
Employee( const char n[], int h ) : Person( "Employee", n), hours(h)
{}
int getVacationHours( ) {
return hours;
}
};
55
class StudentEmployee : public Student, public Employee
{
public:
StudentEmployee( const char n[], int ch, int vh ) :
Person( "StudentEmployee", n ),
Student( "ignored", ch ),
Employee( "ignored", vh )
{}
};
int main( ){
StudentEmployee se( “Popescu", 120, 15 );
61
EXEMPLU:
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b) {
width=a; height=b; }
int getWidth() { return width;}
int getHeight() { return height; }
virtual float area(void) {return 0; }
};//CPolygon class
64
Când un astfel de pointer indică spre un obiect derivat ce
conţine o metodă virtuală, compilatorul C++ determină
care versiune a metodei va fi apelată, în funcţie de tipul
obiectului spre care indică acel pointer
66
4. 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
68
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b) {
width=a; height=b;
}
void main( )
{
Base *Var = new Derived( );
// alte prelucrari 73
delete Var;
}
74
Exemplul 2:
enum Color {Co_red, Co_green, Co_blue};