Sunteți pe pagina 1din 24

MODULUL 4

Polimorfism

Obiective

• Definirea notiunii de polimorfism

• Întelegerea mecanismului de polimorfism

• Definirea functiilor virtuale

• Definirea claselor abstracte

Termeni cheie

Functii virtuale Polimorfism


Legare staticã Legare dinamicã
Clase abstracte Functii virtuale pure

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
106 M. Oprea, Programare orientatã pe obiecte – curs IFR

LECTIA 6

Functii virtuale si polimorfism

În limbajele de programare, un obiect polimorfic este o entitate,


ca de exemplu, o variabilã sau argumentul unei functii, cãreia i
se permite sã pãstreze valori de tipuri diferite în timpul executiei
programului. Functiile polimorfice sunt acele functii care au
argumente polimorfice. În limbajele de programare orientate pe
obiecte, polimorfismul împreunã cu legarea dinamicã reprezintã
una din caracteristicile extrem de utile care conduc la cresterea
calitãtii programelor.

Considerãm un numãr de n obiecte ob1, ob2, …, obn care


rãspund la un mesaj m, fiecare obiect cu o altã functie. Fie x o
variabilã care este legatã dinamic la unul din cele n obiecte.
Trimiterea mesajului m la obiectul legat la variabila x va avea
efecte diferite în functie de obiectul care a fost legat dinamic (la
momentul executiei). În figura 4.1 este prezentatã schematic
notiunea de polimorfism. Limbajele de programare clasice
implementeazã un astfel de comportament cu ajutorul
instructiunii de selectie, care în functie de valoarea variabilei x
apeleazã o anumitã procedurã sau functie.

Ob1
m

m
x Ob2

m .
.
.

Obn

Fig. 4.2 Reprezentare schematicã a no þiunii de polimorfism.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 107

Legare staticã si legare dinamicã

Notiunea de legare (binding) din programare se referã la


procesul prin care un nume sau o expresie este asociatã unui
atribut, cum ar fi o variabilã si tipul valorii pe care îl poate
contine variabila. Existã douã tipuri de legãri, legare timpurie
care are loc la momentul compilãrii si legare târzie care are loc
la momentul executiei.

Definitie: Dacã tipul T al unei variabile este asociat în mod


explicit numelui sãu N printr-o declaratie, spunem cã N este
legat static la T. Procesul de asociere are loc la momentul
compilãrii si se numeste legare staticã sau legare timpurie
(early binding).

A Observatie

• Legarea timpurie permite rezolvarea apelurilor de functii la


momentul compilãrii, avantajul fiind apeluri rapide, iar
dezavantajul, flexibilitatea foarte redusã.

Definitie: Dacã tipul T al unei variabile cu numele N este în


mod implicit asociat de continutul sãu, spunem cã N este legat
dinamic la T. Procesul de asociere are loc la momentul
executiei si se numeste legare dinamicã sau legare târzie (late
binding).

Legarea dinamicã este strâns legatã de notiunea de polimorfism,


ea determinând functionarea comportamentului polimorfic.

A Observatie

• Legarea târzie permite luarea în considerare a evenimentelor


din timpul executiei programului asigurându-se o flexibilitate
mãritã, dezavantajul fiind apeluri mai lente ale functiilor.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
108 M. Oprea, Programare orientatã pe obiecte – curs IFR

Functii virtuale

Implementarea obiectelor polimorfice se realizeazã prin


intermediul functiilor virtuale.

Definitie: Functiile membru ale unei clase pentru care se


realizeazã legarea dinamicã se numesc functii virtuale si se
declarã cu ajutorul cuvântului cheie virtual.

Sintaxa declarãrii unei functii virtuale:

virtual <tip_functie> <nume_functie> ([<lp>]);

<tip_functie> reprezintã tipul întors de functie, <lp> este lista de


parametri ai functiei.

Declararea unei functii membru a unei clase drept functie


