Pagina de start a forumului Informatica
 FAQ  •  Cautare  •  Membri  •  Grupuri   •  Inregistrare  •  Profil  •  Mesaje private  •  Autentificare
Subiectul urmator
Subiectul anterior
Creaza un subiect nou   Raspunde la subiect  Pagina de start a forumului Informatica » C++
Autor Mesaj
Admin
Administrator
Administrator


Data inscrierii: 07/Dec/2013
Mesaje: 1103

MesajTrimis: 14/12/2013 19:28 Raspunde cu citat (quote) Back to top

• Atunci, cand o clasa se defineste in cadrul unei alte clase, se spune ca sunt clase imbricate.

• O clasa imbricata este valida doar in interiorul clasei ce o contine. Avand in vedere posibilitatile oferite prin mecanismul de mostenire, astfel de clase se utilizeaza mai rar.
Exemplu:
#include <iostream> class vector
{ private: class punct
{ public: float x,y; void afis(); void in_punct(float x1=0,float y1=0); }o,v; public: void in_vect(float x1,float y1,float x2,float y2)
{
o.in_punct(x1,y1);
v.in_punct(x2,y2);
}
void afis();
};
void vector::punct::in_punct(float x1,float y1)
{x=x1;y=y1;}
void vector::punct::afis()
{cout<<"\n x="<<x<<" y="<<y;}
void vector::afis()
{o.afis();v.afis();}
void main()
{
vector vect;
vect.in_vect(35,45,55,65);
vect.afis();
}

• O clasa poate contine ca membri, instantieri ale altor clase (obiecte imbricate) cu o remarca asupra faptului, ca nu se consimt initializari in cadrul declararii acestor clase.

• Exista o conventie asupra apelului constructorilor obiectelor membre.
Sa consideram urmatoarea situatie: A este o clasa care contine un obiect imbricat de tip "TB" care, la randul sau, contine un penis M de tip pointer. Sa presupunem ca prin constructorul clasei TB se aloca dinamic o zona de memorie la care va pointa M.
Daca constructorul TB nu a fost apelat, nu se accepta ca prin constructorul A sa se initializeze zona la care pointeaza M, pentru ca:

a) pointerul M va lua o valoare aleatoare;
b) se pot distruge informatii din memorie.
In C++ exista un mecanism convenabil in acest sens.
Sa consideram clasa A care contine ca membri, obiecte ale altor clase A1,A2,..,An.
Pot fi intalnite urmatoarele situatii:
1) clasele Ak nu au constructori (k=1,...,n) (in acest caz, nu vor exista deosebiri intre constructorii clasei A si un constructor al unei clase ce nu contine obiecte membre imbricate);
2) clasele Ak (k=1,...,n) nu au un constructor implicit si nici un constructor cu parametri cu valori implicite (intr-o astfel de situatie este obligatoriu a se specifica explicit numele fiecarui obiect urmat de lista parametrilor actuali):
iden_obiect(lista_param_actuali)
3) clasele Ak (k=1,...,n) au un constructor implicit sau unul cu toti parametrii cu valori implicite (se poate proceda ca in întâiul caz, apelandu-se implicit constructorii respectivi, sau ca in a doua situatie, specificandu-se explicit doar parametrii solicitati).

Intotdeauna apelul constructorilor obiectelor imbricate se va efectua inainte de executarea constructorilor clasei A. Pentru a preciza ordinea de apelare a constructorilor obiectelor imbricate este necesar a se mentiona aceasta in definitia constructorului clasei A si nu in declaratia sa.

• Unele aspecte cu privire la folosirea destructorilor in clasele imbricate:
Sa presupunem ca avem urmatoarea situatie:

class U
{
class imb_1 ob1;
class imb_2 ob2;
………………….
public:
U(int);
………………….
~U( );
}ob;

#n acest caz, apelul destructorilor pentru obiectele ob1 si ob2 se va face dupa executia "~U( )".

• Daca presupunem ca avem o adresare indirecta de forma "pointer la obiect imbricat", in loc de obiecte imbricate, atunci va fi necesar atat alocarea dinamica cat si eliberarea explicita a zonei de memorie necesara pentru obiectele spre care vor pointa membrii respectivi. Aceste operatii se executa prin constructorul / destructorul clasei care contine obiectele imbricate.

• O atentie sporita trebuie acordata mecanismului de copiere bit cu bit a obiectelor. Pot aparea erori nu la copiere, ci la apelul destructorului care este obligat sa elibereze de mai numeroase ori aceeasi zona de memorie.
Exemplu:
class punct
{
int u,v;
public:
punct(int a=0, int b=0)
{u=a;v=b;}
punct(int a, int b)
{u=a; v=b;}
………………………………………
~punct( ); };
class vector
{
punct og,vf;
public:
vector(int,int);
vector(int,int,int,int);
………………………
~vector( );
};
class triunghi
{
punct *p1, *p2, *p3;
public:
triunghi(int,int,int,int,int,int);
~triunghi( );
delete p1;
delete p2;
delete p3;
};

