Documente Academic
Documente Profesional
Documente Cultură
2. CLASE I OBIECTE
2.1. Definiia claselor, acces la membri i timp de via
2.2. Instanierea claselor 2.6. Funcii inline
2.3. Membrii unei clase 2.7. Constructori i destructori
2.4. Pointerul this 2.8. Tablouri de obiecte
2.5. Domeniul numelui, vizibilitate 2.9. Funcii prietene (friend)
Aa cum s-a subliniat n capitolul anterior, o clas reprezint un tip abstract de date, care
ncapsuleaz att elementele de date (datele membre) pentru care s-a adoptat un anumit mod
de reprezentare, ct i operaiile asupra datelor (funciile membre sau metode). n limbajul
C++, structurile i uniunile reprezint cazuri particulare ale claselor, putnd avea nu numai
date membre sau cmpuri de date, dar i funcii membre. Singura diferen ntre structuri i
uniuni const n faptul c la uniuni, pentru memorarea valorilor datelor membre se folosete -
n comun - aceeai zon de memorie. Deosebirea esenial ntre structuri i uniuni - pe de o
parte - i clase - pe cealat parte - const n modul de acces la membri: la structuri i uniuni
membrii (datele i metodele) sunt implicit publici, iar la clase - implicit privai (membrii sunt
ncapsulai). Lipsa unor modaliti de protecie a datelor face ca tipurile de date introduse prin
structuri sau uniuni s nu poat fi strict controlate n ceea ce privete operaiile executate
asupra lor. n cazul claselor, modul de acces la membrii tipului de date (n scopul protejrii
acestora) poate fi schimbat prin utilizarea modificatorilor de control ai accesului: public,
private, protected.
Modul de declarare a unei clase este similar celui de declarare a structurilor i a uniunilor:
class [<nume_tip>]{
<modificator_control_acces>:
<lista_declaraii_membri>;
} [<lista_variabile>];
Modificatorul de acces public se utilizeaz pentru membrii care dorim s fie neprotejai,
ultimii doi modificatori asigurnd protecia membrilor din domeniul de aciune a lor. Membrii
cu acces private pot fi accesai numai prin metodele clasei (sau prin funciile prietene,
capitolul 2.4.). Cei cu acces protected posed caracteristicile celor privai iar, n plus, pot fi
accesai i din clasele derivate. Specificatorii modului de acces pot apare n declararea clasei
de mai multe ori, n orice ordine.
Domeniul unui modificator de acces ine din punctul n care apare modificatorul respectiv,
pn la sfritul declaraiei clasei sau al ntlnirii altui modificator de acces (exemplele 1,2).
Observaie: n limbajul C++, n cazul tipurilor de date definite cu ajutorul structurilor, se pot
aplica modificatorii de acces. n cazul tipurilor definite cu ajutorul uniunilor, accesul implicit
(public) nu poate fi modificat.
Exemplu:
class masina{
char *culoare; // dat membru la care accesul este, implicit, private
int capacit_cil; // dat membru la care accesul este, implicit, private
public:
void citire_date();
//metod cu acces public, care permite introducerea datelor despre o instan a clasei
int ret_capacit(); //metod cu acces public
};
Exemplu:
class persoana{
char *nume; //dat membru privat
public:
void citire_inf_pers(); //metod public
private:
int varsta; //dat membru privat
};
int main()
{ dreptunghi a;
double l1, l2; cout<<"Lungime="; cin>>l1;
cout<<"Latime="; cin>>l2; a.seteaza_dimen(l1, l2);
// sau: Lung=l1; lat=l2;
cout<<"Dimensiunile dreptunghiului sunt:";
cout<<a.arata_Lung();
cout<<" si"<<a.arata_Lat()<<'\n';
cout<<"Aria dreptunghiului:"<<a.calcul_arie()<<'\n';
cout<<"Dimens structurii:"<<sizeof(a)<<'\n';
}
int main()
{ dreptunghi a; double l1, l2;
cout<<"Lungime="; cin>>l1; cout<<"Latime="; cin>>l2;
a.seteaza_dimen(l1, l1);
cout<<"Lung. drept:"<<a.arata_Lung()<<'\n';
double s1=a.arata_Lung(); a.seteaza_dimen(l2, l2);
cout<<"Latimea dreptunghiului este:";
cout<<a.arata_Lat()<<'\n';
cout<<"Aria dreptunghiului:"<<a.calcul_arie(s1)<<'\n';
cout<<"Dimens. uniunii:"<<sizeof(dreptunghi)<<'\n';
}
Nespecificnd nici un modificator de control al accesului, toi membrii (date i metode) sunt
implicit publici. De aceea, de exemplu, atribuirea unei valori pentru data membr Lung se
putea realiza, la fel de bine, n corpul funciei main, astfel: Lung=l1; (n exerciiul 1a,
atribuirea se realizeaz cu ajutorul metodei seteaza_dimen).
Observaii:
1. Pentru fiecare membru (dat membru sau metod) al unei clase se poate specifica modul
de control al accesului. Membrii publici (vizibili, accesibili din exterior) constituie
interfaa public a clasei, iar membrii privai (ncapsulai, ascuni) ofer descrierea datelor
membre ale fiecrei instane a clasei i detalii de implementare particulare clasei
respective.
2. Reamintim c, pentru a indica faptul c metoda seteaz_dimen aparine tipului
dreptunghi, se folosete operatorul scop :: (de apartenen). Astfel, la definirea
metodei, prototipul ei va fi:
void dreptunghi::seteaza_dimen(double L, double l);
3. A defini o clas presupune declararea acesteia i definirea tuturor metodelor sale.
Exerciiul 1: S se defineasc tipul de date data, cu ajutorul unei structuri i a unei clase.
void data::afiseaza()
{ char *den_lun[] = {
"Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie",
"Iulie","August","Septembrie","Octombrie","Noiembrie",
"Decembrie"};
cout << den_lun[luna-1] << " " << zi << ", " << an; }
main()
{ data dat_nast= {4, 6, 1980};
cout << "\nData de nastere a lui Andrei este ";
dat_nast.afiseaza();
int a,z,l;
cout<<"Ziua in care te-ai nascut:"; cin>>z;
cout<<"Luna in care te-ai nascut:"; cin>>l;
cout<<"Anul in care te-ai nascut:"; cin>>a;
data dat_nast_ta = {l, z, a};
cout << "\nData nasterii tale este: "; dat_nast_ta.afiseaza();
}
void data::afiseaza()
{ char *den_lun[] = {
"Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie",
"Iulie","August","Septembrie","Octombrie","Noiembrie",
"Decembrie"};
cout << den_lun[luna-1] << " " << zi << ", " << an; }
main()
{ data dat_nast;
dat_nast.initializare(4, 6, 1980);
cout << "\nData de nastere a lui Andrei este ";
dat_nast.afiseaza();
int a,z,l;
cout<<"Ziua in care te-ai nascut:"; cin>>z;
Observaii:
1. n ambele situaii, n funcia main se declar instanele data_nast i dat_nast_ta.
2. n primul caz tipul este introdus cu ajutorul unei structuri la care membrii sunt, implicit,
publici. De aceea, iniializarea se poate face, direct, n funcia main.
3. n al doilea caz, datele membre sunt implicit private i de aceea, iniializarea lor se poate
realiza doar prin intermediul metodei initializare, apelat pentru fiecare instan a
clasei.
Lung d.Lung
lat d.lat
d
Metodele figureaz ntr-un singur exemplar, oricte instane ale clasei ar exista.
PROGRAMAREA ORIENTATA PE OBIECTE, CURS Autor: Diana tefnescu
22
CAPITOLUL 2 Clase i obiecte
n exemplul anterior, metoda seteaza_dimen este doar declarat n interiorul clasei, fiind
abia apoi definit. La definirea funciei
(void dreptunghi::seteaza_dimen(double L, double l)) s-a folosit operatorul
:: (scope resolution operator) care specific relaia de apartenen a metodei la tipul
dreptunghi.
Operatorul cupleaz <nume_clasa>::<nume_functie_membru> i definete
domeniul (scopul) n care acea funcie va fi recunoscut. Prezena numelui clasei n faa
funciei membru este obligatorie, deoarece, altfel nu s-ar putea face distincia ntre metode cu
nume identice (cu acelai prototip), care aparin unor clase diferite.
n plus, metodele statice pot fi apelate independent de un obiect al clasei, folosind operatorul
de rezoluie (::).
Accesul la o metod presupune o activitate de adresare, transparent utilizatorului. De fapt, n
interiorul obiectului creat se afl doar punctatori la clasa din care provin. n interiorul
definiiei clasei se aloc o singur copie a fiecrei funcie membr i punctatorii respectiv,
prin care obiectul va avea acces la metoda respectiv. Excepia de la aceast regul o
constituie metodele virtuale (capitolul 4).
class dreptunghi{
double Lung, lat;
public:
void seteaza_dimen(double, double );
double arata_Lung();
double arata_Lat();
double calcul_arie();
};
//..
main()
{ dreptunghi a;
//
cout<<"Aria dreptunghiului:"<<a.calcul_arie()<<'\n';
dreptunghi *pa;
pa=&a;
double arie=pa->calcul_arie(); }
#include <iostream.h>
class Data {
int luna, zi, an;
public:
void initializ(int l, int z, int a) {luna=l; zi=z; an=a; }
int get_an() { return an; } // functie membra care returneaza anul
int get_luna() { return luna; } // functie membra care returneaza luna
int get_zi() { return zi; }
int& an_data() { return an; } /* functie membra care permite
schimbarea valorii datei membre an */
PROGRAMAREA ORIENTATA PE OBIECTE, CURS Autor: Diana tefnescu
23
CAPITOLUL 2 Clase i obiecte
main()
{ Data dt; dt.initializ(4, 1, 89);
cout << "\nAnul este: " << dt.get_an();
cout << "\nZiua este: " << dt.get_zi();
cout << "\nLuna este: " << dt.get_luna();
// ------ folosirea metodelor care schimba anul, luna si ziua pentru instanta dt
dt.an_data() = 90;dt.luna_data()=12; dt.zi_data()=31;
cout << "\nNoul an este: " << dt.get_an();
cout << "\nNoua luna este: " << dt.get_luna();
cout << "\nNoua zi este: " << dt.get_zi(); }
#include <iostream.h>
#include <conio.h>
class exemplu
{ int i; // dat membr privat, acces la ea doar prin metode
public:
static int contor;
// dat membr publica,
//neprotejat (scop didactic)
void inc(void)
{i++;}
void arata_i()
{cout<<"i="<<i<<'\n';} exemplu::contor a1.i
void inc_contor(void)
{contor++;}
a2.i
void init(void)
{i=0;}
static void arata_contor() a3.i
{cout<<"Contor=";
cout<<contor<<'\n';}
static void functie(exemplu*);
} a1, a2, a3;
main()
{
a1.init(); a2.init(); a3.init(); //a1.i=0, a2.i=0, a3.i=0
a1.arata_i();a2.arata_i();a3.arata_i(); //i=0, i=0, i=0
Din exemplul anterior, se poate observa c metoda static funcie poate fi apelat ca o
metod obinuit, sau folosind operatorul ::. Pentru data membr static contor se rezerv
o zon de memorie comun obiectelor a1, a2, a3. Pentru data membr i se realizeaz o
copie pentru fiecare instan a clasei. Deasemenea, deoarece data membr contor este
static, nu aparine unui anume obiect, ea apare prefixat de numele clasei i operatorul de
apartenen.
#include <iostream.h>
class ex_mstat{
int a; static double s; ex_mstat::s
public:
int ret_a()
{return a;}
void set_a(int x) a a
{a=x;} p q
static double ret_s()
{return s;}
static void set_s(double x)
{s=x;} Figura 2.3. Alocarea memoriei pentru
void set1_s(double x) membrii clasei ex_mstat
{s=x;}
double ret1_s()
{return s;}
};
double ex_mstat::s;
/*se rezerv spaiu n memorie pentru data membr static s, care figureaz ntr-un singur
exemplar pentru toate instaele clasei ex_mstat (figura 2.3.)*/
main()
{ex_mstat p,q;
p.set_a(100);
p.set_s(200); q.set_a(300);
cout<<"p.a="<<p.ret_a()<<" p.s="<<p.ret_s();
cout<<" ex_mstat::ret_s="<<ex_mstat::ret_s()<<'\n';
PROGRAMAREA ORIENTATA PE OBIECTE, CURS Autor: Diana tefnescu
25
CAPITOLUL 2 Clase i obiecte
Aa cum se observ din exemplul anterior, data membru static s figureaz ntr-un singur
exemplar pentru instanele p i q. Ea poate fi modificat prin metoda static set_s sau prin
metoda set1_s.
Apelul unei metode statice poate fi realizat ca un apel al unei metode obinuite:
p.ret_s(), sau folosind operatorul de rezoluie: ex_mstat::ret_s(). Datorit ultimului
mod de apel, n care metoda static nu este asociat unui obiect anume, n corpul funciilor
statice, nu pot fi accesate dect datele membre statice.
Observaie: Nu trebuie confundai membrii statici ai unei clase cu datele care au clasa de
memorare static.
Exemplu:
class dreptunghi{
double Lung, lat;
public:
//..
void seteaza_dimen(double, double);
};
Dac un nume care are ca domeniu un fiier este redefinit ntr-un bloc inclus n domeniul su,
el poate fi folosit n acest bloc dac este precedat de operatorul rezoluie.
Exemplu:
#include <iostream.h>
int i=80; // i declarat n afara oricrei funcii, domeniul numelui este fiierul
main()
{double i=99.9; // redeclararea variabilei i , ncepe domeniul local
cout<<"Valoarea lui i="<<i<<'\n'; // Valoarea lui i=80
cout<<"Valoarea lui i="<<::i<<'\n'; } // Valoarea lui i=99.9
Domeniul numelui unui tip de date definit printr-o clas (structur sau uniune, deoarece
acestea sunt cazuri particulare de clase, cu toi membrii publici) se stabilete n mod similar
domeniului oricrei variabile. Numele unui membru al unei clase are un domeniu de tip
clas. Ca orice nume, un nume de clas poate fi redeclarat.
Exemplu:
class a{
//
};
//..
{ //instruciune bloc aflat n domeniul numelui a
double a=99; //redeclararea lui a
class::a x; //x este un obiect de tipul a (definit printr-o clas)
}
2.5.2. Vizibilitate
Timpul de via a unei variabile (obiect) este determinat de clasa de memorare a variabilei
(obiectului. n limbajul C++, alocarea dinamic a memoriei se realizeaz cu operatorii new i
delete (vezi i capitolul 3).
Prezena funciilor inline anun compilatorul s nu mai genereze instruciunile n cod main
necesare apelului i revenirii, ceea ce conduce la mrirea timpului de compilare n favoarea
micorrii timpului de execuie. Utilizarea funciilor inline se justific doar n situaiile n care
codul generat de compilator pentru execuia corpului funciei este mai mic dect codul generat
pentru apel i revenire.
Practic, funciile care au corpul format din maximum trei instruciuni i nu conin instruciuni
repetitive (for, while, do-while), pot fi declarate inline. Declararea unei funcii
inline se realizeaz explicit, specificnd n antetul funciei respective cuvntul cheie inline.
inline <tip_val_ret> <nume_fct> (<lista_declar_par_formali>);
n cazul metodelor unei clase, dac acestea sunt definite n interiorul clasei, ele sunt
considerate, implicit, funcii inline (n exerciiul anterior, funciile arat_Lung, arat_Lat
i calcul_arie sunt, implicit, funcii inline).
Exemplu: Dac se dorete ca metoda seteaza_dim din exerciiul anterior s fie funcie
inline, fr a modifica declaraia tipului dreptunghi, se poate proceda astfel:
class dreptunghi{
// . . .
public:
// . . .
void seteaza_dimen(double, double );// declararea metodei
// . . .
};
inline void dreptunghi::seteaza_dimen(double L, double l)
//funcie inline, explicit
{Lung=L; lat=l;}
Exerciiu: S se defineasc tipul de date complex, cu datele membru parte real i parte
imaginar. Operaiile care pot fi realizate asupra datelor de acest tip, vor fi:
Citirea unei date de tip complex (citirea valorilor pentru partea real i cea imaginar);
afiarea unei date de tip complex; calculul modulului unui complex; calculul argumentului
unui complex; incrementarea prii imaginare; decrementarea prii imaginare; funcii care
returneaz valoarea prii reale i a prii imaginare a unei date de tip complex; adunarea a
dou date de tip complex; nmulirea a dou date de tip complex.
#include <iostream.h>
#include <math.h>
#define PI 3.14159
class complex{
double real, imag;
public:
int citire();
void afisare();
double modul();
double arg();
void incrpi() /*incrementeaza partea imaginara; FUNCIE INLINE, implicit,
fiind definit n interiorul clasei */
{ imag++;}
inline void decrpi(); //decrementarea partii imaginare
double retreal(); //returneaza partea reala
double retimag(); //returneaza partea imaginara
void adun_c(complex, complex); //aduna 2 numere complexe
void inm_c(complex*, complex*); //produsul a 2 numere complexe
};
double complex::retimag()
{ return imag; }
void complex::adun_c (complex x1, complex x2)
{real=x1.real+x2.real;
imag=x1.imag+x2.imag;}
void complex::inm_c(complex *x1, complex *x2)
{real=x1->real*x2->real-x1->imag*x2->imag;
imag=x1->real*x2->imag+x1->imag*x2->real;}
main()
{complex z1;z1.citire();cout<<"z1=";z1.afisare();
complex z2;z2.citire();cout<<"z2=";z2.afisare();
cout<<"Modulul z2="<<z2.modul()<<'\n';
cout<<"Agument z2="<<z2.arg()<<'\n';
cout<<"P. reala z2="<<z2.retreal();
cout<<"P imag z2="<<z2.retimag()<<'\n';
z2.incrpi();cout<<"Dupa increm p imag=";
cout<<z2.retimag()<<'\n';z2.afisare();
complex z3;z3.adun_c(z1,z2);cout<<"Adunare z1+z2=";z3.afisare();
complex*pz1=&z1,*pz2=&z2;z3.inm_c(pz1,pz2);
cout<<"Inmultire z1+z2=";z3.afisare();}
La declararea datelor de tip predefinit sau definit de utilizator prin structuri, uniuni sau clase,
compilatorul aloc o zon de memorie corespunztoare tipului respectiv. Este indicat ca n
cazul n care datele structurate au ca membrii pointeri, s se aloce memorie n mod dinamic.
n general, datele statice sunt iniializate automat cu valoarea 0. Celelalte categorii de date, nu
sunt iniializate. Iniializarea datelor simple de tip predefinit se poate realiza dup declararea
acestora, sau n momentul declarrii.
Exemple:
int i; i=30; // declararea variabilei i, apoi iniializarea ei prin atribuire
char c='A'; // declararea i iniializarea variabilei c
Iniializarea datelor structurate se poate realiza n momentul declarrii acestora, prin listele de
iniializare.
Exemple:
//1 declararea i iniializarea vectorului a
int a[]={20, 30, 40, 50};
//2 declararea i iniializarea matricii m
double m[2][3]={{1.1,2.2,3.3}, {11.11,22.22,33.33}};
//3
struct pers{
char nume[20]; int varsta; double salariu;
}p={"Popescu", 20, 3000000};
n cazul tipurilor de date definite cu ajutorul claselor, care au date membru private, listele de
iniializare nu pot fi utilizate. Pentru a elimina aceste neajunsuri, limbajul C++ ofer
mecanismul constructorilor i al desctructorilor.
2.7.2. CONSTRUCTORI
Constructorii sunt metode speciale care folosesc la crearea i iniializarea instanelor unei
clase. Constructorii au acelai nume ca i clasa creia i aparin i sunt apelai de fiecare dat
cnd se creaz noi instane ale clasei. Constructorii asigur iniializarea corect a tuturor
variabilelor membre ale obiectelor unei clase i constituie o garanie a faptului c iniializarea
unui obiect se realizeaz o singur dat. O clas poate avea mai muli constructori (exemplul
3), care difer ntre ei prin numrul i tipul parametrilor acestora. Acest lucru este posibil
deoarece limbajul C++ permite supradefinirea (overloading) funciilor.
Proprietile constructorilor:
Constructorii au acelai nume ca i numele clasei creia i aparin;
Nu ntorc nici o valoare (din corpul lor lipsete intruciunea return <expr>; n antetul
constructorilor nu se specific niciodat - la tipul valorii returnate - cuvntul cheie void);
Constructorii unei clase nu pot primi ca parametri instane ale clasei respective, ci doar
pointeri sau referine la instanele clasei respective;
Apelul constructorului se realizeaz la declararea unui obiect;
Adresa constructorilor nu este accesibil utilizatorului;
Constructorii nu pot fi metode virtuale (capitolul 4);
n cazul n care o clas nu are nici constructor declarat de ctre programator,
compilatorul genereaz un constructor implicit, fr nici un parametru, cu lista
instruciunilor vid. Dac exist un constructor al programatorului, compilatorul nu mai
genereaz constructorul implicit (exemplul 2);
Parametrii unui constructor nu pot fi de tipul definit de clasa al crei membru este
constructorul.
Ca orice alt funcie n limbajul C++, constructorii pot avea parametri implicii, fiind numii
constructori implicii. Varianta constructorului cu parametri implicii poate fi adoptat n toate
cazurile n care constructorul nu necesit argumente. Dac toi parametrii unui constructor
sunt implicii, apelul constructorului are forma unei simple declaraii (exemplul 1).
Constructorii pot fi apelai i n mod explicit (exemplul 1). n cazul n care
Exemplul1: Pentru clasa complex s-a definit un constructor cu parametri implicii; din acest
motiv s-a putut face declaraia "complex z1;". n ultima linie a programului, pentru
obiectul z4, constructorul este apelat n mod explicit.
class complex
{ double real,imag;
public: complex(double x=0, double y=0); // Constructor implicit
};
complex::complex(double x, double y)
{real=x; imag=y; }
main()
{complex z1; //z1.real=0, z1.imag=0
complex z2(1); //z2.real=1, z2.imag=0
complex z3(2,4); //z3.real=2, z3.imag=4
complex z4=complex(); //apel explicit al constructorului
}
Exemplul2: Pentru clasa complex exist un constructor explicit, compilatorul nu mai creeaz
unul implicit.
class complex
{ double real,imag;
public:
complex(double x,double y) // funcie constructor inline
{ real=x; imag=y;}
};
main()
{complex z1(2,3);
complex z; // Eroare : nu exist constructor implicit
}
Exemplul3: Definirea unui constructor implicit vid, care se va apela la instanierea obiectelor
neiniializate.
#include<iostream.h>
class data{
int zi,luna,an;
public:
data() { } // constructor implicit vid
data(int z,int l,int a) // constructor cu parametri
{ zi=z;luna=l;an=a; }
};
main()
{data d; // apelul constructorului vid
data d1(12,11,1998); // apelul constructorului cu parametri
}
PROGRAMAREA ORIENTATA PE OBIECTE, CURS Autor: Diana tefnescu
32
CAPITOLUL 2 Clase i obiecte
n exemplele anterioare, constructorii iniializau membrii unui obiect prin atribuiri. Exist i
modalitatea de a iniializa membrii printr-o list de instaniere (iniializare), care apare n
implementarea constructorului, ntre antetul i corpul acestuia. Lista conine operatorul :,
urmat de numele fiecrui membru i valoarea de iniializare, n ordinea n care membrii apar
n definiia clasei.
main()
{ complex z1(1,3),z2(2,3); }
// Sau:
class complex {
double real,imag;
public:
complex(double x, double y) :real(x),imag(y) { }
//constructor cu list de iniializare
};
Pentru o clas, se poate defini un contructor de copiere, care s permit copierea obiectelor.
Deoarece parametrii unui constructor nu pot fi de tipul definit de clasa al crei membru este,
constructorul de copiere pentru clasa cu numele cls, are, de obicei, prototipul:
<cls> (const <cls> &);
Parametrul transmis prin referin este obiectul a crui copiere se realizeaz, modificatorul de
acces const interzicnd modificarea acestuia. Constructorul de copiere poate avea i ali
parametri, care trebuie s fie implicii.
Dac programatorul nu definete un constructor de copiere, compilatorul genereaz un
asemenea constructor, implicit.
n situaiile n care un tip de date are ca membrii pointeri, este necesar implementarea unui
constructor pentru iniializare (este de dorit s se aloce dinamic memorie) i a unui
constructor de copiere.
Exemplu: Exemplul urmtor, n care se definesc tipurile de date Punct i Linie, ilustreaz
utilizarea constructorilor (cu parametri implicii, de copiere, cu liste de iniializare) definii de
programator.
#include <iostream.h>
class Punct
{public:
Punct(double _x=0.0, double _y=0.0)// Constructor cu parametri impliciti
{ x = _x; y = _y; }
PROGRAMAREA ORIENTATA PE OBIECTE, CURS Autor: Diana tefnescu
33
CAPITOLUL 2 Clase i obiecte
class Linie
{public:
Linie(const Punct& b, Punct& e) : p1(b), p2(e) {}
//Constructor cu lista initializare
void afiseaza();
private:
Punct p1, p2; //Datele membre private: cele 2 puncte care determina dreapta
};
void Punct::afiseaza()
{ cout << "(" << x << " , " << y << ")"; }
void Linie::afiseaza()
{ cout << "Linie determinata de punctele: ";
p1.afiseaza(); p2.afiseaza(); cout <<\n; }
main()
{
Punct a=(10.,15.), b=(20.,30.); a.afiseaza(); b.afiseaza();
Linie l1(a,b); l1.afiseaza(); }
2.7.3. DESTRUCTORI
Destructorii sunt metode ale claselor care acioneaz n sens invers, complementar, fa de
constructori.
Constructorii sunt folosii pentru alocarea memoriei, iniializarea datelor membru sau alte
operaii (cum ar fi, incrementarea unui contor pentru instanele clasei). Constructorul este
apelat n momentul declarrii obiectelor.
Destructorul elibereaz memoria alocat de constructori. Destructorul este apelat automat, la
ieirea din blocul n care este recunoscut acel obiect.
Proprietile destructorilor
Destructorul are acelai nume ca i clasa a cror metod este;
Numele destructorului este precedat de semnul ~;
O clas are un singur destructor;
Destructorul nu are parametri i nu returneaz nici o valoare (antetul nu conine cuvntul
cheie void, iar n corpul destructorului nu apare instruciunea return <expresie>;);
Dac programatorul nu a definit un destructor, compilatorul genereaz automat un
destructor pentru clasa respectiv;
Destructorii se apeleaz la ncheierea timpului de via a obiectelor, n ordine invers
apelurilor constructorilor;
Obiectele dinamice nu se distrug automat, deoarece doar programatorul tie cnd nu mai
este necesar un astfel de obiect.
class Timp
{public:
Timp() { start = clock();} // Constructor
~Timp() // Destructor (calculeaza si afiseaza timpul, in secunde)
{ clock_t stop = clock();
cout << "Timpul = "; cout << (stop - start)/CLK_TCK;
cout << " secunde" << \n; }
private:
clock_t start; // porneste masurarea timpului
};
#endif
main()
{ unsigned long val_cont; cout << "Valoare finala: ";
cin >> val_cont; functie(val_cont);
}
Observaii: Clasa Timp are data membru privat start (de tipul clock_t), constructor i
destructor. Constructorul (definit de programator), n momentul apelului (la declararea
obiectului t n funcia functie), iniializeaz data membr cu valoarea returnat de funcia
clock (deci, momentul nceperii execuiei corpului funciei). Se execut prelucrrile din
corpul funciei (calculul valorilor variabilelor a, b, c i d pentru fiecare valoare a contorului
i). La ieirea din funcie, este apelat destructorul (definit de programator) clasei Timp (se
distruge obiectul t, variabil local funciei). Astfel, n variabila stop, variabil local
destructorului, se memoreaz valoarea returnat de funcia clock (deci timpul momentului de
ncheiere a execuiei corpului funciei funcie). Diferena ntre cele 2 evenimente (nceputul
execuiei corpului funciei funcie i sfritul acesteia) este transformat n secunde i afiat.
Exerciiul 2:
S se defineasc tipul punct, cu datele membre x i y, reprezentnd abscisa i ordonata unui
punct. Operaiile care pot fi realizate asupra obiectelor de tip punct, sunt: afiare (afieaz
coordonatele unui punct), deplasare (deplaseaz un punct, noile coordonate ale punctului
fiind obinute prin adunarea unor valori transmise ca parametri, la valorile anterioare ale
coordonatelor), abscisa (returneaz valoarea abscisei), ordonata (returneaz valoarea
ordonatei). Se vor implementa, deasemenea, constructor cu parametri implicii, constructor
avnd ca parametri valorile abscisei i a ordonatei, constructor de copiere i destructor.
#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
//CLASA PUNCT
class punct
{ double x,y;
public:
punct()
{x=0;y=0;
cout<<"Constr. implicit pentru punct("<<x<<","<<y<<")\n";}
//constructor initializare
punct(double,double);
punct(punct&); //constructor copiere
~punct(); //destructor
double abscisa(){return x;}
double ordonata(){return y;}
void afisare();
void deplasare(double,double);
};
//CLASA SEGMENT
class segment
{private:
punct A,B;
public:
segment(punct&,punct&); //constructor
segment(segment&); //constructor copiere
~segment(); //destructor
punct origine();
punct varf();
void afisare();
void translatie(double,double);
};
main()
{ punct P(7.8,-20.4),Q(-4.82,8.897),A,B;
/*Constructor punct (7.8,-20.4) (Pentru punctul P)
Constructor punct (-4.82,8.897) (Pentru punctul Q)
Constr. implicit pentru punct(0,0)
Constr. implicit pentru punct(0,0) (pentru punctele A, B)*/
punct P3, Q3;
/* Constr. implicit pentru punct(0,0)Constr. implicit pentru punct(0,0) (pentru
punctele P3, Q3) */
segment S(P,Q);
/* Constr. implicit pentru punct(0,0)Constr. implicit pentru punct(0,0)
(pentru membrii A, B ai obiectului S, deci pentru S.A i S.B)
Constructor segment[Punct (7.8,-20.4)Punct (-4.82,8.897)] (pentru obiectul S, de tip
segment) */
segment S1(P3,Q3);
/* Constr. implicit pentru punct(0,0)
Constr. implicit pentru punct(0,0) (pentru membrii A, B ai obiectului S1, deci pentru
S1.A i S1.B)
Constructor segment[Punct (0,0)Punct (0,0)] (pentru obiectul S1, de tip segment) */
printf("Apasa un car. ptr. continuare!\n"); getch();
cout<<"Punctele:\n";
P.afisare();cout<<'\n'; Q.afisare();cout<<'\n';
P3.afisare();cout<<'\n'; Q3.afisare();cout<<'\n';
A.afisare(); cout<<'\n'; B.afisare();cout<<'\n';
cout<<"\nSegment:"; S.afisare(); cout<<'\n';
/* Punctele:
Punct (7.8,-20.4) (pentru obiectul P)
Punct (-4.82,8.897) (pentru obiectul Q)
Punct (0,0) (pentru obiectul A)
Punct (0,0) (pentru obiectul B)
Punct (0,0) (pentru obiectul P3)
Punct (0,0) (pentru obiectul Q3)
Segment:[Punct (7.8,-20.4),Punct (-4.82,8.897)] */
punct D(1,2); punct C;
/* La ieirea din funcia main, deci la terminarea duratei de via a obiectelor, se apeleaz
automat destructorii, n ordinea invers n care au fost apelai constructorii, astfel:
class punct
{ //. . . . .
};
class segment
{ //. . . . .
};
//Implementarea metodelor clasei punct
//Implementarea metodelor clasei segment
punct test1()
{ cout<<"Intrare in test1\n";
static punct P1(20,10);
P1.deplasare(1,1); cout<<"Iesire din test1\n";return P1;}
punct test2()
{ punct P1(100,100);P1.deplasare(10,20);return P1; }
punct A(1,2), B;
segment AB(A, B);
main()
{cout<<"S-a intrat in main!\n"; punct E(1, 1), F, G;
F=test1(); cout<<"F="; F.afisare();
getch();G=test2();cout<<"Intrare in test1\n";cout<<"G=";
G.afisare();
{
cout<<"Intrare in blocul interior\n";
static punct U(5,2);punct C(9,9), D(5.5,6.6);
static punct V(8,3);getch();
F=test1(); cout<<"Intrare in test1\n";F.afisare();G=test2();
cout<<"Intrare in test2\n";G.afisare();
cout<<"Iesire din blocul interior\n";
}
getch();A.afisare();F.afisare();AB.afisare();AB.translatie(10, 10);
cout<<"Segment translatat:"; AB.afisare();
cout<<"Segmentul AB are originea:"; (AB.origine()).afisare();
cout<<"Segmentul AB are varful:"; (AB.varf()).afisare();
cout<<"Iesire din main()\n"; }
#include <iostream.h>
class Paralelipiped {
int Lung, Lat, Inalt; // date membre private
public:
// ------ constructori
Paralelipiped() { /* nimic */ } // constructor null!!!
Paralelipiped(int l1, int l2, int l3)
{ Lung = l1; Lat = l2; Inalt = l3; }
// ----- functie membra
int volum() { return Lung * Lat * Inalt; }
};
main()
{ Paralelipiped c1(7, 8, 9); // declarare obiect de tip Paralelipiped
Paralelipiped c2; // un obiect Paralelipiped fara initializare
c2 = c1; // constructor copiere implicit!!!
cout << c1.volum();cout << c2.volum(); }
#include <stdio.h>
class File
{FILE *fp; // stream C
// ...
public:
File(const char *nume, const char *open_mode); // Constructor
~File(); // Destructor
size_t read(const size_t howmany, const size_t elem_size,
void *buffer); // Citire din fisier in buffer
size_t write(const size_t howmany, const size_t elem_size,
const void *buffer); // Scriere din buffer in fisier
};
PROGRAMAREA ORIENTATA PE OBIECTE, CURS Autor: Diana tefnescu
41
CAPITOLUL 2 Clase i obiecte
class Debug
{ private:
unsigned int indent();
void separator();
static unsigned int debug_level;
static unsigned int debug_on;
static unsigned int indent_prin;
static unsigned int marime_linie;
enum {off = 0, on = 1};
public:
Debug(const char *label = " ");//constructor
~Debug();//destructor
void afiseaza(const char *format, ...);
};
// functii inline
inline Debug::~Debug() //destructorul
{ debug_level--;
separator(); }
// implementarea metodelor
Debug::Debug(const char *label)
{ if(debug_on)
{ int i; separator(); (void) indent();
#include <iostream.h>
class dreptunghi {
int Lung;
int Lat;
public:
dreptunghi(void); //Constructor
void setare(int nou_Lung, int nou_Lat);
int calcul_arie(void);
};
main()
{dreptunghi mic, mediu, mare, vect[4]; /* se apeleaza constructorul pentru
obiectele mic, mediu, mare si pentru fiecare dintre cele 4 elemente ale vectorului vect */
mic.setare(5, 7);
mare.setare(15, 20);
for (int index = 1 ; index < 4 ; index++) /* pentru vect[0] datele
membre Lung si Lat raman cu valorile 8 si 8 */
vect[index].setare(index + 10, 10);
cout<<"Aria dreptunghiului mic este "<< mic.calcul_arie()<< "\n";
cout<<"Aria dreptunghiului mediu e "<<mediu.calcul_arie()<<"\n";
cout<<"Aria dreptunghiului mare e "<< mare.calcul_arie()<<"\n";
class CommandSet
{private:
enum {helpfunc = 0, increase = 1, decrease = 2};
public:
void help(){cout << "Help!" << '\n';}
void nohelp(){cout << "No Help!" << '\n';}
};
main()
{ CommandSet set1;//declararea obiectului set1, de tip CommandSet
//apelul metodei help, pentru obiectul set1, prin intermediul pointerului catre functie
(set1.*f_help)();
f_help = CommandSet::nohelp;// noua valoare a pointerului f_help
//apelul metodei nohelp, pentru obiectul set1, prin intermediul pointerului catre functie
(set1.*f_help)();
getch(); }
Observaie: Nici constructorii, nici destructorii nu pot fi funcii prietene ale unei clase.
O funcie poate fi n acelai timp funcie membr a unei clase i funcie prieten a altei clase.
n exemplul urmtor, f1 este funcie membr a clasei cls1 i funcie prieten a clasei cls2.
Exemplu:
class cls1{ // . . .
int f1(int, char); // f1 - metod a clasei cls1
// . . .
};
n cazul n care se dorete ca toate funciile membre ale unei clase s aib acces la membrii
privai ai altei clase (s fie funcii prietene), prima clas poate fi declarat clasa prieten
pentru cea de-a doua clas. n exemplul urmtor, clasa cls1 este clasa prieten a clasei
cls2.
Exemplu:
class cls1;
class cls2{ //. . .
friend cls1; // clasa cls1 este clas prieten a clasei cls2
//. . .
};
Observaie: Relaia de clasa prieten nu este tranzitiv. Astfel, dac clasa cls1 este clasa
prieten a clasei cls2, iar clasa cls2 este clas prieten a clasei cls3, aceasta nu implic
faptul c, cls1 este clas prieten pentru cls3.
27. Prin ce se realizeaz comunicarea ntre 31. Nici funciile prietene, nici metodele
obiectele unei clase? statice ale unei clase nu primesc ca
28. O clas poate avea mai muli argument implicit pointerul this.
desctructori? Dac da, n ce condiii? Explicai care sunt, totui, diferenele
29. Operatorul :: i rolul su.Ce sunt dintre ele.
funciile prietene? 32. Ce sunt clasele?
30. Ce este o metod? 33. Ce sunt constructorii implicii?
PROBLEME
1. Completai tipul de date complex, cu funciile (membre sau prietene) care vor realiza
urmtoarele operaii: Adunarea unei date de tip complex cu o dat de tip real; scderea a
dou date de tip complex; scderea unui real dintr-un complex; mprirea a dou date de
tip complex; nmulirea unui real cu un complex; ridicarea la o putere ntreag a unei date
de tip complex; compararea a dou date de tip complex.
2. S se scrie un program care citete cte dou date de tip complex, pn la ntlnirea
perechii de date (z1=0+i*0, z2=0+i*0). Pentru fiecare pereche de date, s se afieze suma,
diferena, produsul i ctul.
b) union numar{
private:
char exponent, mantisa[3];
public:
char exp();
};
c) class complex{
int real, imag;
complex (int x, int y)
{real=x; imag=y;}
};
main()
{complex Z(20, 30); }
47
CAPITOLUL 10 Clase i obiecte
a) #include <iostream.h>
class fractie{
int nrt, nmt;
void afis_fractie( );
};
void afis_fractie( )
{cout<<nrt<<"/"<<nmt<<'\n';}
main()
{fractie f1; f1.afis_fractie();}
b) #include <iostream.h>
class fractie{
int nrt, nmt;
void afis_fractie( );
};
protected: void afis_fractie( )
{cout<<nrt<<"/"<<nmt<<'\n';}
main( )
{fractie f1(4,7); f1.afis_fractie();}
c) #include <iostream.h>
class fractie{
int nrt, nmt;
public: fractie(int, int ); };
fractie( int n1, int n2)
{nrt=n1; nmt=n2;}
main( )
{fractie f1; }
d) #include <iostream.h>
#include <math.h>
class complex{
double re, im;
double modul_complex();
};
double complex::modul_complex()
{return sqrt(re*re+im*im;}
main()
{complex x1(3,4); cout<<x1.modul_complex();}
48