Sunteți pe pagina 1din 14

CURSURI POO 1-6

Obiectul reprezinta un element (entitate) care se constituie atat din structuri de date (atribute,
caracteristici) cat si din operatii (actiuni, comportament). Totodata, un obiect este considerat o instanta a unei clase,
un caz particular a acesteia.
Clasa reprezinta o colectie de obiecte similare care impartasesc aceleasi atribute si acelasi comportament.
Operatia de creare a unui obiect dintr-o clasa se numeste instantiere, de aici rezultand si denumirea de instanta
pentru un obiect creat.
Mesajul reprezinta o functie care confera un comportament unui obiect. Trimiterea unui mesaj este
echivalenta unei cereri adresata unui obiect de a invoca o functie. Mesajele sunt cele care permit comunicarea intre
obiecte.
Incapsularea reprezinta principiul asociat abstractizarii datelor, in sensul ca structura de date utilizata este
ascunsa, fiind furnizata doar o interfata. In POO incapsularea datelor se realizeaza cu ajutorul claselor.
Mostenirea: acea tehnica de programare prin care se pot utiliza si extinde clase deja create, utilizand astfel
codul sursa deja scris. Mecanismul mostenirii permite dezvoltarea de noi clase numite clase derivate (subclase)
din clase de baza (superclase). Avantajul este faptul ca o clasa derivata mosteneste toate atributele si
comportamentele clasei de baza, la care se pot adauga atribute si comportamente proprii.
Polimorfismul indica mai multe comportamente alternative intalnite in clase derivate inrudite. Se
intalneste si sub sintagma “o singura interfata, mai multe metode”, avantajul fiind numarul redus de elemente in
cazul unei interfete comune care permite acces la mai multe actiuni.
Tipul de date struct nu ofera protectie a datelor, ceea ce determina ca tipurile de date introduse prin
structuri sa nu poata fi supuse unor controale ce tin de operatiile executate asupra lor.
Implementarea tipurilor de date abstracte cu protejarea datelor si functiilor au condus la aparitia claselor,
din limbajul C++.
Operatiile de I/O se bazeaza pe conceptul de stream ce reprezinta un model abstract al dispozitivelor de
I/O. Un stream este o secvente de octeti.
Sintaxa operatiei de intrare: cin>>v1>>v2>>...>>vn;
Sintaxa operatiei de iesire: cout<<ei<<e2<<...<<en;
Biblioteca folosita este iostream.h. Aceasta include si 4 stream-uri predefinite:
-cin – stream de intrare conectat la intrarea standard
-cout – stream de iesire conectat la iesirea standar
-cerr – strean de iesire setat pentru o iesire fara buffer catre un dispozitiv standard de eroare
-clog – stream similar cu cerr, dar avand buffer
Alocarea dinamica a memoriei – functiile malloc
Eliberarea memoriei – functia free
In limbajul C++ exista 2 operatori new si delete care joaca acelasi rol de alocare, respectiv dealocare a
memoriei.
Operatorul new returneaza un pointer la zona de memorie alocata dinamic, in caz de insucces returnand
NULL.
Operatorul delete elibereaza zona de memorie indicata de argumentul sau, care este de fapt un pointer
obtinut ca urmare a alocarii cu operatorul new.
Sintaxa generala a operatorului de alocare dinamica a memoriei:
tip * pt_tip;
pt_tip=new tip;
sau direct:
tip * pt_tip=new tip;
unde tip reprezinta un tip de date fundamental, iar pt_tip reprezinta pointerul catre tipul de date dorit.
Sintaxa generala a operatorului de dealocare dinamica a memoriei este:
delete pt_tip;
unde pt_tip reprezinta pointerul catre tipul de date dorit pentru care s-a alocat memorie.
Clasa este un tip de date abstract si contine date membru si functii membru sau metode. Clasele ofera un
nivel superior de protectie atat datelor, cat si functiilor membru, prin incapsularea datelor.
Clase si obiecte
O multime de obiecte ce impartasesc aceleasi atribute si aceleasi comportamente alcatuiesc o clasa.
Obiectele sunt instante ale unei clase care comunica intre ele prin intermediul metodelor (invocate la
primirea unui mesaj).
O metoda reprezinta o functie membru a unei clase. Comportamentul unui obiect reprezinta totalitatea
metodelor care ii pot fi asociate.

Structuri vs. Clase


Prin POO s-a facut trecerea de la tipul de date struct la tipul de date class. Structurile, specifice limbajului
C, sunt tipuri de date ce grupeaza date fara functiile membre asociate. In limbajul C++, definitia structurii este
extinsa, astfel incat o structura devine un caz particular de clasa, cu exceptia faptului ca membrii unei clase sunt
impliciti privati, pentru a asigura incapsularea implicita a datelor.

Sintaxa declararii unei clase:


class nume_clasa
{
private: //date si functii membru private
public: //date si functii membru publice
protected: //date si functii membru protejate
};
Sectiunea privata desemnata de cuvantul cheie private sau in mod implicit, la inceputul clasei dupa
acolada deschisa, grupeaza membrii clasei (date si functii), care sunt accesibili doar functiilor membru ale clasei
respective si eventual, asa-numitelor functii prietene ale acesteia. Membrii privati nu sunt accesibili din afara
clasei. Accesarea acestor membrii se face in mod indirect, prin intermediul functiilor publice.
Sectiunea publica desemnata de cuvantul cheie public grupeaza membrii clasei (date si functii), care sunt
accesibili in toate sectiunile programului care acceseaza obiecte ale clasei respective.
Sectiunea protejata desemnata de cuvantul cheie protected grupeaza membrii clasei (date si functii), care
pot fi accesati de catre clasele derivate din clasa respectiva.