vector::vector(int a, int b):vf(a,b){ }
vector::vector(int a1,int b1,int a2,int b2):og(a1,b1),vf(a2,b2){ }
triunghi:: triunghi(int a1, int b1, int a2, int b2, int a3, int b3)
{
p1=new punct(a1,b1);
p2=new punct(a2,b2);
p3=new punct(a3,b3);
}

Exista deosebiri sintactice / semantice intre acest exemplu si ultimul program din aL5s ?

• Cand o clasa este declarata intr-o functie, ea este cunoscuta doar in interiorul acelei functii si nu in exteriorul ei. O astfel de clasa se numeste clasa locala. Daca se utilizeaza o astfel de clasa, trebuie sa tinem cont de urmatoarele:
a) toate functiile membre trebuie definite in interiorul declaratiei clasei;
b) clasa locala nu are acces la variabilele locale ale functiei in care ea este declarata (cu exceptia variabilelor locale declarate static in interiorul functiei);
c) intr-o clasa locala nu se poate declara nici o variabila de tip static, de aceea astfel de clase sunt mai putin uzuale in C++.
Exemplu:
# conține <iostream>
void gama( );
main( )
{
// in aceasta functie nu este cunoscuta clasa LOC
gama( );
return 0;
}

void gama( )
{
// clasa LOC definita in interiorul functiei gama in interiorul careia este cunoscuta.
class LOC
{
int k;

public:
void scrie(int m){k=m;}
int af( ){return k;}
}ob;
ob.scrie(30);
cout<<ob.af( );
}

• Transmiterea obiectelor catre functii se realizeaza asemanator cu transmiterea oricarui alt tip de parametru. Se utilizeaza mecanismul "apel prin valoare", adica prin copiere. Efectuarea unei copii inseamna crearea unui obiect nou. Se pune intrebarea, daca efectuarea unei copii, solicita apelul unui constructor al obiectului la crearea copiei sale si daca se executa destructorul la distrugerea copiei respective.

Sa urmarim urmatoarea secventa:
…………………………………………
class A
{
int k;
public:
A(int p);
~A( );
void init1(int p){k=p;}
int revin( ){return k;}
};
A::A(int p)
{ k=p;
cout<<k<< \n"; // creere
}
A::~A( )
{ cout<<k<<"\n";} // distrugere

void g(A ob);

void main( )
{
A ob_1(13);
g(ob_1);
cout<<ob_1.revin( )<<"\n"; // ce reprezinta?
}
…………………………………………
void g(A ob)
{ ob.init1(12);
cout<<ob.revin( ); // ce reprezinta?
}
Analizand iesirea acestui program, se observa ca se apeleaza de doua ori functia destructor si o singura data functia constructor. Conform iesirii, functia constructor nu este apelata, cand copia lui "ob_1" din main() este transmisa lui "ob" din g( ). Cand se oferă un obiect catre o functie, se vrea dispoziția curenta a obiectului. Daca ar fi apelat constructorul pentru a crea replica obiectului respectiv, s-ar realizează initializarea noului obiect creat si ar putea fi modificat. De aceea, constructorul nu va fi apelat la crearea copiei. Copia, la fel ca o variabila locala obisnuita, se poate distruge la finele executiei functiei. Copia, care se creaza la nivel de bit, poate realiza diverse operatii, ceea ce impune apelul destructorului pentru inlaturarea sa.

• O functie poate returna un obiect in punctul apelant.

Exemplu:
……………………………………….
class A
{
int k;
public:
void init(int m){k=m;}
int afis( ){return k;}
};

A g( );
// returneaza obiect de tipul A
void main( )
{
A ob;
Ob = g( );
cout<<ob.afis( )<<"\n";
}

A g( )
{
A a;
a.init(11);
return a;
}

• Cand un obiect este returnat de o functie, este făcut automat un obiect temporar, care contine valoarea returnata. Acesta este obiectul care este returnat de functie. Dupa returnare, obiectul respectiv este distrus. Distrugerea obiectului temporar poate avea si efecte negative. Daca obiectul, care a fost returnat, are un destructor care elibereaza zona de memorie alocata dinamic, aceea memorie va fi eliberata, chiar daca obiectul, care primeste valoarea returnata, inca o mai foloseste Prevenirea unei astfel de situatii se face cu ajutorul supraincarcarii avezi L.10s operatorului de atribuire si definirea unui constructor de copiere.
• Daca doua obiecte sunt de acelasi tip, se poate realiza o atribuire intre ele. Aceasta inseamna ca datele obiectului din membru drept al operatorului de atribuire vor fi copiate, in mod corespunzator, in datele obiectului din membru stang.
Exemplu;
class A
{
int k;
public:
void init(int m){k=m;}
………………………..
};
void main( )
{
A ob1, ob2;
ob1.init(66);
ob2=ob1;
// copiere bit cu bit a obiectului ob1 in obiectul ob2}
……………………….
}

Aplicatie.
Sa se calculeze aria unor figuri geometrice plane.

