Operatorul dynamic_cast
este folosit pentru a converti un obiect de la o anumita adresa la un alt obiect. Obiectele trebuie sa fie instanta aceleiasi ierarhii. Mai mult, unul dintre obiecte trebuie sa fie subobiect al unuia dintre obiecte.
class Persoana
{
char nume[50];
public:
Persoana(const char* nume){strcpy(nume,nume);}
virtual char* getNume(){return nume;}
virtual ~Persoana(){}
};
class student:public Persoana
{
char matricol[20];
public:
student(const char* nume, const char* matricol):Persoana(nume){strcpy(matricol, nrm);}
char* getMatricol(){return matricol;}
};
class profesor:public Persoana
{
int vechime;
public:
profesor(const char* nume, const int v):Persoana(nume),vechime(v){}
int getVechime(){return vechime;}
};
void main()
{
int n;
cin >> n;
Persoana** pers = new Persoana*[n];
for(int i = 0; i < n; i++)
switch(rand(time(0))%3)
{
case 0: cin >> nume; pers[i] = new Persoana(nume): break;
case 1: cin >> nume >> matricol; pers[i] = new student(nume, matricol); break;
case 2: cin >> nume >> v; pers[i] = new profesor(nume, v);
}
/*
* Pentru vectorul pers, dupa ce a fost creat, dorim
* ca pentru fiecare componenta sa stim ce instantiere
* s-a facut (persoana, student sau profesor).
* Daca cunoastem acest lucru, pentru studenti si
* pentru profesori vom avea informatii suplimentare
* (numar matricol, respectiv vechime).
* In C++ nu exista un mecanism de a afla ce tip de
* informatie se afla la o anumita adresa, deci in
* exemplul nostru, pers[i] nu stim daca este instanta
* persoana, student sau profesor.
* In cazul in care o clasa in intregime sau cel putin
* o functie membra este virtuala informatii despre un
* un obiect instanta acelei clase se retin in VMT. Pe
* baza acestor informatii se poate identifica ce
* obiecte avem in memorie instanta clasei respective.
* Acest lucru se poate obtine apeland la operatorul
*
* dynamic_cast
*
*
*/
...
for (int i = 0; i < n; i++)
if(dynamic_cast<student*>(pers[i]) != nullptr)
cout << "student" << endl;
else if(dynamic_cast<profesor*>(pers[i]) != nullptr)
cout << "profesor" << endl;
else
cout << "persoana" << endl;
/*
* dynamic_cast nu functioneaza (returneaza NULL), decat
* daca in clasa Persoana avem cel putin o metoda
* virtuala sau clasa este mostenita virtual.
*/
for(int i = 0; i < n; i++)
delete pers[i];
//daca nu avem destructor virtual in Persoana avem
//memory leak
delete[] pers;
}
student *s = dynamic_cast<student*>(pers[1]);
Operatorul dynamic_cast
se foloseste ca in exemplul de mai sus. Se incearca a se converti pointerul pers[1]
la tipul student*
. Acest lucru va fi posibil numai daca pentru pers[i]
va exista si obiectul aferent instanta student (pers[i]
s-a initializat cu un apel new student
). In caz de reusita, operatorul returneaza pointerul catre obiectul student
aflat in memorie.
O functie membra unei clase poate fi declarata ca fiind pur virtuala. Evident, aceasta functie este virtuala.
class ...
{
virtual tip_returnat functieMembra (param) = 0;
}
O functie pur virtuala se recunoaste din faptul ca, dupa antetul ei, declarat virtual, apare specificatia = 0;
. O functie pur virtuala nu se implementeaza. O clasa care contine cel putin o functie pur virtuala devine clasa abstracta. O clasa abstracta nu poate fi instantiata. Clasele derivate dintr-o clasa abstracta, daca nu implementeaza toate functiile pur virtuale devin la randul lor clase abstracte. In Java trebuie scris abstract
.
O clasa poate fi instantiata daca nu are functii pur virtuale si a implementat toate functiile pur virtuale mostenite, dintr-o eventuala clasa abstracta (mostenire directa).
O clasa care contine numai functii pur virtuale (ca metode) devine interfata.
O clasa abstracta, de obicei, descrie o ierarhie, trasand specificul acelei ierarhii. O clasa poate intra in ierarhia respectiva numai daca implementeaza toate metodele (specifice ierarhiei) clasei abstracte.
De exemplu: ierarhie figura geometrica. O clasa poate fi introdusa in aceasta ierarhie numai daca are metode pentru arie si perimetru. Cu alte cuvinte, oricine are arie si perimetru este figura geometrica. Ierarhia o deschidem cu o clasa abstracta avand cele doua metode pur virtuale.
class FigGeom
{
char denumire[50];
public:
void setDen(char* den){strcpy(denumire, den);}
virtual float arie() = 0;
virtual float perimetru() = 0;
};
class Dreptunghi:public FigGeom
{
float x1, y1, x2, y2;
public:
Dreptunghi(float X1, float Y1, float X2, float Y2)
{
setDen("Dreptunghi");
x1 = X1;
y1 = Y1;
x2 = X2;
y2 = Y2;
}
float arie(){return fabs((x2-x1)*(y2-y1));}
float perimetru(){return (fabs(x2-x1)+fabs(y2-y1))+2.f;}
};
TPA: Sa se implementeze ierarhia FigGeom din imaginea urmatoare:
Pentru fiecare trebuie sa implementati arie si perimetru. Pornind de la ierarhia de mai sus putem oricand creea oricand un vector de figuri geometrice care contine obiecte (pointeri catre) instanta claselor derivate direct sau indirect din FigGeom.