Definirea si utilizarea obiectelor


Clasele pot fi considerate tipuri noi de date definite de catre programatori pentru rezolvarea unor probleme,
iar obiectele pot fi asociate variabilelor al caror tip este indicat de numele clasei.
Exemplu de declaratii pe obiecte:
Persoana P1,P2(“Dima”, “Ioana”, 35, “romana”);
Numar N1(10);
Calculator C1(“Intel”, 80, 1024);
Se mai pot declara si tablouri de obiecte, pointeri la obiectele unei clase si referinte la obiectele unei clase
oarecare. Exemplu:
NumeClasa TablouObiecte[dimensiune_tablou]; //tablou de obiecte de tip NumeClasa
NumeClasa *pointerOb; //pointer la un obiect de tip NumeClasa
NumeClasa &RefOb; //referinta la un obiect de tip NumeClasa
Sintaxa de definire a unei functii membru:
{declaratii locale;
instructiuni;
}

Modalitati de accesare a membrilor unei clase


Accesarea membrilor publici (date si functii) ai unei clase se poate face astfel:
NumeObiect.Variabila;
PointerObiect->Variabila;
NumeObiect.NumeFunctieMembru(lista parametri);
PointerObiect->NumeFunctieMembru(lista parametri);
Mai exista inca 2 modalitati de accesare a mebrilor publici, utilizand pointeri la functii. Un pointer la o
functie membru a unei clase A se defineste astfel: A::*.
NumeObiect.*Pointer_la_Functie_Membru;
PointerObiect->*Pointer_la_Functie_membru;
Constructori si destructori
Constructorii si destructorii sunt functii speciale in cadrul claselor ce permit construirea, respectiv
“distrugerea” obiectelor clasei respective. Cu ajutorul constructorilor se face alocarea spatiului de memorie pentru
obiectele unei clase, dealocarea realizandu-se prin intermediul destructorului clasei. In cazul in care nu exista un
constructor, respectiv destructor definit de programator, compilatorul presupune ca acestia exista implicit, intr-o
forma cat mai simpla.
Tipuri de constructori
Constructorul este utilizat la initializarea corecta a datelor membru ale claselor, are acelasi nume cu
numele clasei si poate fi de mai multe tipuri:
-implicit (fara parametri): Persoana();
-cu lista de parametri: Persoana(char*, char*, int, char*);
-de copiere: Persoana(Persoana&);
-de convertire si atribuire: Student(Persoana&); //a unui obiect de tip Persoana unui obiect de tip Student
Constructorul implicit poate fi obtinut prin declararea de catre programator a unui constructor fara
parametri, corpul constructorului putand contine orice instructiuni, fie prin generarea automata de catre compilator
atunci cand nu exista o declarare explicita a acestuia, iar corpul constructorului nu contine nicio instructiune.
Constructorul cu parametri este acel constructor al unei clase ce contine o lista de argumente,
corespunzatoare datelor membru ale clasei. Exemple:
Varianta 1 Varianta 2
class numar_rational class numar_rational
{ {
int numarator, numitor; int numarator, numitor;
public: numar_rational(int x, int y): numarator(x), public: numar_rational(int x, int y)
numitor(y){} {
}; numarator=x;
numitor=y;
}
};
Constructorul de copiere are rolul de a copia membru cu membru toate variabilele argumentului in cele
ale obiectului ce este copiat. Variantele de apelare ale constructorului de copiere sunt:
NumeClasa A2=A1;
NumeClasa A2(A1);
Constructorul de convertire si atribuire este asemanator constructorului de copiere, doar ca se face o
copie a unui obiect dintr-o clasa T intr-un obiect al unei clase A.
Destructorul este o functie membru a unei clase care are acelasi nume cu numele clasei, doar ca este
precedat de semnul ~. O clasa poate avea un singur destructor care se autoapeleaza la finalul programului.
Definirea unui constructor cu parametri si destructorului clasei numar_rational:
class numar_rational
{int numarator, numitor;
public: numar_rational(int x, int y)
{numarator=x;
numitor=y;
}
~numar_rational()
{cout<<”\n Apel destructor!”;
}
};

Clase si obiecte compuse


O clasa compusa este acea clasa care contine o alta clasa sau un obiect din alta clasa. Un obiect al unei
clase compuse se numeste obiect compus. Exemplu:
class dreptunghi {
{ coltStgSus, initializarePunct(x1,y1);
class punct coltDrJos, initializarePunct(x2,y2);
{ }
int x,y; };
public: void initializarePunct(int x1=0,inty1=0); void main()
} { punct a1;
coltStgSus, coltDrJos; //obiecte interne dreptunghi d1;
public: void initializareDreptunghi(int x1,int x2,int d1.initializareDreptunghi(4,5,6,7);
y2) }
Utilizarea pointerului this
Pointer-ul this este utilizat in mod implicit pentru referirea atat la membrii date cat si la functiile membru
ale unui obiect. La apelarea functiilor membru, acestea sunt informate asupra identitatii obiectului asupra caruia
vor actiona aceste functii, prin transferul unui parametru implicit, care reprezinta adresa obiectului.
Exemplu:
class complex void main()
{ {
double real, imaginar; complex z1(2,3), z2(-2,4);
public: complex() {real=imaginar=0.0;} cout<<”\n Partea reala a obiectului
complex (double a, double b) z1:”<<z1.getReal();
{real=a;imaginar=b;} cout<<”\n Partea imagina a obiectului
double getReal() z1:”<<z1.getImaginar();
{return this->real; cout<<”\n Partea reala a obiectului
} z2:”<<z2.getReal();
double getImaginar() cout<<”\n Partea imagina a obiectului
{return this->imaginar; z2:”<<z2.getImaginar();
} }
};