#include<iostream>
#include<conio>
#include<stdlib>
#include<math>
#define EROARE -1
#define CERC 0
#define PATRAT 1
#define DREPTUNGHI 2
#define TRIUNGHI 3
#define PI 3.141
class GEOM
{
private:
union
{
public:
double raza,lp,ld[2],lt[3];
}fig;
public:
int tip;
GEOM();
double aria(GEOM*p);
int cit_fig(GEOM*p);
};
double GEOM::aria(GEOM*p)
{
double sp,a,b,c;
switch(p->tip){
case CERC:return PI*(p->fig.raza)*
(p->fig.raza);
case PATRAT: return p->fig.lp*p->fig.lp;
case DREPTUNGHI: return p->fig.ld[0]*
p->fig.ld[1];
case TRIUNGHI: {sp=(p->fig.lt[0]+p->fig.lt[1]+
p->fig.lt[2])/2;
cout<<"Semiperimetrul este:"<<sp>fig.lt[0])>0&&
(b=sp-p->fig.lt[1])>0&&
(c=sp-p->fig.lt[2])>0)
return sqrt(sp*a*b*c);
else
cout<<"Nu se formeaza triunghi!";
return 0;}
default:return 0;
}
}
int GEOM:: cit_fig(GEOM*p)
{
switch(p->tip){
case CERC:for(;;){ cout<<"raza="; cin>>p->fig.raza;
if(p->fig.raza<=0)cout<<"Citire
raza eronata!";
else return 1; }
case PATRAT:for(;;){
cout<<"Latura patratului=";
cin>>p->fig.lp;
if(p->fig.lp<=0)cout<<"\n citire
lp eronata!";
else return 1;}
case DREPTUNGHI:for(;;){ cout<<"Dimensiunile
dreptunghi:\n"; cin>>p->fig.ld[0]; cin>>p->fig.ld[1];
if(p->fig.ld[0]<0>fig.ld[1]<=0)
cout<<"citire ld eronata!";
else return 1;} case TRIUNGHI:for(;;){
cout<<"Laturile triunghiului:\n";
cin>>p->fig.lt[0];
cin>>p->fig.lt[1];
cin>>p->fig.lt[2];
if(p->fig.lt[0]<0>fig.lt[1]<0>fig.lt[2]<=0)
cout<<"citire lt eronata!";
else return 1;}
default:return 0;
}
}
void main(void)
{
char c;
GEOM f;
for(;;){
cout<<"Tastati o tasta: C D P T\n";
cin>>c;
switch(c){
case 'C':{f.tip=CERC;
break;}
case 'D':{f.tip=DREPTUNGHI;
break;}
case 'P':{f.tip=PATRAT;
break;}
case 'T':{f.tip=TRIUNGHI;
break; }
default:cout<<"S-a tastat alt caracter!";
}
if(f.tip!=EROARE)break;}
if(f.cit_fig(&f)==0)exit (1);
if(f.aria(&f)==0)exit(1);
cout<<"ARIA FIGURII:\n"<<f.aria(&f);
}
Ce se intampla cu constructorii si destructorii in aceasta implementare? Este o eroare? De ce? Sa se realizeze o noua implementare in C++ pentru o astfel de aplicatie care sa contina clase imbricate. Aplicatie:
Sa se selecteze un anumit numar de elemente dintr-un sir de numere intregi, sa se ordoneze subsirul extras si sa se calculeze norma acestuia din urma. Utilizati o clasa locala in functia de afisare a normei.

#include<iostream> #include<conio> #include<math> #define MAX 50 void afis(double);

void sort(int a[],int m)
{
int*p,i,r,q=1;
while (q)
{
q=0;
p=&a[1];
for(i=1;i<m>*(p+1)){
r=*p;
*p=*(p+1);
*(p+1)=r;
q=1;}
p++;}
}
}

void suma_patrat(int a[],int m)
{
double nv=0;
for(int i=1;i<m+1;i++)
nv+=(a[i]*a[i]);
afis(nv);
}

void afis(double t)
{
class N
{
double u,t;
public:
void scrie(){cout<<"Norma vectorului extras:";}
void af(double t){u=sqrt(t);cout<<u;}
}v;
v.af(t);
}
void main(void)
{
int n,m,i,a[MAX];
clrscr();
cout<<"Dimensiunea vector:";
cin>>n;
cout<<"Dati elementele vector:";
for (i=1;i<n>>a[i];
cout<<"";}
cout<<"Numar elemente sortate:";
cin>>m;
sort(a,m);
cout<<"Elem.sortate:\n";
for(i=1;i<m+1;i++){
cout<<a[i];
cout<<"\n";}suma_patrat(a,m);}
Vezi profilul utilizatorului Trimite mesaj privat
Afiseaza mesajele pentru a le previzualiza:   
Creaza un subiect nou   Raspunde la subiect

Subiectul urmator
Subiectul anterior
Nu puteti crea un subiect nou in acest forum
Nu puteti raspunde in subiectele acestui forum
Nu puteti modifica mesajele proprii din acest forum
Nu puteti sterge mesajele proprii din acest forum
Nu puteti vota in chestionarele din acest forum


Powered by phpBB © 2001, 2002 phpBB Group