Documente Academic
Documente Profesional
Documente Cultură
Capitolul 10
Capitolul 10
Clase i obiecte
CLASE I OBIECTE
10.1. Definiia claselor i accesul la membrii
10.1.1. Legtura clas-structur-uniune
10.1.2. Declararea claselor
10.1.3. Obiecte
10.1.4. Membrii unei clase
10.1.5. Pointerul this
10.1.6. Domeniul unui nume,
vizibilitate i timp de via
CAPITOLUL 10
Clase i obiecte
metodele clasei (sau prin funciile prietene, capitolul 10.4.). Cei cu acces protected posed caracteristicile
celor privai, n plus, putnd 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).
Observaiile legate de prezena nume_tip sau lista_variabile (din capitolul 8) sunt valabile i n cazul
claselor.
Variabilele din lista_variabile sunt de tipul nume_tip i se numesc instane (obiecte) ale clasei.
Observaie: 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
Membrii culoare i capacitate_cil (accesul private) pot fi accesai doar prin intermediul metodelor
clasei.
Exemplu:
class persoana{
char *nume; //dat membru privat
public:
void citire_inf_pers(); //metod public
private:
int varsta; //dat membru privat
};
Exerciiu: S se defineasc tipul de date dreptunghi, cu ajutorul unei structuri, a unei uniuni i a unei
clase.
Datele membre sunt lungimea i limea (variabilele Lung, lat).
Funciile membre sunt:
void seteaza_dimen(double, double) - primete ca argumente dou valori reale i
iniializeaz datele membre cu valorile argumentelor.
double arata_Lung( ) - returneaz valoarea lungimii (a datei membre Lung).
double arata_Lat( ) - returneaz valoarea limii (a datei membre lat).
double calcul_arie( ) - returneaz valoarea ariei dreptunghiului.
//a) Implementarea tipului dreptunghi cu ajutorul unei structuri.
#include <iostream.h>
struct dreptunghi{
double Lung, lat;
void seteaza_dimen(double, double );//prototipul funciei seteaza_dimen
double arata_Lung()
{return Lung;}
double arata_Lat()
{return lat;}
double calcul_arie()
{return Lung*lat;}
};
void dreptunghi::seteaza_dimen(double L, double l)
{Lung=L; lat=l;}
134
CAPITOLUL 10
Clase i obiecte
void 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:"<<a.arata_Lung();
cout<<" si"<<a.arata_Lat()<<'\n';
cout<<"Aria dreptunghiului:"<<a.calcul_arie()<<'\n';
cout<<"Dimens structurii:"<<sizeof(a)<<'\n';
}
n exerciiul 1 a, b se definete tipul dreptunghi printr-o structur, respectiv o uniune. Tipul conine att
datele membre, ct i metodele care implementeaz operaiile care pot fi realizate asupra variabilelor de tipul
dreptunghi. Metodele arata_Lung, arata_Lat, calcul_arie sunt definite n structur (uniune). Metoda
seteaza_dimen este doar declarat n interiorul structurii (uniunii), fiind abia apoi definit. n varianta b
(implementarea cu uniune, unde pentru memorarea valorilor datelor membre se utilizeaz aceeai zon de
memorie), pentru a pstra valorile att pentru lungimea dreptunghiului, ct i pentru lime, metodele au fost
modificate.
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).
//c) Implementarea tipului dreptunghi cu ajutorul unei clase
#include <iostream.h>
class dreptunghi{
double Lung, lat;
public:
void seteaza_dimen(double, double );
double arata_Lung()
{return Lung;}
double arata_Lat()
{return lat;}
double calcul_arie()
135
CAPITOLUL 10
Clase i obiecte
{return Lung*lat;}
};
void dreptunghi::seteaza_dimen(double L, double l)
{Lung=L; lat=l;}
void main()
{ dreptunghi a;double l1, l2;
cout<<"Lungime="; cin>>l1;cout<<"Latime="; cin>>l2;
a.seteaza_dimen(l1, l2);cout<<"Dimensiunile dreptunghiului sunt:";
cout<<a.arata_Lung()<<" si"<<a.arata_Lat()<<'\n';
cout<<"Aria dreptunghiului:"<<a.calcul_arie()<<'\n';
cout<<"Dimens :"<<sizeof(a)<<'\n';
}
n exerciiul 1c se definete tipul de date dreptunghi cu ajutorul unei clase. Nivelul de acees implicit la
membrii clasei este private. Dac pentru metode nu s-ar fi folosit modificatorul de acces public, metodele
nu ar fi putut fi folosite n funcia main.
10.1.3. OBIECTE
Un obiect este o dat de tip definit printr-o clas. n exerciiul anterior, punctul c, n funcia main, se declar
obiectul (variabila) a de tip dreptunghi. Spunem c obiectul a este o instan a clasei dreptunghi. Se pot
declara oricte obiecte (instane) ale clasei. Aa cum se observ din exemplu, declararea obiectelor de un
anumit tip are o form asemntoare celei pentru datele de tip predefinit:
nume_clasa lista_obiecte;
Exemple:
dreptunghi a;
dreptunghi b, c, d;
Lung
a.Lung
Lung
b.Lung
lat
a.lat
lat
b.lat
Lung
d.Lung
lat
d.lat
Lung
c.Lung
lat
c.lat
Metodele figureaz ntr-un singur exemplar, oricte instane ale clasei ar exista.
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
136
CAPITOLUL 10
Clase i obiecte
//..
void main()
{ dreptunghi a;
//
cout<<"Aria dreptunghiului:"<<a.calcul_arie()<<'\n';
dreptunghi *pa;
pa=&a;
double arie=pa->calcul_arie();
Exerciiu: S urmrim exerciiul urmtor, care ilustreaz problemele legate de membrii statici ai unei clase
(figura 10.2.).
#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++;}
Memoria
void arata_i()
static
{cout<<"i="<<i<<'\n';}
void inc_contor(void)
exemplu::
{contor++;}
contor
void init(void)
{i=0;}
static void arata_contor()
{cout<<"Contor="<<contor<<'\n';}
static void functie(exemplu*);
} a1, a2, a3;
int exemplu::contor=0;
Stiv
a1.i
a2.i
a3.i
CAPITOLUL 10
Clase i obiecte
void main()
{clrscr();
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
a1.inc(); a2.inc(); a3.inc();
//a1.i=1, a2.i=1, a3.i=1
a1.arata_i();a2.arata_i();a3.arata_i();
//i=1, i=1, i=1
a1.functie(&a1);
//contor=1, i=2
exemplu::functie(&a2);
//contor=2, i=2
//functie();
//incorect
a1.inc_contor();
//contor=3
exemplu::arata_contor();
a2.inc_contor();
//contor=4
exemplu::arata_contor();
a3.inc_contor();
//contor=5
exemplu::arata_contor();
exemplu::arata_contor();
exemplu::contor+=100;
//membru public; contor=105
cout<<"Contor="<<exemplu::contor<<'\n';
//Contor=105
}
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.
Exerciiu: S se urmreasc urmtorul exerciiu, care definete tipul ex_mstat, cu o dat membru static
(s) i metodele statice (set_s, ret_s).
#include <iostream.h>
class ex_mstat{
int a; static double s;
public:
int ret_a(){return a;}
void set_a(int x){a=x;}
static double ret_s(){return s;}
static void set_s(double x){s=x;}
void set1_s(double x){s=x;}
double ret1_s(){return s;}
};
double ex_mstat::s;
/*se rezerv spaiu n memoria static pentru data membr
static s, care figureaz ntr-un singur exemplar pentru toate
instaele clasei ex_mstat (figura 10.3.)*/
ex_mstat::s
void main()
Figura 10.3. Alocarea memoriei
{ex_mstat p,q;
p.set_a(100);
pentru membrii clasei ex_mstat
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';//p.a=100 p.s=200 ex_mstat::ret_s=200
cout<<"q.a="<<q.ret_a()<<" q.s="<<q.ret1_s();
cout<<" ex_mstat::ret_s="<<ex_mstat::ret_s()<<'\n';//q.a=300 q.s=200 ex_mstat::ret_s=200
ex_mstat::set_s(500.20);
cout<<"p.a="<<p.ret_a()<<" p.s="<<p.ret_s();
cout<<" ex_mstat::ret_s()="<<ex_mstat::ret_s()<<'\n';
CAPITOLUL 10
cout<<"q.a="<<q.ret_a()<<" q.s="<<q.ret1_s();
cout<<" ex_mstat::ret_s()="<<ex_mstat::ret_s()<<'\n';
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.
//..
void seteaza_dimen(double, double);
};
void dreptunghi::seteaza_dimen(double L, double l)
{//Lung=L; lat=l;
this->Lung=L; this->lat=l;}
Deoarece o metod static se apeleaz independent de un obiect al clasei, pointerul this nu mai poate fi
utilizat.
CAPITOLUL 10
Clase i obiecte
#include <iostream.h>
int i=80;
// i declarat n afara oricrei funcii, domeniul numelui este fiierul
void 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 (struct sau union, deoarece structurile i
uniunile sunt cazuri particulare de clase cu 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)
}
10.1.6.2. Vizibilitate
Domeniul de vizibilitate a unei variabile (obiect) este determinat de clasa de memorare a variabilei
(obiectului), aa cum prezint tabelul 6.1. (capitolul 6). De obicei, domeniul de vizibilitate al unui nume
coincide cu domeniul numelui.
CAPITOLUL 10
Clase i obiecte
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). Exist i posibilitatea de a declara metoda la declararea clasei i de a specifica, explicit, c
este funcie inline la definirea funciei.
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;}
Prefixarea definiiei funciei seteaza_dimen cu cuvntul cheie inline este echivalent cu definirea
metodei n cadrul declaraiei clasei dreptunghi.
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
};
inline double complex::modul()
{ return sqrt(real*real+imag*imag);}
int complex::citire()
{ cout<<"P. reala:"; if (!(cin>>real)) return 0;
cout<<"P. imag:";if (!(cin>>imag)) return 0 ;
return 1; }
void complex::afisare()
{ if (imag>=0)
cout<<real<<"+"<<imag<<"*i"<<"\n";
else cout<<real<<imag<<"*i\n";}
double complex::arg()
141
CAPITOLUL 10
{if (real==0 && imag==0)
return 0.0;
if (imag==0)
//z=p. reala
if (real>0) return 0.0;
else return PI;
if (real==0)
if (imag>0) return PI/2;
else return (3*PI)/2;
double x=atan(imag/real);
if (real<0) return PI+x;
if (imag<0) return 2*PI+x;
return x;}
Clase i obiecte
CAPITOLUL 10
Clase i obiecte
//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.
10.3.1. 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.
Suprancarcarea (supradefinirea) reprezint posibilitatea de a atribui unui nume mai multe semnificaii, care
sunt selectate n funcie de context. Practic, se pot defini funcii cu acelai nume, dar cu liste de parametri
diferite, ca numr i/sau ca tipuri de parametri. n momentul apelului funciei, selectarea funciei adecvate se
face n urma comparrii tipurilor parametrilor efectivi cu tipurile parametrilor formali. De aceea, declararea
unor funcii cu acelai nume i acelai set de parametri este ilegal i este semnalat ca eroare la compilare.
La ntlnirea declaraiei unui obiect, se apeleaz automat un constructor al clasei respective. La fiecare
instaniere a clasei se aloc memorie pentru datele membre. Deci pentru fiecare obiect declarat se aloc
memorie pentru datele membre ale clasei. Excepie de la aceast regul o constituie datele membru statice.
Acestea figureaz ntr-un singur exemplar pentru toate instanele clasei respective. Funciile membru exist
ntr-un singur exemplar pentru toate instanele clasei. Ordinea n care sunt apelai constructorii corespunde
ordinii declarrii obiectelor.
Proprietile constructorilor:
Constructorii au acelai nume ca i numele clasei creia i aparin;
Nu ntorc nici o valoare (din corpul lor lipsete intruciunea return; 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 12);
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 (vezi capitolul 6.5.), 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 dorim s instaniem obiecte att iniializate, ct i neiniializate se
poate folosi un constructor implicit vid, care se va apela la instanierea obiectelor neiniializate (exemplul 3).
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.
143
CAPITOLUL 10
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; }
void 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
}
Clase i obiecte
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()
{ }
data(int z,int l,int a)
{ zi=z;luna=l;an=a; }
};
void main()
{data d;
data d1(12,11,1998);
}
CAPITOLUL 10
Clase i obiecte
// Sau:
class complex {
double real,imag;
public:
complex(double x, double y) :real(x),imag(y) { }
10.3.2. 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;);
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.
145
CAPITOLUL 10
Clase i obiecte
Exerciiu:
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.
S se defineasc tipul segment, cu datele membre A i B, de tip punct, reprezentnd capetele unui segment
(originea i vrful). Operaiile care pot fi realizate asupra obiectelor de tip segment, sunt: afiare (afieaz
coordonatele capetellor segmentului), deplasare (translateaz un segment, deplasnd capetele acestuia cu
valorile transmise ca parametri), origine (returneaz originea segmentului), vrf (returneaz vrful
segmentului). Se vor implementa, deasemenea, constructor, constructor de copiere i destructor.
S se testeze tipurile de date punct i segment.
#include
#include
#include
#include
<iostream.h>
<stdlib.h>
<stdio.h>
<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);
};
CAPITOLUL 10
void punct::afisare()
{ cout<<"Punct ("<<x<<','<<y<<')';}
Clase i obiecte
// Constr. implicit pentru punct(0,0)Constr. implicit pentru punct(0,0) (pentru punctele P3, Q3)
segment S(P,Q);
/* 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;
CAPITOLUL 10
Clase i obiecte
// Varf segment S=Constructor copiere pct (-4.82,8.897) (metoda varf returneaza un punct, copiere)
// Punct (-4.82, 8.897)
//Destructor punct (-4.82,8.897)
cout<<"Origine segment S="; CC=S.origine();
/* Origine segment S=Constructor copiere pct (7.8,-20.4) (metoda origine returneaza un punct,
copiere) Destructor punct (7.8,-20.4) */
CC.afisare();
// Punct (-4.82, 8.897)
S1=S;
//operatie de atribuire
S1.afisare();
/* 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:
Destructor segment [Punct (107.8,979.6),Punct (95.18,1008.897)] (pentru segmentul S2)
Destructor punct (95.18,1008.897) (pentru membrii B, respectiv A, ai segmentului S2: S2.B, apoi S2.A)
Destructor punct (107.8,979.6)
Destructor punct (7.8,-20.4) (pentru CC)
Destructor punct (1,2) (pentru C)
Destructor punct (1,2) (pentru D)
Destructor segment [Punct (107.8,979.6),Punct (95.18,1008.897)] (pentru segmentul S1)
Destructor punct (95.18,1008.897) (pentru membrii B, respectiv A, ai segmentului S1: S1.B, apoi S1.A)
Destructor punct (107.8,979.6)
Destructor segment [Punct (7.8,-20.4),Punct (-4.82,8.897)] (pentru segmentul S)
Destructor punct (-4.82,8.897) (pentru membrii B, respectiv A, ai segmentului S: S.B, apoi S.A)
Destructor punct (7.8,-20.4)
Destructor punct (0,0) (pentru punctul Q3)
Destructor punct (0,0) (pentru punctul P3)
Destructor punct (0,0) (pentru punctul B)
Destructor punct (0,0) (pentru punctul A)
Destructor punct (-4.82,8.897) (pentru punctul Q)
Destructor punct (7.8,-20.4) (pentru punctul P) */
Exerciiul evideniaz urmtoarele probleme:
1. n situaia n care o clas C1 are ca date membre obiecte ale altei clase C2 (clasa segment are ca date
membre obiecte de tipul punct), la construirea unui obiect din C1, se apeleaz nti constructorul C2
pentru membrii (de tip C2), apoi constructorul C1.
Un astfel de exemplu l constituie declararea segmentului S: segment S(P,Q);
148
CAPITOLUL 10
Clase i obiecte
Se apeleaz nti constructorul implicit al clasei punct pentru membrii A i B ai segmentului S (deci
pentru S.A i S.B), apoi constructorul clasei segment (figura 10.4.). La distrugerea obiectului din clasa
C1, destructorii sunt apelai n ordinea invers constructorilor (nti se apeleaz destructorul clasei
segment - nveliul exterior, apoi destructorul pentru membrii de tip punct).
2. S revedem secvena:
punct D(1,2); punct C; C=D;
A.x
punct CC=C;
7.8
B.x
A.y
-20.4
B.y
-4.82 8.897
Constructorul primete ca parametri referine ctre obiecte de tipul punct. Apelul constructorului:
segment S(P, Q);
Parametrii efectivi P i Q sunt referine pentru A1 i B1 (aceleai obiecte). Ca urmare, se apeleaz cei doi
constructori implicii pentru membrii A i B ai segmentului S. n urma operaiei de atribuire din corpul
constructorului segmentului, ei sunt iniializai. Mesajele:
"Constructor pct implicit!!" (pentru membrul A al segmentului S)
"Constructor pct implicit!!" (pentru membrul B al segmentului S)
"Constructor segment"
(pentru segmentului S)
Constructorului puteau s i se transmit parametri prin pointeri:
segment::segment(punct *A1,punct *B1)
{ A=*A1;B=*B1;cout<<"Constructor segment\n";}
Apelul:
segment S(&P, &Q);
Parametrii formali A1 i B1 sunt iniializai n momentul apelului constructorului cu adresele punctelor P,
respectiv Q. Situaia este similar celei anterioare, mesajele obinute sunt identice celor obinute n cazul
transmiterii parametrilor prin referin.
Constructorului puteau s i se transmit parametri prin valoare:
segment::segment(punct A1,punct B1)
{ A=A1;B=B1;cout<<"Constructor segment\n";}
segment S(P, Q);
Apelul:
n aceast situaie, la apel, pentru parametrii formali A1 i B1 se rezerv memorie pe stiv: obiectele locale
constructorului, A1 i B1, sunt iniializate prin copiere (la transmiterea parametrilor prin valoare, se
realizeaz o copiere a parametrilor efectivi n parametrii formali, vezi capitolul 6.3.1.). La terminarea
execuiei corpului funciei, punctele A1 i B1 sunt distruse. De aceea, mesajele din aceast situaie, sunt:
"Constructor copiere punct!!" (pentru A1, local constructorului)
"Constructor copiere punct!!" (pentru B1, local constructorului)
"Constructor pct. implicit!!" (pentru membrul A al segmentului)
"Constructor pct. implicit!!" (pentru membrul B al segmentului)
"Constructor segment!" (pentru segmentul S)
"Destructor punct!" (pentru B1, la ieirea din constructor)
"Destructor punct!" (pentru A1, la ieirea din constructor)
Exerciiu: Pentru tipurile punct i segment implementate anterior, s se scrie i s se testeze urmtorul
program, n care obiectele A, B (de tip punct) i AB (de tip segment) sunt globale (declarate n afara oricrei
funcii). Se folosesc, deasemenea, variabile locale statice. Pentru variabilele globale (A, B, AB) i cele locale
declarate explicit statice ( P1 din test1, U i V din blocul interior funciei main), se aloc memorie static.
149
CAPITOLUL 10
Clase i obiecte
Pentru variabilele locale se aloc memorie automatic, pe stiv. S se urmreasc evidenieze crearea i
distrugerea obiectelor statice i automatici, domeniul de vizibilitate i timpul de via.
class punct{ //. . . . .
};
class segment
{
//. . . . .
};
//
};
//apelul constructorului cu parametri pentru fiecare din cele 2 elemente, V2[0] si V2[1]
segment SV[2];
CAPITOLUL 10
Clase i obiecte
segment SV[2]={segment(PC, P), segment(QC, Q)};
segment SV[2]={segment(punct(5,5), punct(55,55)), segment (punct(10,10),
punct(100,100))};
}
//. . .
};
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;
//. . .
};
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.
NTREBRI I EXERCIII
Chestiuni teoretice
1. Cnd acioneaz constructorul unei clase?
2. Cnd acioneaz destructorul unei clase?
3. Cnd este absolut necesar definirea unui
constructor de copiere?
4. Cnd se justific utilizarea funciilor inline?
5. Caracteristicile destructorului unei clase.
6. Care este utilitatea motenirii?
7. Care sunt deosebirile ntre o funcie membr a
unei clase i o functie prieten a unei clase?
8. Ce fel de metode pot aciona asupra datelor
membre statice ale unei clase?
151
CAPITOLUL 10
Clase i obiecte
Chestiuni practice
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.
3. S se scrie un program care citete datele a, b, c de tip complex, rezolv i afieaz rdcinile ecuaiei de
gradul doi: ax 2 +bx+c=0.
4. Care sunt greelile din urmtoarele secvene?
a) class ex1{
char *nume; int lungime;
void init (char *s, int l)
{strcpy(nume, s); lungime=l;}
};
ex1 A; A.init("teava", 20);
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;}
};
void main()
{
complex Z(20, 30);
}
152