Manevrarea dinamica a obiectelor unei clase
Informatica :: IT :: C++
Pagina 1 din 1
Manevrarea dinamica a obiectelor unei clase
• Pentru gestionarea dinamica a memoriei, in C++ exista doi operatori new si delete mai evoluati, din punct de vedere al domeniului de actiune, decat functiile malloc( ) si free( ) din C. Spre deosebire de functia malloc(), operatorul new stie, fara a i se specifica, cata memorie trebuie alocata fiecarui tip de obiect si poate produce apelul unui constructor.
Exemplu:
In loc de:
int*p=(int*)malloc(sizeof (int)); //functia de alocare dinamica de memorie in C
vom scrie:
int*p=new int; // alocare dinamica de memorie prin operatorul new in C++
sau
int*p=new(int); // new actioneaza ca functie in C++
• Operatorul new, in general, este utilizat in interiorul constructorilor.
• Operatorul new apeleaza un constructor, pentru a crea un obiect, atunci cand, initial, valoarea atribuita lui this, in cadrul acelui constructor, este NULL.
• Un obiect poate fi creat in mod:
a) static ( fara a se aloca memorie cu operatorul new);
b) dinamic (cu sau fara alocare de memorie);
In cazul creerii unui obiect in mod dinamic fara alocare de memorie, pointerul „this“ al unui nou obiect va fi setat la o valoare ce reprezinta un pointer la un obiect de acelasi tip, deja existent. Orice modificare efectuata asupra unor membri ai noului obiect va modifica membrii corespunzatori ai celuilalt obiect referit. Cu alte cuvinte, se poate spune ca este vorba de o redenumire a obiectului care deja exista.
• Un masiv(tablou) de obiecte poate fi initializat:
a) in momentul declararii;
Exemplu:
Class tt
{
int j;
public:
tt(int k){j=k;} // constructor
int ret( ){return j;}
};
void main( )
{
tt tab[4]={11,12,13,14}; // initializare
for(int k=10;k<14;k++)
cout<<tab[k].ret( )<<”\n”;
}
Exemplu:
//un tablou de obiecte de tip punct
class punct{
public:
int u,v;
…………….
};
punct tab[5];
punct tab[5]={{0,0},{5,7},{10,17},{8,23},{3,23}};
//init. tabloului in momentul declararii sale
b) in cadrul declararii, cu ajutorul unei liste de instantiere avand ca elemente constructori ai
obiectului;
Daca clasa obiectului de baza accepta restrictiile cu privire la tipul de instantiere, atunci se va crea o lista de instantiere in vederea initializarii tabloului de obiecte. Identificarea constructorilor se va face in functie de lista de instantieri.
Exemplu:
Class t_2
{
int k,j;
public:
t_2(int u, int v){k=u; j=v;}
int ret( ){return k;}
int ret( ){return j;}
};
void main( )
{
t_2 t[4]={t_2(11,12), t_2(13,14), t_2(15,16), t_2(17,18)};
int k;
for( k=10;k<17;k++)
{
cout<<t[k].ret( );
cout<<”,”;
cout<<t[k+1].ret( )<<”\n”;
}
}
Exemplu:
class punct
{
public:
int u,v;
punct(int a, int b){u=a; v=b;}
punct(int a){u=a;v=a;}
};
punct tab [5]={
0,
// se apeleza constructorul cu un parametru: punct(0)
punct(3,5),
//se apeleaza constructorul cu doi parametri: punct(3,5)
10,
// se apeleaza constructorul cu un parametru: punct(10)
………..
};
• Un constructor implicit (fara parametri) este util la instantierea unui tablou de obiecte, avand in vedere situatia in care este imposibila transmiterea de parametri necesari constructorului. In prezenta constructorului implicit, se pot face instantieri partiale ale unui obiect.
Exemplu:
punct tab[5];// nu exista lista de initializari
Exemplu:
class punct
{
public:
int u,v;
punct(int a, int b){u=a; v=b;}
punct(int a){u=a;v=a;}
punct( ){u=0; v=0;}
};
punct tab [5]={ 0, punct(3,5)}; //initializare partiala
• Actiunea operatorului new in cazul tablourilor:
Sintaxa:
id_tablou=new tip_tablou[dim];
• Adresa returnata de operatorul new va fi adresa primului obiect din tablou.
Exemplu:
int*q=new int[5]; //Care este valoarea lui q?
Prin declaratia
punct*q=new punct(5,;
se indica o rezervare de memorie pentru obiectul precizat, dupa care se va apela constructorul pentru acest obiect.
• Se pot declara tablouri de obiecte, incluzand alocarea de memorie prin operatorul new.
Exemplu:
punct*tab=new punct[5];
Asa dupa cum am mentionat, pentru a se realiza transmiterea de parametri, clasa obiectelor ce formeaza tabloul, trebuie sa contina constructorul implicit.
• Analog functiei free( ) din C, in C++ exista operatorul delete care are ca scop eliberarea zonei de memorie alocata dinamic cu operatorul new. Operatorul delete este prezent in cadrul destructorilor. Inainte de a elibera zona de memorie alocata unui obiect, se va apela destructorul sau. Cu operatorul delete se poate realiza o eliberare selectiva a spatiului alocat dinamic cu operatorul new.
Exemplu:
int*p=new int[12];
// se aloca un spatiu de memorie pentru 12 elemente intregi
delete p;
// se elibereaza spatiul ocupat doar de obiectul p[0]
delete[ ] p;
// se elibereaza tot spatiul alocat
Exemplu:
class sir
{
char *s;
int dim;
public:
sir(char*); //constructor (prototip)
~sir( ); //destructor (prototip)
……………
};
// definirea constructorului
sir::sir(char*t)
{
dim=strlen(t)+1;
s=new charadims; //alocare de memorie
strcpy(s,t);
}
// definirea destructorului
sir::~sir( )
{
delete s;
}
……………………………………….
// exemplu de instantiere
sir secventa("Sectia Informatica");
// se distruge obiectul, apeland indirect destructorul
delete secventa;
// apelul direct al destructorului se face atunci cand identificatorul lui este precedat de iden_clasa
// si operatorul "::"
Exemplu:
secventa.sir::~sir( );
• Pentru a se evita o recursivitate infinita, nu se va folosi functia exit intr-un destructor. Cand se apeleaza functia exit, in timpul executiei unui program, vor fi apelati doar destructorii variabilelor globale, nu si ai variabilelor locale.
Aplicatie:
// Crearea si utilizarea unor tablourilor statice si dinamice de obiecte.
#include<iostream.h>
#include<string.h
class salariat
{
private:
char*nume;
long sal;
void init(char*s=" ",long a=0){
nume=new char[strlen(s)+1];
strcpy(nume,s);
}
public:
salariat(char*s,long a){init(s,a);}
salariat(void){init( );}
~salariat ( ) {delete nume;}
void introduc_salariat(char*s,long a){init(s,a);}
void afis_salariat( ){cout<<"\n Nume"<<nume<<"\t salariu:"<<sal;}
};
class serv{
int nr_sal;
salariat*sal;
public:
serv (int nr){
sal=new salariat[nr];
if(!sal){ cout<<"\n"<<nr<<"prea multi";
return;
}
nr_sal=nr;}
~serv( ){delete[nr_sal]sal;
}
void introd_serv( );
void afis_serv( );
int NR_SAL( ){return nr_sal;}
};
void serv::introd_serv( ){
char nume[25];long sal;
for(int i=0;i<nr_sal;i++){
cout<<"Nume:"; cin>>nume;
cout<<"Salariu:";cin>>sal;
}
}
• Elementele protejate dintr-o clasa formeaza, dupa cum am mai precizat, asa numita implementare a tipului abstract definit prin acea clasa. O functie membra a acelei clase se apeleaza intotdeauna prin obiectul curent, dupa cum urmeaza:
ident_obiect.ident_functie_memb (…);
sau
pointer_id_clasa->id_functie_memb( );
• Functiile obisnuite nu admit astfel de apeluri, datele prelucrate de ele fie ca sunt transferate prin parametri, fie ca sunt date globale. De aceea, o astfel de functie, pentru a prelucra obiectele unei clase, trebuie sa devina mai intai functie membra a acelei clase. Pentru o rezolvare mai comoda a acestei situatii, s-a cautat sa se gaseasca niste functii, care, desi nu sunt functii membre ale clasei, sa aiba acces la elementele protejate ale acesteia. Functiile prietene(friend ) sunt functii asociate unor clase. Ele nu sunt functii membre ale clasei la ai carei membri are acces. Aceste functii ignora caracterul privat si protected al membrilor clasei careia ii este prietena. Clasa cuprinde doar prototipurile functiilor prietene ei.
Exemplu:
//Sa consideram un tip definit de utilizator:
#include <iostream.h>
class X
{
int u,v;
public:
X(int k, int q){u=k;v=q;}
int dif(){return u*u-v*v;}
};
void main()
{
X z(6,3);
int p=z.dif(); cout<<"p="<<p; }
Se obtine pentru p valoarea 27, folosind functia membra, dif( ). La acelasi rezultat se va ajunge folosind functia friend dif( ) a clasei X, care nu mai este functie membra a acestei clase.
#include <iostream.h> class X
{ int u,v; public: X(int k, int q){u=k;v=q;} friend int dif(X w); }; int dif(X w){return w.u*w.u-w.v*w.v;} void main()
{ X z(6,3);
cout<<dif(z);
}
Functia dif( ) are acces deplin la membrii particulari ai clasei X (la u si v). Apelul ei se face in mod obisnuit.
• Declararea unei functii friend se face incluzand prototipul ei, precedat de cuvantul cheie friend, in acea clasa. Indiferent de pozitia declararii unei astfel de functii, in corpul clasei, ea va fi considerata publica. O functie friend, nefiind functie membra a clasei a carei prietena este, nu poate sa aiba un nume de obiect al clasei repective. In definitia sa, nu mai apare cuvantul cheie friend.
• Utilizarea functiilor friend aduc o serie de avantaje:
a) la supraincarcarea unor tipuri de operatori [vezi L5];
b) ofera o facilitate in crearea anumitor tipuri de functii de intrare/iesire;
c) sunt necesare cand doua sau mai multe clase contin membri corelati cu alte sectiuni din program.
• Am remarcat faptul ca orice functie membra nu poate fi functie friend aceleiasi clase, dar este posibil sa fie functie prietena unei alte clase. De aceea se spune ca functiile friend constituie o legatura intre clase. Exista doua situatii in declararea functiilor friend ale unei clase:
a) se specifica faptul ca functia membra a unei clase este functie friend a unei alte clase. Mai exact, se declara functia membra din prima clasa ca fiind de tip friend in a doua clasa.
Exemplu:
class Y;
// se predeclara clasa care contine functii prietene ale unei alte clase X
class X
{
……………
void F1(Y &a); // functie membra a clasei X
…………….
};
class Y
{
………………
friend void X::F1(Y &a); //functie friend pentru clasa Y
………………..
};
b) se poate declara o intreaga clasa prietena , in care toate functiile membre ale sale sunt functii
prietene ale unei alte clase. Exemplu:
class Y;
class X
{
………………..
void F1(Y &a);
………………..
};
class Y
{
………………..
friend X;
// se declara clasa X ca prietena a clasei Y(toate functile membre
// ale clasei X sunt functii friend pentru clasa Y)
………………..
};
• Clasele friend sunt utile atunci cand este necesara o comunicare intre clase, care au acelasi nivel ierarhic. In aceasta situatie, clasa friend are acces la membrii protejati prezenti in cealalta clasa care pot include nume de tipuri, enumerari de constante. Membrii clasei la care se permite accesul nu devin membri ai clasei friend.
Aplicatie:
Sa se implementeze o stiva de caractere (ca lista simplu inlantuita) folosind o clasa atasata nodurilor din lista si una atasata stivei respective.
class stiva;
//predeclarare a clasei care contine ca functii membre, functii prietene
// unei alte clase
class nod
{
private:
friend stiva; //clasa friend
nod(int i, nod*n);
int inf;
nod *prec;
};
class stiva{
private:
nod*varf;
public:
stiva( ){varf=NULL;}
~stiva( );
void push(int c);
int pop( );
};
Clasa nod este o clasa privata. Accesul la membrii ei se face prin intermediul unor functii friend (clasa stiva).
• Functiile friend nu poseda pointerul this.
Puneti in evidenta caracteristicile programului urmator.
#include<iostream.h> #include<conio.h> class punct{ float x,y; public: punct(float a=0,float b=0){x=a;y=b;} ~punct(){cout<<"Se distruge punct! \n";}
void afis()
{
cout<<"\n Punct de coordonate x="<<x<<" y="<<y;}
};
class vector
{
punct o,v;
public:
vector(float x_1=0,float y_1=0,float x_2=0,
float y_2=0)(x_1,y_1),v(x_2,y_2){} ~vector(){cout<<"\n Se distruge vector!";}
void afis(){cout<<"\n Vector:";
o.afis();
v.afis();
}};
class triunghi{
punct *p_1,*p_2,*p_3;
public:
triunghi(float a_1=0,float b_1=0,float a_2=0,
float b_2=0,float a_3=0,float b_3=0)
{
p_1=new punct(a_1,b_1);
p_2=new punct(a_2,b_2);
p_3=new punct(a_3,b_3);
}
~triunghi(){
delete p_1;
delete p_2;
delete p_3;
}
void afis()
{
cout<<"\n TRIUNGHI:";
p_1->afis();
p_2->afis();
p_3->afis();
}
};
void main(void)
{
clrscr();
punct p,p_1(3.5,5.6);
p.afis();
p_1.afis();
vector v_1,v_2(1.5,2.5,3.5,4.5);
vector v_3(2,3);
v_1.afis();
v_2.afis();
v_3.afis();
triunghi t_1,t_2(1.2,3.4,5.6);
t_1.afis();
t_2.afis();
getch();
}
Aplicatie:
Folosind functii friend, sa se calculeze o putere a unui numar complex.
#include <iostream.h> #include <conio.h> #include <math.h> #define PI 3.14159265358979
class complex
{ double re; double im; public: double modul; double arg(); void afis(); friend void cp(complex&,int); void init(double x,double y)
{
re=x;
im=y;
modul=sqrt(re*re+im*im);
}
};
inline void complex::afis(){cout<<re<<"+i*"<<"("<<im<<")";}
double complex::arg()
{
if(re==0.0&&im==0.0)return 0.0;
if(im==0.0)
if(re>0.0) return 0.0;
else
return PI;
if(re==0.0)
if(im>0.0)return (PI/2);
else
return (3*PI)/2;
double a=atan(im/re);
if(re<0.0)return PI+a;
if(im<0.0)return 2*PI+a;
return a;
}
void cp(complex &z,int n)
{
double r;
double a;
r=z.modul;
a=z.arg();
double r_la_n=pow(r,(double)n);
double aa=n*a;
z.re=r_la_n*cos(aa);
z.im=r_la_n*sin(aa);
}
void main()
{
clrscr();
complex u;
u.init(-1,-1);
cout<<"\n U=";
u.afis();
cout<<"\n Modulul nr.U:"<<u.modul;
cout<<"\n Nr. ridicat la putere:";
cp(u,3);
u.afis();
}
Exemplu:
In loc de:
int*p=(int*)malloc(sizeof (int)); //functia de alocare dinamica de memorie in C
vom scrie:
int*p=new int; // alocare dinamica de memorie prin operatorul new in C++
sau
int*p=new(int); // new actioneaza ca functie in C++
• Operatorul new, in general, este utilizat in interiorul constructorilor.
• Operatorul new apeleaza un constructor, pentru a crea un obiect, atunci cand, initial, valoarea atribuita lui this, in cadrul acelui constructor, este NULL.
• Un obiect poate fi creat in mod:
a) static ( fara a se aloca memorie cu operatorul new);
b) dinamic (cu sau fara alocare de memorie);
In cazul creerii unui obiect in mod dinamic fara alocare de memorie, pointerul „this“ al unui nou obiect va fi setat la o valoare ce reprezinta un pointer la un obiect de acelasi tip, deja existent. Orice modificare efectuata asupra unor membri ai noului obiect va modifica membrii corespunzatori ai celuilalt obiect referit. Cu alte cuvinte, se poate spune ca este vorba de o redenumire a obiectului care deja exista.
• Un masiv(tablou) de obiecte poate fi initializat:
a) in momentul declararii;
Exemplu:
Class tt
{
int j;
public:
tt(int k){j=k;} // constructor
int ret( ){return j;}
};
void main( )
{
tt tab[4]={11,12,13,14}; // initializare
for(int k=10;k<14;k++)
cout<<tab[k].ret( )<<”\n”;
}
Exemplu:
//un tablou de obiecte de tip punct
class punct{
public:
int u,v;
…………….
};
punct tab[5];
punct tab[5]={{0,0},{5,7},{10,17},{8,23},{3,23}};
//init. tabloului in momentul declararii sale
b) in cadrul declararii, cu ajutorul unei liste de instantiere avand ca elemente constructori ai
obiectului;
Daca clasa obiectului de baza accepta restrictiile cu privire la tipul de instantiere, atunci se va crea o lista de instantiere in vederea initializarii tabloului de obiecte. Identificarea constructorilor se va face in functie de lista de instantieri.
Exemplu:
Class t_2
{
int k,j;
public:
t_2(int u, int v){k=u; j=v;}
int ret( ){return k;}
int ret( ){return j;}
};
void main( )
{
t_2 t[4]={t_2(11,12), t_2(13,14), t_2(15,16), t_2(17,18)};
int k;
for( k=10;k<17;k++)
{
cout<<t[k].ret( );
cout<<”,”;
cout<<t[k+1].ret( )<<”\n”;
}
}
Exemplu:
class punct
{
public:
int u,v;
punct(int a, int b){u=a; v=b;}
punct(int a){u=a;v=a;}
};
punct tab [5]={
0,
// se apeleza constructorul cu un parametru: punct(0)
punct(3,5),
//se apeleaza constructorul cu doi parametri: punct(3,5)
10,
// se apeleaza constructorul cu un parametru: punct(10)
………..
};
• Un constructor implicit (fara parametri) este util la instantierea unui tablou de obiecte, avand in vedere situatia in care este imposibila transmiterea de parametri necesari constructorului. In prezenta constructorului implicit, se pot face instantieri partiale ale unui obiect.
Exemplu:
punct tab[5];// nu exista lista de initializari
Exemplu:
class punct
{
public:
int u,v;
punct(int a, int b){u=a; v=b;}
punct(int a){u=a;v=a;}
punct( ){u=0; v=0;}
};
punct tab [5]={ 0, punct(3,5)}; //initializare partiala
• Actiunea operatorului new in cazul tablourilor:
Sintaxa:
id_tablou=new tip_tablou[dim];
• Adresa returnata de operatorul new va fi adresa primului obiect din tablou.
Exemplu:
int*q=new int[5]; //Care este valoarea lui q?
Prin declaratia
punct*q=new punct(5,;
se indica o rezervare de memorie pentru obiectul precizat, dupa care se va apela constructorul pentru acest obiect.
• Se pot declara tablouri de obiecte, incluzand alocarea de memorie prin operatorul new.
Exemplu:
punct*tab=new punct[5];
Asa dupa cum am mentionat, pentru a se realiza transmiterea de parametri, clasa obiectelor ce formeaza tabloul, trebuie sa contina constructorul implicit.
• Analog functiei free( ) din C, in C++ exista operatorul delete care are ca scop eliberarea zonei de memorie alocata dinamic cu operatorul new. Operatorul delete este prezent in cadrul destructorilor. Inainte de a elibera zona de memorie alocata unui obiect, se va apela destructorul sau. Cu operatorul delete se poate realiza o eliberare selectiva a spatiului alocat dinamic cu operatorul new.
Exemplu:
int*p=new int[12];
// se aloca un spatiu de memorie pentru 12 elemente intregi
delete p;
// se elibereaza spatiul ocupat doar de obiectul p[0]
delete[ ] p;
// se elibereaza tot spatiul alocat
Exemplu:
class sir
{
char *s;
int dim;
public:
sir(char*); //constructor (prototip)
~sir( ); //destructor (prototip)
……………
};
// definirea constructorului
sir::sir(char*t)
{
dim=strlen(t)+1;
s=new charadims; //alocare de memorie
strcpy(s,t);
}
// definirea destructorului
sir::~sir( )
{
delete s;
}
……………………………………….
// exemplu de instantiere
sir secventa("Sectia Informatica");
// se distruge obiectul, apeland indirect destructorul
delete secventa;
// apelul direct al destructorului se face atunci cand identificatorul lui este precedat de iden_clasa
// si operatorul "::"
Exemplu:
secventa.sir::~sir( );
• Pentru a se evita o recursivitate infinita, nu se va folosi functia exit intr-un destructor. Cand se apeleaza functia exit, in timpul executiei unui program, vor fi apelati doar destructorii variabilelor globale, nu si ai variabilelor locale.
Aplicatie:
// Crearea si utilizarea unor tablourilor statice si dinamice de obiecte.
#include<iostream.h>
#include<string.h
class salariat
{
private:
char*nume;
long sal;
void init(char*s=" ",long a=0){
nume=new char[strlen(s)+1];
strcpy(nume,s);
}
public:
salariat(char*s,long a){init(s,a);}
salariat(void){init( );}
~salariat ( ) {delete nume;}
void introduc_salariat(char*s,long a){init(s,a);}
void afis_salariat( ){cout<<"\n Nume"<<nume<<"\t salariu:"<<sal;}
};
class serv{
int nr_sal;
salariat*sal;
public:
serv (int nr){
sal=new salariat[nr];
if(!sal){ cout<<"\n"<<nr<<"prea multi";
return;
}
nr_sal=nr;}
~serv( ){delete[nr_sal]sal;
}
void introd_serv( );
void afis_serv( );
int NR_SAL( ){return nr_sal;}
};
void serv::introd_serv( ){
char nume[25];long sal;
for(int i=0;i<nr_sal;i++){
cout<<"Nume:"; cin>>nume;
cout<<"Salariu:";cin>>sal;
}
}
• Elementele protejate dintr-o clasa formeaza, dupa cum am mai precizat, asa numita implementare a tipului abstract definit prin acea clasa. O functie membra a acelei clase se apeleaza intotdeauna prin obiectul curent, dupa cum urmeaza:
ident_obiect.ident_functie_memb (…);
sau
pointer_id_clasa->id_functie_memb( );
• Functiile obisnuite nu admit astfel de apeluri, datele prelucrate de ele fie ca sunt transferate prin parametri, fie ca sunt date globale. De aceea, o astfel de functie, pentru a prelucra obiectele unei clase, trebuie sa devina mai intai functie membra a acelei clase. Pentru o rezolvare mai comoda a acestei situatii, s-a cautat sa se gaseasca niste functii, care, desi nu sunt functii membre ale clasei, sa aiba acces la elementele protejate ale acesteia. Functiile prietene(friend ) sunt functii asociate unor clase. Ele nu sunt functii membre ale clasei la ai carei membri are acces. Aceste functii ignora caracterul privat si protected al membrilor clasei careia ii este prietena. Clasa cuprinde doar prototipurile functiilor prietene ei.
Exemplu:
//Sa consideram un tip definit de utilizator:
#include <iostream.h>
class X
{
int u,v;
public:
X(int k, int q){u=k;v=q;}
int dif(){return u*u-v*v;}
};
void main()
{
X z(6,3);
int p=z.dif(); cout<<"p="<<p; }
Se obtine pentru p valoarea 27, folosind functia membra, dif( ). La acelasi rezultat se va ajunge folosind functia friend dif( ) a clasei X, care nu mai este functie membra a acestei clase.
#include <iostream.h> class X
{ int u,v; public: X(int k, int q){u=k;v=q;} friend int dif(X w); }; int dif(X w){return w.u*w.u-w.v*w.v;} void main()
{ X z(6,3);
cout<<dif(z);
}
Functia dif( ) are acces deplin la membrii particulari ai clasei X (la u si v). Apelul ei se face in mod obisnuit.
• Declararea unei functii friend se face incluzand prototipul ei, precedat de cuvantul cheie friend, in acea clasa. Indiferent de pozitia declararii unei astfel de functii, in corpul clasei, ea va fi considerata publica. O functie friend, nefiind functie membra a clasei a carei prietena este, nu poate sa aiba un nume de obiect al clasei repective. In definitia sa, nu mai apare cuvantul cheie friend.
• Utilizarea functiilor friend aduc o serie de avantaje:
a) la supraincarcarea unor tipuri de operatori [vezi L5];
b) ofera o facilitate in crearea anumitor tipuri de functii de intrare/iesire;
c) sunt necesare cand doua sau mai multe clase contin membri corelati cu alte sectiuni din program.
• Am remarcat faptul ca orice functie membra nu poate fi functie friend aceleiasi clase, dar este posibil sa fie functie prietena unei alte clase. De aceea se spune ca functiile friend constituie o legatura intre clase. Exista doua situatii in declararea functiilor friend ale unei clase:
a) se specifica faptul ca functia membra a unei clase este functie friend a unei alte clase. Mai exact, se declara functia membra din prima clasa ca fiind de tip friend in a doua clasa.
Exemplu:
class Y;
// se predeclara clasa care contine functii prietene ale unei alte clase X
class X
{
……………
void F1(Y &a); // functie membra a clasei X
…………….
};
class Y
{
………………
friend void X::F1(Y &a); //functie friend pentru clasa Y
………………..
};
b) se poate declara o intreaga clasa prietena , in care toate functiile membre ale sale sunt functii
prietene ale unei alte clase. Exemplu:
class Y;
class X
{
………………..
void F1(Y &a);
………………..
};
class Y
{
………………..
friend X;
// se declara clasa X ca prietena a clasei Y(toate functile membre
// ale clasei X sunt functii friend pentru clasa Y)
………………..
};
• Clasele friend sunt utile atunci cand este necesara o comunicare intre clase, care au acelasi nivel ierarhic. In aceasta situatie, clasa friend are acces la membrii protejati prezenti in cealalta clasa care pot include nume de tipuri, enumerari de constante. Membrii clasei la care se permite accesul nu devin membri ai clasei friend.
Aplicatie:
Sa se implementeze o stiva de caractere (ca lista simplu inlantuita) folosind o clasa atasata nodurilor din lista si una atasata stivei respective.
class stiva;
//predeclarare a clasei care contine ca functii membre, functii prietene
// unei alte clase
class nod
{
private:
friend stiva; //clasa friend
nod(int i, nod*n);
int inf;
nod *prec;
};
class stiva{
private:
nod*varf;
public:
stiva( ){varf=NULL;}
~stiva( );
void push(int c);
int pop( );
};
Clasa nod este o clasa privata. Accesul la membrii ei se face prin intermediul unor functii friend (clasa stiva).
• Functiile friend nu poseda pointerul this.
Puneti in evidenta caracteristicile programului urmator.
#include<iostream.h> #include<conio.h> class punct{ float x,y; public: punct(float a=0,float b=0){x=a;y=b;} ~punct(){cout<<"Se distruge punct! \n";}
void afis()
{
cout<<"\n Punct de coordonate x="<<x<<" y="<<y;}
};
class vector
{
punct o,v;
public:
vector(float x_1=0,float y_1=0,float x_2=0,
float y_2=0)(x_1,y_1),v(x_2,y_2){} ~vector(){cout<<"\n Se distruge vector!";}
void afis(){cout<<"\n Vector:";
o.afis();
v.afis();
}};
class triunghi{
punct *p_1,*p_2,*p_3;
public:
triunghi(float a_1=0,float b_1=0,float a_2=0,
float b_2=0,float a_3=0,float b_3=0)
{
p_1=new punct(a_1,b_1);
p_2=new punct(a_2,b_2);
p_3=new punct(a_3,b_3);
}
~triunghi(){
delete p_1;
delete p_2;
delete p_3;
}
void afis()
{
cout<<"\n TRIUNGHI:";
p_1->afis();
p_2->afis();
p_3->afis();
}
};
void main(void)
{
clrscr();
punct p,p_1(3.5,5.6);
p.afis();
p_1.afis();
vector v_1,v_2(1.5,2.5,3.5,4.5);
vector v_3(2,3);
v_1.afis();
v_2.afis();
v_3.afis();
triunghi t_1,t_2(1.2,3.4,5.6);
t_1.afis();
t_2.afis();
getch();
}
Aplicatie:
Folosind functii friend, sa se calculeze o putere a unui numar complex.
#include <iostream.h> #include <conio.h> #include <math.h> #define PI 3.14159265358979
class complex
{ double re; double im; public: double modul; double arg(); void afis(); friend void cp(complex&,int); void init(double x,double y)
{
re=x;
im=y;
modul=sqrt(re*re+im*im);
}
};
inline void complex::afis(){cout<<re<<"+i*"<<"("<<im<<")";}
double complex::arg()
{
if(re==0.0&&im==0.0)return 0.0;
if(im==0.0)
if(re>0.0) return 0.0;
else
return PI;
if(re==0.0)
if(im>0.0)return (PI/2);
else
return (3*PI)/2;
double a=atan(im/re);
if(re<0.0)return PI+a;
if(im<0.0)return 2*PI+a;
return a;
}
void cp(complex &z,int n)
{
double r;
double a;
r=z.modul;
a=z.arg();
double r_la_n=pow(r,(double)n);
double aa=n*a;
z.re=r_la_n*cos(aa);
z.im=r_la_n*sin(aa);
}
void main()
{
clrscr();
complex u;
u.init(-1,-1);
cout<<"\n U=";
u.afis();
cout<<"\n Modulul nr.U:"<<u.modul;
cout<<"\n Nr. ridicat la putere:";
cp(u,3);
u.afis();
}
Subiecte similare
» Crearea, iniţializarea şi distrugerea obiectelor unei clase
» Mostenire clase de baza clase derivate
» Serializarea obiectelor in Java
» Clase imbricate - obiecte si functii
» Functii virtuale clase abstracte
» Mostenire clase de baza clase derivate
» Serializarea obiectelor in Java
» Clase imbricate - obiecte si functii
» Functii virtuale clase abstracte
Informatica :: IT :: C++
Pagina 1 din 1
Permisiunile acestui forum:
Nu puteti raspunde la subiectele acestui forum