Professional Documents
Culture Documents
Obiective:
Prezentarea conceptului OOP de mostenire
Derivarea claselor ȋn C++
Vizibilitatea membrilor ȋn clasele derivate.
Drepturi de acces
1
Mihai TOGAN
Ne propunem un exemplu de aplicaţie pentru gestionarea unor studenţi. Fiecare student are
un nume, o colecţie de note, medii, etc.
/*****************************************************************************/
class Student
{
int m_Id;
char *m_Nume;
int m_Note[100]; /* lista de note (prima valoare 0 => finalul listei) */
public:
Student (int id, char *nume, int note[]);
Student (const char *stdinfo); /* init std pe baza unui sir formatat */
/*****************************************************************************/
Student::Student (int id, char *nume, int note[]) : m_Id(id)
{
this->setNume (nume);
int step = 0;
char *p = strtok (linfo, ",");
while (p != NULL)
{
switch (step) {
case 0:
m_Id = atoi (p); break;
case 1:
this->setNume (p); break;
default:
this->addNota (atoi(p));
};
if (nume == NULL)
return;
if (m_Nume != NULL)
delete[] m_Nume;
float Student::getMedie () {
int i;
float s = 0;
for (i = 0; i < sizeof(m_Note) / sizeof(int) && m_Note[i] != 0; i++)
s = s + m_Note[i];
void Student::print () {
std::cout << "id: " << m_Id;
std::cout << "\nnume: " << m_Nume;
std::cout.precision (2);
std::cout << "\nmedie: " << std::fixed << this->getMedie() << std::endl;
}
int i = 0;
while (i < sizeof(m_Note)/sizeof(int) && m_Note[i] != 0) i++;
/*****************************************************************************/
void main ()
{
/* Instantiem un std cu id=101, nume=Ionescu Vasile, notele 8,9,5,... */
Student S1 ("101,Ionescu Vasile,8,9,5,10,8,9");
S1.print();
3
Mihai TOGAN
Putem rafina puţin problema anterioară. De exemplu, ȋn universitatea ATM există studenţi la
buget (studenţi militari) și studenţi cu taxa (studenţi civili). Ei au anumite caracteristici
comune, cum ar fi informaţiile gestionate de clasa Student, dar și caracteristi diferite, astfel:
studenţii de la buget pot avea un grad militar, şi/sau alte informatii specifice.
studenţii de la taxă pot avea o taxă platită până acum, şi/sau alte informatii specifice.
Dacă ne propunem să gestionăm ambele categorii de studenţi (buget şi taxă), putem aborda
următoarele variante de implementare:
V1. Crearea a două clase total diferite (StudentBuget și StudentTaxa) care să gestioneze
cele două categorii diferite de studenţi.
Avantajul: există două clase diferite care gestionează cele două entitați diferite (studentul
aflat la taxă, respectiv studentul la buget).
Dezavantajul: duplicarea codului. Aproximativ 80-90 % din codul sursă specific celor două
clase este identic.
4
Mihai TOGAN
V2. Adăugarea la nivelul claselor Student propuse mai sus a tuturor informaţiilor specifice
(extra Student), cumulate pentru ambele categorii de studenţi, precum și un tip (membru
ȋn clasa Student) care sa menţioneze tipul studentului: BUGET sau TAXĂ.
class StudentAny
{
typedef enum {
STD_BUGET, STD_TAXA } t_STDTYPE;
typedef enum {
STD_FR, STD_CAP, STD_SG, STD_SGMAJ } t_GRAD;
int m_Id;
char* m_Nume;
int m_Note[100];
t_STDTYPE m_Tip;
t_GRAD m_Grad;
int m_TaxeAchitate[20];
public:
StudentAny (int id, char *nume, int note[],
t_STDTYPE tip, t_GRAD grad, int taxe[]);
5
Mihai TOGAN
V3. Utilizarea mecanismului OOP de moştenire (derivarea claselor). Din clasa Student se
vor moşteni (deriva) două clase specializate: una specializată pentru studentul de la buget,
şi cealaltă specializată pe studentul la taxă.
class Student
{
int m_Id;
char* m_Nume;
int m_Note[100];
public:
Student (int id, char *nume, int note[]);
Student (const char *stdinfo);
typedef enum {
STD_FR,STD_CAP,STD_SG,STD_SGMAJ}
t_GRAD;
class StudentTaxa: public Student
class StudentBuget : public Student {
{ int m_TaxeAchitate[20];
t_GRAD m_Grad;
public:
public: StudentTaxa(int id, char *nume,
StudentBuget(int id, char *nume, int note[], int
int note[], t_GRAD grad); taxe[]);
StudentBuget(const char *stdinfo); StudentTaxa(const char *stdinfo);
Observaţii:
Această soluţie este de fapt o combinaţie între cele două versiuni de mai sus. Codul
comun necesar există o singură dată în clasa Student, iar mai departe avem două clase
diferite StudentBuget şi respectiv StudentTaxa, specifice pentru cele două entităţi diferite.
Deşi la prima vedere, mărim numărul de clase ȋn cadul programului, rezultatul obţinut
este însă mult mai eficient:
o distingem clar entităţile (fiecare clasă specializată se ocupă de entitatea ei) –
avantajul variantei V1 prezentată anterior.
o nu duplicăm codul – avantajul variantei V2 prezentată anterior.
6
Mihai TOGAN
Câteva elemente privind moştenirea claselor:
7
Mihai TOGAN
void main ()
{
Student S ("101,Ionescu Vasile,8,9,5,10,8,9");
StudentBuget SB ("102,Popescu Ion,7,9,5,10,8,9,10,4");
StudentTaxa ST ("103,Vasilescu Bogdan,8,9,10,4");
S.print();
SB.print();
ST.print();
8
Mihai TOGAN
Observaţie: putem modifica constructorii de mai sus, astfel încât informaţiile specifice să fie
„preluate” tot din stringul stdinfo.
Pentru a fi corecţi, la nivelul claselor derivate suprascriem metoda print ( ):
class StudentBuget : public Student
{
public:
typedef enum {
STD_FR,STD_CAP,STD_SG,STD_SGMAJ } t_GRAD;
private:
t_GRAD m_Grad;
public:
StudentBuget (int id, char *nume, int note[], t_GRAD grad);
StudentBuget (const char *stdinfo);
void StudentBuget::print()
{
std::cout << "id: " << m_Id;
std::cout << "\nnume: " << m_Nume;
std::cout.precision (2);
std::cout << "\nmedie: " << std::fixed << this->getMedie() << std::endl;
std::cout << "grad: " << this->getGradStr();
}
const char* StudentBuget::getGradStr () const
{
switch (m_Grad) {
case STD_FR: return "std.fr.";
case STD_CAP: return "std.cap.";
case STD_SG: return "std.sg.";
case STD_SGMAJ: return "std.sg.maj";
default: return "std";
};
}
void StudentBuget::print()
{
Student::print();/* apel metoda print originala (din clasa de baza) */
std::cout << "grad: " << this->getGradStr();
}
Derivarea poate fi de tip public sau private. Ideea rămâne aceeaşi, însă există o serie de
diferenţe în anumite contexte.
class B { /*...*/ };
class D : public B // public derivation
{ /*...*/ };
class B { /*...*/ };
class D : B // private derivation
{ /*...*/ };
class B { /*...*/ };
class D : private B // private derivation
{ /*...*/ };
În tabelul următor este figurat accesul (vizibilitatea) din clasa derivată la membrii moşteniti
din clasa de bază:
Private inaccesibil
private protected private
Public public
10