0% found this document useful (0 votes)
45 views14 pages

Prezentarea Conceptului OOP de Mostenire 2. Derivarea Claselor in C++ 3. Vizibilitatea Membrilor in Clasele Derivate Drepturi de Acces

The document discusses inheritance in C++, including: 1. Calling constructors and destructors of derived classes, where calling the base class constructor is done before the derived class constructor and destructors are called in reverse order. 2. Type conversions when assigning objects, where implicit conversion is allowed from derived to base but not vice versa. 3. The difference between inheritance ("is-a" relationship) and composition ("has-a" relationship).

Uploaded by

sophia andres
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
45 views14 pages

Prezentarea Conceptului OOP de Mostenire 2. Derivarea Claselor in C++ 3. Vizibilitatea Membrilor in Clasele Derivate Drepturi de Acces

The document discusses inheritance in C++, including: 1. Calling constructors and destructors of derived classes, where calling the base class constructor is done before the derived class constructor and destructors are called in reverse order. 2. Type conversions when assigning objects, where implicit conversion is allowed from derived to base but not vice versa. 3. The difference between inheritance ("is-a" relationship) and composition ("has-a" relationship).

Uploaded by

sophia andres
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

1.

Prezentarea conceptului OOP de mostenire


2. Derivarea claselor in C++
3. Vizibilitatea membrilor in clasele derivate; drepturi de acces
4. Apelul constructorilor/destructorilor claselor derivate
5. Conversii de tip la atribuirea obiectelor
6. Diferenta intre “este-un” fata de “are-un” (is-a vs. has-a)
7. Mostenirea multipla
8. ...
Apelul constructorilor/destructorilor
/******************************************************************************/
//...
class Student
{
protected:
int m_Id;
char *m_Nume;
int m_Note[100];

public:
Student (int id, char *nume, int note[]);
Student (const char *stdinfo);

void setNume (const char *nume);


float getMedie ();
void print ();
void addNota (int nota);
void modifyNota (int index, int nota);
//...
};

Student::Student (const char *stdinfo)


: m_Id (0), m_Nume (NULL)
{
printf ("\nConstructor clasa Student(this=%p)", this);

memset (m_Note, 0, sizeof (m_Note));

char *linfo = new char [strlen (stdinfo) + 1];


strcpy (linfo, 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 setGrad (t_GRAD grad) {m_Grad = grad;}


t_GRAD getGrad () {/*...*/}

const char* getGradStr () const;


void print ();
//...
};
StudentBuget::StudentBuget (const char *stdinfo)
: Student(stdinfo)
{
printf ("\nConstructor StudentTaxa(this=%p):initializare date spec(m_Grad)", this);
m_Grad = STD_FR;
}

//...

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);

void payTaxa (int val) {/*...*/}


int getSumaAchitata() {/*...*/}
//...
};

StudentTaxa::StudentTaxa (const char *stdinfo)


: Student(stdinfo)
{
printf("\nConstructor StudentTaxa(this=%p):initializare date spec(m_TaxeAchitate)",
this);
m_TaxeAchitate[0] = 0;
}
/******************************************************************************/
/******************************************************************************/
void main ()
{
std::cout << std::endl << std::endl;
std::cout << "\nDefinim un obiect Student:";
Student S ("101,Ionescu Vasile,8,9,5,10,8,9");
std::cout << "\nDefinim un obiect StudentBuget:";
StudentBuget SB ("102,Popescu Ion,7,9,5,10,8,9,10,4");
std::cout << "\nDefinim un obiect StudentTaxa:";
StudentTaxa ST ("103,Vasilescu Bogdan,8,9,10,4");

std::cout << "\nAfisam obiectul Student:";


S.print();
std::cout << "\nAfisam obiectul StudentBuget:";
SB.print();
std::cout << "\nAfisam obiectul StudentTaxa:";
ST.print();

std::cout << "\n\nModificam obiectul StudentBuget...";


SB.setGrad(StudentBuget::STD_CAP);
std::cout << "\nAfisam obiectul StudentBuget:";
SB.print();

std::cout << std::endl;


}
Concluzie: daca avem doua clase Baza si Derivata astfel incat:

class Derivata : public Baza sau


class Derivata : private Baza

La definitia unui obiect Derivata D;


Se creaza un singur obiect pentru care se apeleaza ambii constructori, in
ordinea:

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.

Pentru destructori este invers.


La distrugerea obiectului D, se vor apela automat destructorii in ordine inversa apelului
constructorilor:

~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");

Student *pS = &S; // OK


