Prezentarea Conceptului OOP de Mostenire 2. Derivarea Claselor in C++ 3. Vizibilitatea Membrilor in Clasele Derivate Drepturi de Acces
Prezentarea Conceptului OOP de Mostenire 2. Derivarea Claselor in C++ 3. Vizibilitatea Membrilor in Clasele Derivate Drepturi de Acces
public:
Student (int id, char *nume, int note[]);
Student (const char *stdinfo);
//...
}
//...
void Student::print () {
std::cout << "\nStudent::print() this " << this;
std::cout << ";id:" << m_Id;
std::cout << ";nume:" << m_Nume;
std::cout.precision (2);
std::cout << ";medie:" << std::fixed << this->getMedie();
}
/******************************************************************************/
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()
{
Student::print();
std::cout << ";grad:" << this->getGradStr();
}
/******************************************************************************/
class StudentTaxa: public Student
{
int m_TaxeAchitate[20];
public:
StudentTaxa (int id, char *nume, int note[], int taxe[]);
StudentTaxa (const char *stdinfo);
Baza()
Derivata()
Obs: daca nu exista constructor implicit (fara parametrii) in clasa de baza (Baza), trebuie apelat
unul din constructorii cu parametrii ai clasei Baza, la implementarea constructorului clasei
Derivata (ca in exemplul de mai sus). Spunem ca apelam in mod explicit constructorul clasei
de baza.
~Derivata()
~Baza()
Obs: Daca avem un lant mai mare de derivari succesive:
class D: public C
class C: public A
class A: public B
La definitia obiectului D d;
se apeleaza automat constructorii: A(), B(), C(), D()
respectiv destructorii: ~D(), ~C(), ~B(), ~A()
Conversii de tip la atribuirea obiectelor
/******************************************************************************/
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,10,9,10,4");
//...
//pSB = &S; // EROARE (de compilator)!!!
//pSB = &ST; // EROARE (de compilator)!!!
pS = &SB; // OK
pS->print(); // se apeleaza doar metoda Student::print()
/******************************************************************************/
string stringify (int value)
{
char pvalue[100];
sprintf_s (pvalue, sizeof (pvalue), "%d", value);
return string (pvalue);
}
/******************************************************************************/
class Vehicle
{
protected:
int m_Year;
string m_Color;
public :
Vehicle( const string &color, const int year)
: m_Year(year), m_Color(color) {}
return str;
}
/******************************************************************************/
class Car : public Vehicle // Makes Car inherit from Vehicle
{
string m_Model;
int m_Power;
public :
Car(const string &color, const int year, const string &model, const int power)
: Vehicle(color, year), m_Model(model), m_Power (power) {}
return str;
}
//...
};
/***********************************************************************/
void main ()
{
Car C ("Black", 2006, "Toyota Avensis", 100);
cout << C.getDesc().c_str() << endl;
}
/******************************************************************************/
Cateva observatii:
- Clasa string face parte din biblioteca de clase STL (Standard Template Library), si este
accesibila din namespace –ul std.
- La nivelul clasei string exista deja definiti constructori de copiere si operatori ( =, +, +=,
etc.)
- Clasa Car are (mosteneste) toate proprietatile unui Vehicle: structura (datele) +
comportamentul (metodele).
- Metoda getDesc( ) a fost suprascrisa (overriding) in clasa mostenita.
- Superclasa Vehicle si subclasa Car
- Pentru a se construi un obiect de tip Car, mai intai “se construieste” “partea obiectului”
mostenita din clasa Vehicle.
o Se observa modul de apel al constructorului clasei de baza in cosntructorul clasei
derivate.
o Daca nu se apeleaza in mod explicit constructorul clasei de baza (ca in exemplele de
mai sus), se va apela constructorul implicit (fara parametrii) din clasa de baza. El
trebuie sa existe.
- Atentie:
o la instantierea clasei derivate Car, exista un singur obiect
o nu exista doua obiecte: unul Car care ar include in vreun fel un “sub-obiect” Vehicle.
- Din punct de vedere schematic, derivarea se poate reprezenta ca in figura de mai jos:
Diferenta intre “este un” fata de “are un” (is-a vs. has-a)
- Mostenire (Derivare): Fiecare obiect al clasei A este (la baza) un obiect de tip B. De
exemplu: fiecare Car este in fapt, foarte bine si un Vehicle.
- Alte situatii: Obiecte sau referinte la clasa B sunt parametrii/valori intoarse in/din metodele
clasei A.
Obs:
- Prin mostenire se implementeaza relatia “is-a”.
- Ea nu trebuie folosita pentru implementarea relatiei “has a”. De exemplu, ar fi o eroare de
proiectare (design) sa se implementeze clasa Vehicle ca fiind derivata din clasa string, avand
plecand de la ideea ca un Vehicle este de o anumita culoare.
Un Vehicle are o coloare, nu este o culoare !!
- Relatia “has-a” trebuie implementata prin date membre in cadrul unei clase si nu prin
mostenire.
- In orice design trebuie analizata corect relatiile dintre clase. Pentru a implementa o
mostenire, intotdeauna clasa derivata trebuie sa permita instantierea de obiecte care la baza
pot fi considerate obiecte de tip clasa de baza.
Mostenirea multiplă
- O clasă poate fi mostenita din doua (sau mai multe) clase derivate.
- Nu toate limbajele OOP permit/suporta acest lucru. C++ permite !!
Exemplu 1:
class InsuredItem
{
time_t m_NotBefore;
time_t m_NotAfter;
int m_Amount;
InsurancePolicy m_Policy;
public:
int getAmount () const {return m_Amount; }
string getStartAsString () const {/*...*/}
string getEndAsString () const {/*...*/}
//...
string getAllDetails() const {
//...
}
//...
};
//...
}
Exemplu 2:
class Animal
{
//describes the behavior of the animal
}
class Drawing
{
//contains the drawing properties of the entity like colors, size etc
}
class Snake
{
public:
...
private:
Animal *m_animal;
Drawing *m_drawing;
};
Alte exemple:
class A { /* ... */ };
class B { /* ... */ };
class C { /* ... */ };
class X : public A, private B, public C { /* ... */ };
- Putem intalni cazuri cand se mostenesc doua clase avand acelasi membru x. Trebuie evitata
ambiguitatea prin folosirea operatorului de scop :: (Vehicle::x si InsuredItem::x)
aka.
class L { /* ... */ }; // indirect base class
class B2 : public L { /* ... */ };
class B3 : public L { /* ... */ };
class D : public B2, public B3 { /* ... */ }; // valid
/**********************************************************************/
void main ()
{
D d;
d.f();
}
/**********************************************************************/
Obs:
Folosind mostenirea de tip virtual, avem o singura instanta a lui x
Fara utilizarea mostenirii virtuale avem doua instante diferite ale lui x (B2::x si B3::x)
class storable //this is the our base class inherited by transmitter and
receiver classes
{
public:
storable() {}
~storable(){}
void read() {cout << "\nread from storable...";}
void write(){cout << "\nwrite from storable...";}
private:
//....
};
/*****************************************************************/
void main ()
{
storable *p = new radio;
p->read();
}
/*****************************************************************/