virtualã schimbã modul în care compilatorul va determina apelul
ei. Când se mosteneste o clasã care contine o functie virtualã,
clasa derivatã redefineste functia virtualã a clasei de bazã.
Functia virtualã din interiorul clasei de bazã defineste forma
interfetei cu acea functie, iar fiecare redefinire a ei în clasa
derivatã implementeazã operatiile ei, specifice clasei derivate
(astfel, redefinirea creeazã o metodã specificã). Când o functie
virtualã este modificatã într-o clasã derivatã, nu este necesarã
utilizarea cuvântului cheie virtual.

Când un pointer al clasei de bazã puncteazã la o functie virtualã


din clasa derivatã si aceasta este apelatã prin intermediul acestui
pointer, compilatorul determinã care versiune a functiei trebuie
apelatã, tinând cont de tipul obiectului la care puncteazã acel
pointer. Astfel, tipul obiectului la care puncteazã determinã
versiunea functiei virtuale care va fi executatã.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 109

A Observatii

• Constructorii nu pot fi functii virtuale. În schimb, destructorii


pot fi functii virtuale.

• Functiile inline nu pot fi virtuale.

• Functiile virtuale sunt întotdeauna functii membru nestatice


ale unei clase.

• Pentru o functie declaratã virtualã într-o clasã B, orice


redefinire cu acelasi prototip în întreaga ierarhie de clase
derivate din B este supusã legãrii dinamice.

Programul P4.1 defineste o clasã genericã Forma2D, carac-


terizatã prin cele douã dimensiuni ale unei forme 2D, dim1 si
dim2. Functia aria() calculeazã aria unei forme 2D si ea este
virtualã (nerealizând ceva concret în clasa de bazã Forma2D,
doar afisarea unui mesaj si întoarcerea valorii 0.0), urmând a fi
redefinitã în clasele derivate Dreptunghi si Triunghi.

// fisierul sursa p4_1.cpp

#include <iostream.h>

class Forma2D {
double dim1, dim2;
public:
void initializare(double a1, double a2)
{
dim1 = a1; dim2 = a2;
}
virtual double aria()
{
cout<<"\n Functie care trebuie redefinita";
return 0.0;
}
void preiaDim(double &d1, double &d2)
{
d1 = dim1; d2 = dim2;
}
};

Programul P4.1 (1/2)

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
110 M. Oprea, Programare orientatã pe obiecte – curs IFR

class Dreptunghi : public Forma2D {


public:
double aria()
{
double x1, x2;
preiaDim(x1, x2);
return x1*x2;
}
};

class Triunghi : public Forma2D {


public:
double aria()
{
double x1, x2;
preiaDim(x1, x2);
return 0.5*x1*x2;
}
};