StudentBuget *pSB = &SB; // OK
StudentTaxa *pST = &ST; // OK
pS->print();
pSB->print();
pST->print();

//...
//pSB = &S; // EROARE (de compilator)!!!
//pSB = &ST; // EROARE (de compilator)!!!

pS = &SB; // OK
pS->print(); // se apeleaza doar metoda Student::print()

pSB = (StudentBuget *) &S; // merge la compilare;


// conversie fortata, nerecomandat!!!

pSB->print(); // rezultat NEDEFINIT (poate CRASH !!)

pSB = (StudentBuget *) &ST; // merge la compilare;


// conversie fortata, nerecomandat!!!

pSB->print(); // rezultat NEDEFINIT (poate CRASH !!)

std::cout << std::endl;


}
/******************************************************************************/

Concluzie: daca derivarea este de tip public :


conversia (Derivat *) --> (Baza *) se face automat (implicit).
In orice alt caz: NU !!!

Obs: acest mecanism va fi foarte util la implementarea de functionalitate polimorfica prin


functii virtuale suprascrise in clasele derivate.
Un alt exemplu:

using namespace std;

/******************************************************************************/
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) {}

const string getDesc() const {


string str = m_Color;
str += " from "; str += stringify(m_Year);

return str;
}

const string &getColor() const {return m_Color;}


const int getYear() const {return m_Year;}
//...
};

/******************************************************************************/
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) {}

const string &getModel() {return m_Model;}


const int getPower() {return m_Power;}

const string getDesc () const {


string str = m_Model;
str += " from "; str += stringify(m_Year);
str += " having "; str += m_Color; str += " color (power: ";
str += stringify(m_Power);
str += " kW)";

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)

O clasa A poate depinde de o alta clasa B in mai multe situatii:

- Compozitie (Agregare): Fiecarea obiect al clasei A contine un obiect al clasei B. De


exemplu: fiecare Vehicle contine un obiect m_Color care este un string.

- 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 {
//...
}
//...
};

// Makes Car inherit from Vehicle and InsuredItem


class Car : public Vehicle, public InsuredItem {

//...
}

In acest caz, un Vehicle


 este oricand un Car
 dar de asemenea este oricand si un InsuredItem

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 Animal, public Drawing


{
//... (diferences vs. Animal + Drawing)
}
O varianta incorecta ar fi fost:

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)

- Obs : situatia de mai jos nu este permisa:


class B1 { /* ... */ }; // direct base class
class D : public B1, private B1 { /* ... */ }; // error

Cazul special de mostenire in romb (diamond inheritance)

aka.
class L { /* ... */ }; // indirect base class
class B2 : public L { /* ... */ };
class B3 : public L { /* ... */ };
class D : public B2, public B3 { /* ... */ }; // valid

Obs: este ok !! Insa este necesara rezolvarea ambiguitatii (automat) generata.


Exista doua solutii:
1) B2::x, B3::x, sau prin
2) Utilizarea mostenirii de tip virtual:
class L { // indirect base class
public:
int x;
L():x(10){}
/* ... */
};

class B2 : virtual public L { /* ... */ };


class B3 : virtual public L { /* ... */ };

class D : public B2, public B3 { // valid


public:
void f() {
B2::x = 1;
B3::x = 2;
cout << B2::x;
cout << endl << B3::x;
cout << x; /* daca nu am folosi mostenirea virtuala, aici se
obtine eroare la compilare */
}
/* ... */
};

/**********************************************************************/
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)

Daca modificam codul de mai sus:

class B2 : public L { /* ... */ };


class B3 : public L { /* ... */ };

class D : public B2, public B3 { // valid


public:
void f() {
B2::x = 1;
B3::x = 2;
cout << "B2::x = " << B2::x << endl;
cout << "B3::x = " << B3::x << endl;
//cout << "x = " << x << endl;
}
/* ... */
};

Alt exemplu (http://www.cprogramming.com/tutorial/virtual_inheritance.html)

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:
//....
};

class transmitter: virtual public storable


{
public:
void write(){cout << "\nwrite from transmitter...";}
//...
};
class receiver: virtual public storable
{
public:
void read() {cout << "\nread from receiver...";}
//...
};

class radio: public transmitter, public receiver


{
public:
void read() {cout << "\nread from radio...";}
void write() {cout << "\nwrite from radio...";}
//....
};

/*****************************************************************/
void main ()
{
storable *p = new radio;
p->read();
}
/*****************************************************************/

Intrebare: De ce se apeleaza metoda din clasa de baza (obiectul este radio) ?


Răspuns: ...

You might also like