Definirea si utilizarea functiilor friend


Functiile prietene sunt declarate cu ajutorul cuvantului cheie friend si au acces la membri privati ai unei
clase, incalcandu-se astfel principiul incapsularii informatiei. Functiile friend pot fi functii membru ale altor clase
sau pot fi functii independente. O clasa intreaga poate fi declarata prietena a unei alte clase.
Sintaxa declararii unei functii friend: friend tip nume_functie(lista parametri);
Exemplu: friend int getNume(Persoana&);
Obs: In lista de parametri ai unei functii friend trebuie sa existe un obiect sau o referinta la un obiect al
clasei cu care functia este prietena.
Exemplu:
class A class Persoana
{ //date si functii membru { int varsta;
}; char nume[30];
class B public: Persoana(int, char*);
{ //date si functii membru void afisarePersoana();
friend class A; };
}; class Institutie
{ int nr_angajati;
char domeniu[30];
public: friend class Persoana;
};
Exemplu de utilizare a functiilor friend:
#include<iostream.h> cout<<”\n Specializarea:”<<specializarea<<”\n”;
#include<string.h> }
class student };
{ void setMedia(student*S, double x)
double media; {S.media=x;}
char specializare[20]; void main()
public: student(){ {
media=5.00; Student S;
strcpy(specializare,” ”); S.afisare();
} setMedia(S, 8.96);
friend void setMedia(student&, double ); cout<<”\n Afisare date dupa modificarea
void afisare() mediei:\n”;
{ S.afisare();
cout<<”\n Media anuala:”<<media; }

Definirea si utilizarea functiilor inline


Functiile inline sunt functii de dimensiuni mici care permit compilatorului inserarea in program a unor
copii multiple in vederea evitarii unui apel de functie, micsorand astfel timpul de executie. Orice functie al carei
antet este prefixat de cuvantul cheie inline are aceste caracteristici. Dezavantajul principal este faptul ca sunt
inserate in program copii multiple ale codului functiei si astfel creste marimea codului asociat programului
respectiv. Daca o functie membru este definita in interiorul unei clase atunci ea devine automat functie inline.
Sintaxa definirii unei functii inline: inline tip nume_functie(lista parametri);
Exemplu: inline int getNume();
inline setSalariu(double x);
Obs. In functiile inline nu sunt permise structuri repetitive de tipul do while, while si for.
Exemplu:
#include<iostream.h> };
class complex double complex::getReal()
{ {
double real, imaginar; return this->real;
public: complex(){real=imaginar=0.0;} }
complex(double x, double y) void main()
{real=x; {
imaginar=y; complex z1(-3,5);
} cout<<”\n Partea reala a lui z1:”<<z1.getReal();
inline double getReal(); cout<<”\n Partea imaginara a lui
double getImaginar() z1:”<<z1.getImaginar();
{return this->imaginar; }
}

Tablouri de obiecte
Tablourile de obiecte reprezinta o colectie de obiecte similare ce apartin aceleiasi clase. In limbajul C++,
tablourile de obiecte pot fi implementate doar daca acea clasa care incluse tabloul de obiecte contine un constructor
implicit. Aceasta restrictie se datoreaza imposibilitatii de a furniza argumentele necesare constructorilor.
Exemplu: Persoana tab[20];
Exemplu de program:
#include<iostream.h> int numar_rational::getNumarator()
class numar_rational {
{ return this->numarator;
int numarator, numitor; }
public: numar_rational(){numarator=0;numitor=1;} void main()
void setare_numar_rational() {
{cout<<”\n Numarator=”; numar_rational tablou[10];
cin>>numarator; int i, n;
cout<<”\n Numitor=”; cout<<”\n Numarul de obiecte ce vor fi create:”;
cin>>numitor; cin>>n;
} for(i=0;i<n;i++)
inline int getNumarator(); tabolou[i].setare_numar_rational();
int getNumitor() cout<<”\n Au fost create urmatoarele obiecte:\n”;
{return this->numitor; for(i=0;i<n;i++)
} tabolou[i].afisare();
void afisare() cout<<”\n Numitorul obiectului tablou[3]
{cout<<numarator<<”/”<<numitor<<”\n”; este:”<<tablou[3].getNumitor();
} }
};
Definirea membrilor statici
In limbajul C++ prefixarea membrilor unei clase cu cuvantul cheie static le confera acestora proprietati
deosebite. Membrii statici nu apartin unui anumit obiect, ci sunt comuni tuturor obiectelor unei clase. Membrii
statici sunt folositi in situatiile in care obiectele unei clase folosesc date in comun, reducandu-se numarul de
variabile globale. Initializarea membrilor statici se face o singura data.
Exemplu:
#include<iostream.h> angajat(char* F, int V, double S){
#include<string.h> functie=new char[strlen(F)+1];
class angajat strcpy(functie, F);
{ char *functie; vechime=V;
int vechime; salariu=S;
double salariu; ++Nr;//s-a creat un obiect din clasa angajat
static int Nr; }
public: angajat(){ static int getNrAngajati();
strcpy(functie, ” ”); double getsalariu(){ return salariu;}
vechime=10; int getvechime(){return vechime;}
salariu=0.0; void setsalariu(double);
} };
int angajat::Nr=0; angajat *A1= new angajat(”inginer”, 15, 2450.57);
int angajat::getNrAngajati(){ return Nr;} angajat *A1=new angajat(” economist”, 25,
angajat::~angajat() 4500.64);
{delete functie; cout<<”\n Numarul de angajati dupa
--Nr; creare:”<<A1-
} >getNrAngajati();
void angajat::setsalariu(double x) delete A1;
{ A1=0;
salariu+=salariu*x/100; delete A2;
cout<<“\n Salariul indexat cu “<<x<<“% A2=0;
este”<<this->salariu; Cout<<”\n Numarul de angajati dupa eliberarea
} spatiului de
void main() memorie:”<<angajat::getNrAngajati();
{ }
cout<<”\n Initial sunt ”<<angajat::getNr()<< ”
angajati”;

Pointeri la metode
Limbajul C++ ofera posibilitatea de a lucra cu pointeri catre membrii unei clase (date sau functii membru),
acestia avand asociate atat tipul membrului, cat si tipul clasei respective. Un pointer catre un membru al unei clase
(data sau functie) nu este asociat unui anumit obiect, ci clasei. Preluarea adresei unui membru se face cu ajutorul
operatorului de adresa &, precizandu-se identitatea membrului.
Sintaxa definirii unui pointer la o functie membru:
NumeClasa::*;
PointerMembru=&NumeClasa::Membru
Dupa preluarea adresei, accesarea membrului respectiv se face astfel:
NumeObiect.*PointerMembru
PointerObiect->*PointerMembru

Supraincarcarea operatorilor
Redefinirea operatorilor
Limbajul C++ preia operatorii din limbajul C, dar utilizeaza si operatori noi precum operatorii de alocare,
respectiv dealocarea spatiului memoriei (new si delete). Pentru a extinde orizontul de utilizare a operatorilor a
aparut mecanismul de redefinire a operatorilor, care permite definirea propriilor functii asociate operatorilor, pe
care compilatorul sa le apeleze atunci cand intalneste acei operatori redefiniti.
Sintaxa redefinirii unui operator: operator simbol_operator
Pot exista mai multe redefiniri ale unui operator, dar ele trebuie sa aiba argumente diferite, pentru a putea
fi posibila diferentierea lor de catre compilator.
Exista doua modalitati de redefinire a operatorilor:
-prin functii membru ale clasei respective
-prin functii friend ale clasei respective

Modalitati de redefinire a operatorilor


Prin functii membru
tip NumeClasa::operator simbol_operator(lista argumente)
{corpul functiei}
Prin functii
friend tip operator simbol_operator(lista argumente) //declararea functiei operator pentru redefinirea unui operator
tip operator simbol_operator(lista argumente) //definirea functiei operator pentru redefinirea unui operator
Exemplu:
#include<iostream.h> {
class NrComplex real = a; imaginar = b;
{ }
private: void afisare()
double real, imaginar; {
public: complex() if(imag>=0)
{ cout<<real<<”+i”<<imaginar<<”\n”;
real = 0.0; imaginar = 0.0; else
} cout<<real<<imaginar<<”i \n”;
complex(double a, double b) }
NrComplex operator+(NrComplex&); NrComplex rez;
NrComplex operator-(NrComplex&); rez.real= z1.real*z2.real-z1.imaginar*z2.imaginar;
friend NrComplex operator*(NrComplex&, rez.imaginar=z1.real*z2.imaginar+z1.imaginar*z2.r
NrComplex&); eal;
}; return rez;
NrComplex NrComplex::operator+(NrComplex&z) }
{ void main()
NrComplex rez; {
rez.real=this->real+z.real; NrComplex z1(2,5),z2(6,-2),z3,z4,z5;
rez.imaginar=this->imaginar+z.imaginar; z1.afisare();
return rez; z2.afisare();
} z3=z1+z2;
NrComplex NrComplex::operator-(NrComplex&z) cout<<”\n z1+z2=”;
{ z3.afisare();
NrComplex rez; z4=z1-z2;
rez.real=this->real-z.real; cout<<”\n z1-z2=”;
rez.imaginar=this->imaginar-z.imaginar; z4.afisare();
return rez; z5=z1*z2;
} cout<<”\n z1*z2=”;
NrComplex operator * (NrComplex&z1, z5.afisare();
NrComplex&z2) }
{
Exceptii de redefinire a operatorilor
Operatori care nu permit redefinirea lor: . , .* , :: , ?:
Alti doi operatori considerati exceptii de la redefinire sunt: operatorul de atribuire (=) si operatorul adresa
(&). Operatorul de atribuire poate fi folosit fara a fi redefinit explicit, rolul acestuia fiind de a atribui membru cu
membru componentele clasei unde are loc redefinirea. Operatorul adresa poate fi aplicat obiectelor oricarei clase
fara o redefinire explicita, rolul sau fiind de a intoarce adresa obiectului din memorie.
Obsevatii:
-redefinirea operatorilor este posibila doar pentru clasele definite de programator, pentru tipurile standard
de date, operatorii comportandu-se normal.
-nu se permite alegerea pentru operatori a altor simboluri decat cele deja existente si nu se pot combina
operatori cunoscuti pentru crearea de noi operatori.

Redefinirea operatorilor << si >>


friend ostream& operator<<(ostream&, NumeClasa&);
friend istream& operator>>(istream&, NumeClasa&);
Exemplu:
#include<iostream.h> }
#include<conio.h> iostream& operator>>(istream&in, angajat&A)
#include<string.h> {
class angajat cout<<”\n Introduceti functia:”;
{ in>>A.functie;
private: char functie[30]; cout<<”\n Introduceti salariul”;
double salariu; in>>A.salariu;
int vechime; cout<<”\n introduceti vechimea:”;
public: angajat(){ in>>A.vechime;
strcpy(functie, “ “); return in;
salariu=0.0; }
vechime=5; void main()
} {
friend ostream& operator<<(ostream&, angajat&); clrscr();
friend istream& operator>>(istream&, angajat&); angajat A;
}; cout<<”\n Utilizarea operatorului >>”;
iostream& operator<<(ostream&out, angajat&A) cin>>A;
{ cout<<”\n Utilizarea operatorului >>”;
cout<<”\n Functia angajatului:”<<A.functie<<”\n cout>>A;
Salariul lunar:”<<A.salariu<<”\n Vechimea in getch();
munca:”<<vechime; }
return out;
Observatii:
-daca functia operator este implementata ca o functie membru, operandul cel mai din stanga trebuie sa fie
un obiect sau o referinta catre un obiect al clasei respective
-daca functia operator este implementata ca o functie nemembru, atunci operandul cel mai din stanga este
un obiect al unei clase diferite sau un tip de data predefinit
-daca se doreste ca functia operator sa acceseze direct membrii privati sau protejati ai unei clase ea se
declara functie friend.

Mostenirea
Mostenirea este o modalitate de reutilizare a codului si este folosita pentru extinderea claselor deja create.
Mecanismul mostenirii presupune definirea unei clase noi, numita clasa derivata sau subclasa dintr-o clasa
existenta numita clasa de baza sau superclasa.
Clasa derivata mosteneste (preia) toate caracteristicile clasei de baza si poate adauga alte caracteristici noi,
specifice.
Sintaxa declararii unei clase derivate:
Class NumeClasaDerivata: ModificatorAcces NumeClasaBaza
{
// membrii clasei derivate
}
Exemplu:
class Angajat: public Persoana
{ float salariu;
public:
Angajat(char*, char*,int, float);
void afisare();
float getSalariu();
};
Observatii:
-modificatorul de acces determină modul în care elementele clasei de bază sunt moştenite în clasa derivată.
Exemplu:
o în cazul în care modificatorul de acces este public, toţi membrii publici din clasa de bază rămân
membri publici în clasa derivate.
o când modificatorul de acces este private, atunci toţi membrii publici din clasa de bază devin
membri privaţi în clasa derivată.
-la moştenire, membrii privaţi din clasa de bază nu sunt accesibili claselor derivate decât prin intermediul
funcţiilor membru moştenite din clasa de bază.
-pentru a avea acces direct la membrii clasei derivate, aceştia se pot declara în secţiunea protected.
-funcţiile friend nu se moştenesc.

Clase de baza si clase derivate


O clasa se numeşte clasă de bază dacă din acesta se poate deriva
una sau mai multe clase noi, care moştenesc caracteristicile acesteia. O
clasă nouă rezultată în urma derivării dintr-o clasă existentă se numeşte
clasă derivată şi extinde clasa iniţială (de bază).

Ordinea apelarii constructorilor si destructorilot intr-o relatie de mostenire


Constructorii claselor de bază se execută înainte constructorilor claselor derivate, iar destructorii claselor
derivate sunt primii care se apelează înaintea destructorilor claselor de bază. Atât constructorii, cât şi destructorul
clasei derivate nu se moştenesc.

Rolul membrilor protejati


Pentru accesarea directă a anumitor membrii ai clasei de bază din clasa derivată, aceştia trebuie declaraţi în
secţiunea protected. Această secţiune permite o protecţie de nivel intermediar a membrilor clasei de bază, între
nivelul privat şi cel public. Accesarea membrilor protejaţi ai unei clase de bază se poate face de către funcţiile
friend din clasa de bază, dar şi de către funcţiile friend din clasa derivată.
Exemplu:
#include<iostream.h> {
#include<string.h> strcpy(sistem_operare, SO);
class Calculator }
{ void afisare(){
private: double pret; {
protected: Calculator::afisare();
int capacitateHDD; cout<<”\n Sistem de operare
char procesor[20]; instalat:”<<sistem_operare<<”\n”;
public: Calculator(double P, int H, char* Pro){ }
pret=P; int getCapacitateHDD()
capacitateHDD=H; {
strcpy(processor,Pro); return capacitateHDD;}
} char *getProcesor()
void afisare() {
{ return procesor;}
cout<<”\n Pretul calculatorului:”<<pret; ~Laptop()
cout<<”\n Capacitate HDD:”<<capacitateHDD; {
cout<<”\n Tip processor:”<<processor<<”\n”; cout<<”\n Apel destructor clasa derivata\n”;}
} };
double getPret(){return pret;} void main()
~Calculator() {
{ Calculator Ob1(1260.45, 1024, “Intel”);
cout<<”\n Apel destructor clasa de baza\n”;} Ob1.afisare();
}; Laptop Ob2(3450.05, 1024,”AMD”, “Vista”);
class Laptop: public Calculator Ob2.afisare();
{ cout<<”\n Laptopul are un HDD de capacitate
private: “<<Ob2.getCapacitateHDD()<< “ MB”<<”\n”;
char sistem_operare[30]; cout<<”\n Laptopul are un processor
public: “<<Ob2.getProcesor();
Laptop(double P, int H, char* Pro, char* SO): }
Calculator(P,H, Pro)

Redefinirea membrilor unei clase de baza intr-o clasa derivata


Atunci când se doreşte ca în clasele derivate să fie definite funcţii cu structură asemănătoare celor din clasa
de bază, dar cu anumite caracteristici se utilizează redefinirea funcţiilor membru. În cazul în care, la crearea unei
noi funcţii în clasa derivată se păstrează antetul funcţiei din clasa de bază atunci mecanismul se numeşte function
overriding (redefinire). Dacă funcţia din clasa de bază este modificată aşa încât nu se păstrează antetul acesteia
pentru funcţia nouă din clasa derivată, mecanismul este denumit function overloading (supraîncărcare).
Exemplu:
#include<iostream.h> {
#include<string.h> cout<<”\n Apel destructor clasa de baza\n”;}
class Carte };
{ class Dictionar: public Carte
private: double pret; {
char editura[20]; private:
char titlu[30]; int nrpagini;
public: Carte(double P, char *Ed, char* T){ int an_aparitie;
pret=P; public:
strcpy(editura, Ed); Dictionar(double P, char* Ed, char *T, int Nr, int
strcpy(titlu,T); An):Carte(P,Ed, T)
} {
void afisare() nrpagini=Nr;
{ an_aparitie=An;
cout<<”\n Pretul cartii:”<<pret; }
cout<<”\n Editura:”<<editura; void afisare(){
cout<<”\n Titlul cartii:”<<titlu<<”\n”; { Carte::afisare(); //redefinirea functiei de afisare din
} clasa de baza
double getPret(){return pret;} cout<<”\n Numarul de pagini:”<<nrpagini;
~Carte() cout<<:\n Anul aparitiei:”<<an_aparitie<<”\n”;
} }
int getAnAparitie()
{ Carte Ob1(34.56, “Editura ALL Bucuresti”,
return an_aparitie;} “Programarea
int getNrPagini() orientate pe obiecte”);
} Ob1.afisare();
return nrpagini;} Dictionar Ob2(345.05, “Editura Humanitas
~Dictionar() Bucuresti”,”Dictionarul limbii romane”, 300, 2007);
{ Ob2.afisare();
cout<<”\n Apel destructor clasa derivata\n”;} cout<<”\n Dictionarul are un numar de
}; “<<Ob2.getNrPagini()<< “ pagini”<<”\n”;
void main() cout<<”\n Anul aparitiei dictionarul este
{ “<<Ob2.getAnAparitie();
}
La execuţie, compilatorul va identifica funcţia de afişare care trebuie apelată de către cele două obiecte,
conform definiţiilor funcţiilor membru.