void main()
{
Forma2D *ob1;
Dreptunghi ob2;
Triunghi ob3;

ob2.initializare(2.8, 1.5);
ob3.initializare(3.2, 5.2);
ob1 = &ob2;
cout << "\n Aria dreptunghiului = " << ob1->aria();
ob1 = &ob3;
cout << "\n Aria triunghiului = " << ob1->aria();

Programul P4.1 (2/2)

Redefinirea functiei virtuale aria() în clasele derivate întoarce


aria tipului de formã 2D definitã în clasa derivatã. În programul
P4.1 se calculeazã aria unui dreptunghi si aria unui triunghi.

În continuare, discutãm despre functii virtuale pure, care sunt


doar declarate în clasa de bazã, ele urmând a fi obligatoriu
definite în clasele derivate.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 111

Clase abstracte

Generarea unei ierarhii de clase poate începe cu definirea unui


tip generic de clasã numit clasã abstractã. Întrucât o clasã
abstractã trebuie sã continã cel putin o functie virtualã purã, vom
defini mai întâi acest tip de functie.

Definitie: O functie virtualã purã numitã si functie purã este


o functie dintr-o clasã de bazã pentru care nu este necesarã
definitia, ci doar prototipul, urmând ca definitia sã fie datã în
clasele derivate.

Sintaxa declarãrii unei functii virtuale pure:

virtual <tip_functie> <nume_functie>([<lp>]) = 0;

Exemplu:

virtual double f() = 0;

A Observatie

• O functie virtualã purã este initializatã în mod obligatoriu cu


valoarea 0.

Definitie: O clasã A este clasã abstractã dacã este utilizatã


doar ca o superclasã (clasã de bazã) pentru alte clase. Clasa A
specificã doar proprietãtile si nu este utilizatã pentru a crea
obiecte. Clasele derivate din A trebuie sã defineascã proprie-
tãtile lui A.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
112 M. Oprea, Programare orientatã pe obiecte – curs IFR

O clasã care contine functii virtuale pure se numeste clasã


abstractã. Întrucât o clasã abstractã este incompletã, ea
continând cel putin o functie virtualã purã, nu se pot crea obiecte
din acea clasã. Utilitatea claselor abstracte este datã de operatia
de derivare de noi clase permitând astfel generarea unei ierarhii
de clase.

Clasele din care se pot crea obiecte se numesc clase concrete.


De exemplu, clasele Cerc, Dreptunghi, Patrat din secventa de
program prezentatã în figura 4.2 sunt clase concrete. Clasa
ObiectGrafic este clasã abstractã.

Programul P4.2 este programul P4.1 în care clasa Forma2D este


o clasã abstractã, întrucât functia aria() este declaratã drept
functie virtualã purã.

// fisierul sursa p4_2.cpp versiunea functie virtuala pura

#include <iostream.h>

// clasa abstracta
class Forma2D {
double dim1, dim2;
public:
void initializare(double a1, double a2)
{
dim1 = a1; dim2 = a2;
}

// functie virtuala pura


virtual double aria() = 0;

void preiaDim(double &d1, double &d2)


{
d1 = dim1; d2 = dim2;
}
};

class Dreptunghi : public Forma2D {


public:
double aria()
{
double x1, x2;
preiaDim(x1, x2);
return x1*x2;
}
};

Programul P4.2 (1/2)

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 113

class Triunghi : public Forma2D {


public:
double aria()
{
double x1, x2;
preiaDim(x1, x2);
return 0.5*x1*x2;
}
};

void main()
{
Forma2D *ob1;
Dreptunghi ob2;
Triunghi ob3;

ob2.initializare(2.8, 1.5);
ob3.initializare(3.2, 5.2);
ob1 = &ob2;
cout << "\n Aria dreptunghiului = " << ob1->aria();
ob1 = &ob3;
cout << "\n Aria triunghiului = " << ob1->aria();
}

Programul P4.2 (2/2)

A Observatie

• O clasã abstractã defineste o interfatã pentru diferiti membrii


ai unei ierarhii de clase. Toate functiile din ierarhia de clase
pot utiliza aceeasi interfatã prin proprietatea numitã
polimorfism.

Sintaxa definirii unei clase abstracte:

class <nume_clasã_abstractã> {

// …
public:
//…
virtual <tip_functie> <nume_functie> ([<lp>]) = 0;
//…
};

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
114 M. Oprea, Programare orientatã pe obiecte – curs IFR

Polimorfism

Polimorfismul permite unei entitãti (de exemplu, variabilã,


functie, obiect) sã aibã o varietate de reprezentãri. El este
furnizat atât la momentul compilãrii (legare timpurie), prin
folosirea operatorilor si a functiilor redefinite, cât si la
momentul executiei (legare târzie), prin utilizarea functiilor
virtuale.

Definitie (Polimorfism versiunea 1): Conceptul de legare


dinamicã permite unei variabile sã aibã tipuri diferite în functie
de continutul ei la un moment dat. Aceastã abilitate a variabilei
se numeste polimorfism, iar variabila se numeste variabilã
polimorficã.

În limbajul C++ variabilele polimorfice apar doar prin utilizarea


pointerilor sau referintelor. În cazul în care un pointer al clasei
de bazã puncteazã cãtre o functie virtualã, programul va
determina la momentul executiei la care tip de obiect puncteazã
pointerul si apoi va selecta versiunea corespunzãtoare functiei
redefinite.

Prezentãm un exemplu de utilizare a variabilelor polimorfice.


Programul P4.3 defineste douã clase: A1, clasã de bazã si A2
clasã derivatã din A1. Clasa A1 defineste o metodã virtualã
valoare() care întoarce valoarea 1. Aceeasi metodã este înlocuitã
în clasa A2 de o metodã care întoarce valoarea 2. În program
sunt definite trei functii AtribuireDirecta(), AtribuirePointer(),
AtribuireReferinta(), care preiau ca argument o valoare de tip
A1 pe care o transferã prin valoare, prin pointer, respectiv, prin
referintã. În cazul în care aceste functii sunt executate asupra
unui argument de tip A2, acesta va fi convertit într-o valoare de
tip A1 si rezultatul întors va fi 1. Functiile AtribuirePointer si
AtribuireReferinta definesc argumente polimorfice. În ambele
cazuri, valoarea transferatã va retine tipul ei dinamic si va afisa
valoarea corespunzãtoare clasei obiectului dat ca parametru.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 115

// fisierul sursa p4_3.cpp

#include <iostream.h>

class A1 {
public:
// defineste o functie virtuala
virtual int valoare()
{ return 1; }
};

class A2 : public A1 {
public:
// redefineste functia virtuala din clasa A1
virtual int valoare()
{ return 2; }
};

// obiect referit direct, prin nume


void AtribuireDirecta(A1 a)
{
cout<<"\n Atribuire directa - valoare = " << a.valoare();
}

// obiect referit prin pointer


void AtribuirePointer(A1 *a)
{
cout<<"\n Atribuire pointer - valoare = " << a->valoare();
}

// obiect referit prin referinta


void AtribuireReferinta(A1& a)
{
cout<<"\n Atribuire referinta - valoare = " << a.valoare();
}

void main()
{
A1 ob1;
A1 *ptr=&ob1;
A2 ob2;

cout << "\n Atribuire directa - obiectul 1:";


AtribuireDirecta(ob1);

cout << "\n Atribuire directa - obiectul 2:";


// se va afisa valoarea corespunzatoare clasei A1 si nu A2
AtribuireDirecta(ob2);

cout << "\n Obiect 1:";


AtribuirePointer(ptr);
AtribuireReferinta(ob1);

cout << "\n Obiect 2:";


AtribuireReferinta(ob2);
}
Programul P4.3

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
116 M. Oprea, Programare orientatã pe obiecte – curs IFR

Definitie (Polimorfism versiunea 2): Dacã o functie (sau


metodã) este definitã prin combinatia

• Nume
• Lista cu tipurile parametrilor

discutãm despre polimorfism. Acest tip de polimorfism ne


permite sã reutilizãm acelasi nume pentru functii (sau metode)
atâta timp cât lista parametrilor diferã. Uneori, el se numeste
supraîncãrcare (overloading).

Polimorfismul de tip supraîncãrcare permite unui obiect sã


aleagã metodele corecte.

Definitie (Polimorfism versiunea 3): Obiectele unei superclase


pot fi compuse din obiecte ale subclaselor corespunzãtoare.
Metodele subclaselor pot fi definite pentru a fi evaluate în douã
contexte:

• Pe baza tipului obiectului, conducând la o evaluare din


domeniul superclasei.
• Pe baza continutului obiectului, conducând la o evaluare din
domeniul subclasei continute.

Al doilea mod de evaluare, pe baza continutului obiectului, se


numeste polimorfism.

Unii autori denumesc polimorfism pur cazul în care o functie


poate fi utilizatã cu o varietate de argumente si supraîncãrcare
cazul în care existã mai multe functii definite, toate având
acelasi nume.

Sintetizând cele trei definitii prezentate, putem spune cã în cazul


programãrii orientate pe obiecte polimorfismul apare atunci
când o multime de clase distincte partajeazã o interfatã comunã,
ele fiind derivate din aceeasi clasã de bazã. Întrucât clasele deri-
vate sunt distincte, implementãrile lor pot diferi. De exemplu, o
functie mostenitã poate fi redefinitã, astfel cã la un apel al

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 117

functiei (care are acelasi nume în toate clasele derivate din


aceeasi clasã) se va executa corpul functiei corespunzãtor clasei
de care apartine obiectul care invocã apelul. Astfel, aceeasi
functie are comportament diferit în conformitate cu contextul
apelului.

Considerãm un program pentru crearea unor desene simple.


Presupunem cã programul furnizeazã o multime de obiecte
grafice primitive cum ar fi, cercuri, dreptunghiuri si pãtrate, iar
utilizatorul programului selecteazã obiectele dorite si apoi
apeleazã comenzile pentru desenare. În figura 4.2 este
prezentatã o secventã de cod din acest program. Functia
Deseneaza() este polimorficã.

// fisierul sursa p4_4.cpp

class Punct
{
int x, y;
public:
Punct(int, int);
//...
};

class ObiectGrafic
{
protected:
Punct centru;
ObiectGrafic(Punct const& a):
centru(a) {}
public:
virtual ~ObiectGrafic();
virtual void Deseneaza() const=0;
};

class Cerc:public ObiectGrafic


{
int raza;
public:
Cerc(Punct const& a, int r):
ObiectGrafic(a), raza(r) {}
void Deseneaza();
};

class Dreptunghi:public ObiectGrafic


{
int lung, lat;
public:
Dreptunghi(Punct const& a, int lg, int lt):
ObiectGrafic(a), lung(lg), lat(lt) {}
void Deseneaza();
};

Fig. 4.2 Secventã de cod (1/2).

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
118 M. Oprea, Programare orientatã pe obiecte – curs IFR

class Patrat:public Dreptunghi


{
public:
Patrat(Punct const& a, int lt):
Dreptunghi(a,lt,lt) {}
};

void main()
{
//...

Cerc c(Punct(0,0),3);
c.Deseneaza();

//...
}

Fig. 4.2 Secventã de cod (2/2).

Prezentãm un alt exemplu de implementare si utilizare a


polimorfismului. Programul P4.4 defineste clasa de bazã
Persoana si douã clase derivate, Student si Salariat. Clasa de
bazã Persoana este o clasã abstractã având declaratã o functie
virtualã purã, venit(), definitã în clasele derivate. De asemenea,
clasa Persoana mai contine o altã functie virtualã, afisare(),
care este redefinitã în clasele derivate. În programul principal
sunt create douã obiecte S1 si T1 din clasele Student si
respectiv Salariat. Pentru fiecare din cele douã obiecte se
executã o secventã de patru instructiuni: primele douã
instructiuni ilustreazã legarea staticã, prin apelul celor douã
functii afisare() si venit(), corespunzãtoare obiectului referit prin
nume; ultimele douã instructiuni ilustreazã legarea dinamicã
apelând cele douã functii afisare() si venit() prin intermediul a
douã functii, Ref_Pointer(.), Ref_Referinta(.), care utilizeazã un
pointer, respectiv o referintã cãtre clasa de bazã Persoana.
Aceste ultime douã instructiuni genereazã un comportament
polimorfic, la momentul executiei programului.

// fisierul sursa p4_4.cpp

#include <iostream.h>
#include <string.h>
#include <assert.h>

Programul P4.4 (1/4)

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 119

// clasa de baza Persoana, clasa abstracta


class Persoana {
char* prenume;
char* nume;
public:
Persoana(char*, char*);
~Persoana();
char* preiaPrenume();
char* preiaNume();

// functie virtuala pura


virtual double venit() = 0;

virtual void afisare();


};

Persoana::Persoana(char* P, char* N)
{
prenume = new char[strlen(P)+1];
assert(prenume!=0);
strcpy(prenume, P);

nume = new char[strlen(N)+1];


assert(nume!=0);
strcpy(nume, N);
}

Persoana::~Persoana()
{
delete prenume;
delete nume;
}

char* Persoana::preiaPrenume()
{
return prenume;
}

char* Persoana::preiaNume()
{
return nume;
}

void Persoana::afisare()
{
cout << prenume << " " << nume << "\n";
}

// definim clasa Student derivata din clasa Persoana


class Student : public Persoana {
double bursa;
double media;
public:
Student(char*, char*, double = 0.0, double = 0.0);
void seteazaBursa(double);
void seteazaMedia(double);
virtual double venit();
virtual void afisare();
};
Programul P4.4 (2/4)

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
120 M. Oprea, Programare orientatã pe obiecte – curs IFR

Student::Student(char* P, char* N, double B, double M)


:Persoana(P,N)
{
M>=8.50?seteazaBursa(B):seteazaBursa(0.0);
seteazaMedia(M);
}

void Student::seteazaBursa(double B)
{
bursa = B>0?B:0;
}

void Student::seteazaMedia(double M)
{
media = M>0?M:0.0;
}

double Student::venit()
{
return bursa;
}

void Student::afisare()
{
cout << "\n Student:";
Persoana::afisare();
cout << "\t Media = " << media << "\n";
}

// definim clasa Salariat derivata din clasa Persoana


class Salariat:public Persoana {
double salariu;
double venit_ora;
int nr_ore;
public:
Salariat(char*, char*, double = 0.0, double = 0.0, int = 0);
void seteazaSalariu(double);
void seteazaVenitOra(double);
void seteazaNrOre(int);
virtual double venit();
virtual void afisare();
};

Salariat::Salariat(char* P,char* N,double S,double V,int nr)


:Persoana(P, N)
{
seteazaSalariu(S);
seteazaVenitOra(V);
seteazaNrOre(nr);
}

void Salariat::seteazaSalariu(double S)
{
salariu = S>0 ? S : 0;
}

Programul P4.4 (3/4)

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 121

void Salariat::seteazaVenitOra(double V)
{
venit_ora = V>0.0 ? V : 0.0;
}

void Salariat::seteazaNrOre(int nr)


{
nr_ore = nr>0 ? nr : 0;
}

double Salariat::venit()
{
return salariu + nr_ore*venit_ora;
}

void Salariat::afisare()
{
cout << "\n Salariat:";
Persoana::afisare();
}

// functie care apeleaza functiile virtuale prin legare


// dinamica, in cazul unui pointer al clasei de baza
// referire prin pointer
void Ref_Pointer(Persoana *Ptr)
{
Ptr->afisare();
cout << " venit (lei) " << Ptr->venit();
}

// functie care apeleaza functiile virtuale prin legare


// dinamica, in cazul unei referinte la clasa de baza –
// referire prin referinta
void Ref_Referinta(Persoana &Ptr)
{
Ptr.afisare();
cout << " venit (lei) " << Ptr.venit();
}

void main()
{
Student S1("Alexandra", "Stoica", 1500000, 10);
cout << "\n Legare statica:\n";
S1.afisare();
cout << " venit (lei) "<<S1.venit();
cout << "\n Legare dinamica:\n";
Ref_Pointer(&S1);
Ref_Referinta(S1);

Salariat T1("Silvan", "Manole", 50000000, 100000, 30);


cout << "\n Legare statica:\n";
T1.afisare();
cout<<" venit (lei) "<<T1.venit();
cout << "\n Legare dinamica: \n";
Ref_Pointer(&T1);
Ref_Referinta(T1);
}
Programul P4.4 (4/4)

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
122 M. Oprea, Programare orientatã pe obiecte – curs IFR

A Observatii

• Principiul care stã la baza polimorfismului este “o singurã


interfatã, metode multiple”. Practic, polimorfismul
reprezintã abilitatea obiectelor din clase diferite ale unei
ierarhii de clase de a rãspunde diferit la acelasi mesaj (adicã,
la apelul unei functii membru).

• Implementarea polimorfismului este realizatã prin


intermediul functiilor virtuale.

• În cazul în care o functie membru ne-virtualã este definitã


într-o clasã de bazã si redefinitã într-o clasã derivatã,
comportamentul este ne-polimorfic. Astfel, dacã functia
membru este apelatã printr-un pointer al clasei de bazã la
obiectul clasei derivate, se utilizeazã versiunea clasei de
bazã. Dacã functia membru este apelatã printr-un pointer al
clasei derivate, se utilizeazã versiunea clasei derivate.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 123

Rezumat

• În limbajele de programare, un obiect polimorfic este o


entitate, ca de exemplu, o variabilã sau argumentul unei
functii, cãreia i se permite sã pãstreze valori de tipuri diferite
în timpul executiei programului.

• Functiile polimorfice sunt acele functii care au argumente


polimorfice.

• Notiunea de legare (binding) din programare se referã la


procesul prin care un nume sau o expresie este asociatã unui
atribut, cum ar fi o variabilã si tipul valorii pe care îl poate
contine variabila. Legarea staticã (legarea timpurie) are loc la
momentul compilãrii, iar legarea dinamicã (legarea târzie)
are loc la momentul executiei.

• În limbajele de programare orientate pe obiecte,


polimorfismul împreunã cu legarea dinamicã reprezintã una
din caracteristicile extrem de utile care conduc la cresterea
calitãtii programelor.

• Functiile membru ale unei clase pentru care se realizeazã


legarea dinamicã se numesc functii virtuale si se declarã cu
ajutorul cuvântului cheie virtual.

• Constructorii nu pot fi functii virtuale. În schimb, destructorii


pot fi functii virtuale.

• O functie virtualã purã numitã si functie purã este o


functie dintr-o clasã de bazã pentru care nu este necesarã
definitia, ci doar prototipul, urmând ca definitia sã fie datã în
clasele derivate. O functie virtualã purã este initializatã în
mod obligatoriu cu valoarea 0.

• O clasã A este clasã abstractã dacã este utilizatã doar ca o


superclasã (clasã de bazã) pentru alte clase. Clasa A specificã
proprietãtile si nu este utilizatã pentru a crea obiecte. Clasele
derivate din A trebuie sã defineascã proprietãtile lui A.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
124 M. Oprea, Programare orientatã pe obiecte – curs IFR

• O clasã care contine functii virtuale pure se numeste clasã


abstractã.

• Clasele din care se pot crea obiecte se numesc clase


concrete.

• O clasã abstractã defineste o interfatã pentru diferiti membrii


ai unei ierarhii de clase. Toate functiile din ierarhia de clase
pot utiliza aceeasi interfatã prin proprietatea numitã
polimorfism.

• Polimorfismul permite unei entitãti (de exemplu, variabilã,


functie, obiect) sã aibã o varietate de reprezentãri. El este
furnizat atât la momentul compilãrii (legare timpurie), prin
folosirea operatorilor si a functiilor redefinite, cât si la
momentul executiei (legare târzie), prin utilizarea functiilor
virtuale.

• Conceptul de legare dinamicã permite unei variabile sã aibã


tipuri diferite în functie de continutul ei la un moment dat.
Aceastã abilitate a variabilei se numeste polimorfism, iar
variabila se numeste variabilã polimorficã.

• În limbajul C++ variabilele polimorfice apar doar prin


utilizarea pointerilor sau referintelor. În cazul în care un
pointer al clasei de bazã puncteazã cãtre o functie virtualã,
programul va determina la momentul executiei la care tip de
obiect puncteazã pointerul si apoi va selecta versiunea
corespunzãtoare functiei redefinite.

• Dacã o functie (sau metodã) este definitã prin combinatia


nume si lista cu tipurile parametrilor discutãm despre
polimorfism. Acest tip de polimorfism ne permite sã
reutilizãm acelasi nume pentru functii (sau metode) atâta
timp cât lista parametrilor diferã. Uneori, acest tip de
polimorfism se numeste supraîncãrcare (overloading).

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 125

• Obiectele unei superclase pot fi compuse din obiecte ale


subclaselor corespunzãtoare. Metodele subclaselor pot fi
definite pentru a fi evaluate în douã contexte: (a) pe baza
tipului obiectului, conducând la o evaluare din domeniul
superclasei; (b) pe baza continutului obiectului, conducând la
o evaluare din domeniul subclasei continute. Al doilea mod
de evaluare, pe baza continutului obiectului, se numeste
polimorfism.

• Unii autori denumesc polimorfism pur cazul în care o


functie poate fi utilizatã cu o varietate de argumente si
supraîncãrcare cazul în care existã mai multe functii
definite, toate având acelasi nume.

• În cazul în care o functie membru ne-virtualã este definitã


într-o clasã de bazã si redefinitã într-o clasã derivatã,
comportamentul este ne-polimorfic.

• Principiul care stã la baza polimorfismului este “o singurã


interfatã, metode multiple”. Practic, polimorfismul repre-
zintã abilitatea obiectelor din clase diferite ale unei ierarhii
de clase de a rãspunde diferit la acelasi mesaj.

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
126 M. Oprea, Programare orientatã pe obiecte – curs IFR

Notiuni fundamentale

Functii virtuale
Polimorfism

Legare staticã, legare timpurie

Legare dinamicã, legare târzie

Functii virtuale pure

Clase abstracte

Polimorfism pur

Supraîncãrcare

Variabile polimorfice

Obiecte polimorfice

Functii polimorfice

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
Modulul 4 - Polimorfism 127

Teste de autocontrol

4.1 Utilizarea mostenirii si a polimorfismului permite eliminarea


unei anumite instructiuni. Care este aceastã instructiune în
limbajul C++?

4.2 Cum este specificatã o functie virtualã purã?

4.3 Cum se numeste o clasã care contine una sau mai multe
functii virtuale pure?

4.4 Dacã apelul unei functii este rezolvat la momentul executiei


legarea este

(a) staticã
(b) timpurie
(c) nulã
(d) dinamicã

4.5 Care dintre afirmatiile urmãtoare sunt adevãrate?

(a) Constructorii pot fi functii virtuale.


(b) Destructorul poate fi functie virtualã.
(c) Orice functie membru staticã este functie virtualã.
(d) Functiile inline nu pot fi functii virtuale.

4.6 Care este diferenta între o functie virtualã si o functie


virtualã purã?

4.7 Ce se întelege prin polimorfism pur? Comparati cu notiunea


de supraîncãrcare.

4.8 Cum pot fi definite variabilele polimorfice în limbajul C++?

4.9 Explicati pe scurt notiunea de polimorfism în cazul


programãrii orientate pe obiecte.

4.10 Care este rolul claselor abstracte?

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -
128 M. Oprea, Programare orientatã pe obiecte – curs IFR

Exercitii

T4.1 Explicati comportamentul polimorfic al functiilor afisare()


si venit() din programul P4.5.

T4.2 Scrieti un program care defineste clasa de bazã Forma3D


si clasele derivate Paralelipiped si Sfera. Declarati în clasa
Forma3D o functie virtualã purã Volum() pe care o definiti în
clasele derivate. Testati comportamentul polimorfic al functiei
Volum() pentru douã obiecte create, Ob1 si Ob2 de tipul clase-
lor derivate Paralelipiped si Sfera. Se va utiliza drept exemplu
programul P4.5.

T4.3 Explicati comportamentul ne-polimorfic si scrieti un


program în limbajul C++ care sã ilustreze un exemplu de
comportament de acest tip.

T4.4 Explicati notiunile de legare staticã si legare dinamicã.


Care sunt avantajele si dezavantajele lor principale?

T4.5 Care este utilitatea functiilor virtuale pure?

 Mihaela M. Oprea, Programare orientatã pe obiecte


- curs pentru învãtãmântul cu frecventã redusã -

S-ar putea să vă placă și