Ierarhii de clase

Sintaxa mostenirii multiple:


class NumeClasaDerivata: ModificatorAcces 1
NumeClasaBaza 1,
ModificatorAcces 2 NumeClasaBaza 2,…, ModificatorAcces n
NumeClasaBaza n,
{
// membrii clasei derivate
}
Exemplu 1:
#include<iostream.h> return V.alimentare;}
#include<string.h> class Autoturism:public Vehicul
#include<conio.h> {
class Vehicul int nr_locuri;
{ char firma[20];
int nr_roti; public: Autoturism(int Nr, char *A, int Loc, char
char alimentare[30]; *F):Vehicul(Nr,
public:Vehicul(int Nr, char*A){ A), nr_locuri(Loc)
nr_roti=Nr; {
strcpy(alimentare, A); strcpy(firma, F);}
} ~Autoturism()
~Vehicul() {
{ cout<<”\n Apel destructor clasa Autoturism \n”;}
cout<<”\n Apel destructor clasa Vechicul \n”;} void afisare()
void afisare(){ {
cout<<”\n Nr roti:”<<nr_roti; Vehicul::afisare();
cout<<”\n Tip alimentare:”<<alimentare<<”\n”; cout<<”\n Nr locuri:”<<nr_locuri;
} cout<<”\n Firma producatoare:”<<firma<<”\n”;
int getNrRoti(){ return nr_roti;} }
friend char*getAlimentare(Vehicul&V); int getNrLocuri(){ return nr_locuri;}
}; char *getFirma(){ return firma;}
char * getAlimentare(Vehicul&V) };
{ class Motocicleta:public Vehicul
{double pret; strcpy(accesorii,Acc);}
double km_parcursi; ~Auto_familie()
public:Motocicleta(int Nr, char *A, double P, double {cout<<”\n Apel destructor clasa Auto_familie \n”;}
Km):Vehicul(Nr, A), pret(P), km_parcursi(Km){} void afisare()
~Motocicleta() {Autoturism::afisare();
{cout<<”\n Apel destructor clasa Motocicleta \n”;} cout<<”\n Accesorii in dotare:”<<accesorii;
void afisare() cout<<”\n Numar airbaguri:”<<nr_airbag<<”\n”;
{Vehicul::afisare(); }
cout<<”\n Pret:”<<pret; int getAirbag(){ return nr_airbag;}
cout<<”\n Distanta parcursa in char *getAccesorii(){ return accesorii;}
km:”<<km_parcusi<<”\n”; };
} void main()
double getPret(){ return pret;} {Vehicul V(4,”benzina);
void setKm(double K){ km_parcursi=K;} Autoturism A(4,”motorina”,5, ”Opel”);
}; Motocicleta M(2,”benzina”,5000, 1230);
class Autoutilitar:public Vehicul Autoutilitara B(4,”motorina’,”transport alimente”,
{char tip_transport[30]; 120);
double viteza_max; Auto_teren C(4,”motorina”,5,”Suzuki”,1700, ”
public: tractiune
Autoutilitar(int Nr, char *A, char* Trans, double totala”);
Vmax):Vehicul(Nr, A), viteza_max(Vmax) Auto_familie D(4, ” benzina”, 5, ”Ford”, ”suport
{ schiuri”, 4);
strcpy(tip_transport, Trans);} cout<<”\n Date vehicul:\n”;
~Autoutilitar() V.afisare();
{ getch();
cout<<”\n Apel destructor clasa Autoutilitar \n”;} cout<<”\n Date autoturism:\n”;
void afisare() A.afisare();
{Vehicul::afisare(); getch();
cout<<”\n Tip transport:”<<tip_transport; cout<<”\n Date motocicleta:\n”;
cout<<”\n Viteza maxima: M.afisare();
”<<viteza_max<<”\n”; getch();
} cout<<”\n Date autoutilitara:\n”;
double getVitezaMax(){ return viteza_max;} B.afisare();
char *getTipTransport(){ return tip_transport; getch();
} cout<<”\n Date masina de teren:\n”;
}; C.afisare();
class Auto_teren:public Autoturism getch();
{int capacitate; cout<<”\n Date masina de familie:\n”;
char tractiune[30]; D.afisare();
public: Auto_teren(int Nr, char *A, int Loc, char *F, getch();
int C, char*Trac):Autoturism(Nr,A,Loc,F), clrscr();
capacitate(C) cout<<”\n Vehiculul are “<<V.getNrRoti()<<” si
{strcpy(tractiune, Trac);} este
~Auto_teren() alimentat pe “<<getAlimentare(V)<<”\n”;
{cout<<”\n Apel destructor clasa Auto_teren \n”; cout<<”\n Autoturimul are
} “<<A.getNrLocuri()<<” locuri si
void afisare() este produs de “<<A.getFirma()<<”\n”;
{Autoturism::afisare(); cout<<”\n Motocicleta costa ”<<M.getPret()<<”
cout<<”\n Capacitate cilindrica:”<<capacitate; lei \n”;
cout<<”\n Tip tractiune:”<<tractiune<<”\n”; M.setKm(2350);
} M.afisare();
int getCapacitate(){ return capacitate;} cout<<”\n Autoutilitara este de
char *getTractiune(){ return tractiune;} ”<<B.getTipTransport()<<” si
}; are viteza maxima de ”<<B.getVitezaMax()<<”\n”;
class Auto_familie:public Autoturism cout<<”\n Masina de teren are o capacitate de
{char accesorii[40]; ”<<C.getCapacitate()<<” si
int nr_airbag; ”<<C.getTractiune()<<”\n”;
public:Auto_familie(int Nr, char *A, int Loc, char cout<<”\n Masina de familie are ca accesorii
*F, char*Acc, int AirB):Autoturism(Nr,A,Loc,F), ”<<D.getAccesorii()<<” si un numar de
nr_airbag(AirB) ”<<D.getAirbag()<<”\n”;
{ getch(); }
Exemplu 2:
#include<iostream.h> cout<<”\n Domeniu:”<<domeniu<<”\n”;
#include<string.h> }
#include<conio.h> char *getTip(){ return tip;}
class Persoana char*getDomeniu(){return domeniu;}
{ };
char nume[20]; class Angajat:public Persoana,
char prenume[30]; public Cont_bancar,
public: Persoana(char *N, char*P) public Institutie
{strcpy(nume, N); {int vechime;
strcpy(prenume, A); double salariu;
} public:
~Persoana() Angajat(char *N, char*P, double S, char *M,
{cout<<”\n Apel destructor clasa Persoana \n”; char*T,
} char*D, int V, double Sal):Persoana(N,P),
void afisare() Cont_bancar(S,M), Institutie(T,D)
{cout<<”\n Nume:”<<nume; {vechime=V;
cout<<”\n Prenume:”<<prenume<<”\n”; Salariu=Sal;}
} ~Angajat()
char *getNume() {cout<<”\n Apel destructor clasa Angajat \n”;}
{ return nume; void afisare()
} {Persoana::afisare();
char*getPrenume() Cont_bancar::afisare();
{return prenume; Institutie::afisare();
} cout<<”\n Vechime in munca:”<<vechime;
}; cout<<”\n Salariu lunar:”<<salariu<<\n”;
class Cont_bancar }
{ int getVechime(){ return vechime;}
double suma; void setSalariu(double Sal){ salariu=Sal;}
char moneda[10]; };
public: Cont_bancar(double S, char*M) void main()
{suma=S; {Persoana A(”Dima”,”Claudia);
strcpy(moneda, M); Cont_bancar B(2350.45,”Lei”);
} Institutie C(”public”,”financiar”);
~Cont_bancar() Anagajat D(”Teodorescu”,
{cout<<”\n Apel destructor clasa Cont_bancar ”Simion”,1587,”Euro”,”privat”,
\n”; ”petrolier”);
} cout<<”\n Date persoana:\n”;
void afisare() A.afisare();
{ getch();
cout<<”\n Suma din cont:”<<suma; cout<<”\n Date cont bancar:\n”;
cout<<”\n Moneda:”<<moneda<<”\n”; B.afisare();
} getch();
void setSuma(double S){ suma=S; cout<<”\n Date institutie:\n”;
} C.afisare();
char*getMoneda(){return moneda; getch();
} cout<<”\n Date angajat:\n”;
}; D.afisare();
class Institutie getch();
{ clrscr();
char tip[20]; cout<<”\n Angajatul
char domeniu[30]; “<<D.getNume()<<”\t”<<D.getPrenume()<<” are
public:Institutie(char *T, char*D) cont in
{strcpy(tip, T); “<<D.getMoneda();
strcpy(domeniu, D); cout<<”\n Angajatul lucreaza la o institutie de tip
} “<<D.getDomeniu()<<” in domeniul
~Institutie() “<<D.getTip();
{cout<<”\n Apel destructor clasa Insitutie \n”; cout<<”\n Angajatul are o vechime
} de“<<D.getVechime()<<” ani \n”;
void afisare() getch();
{cout<<”\n Tip insitutie:”<<tip; }
Polimorfismul
Obiecte si functii polimorfice
Termenul de polimorfism se referă în general la “o singură interfaţă, mai multe comportamente“. Un
obiect polimorfic este acea entitate căreia i se permite să păstreze valori de tipuri diferite în timpul execuţiei
programului. În POO polimorfismul este implementat cu ajutorul funcţiilor virtuale. La baza acestor funcţii şi a
polimorfismului în momentul execuţiei se află variabilele de tip pointer care punctează la clasele derivate.
Mecanismul funcţiilor virtuale este următorul: dacă într-o clasă de bază este declarat un pointer care punctează spre
acesta, pointerul respectiv poate fi folosit pentru a puncta şi la alte clase derivate din clasa de bază.
Exemplu:
class NumeClasaBaza void main()
{ {
//membrii clasei de baza NumeClasaBaza *ptr; //pointer la clasa de baza
}; NumeClasaDerivata1 ob //obiect al clasei derivate1
class NumeClasaDerivata1 NumeClasaDerivata2 ob2 //obiect al clasei derivate2
{ ptr=&ob1 //pointerul ptr puncteaza la un obiect din
//membrii clasei derivate1 clasa
}; derivate 1
class NumeClasaDerivata2 ptr=&ob2; //pointerul ptr puncteaza la un obiect din
{ clasa
//membrii clasei derivate2 derivate 1
}; }

Legarea statica si legarea dinamica


În limbajele de programare, legarea (statică sau dinamică) se referă la mecanismul prin care un nume sau o
expresie este asociată unui atribut (variabilă) şi tipul valorii pe care îl poate conţine variabila respectivă. În cazul în
care legarea se produce în momentul compilării, legarea este de tip statică sau timpurie. Dacă legarea are loc în
momentul execuţiei legarea este de tip dinamic sau târzie. Polimorfismul presupune legare dinamică, prin apelul
funcţiilor virtuale.
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.
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.

Functii virtuale
Funcţiile virtuale sunt identificate cu ajutorul cuvântului cheie virtual şi au următoarea sintaxă:
virtual tip nume_functie(lista parametri);
Caracteristici:
o Funcţiile nemembre, funcţiile membre statice şi cele inline nu pot fi declarate funcţii virtuale;
o Dacă o funcţie este declarată virtuală în clasa de bază, ea trebuie redefinită în clasele derivate din clasa de bază
respectivă;
o Funcţiile declarate virtuale în clasa de bază şi redefinite cu acelaşi prototip în clasele derivate sunt automat
identificate ca fiind virtuale, astfel încât specificatorul virtual poate lipsi;
o Constructorii nu pot fi funcţii virtuale, în schimb destructorii pot fi.

Clase abstracte
O funcţie virtuală care este doar declarată, nu şi definită, iar iniţializarea ei se face cu valoarea 0 este o
funcţie virtuală pură. Compilatorul este înştiinţat astfel că acea funcţie din clasa de bază nu are corp (fiind
iniţializată cu 0), şi prin urmare nu se pot crea obiecte din acea clasă de bază. O clasă care conţine o funcţie
virtuală pură este o clasă abstractă şi, neavând instanţieri (obiecte) nu este proiectată pentru crearea obiectelor,
fiind o clasă generică. Din clasa abstractă se pot deriva clase noi care vor redefini funcţia virtuală pură existentă în
clasa de bază. Clasele abstracte sunt folosite pentru crearea ierarhiilor de clase, având un grad sporit de
generalitate, permiţând astfel definirea de caracteristici comune pentru întreaga familie de clase.
Sintaxa declarării unei funcţii virtuale pure:
class NumeClasaAbstracta
{
public: NumeClasaAbstracta()
{ //…
}
virtual tip nume_functie_pura()=0;
};
Exemplu:
#include<iostream.h> {
class Figura_geometrica class Triunghi : public Forma_geometrica{
{ public: double aria()
private: double dim1, dim2; {
public: void init_dimensiuni(double x1, double x2) double d1, d2;
{ actualizareDim(d1, d2);
dim1 = x1; dim2 = x2; return 0.5*d1*d2;
} }
virtual double aria()=0; //Functie care trebuie };
redefinita in clasele derivate void main()
void actualizareDim(double &x1, double &x2) {
{ Forma_geometrica *ptr;
x1 = dim1; x2 = dim2; Dreptunghi Ob1;
} Triunghi ob2;
}; Ob1.init_dimensiuni(2.5, 1.5);
class Dreptunghi : public Forma_geometrica Ob2.init_dimensiuni(3.5, 7.5);
public: double aria() ptr = &Ob1;
{ cout << "\n Aria dreptunghiului este: " << ptr-
double d1, d2; >aria();
actualizareDim(d1, d2); ptr = &Ob1;
return d1*d2; cout << "\n Aria triunghiului este:" << ptr->aria();
} }
};

Observatii:
-o clasă abstractă nu poate fi transferată prin valoare şi nu poate fi returnată de către o funcţie.
-o modalitate de transfer este prin intermediul pointerilor şi a referinţelor, dar numai pentru a putea fi
posibilă implementarea polimorfismului.

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