CPP_RO_6_POINTERI ?I CLASE

6.1. Declararea pointerilor spre obiectele unei clase

6.1. Declararea pointerilor spre obiectele unei clase

Cum declar?m pointeri pentru orice tip de date, putem declara pointeri pentru orice clas?. De exemplu:

fractie_rationala fr19(1, 2), fr20(2, 5);
fractie_rationala *p1, *p2=&fr19, *p3;

Aici p1, p2 ?i p3 sunt trei pointeri cu tipul de baz? fractie_rationala. Pointerul p2 a fost ini?ializat cu adresa obiectului fr19, pointerii p1 ?i p3 deocamdat? nu con?in nici o adres?, ?ns? atribuirea poate fi f?cut? ?n orice moment ?n mod obi?nuit pentru pointeri:

p1 = &fr20;
p3 = p2;

Pointerului p1 i-a fost atribuit? adresa obiectului fr20, pointerul p3 acum con?ine adresa obiectului fr19, fiindc? pointerului p3 i-a fost atribuit con?inutul pointerului p2.

Obiectele pot fi accesate prin intermediul pointerilor, ?n mod normal, folosind operatorul unar *. Astfel, *p1 reprezint? ?n cazul nostru referin?a la obiectul fr20, iar *p2 ?i *p3 reprezint? referin?ele la obiectul fr19. De aceea fragmentul:

cout << fr20 << ' ' << *p1 << endl;
cout << fr19 << ' ' << *p2 << ' ' << *p3 << endl;

va afi?a:

2/5 2/5
1/2 1/2 1/2
_________________________
Autorul: dr.conf. S. Pereteatcu

6.2. Accesarea membrilor unei clase prin intermediul pointerilor

6.2. Accesarea membrilor unei clase prin intermediul pointerilor

Membrii publici ai clasei pot fi accesa?i folosind operatorul . (punct). De exemplu:

fractie_rationala fr21(3, 7);
fractie_rationala *p = &fr21;
cout << fr21.numarator()<< ' ' << (*p).numarator() << endl;

va afi?a:

3 3

Subliniem c? *p.numarator() nu va fi corect, lu?nd ?n considera?ie preceden?a operatorilor.

Totu?i, pentru accesarea membrilor publici prin intermediul pointerilor, mai comod este de a utiliza operatorul ->. Adic?:

cout << fr21.numarator()<< ' '<< p->numarator() << endl;

d? acela?i rezultat.

?n zonele de vizibilitate (func?ia membr? a clasei, sau func?ia prieten? a clasei) ceilal?i membri ai clasei (proteja?i sau priva?i) pot fi accesa?i prin intermediul pointerilor, folosind operatorii . sau ->, exact a?a cum se acceseaz? ?i membrii publici.
_________________________
Autorul: dr.conf. S. Pereteatcu

6.3. Alocarea dinamic? a memoriei pentru obiecte

6.3. Alocarea dinamic? a memoriei pentru obiecte

Obiectele pot fi create dinamic ?n memoria heap cu operatorul new ?i apoi eliminate dup? utilizarea cu operatorul delete. ?ns?, specific pentru obiecte este faptul c? la crearea obiectului va fi automat apelat unul din constructori, iar la distrugerea obiectului va fi automat apelat destructorul clasei. Care din constructori va fi apelat depinde de lista parametrilor dup? numele clasei ?n operatorul new.

Indicarea numai a numelui de clas?, f?r? parametri, se admite doar dac? clasa are constructorul f?r? parametri, sau are constructorul la care pentru to?i parametrii este definit? valoarea implicit?. Pentru exemple mai ad?ug?m la func?ia main() urm?torul cod:
 

   p1 = new fractie_rationala(1, 3);
   cout << "*p1=" << *p1 << endl;
   cout << "*p1="; p1->print(); cout << endl;
 
   fractie_rationala fr22 = *p1;
   cout << "fr22=" << fr22 << endl;
 
   p2 = new fractie_rationala;
   cout << "*p2=" << *p2 << endl;
 
   delete p1;
   delete p2;
sau:
   delete p1, delete p2;
Fragmentul ad?ugat va afi?a urm?torul text:
*p1=1/3
*p1=1/3
fr22=1/3
*p2=0/1


?n instruc?iunea:

p1 = new fractie_rationala(1, 3);

operatorul new apeleaz? constructorul clasei fractie_rationala, transmi??nd dou? argumente, respectiv 1 ?i 3.

?n instruc?iunea:

p2 = new fractie_rationala;

operatorul new apeleaz? acela?i constructor, ?ns? cu valorile implicite pentru ambele argumente, respectiv 0 ?i 1. Ne amintim c? constructorul clasei fractie_rationala are o a?a facilitate.

?n instruc?iunea:

delete p1;

operatorul delete apeleaz? destructorul clasei fractie_rationala.

Dac? o clas? admite apelul constructorului f?r? indicarea explicit? a argumentelor, atunci pot fi create dinamic matrice de obiecte ale acestei clase. ?n acest caz ?n operatorul new se indic? dup? numele clasei, ?n paranteze p?trate, num?rul de obiecte-elemente. Operatorul new va aloca respectiv at?tea obiecte consecutiv ?n memoria heap, ?i pentru fiecare din aceste obiecte va apela constructor f?r? argumente explicite. Mai ad?ug?m la func?ia main() ?nc? un fragment de cod, care va demonstra cele expuse:

// vector dinamic de obiecte 
   fractie_rationala *v;
   v = new fractie_rationala[5]; // cre?m dinamic un
                                 // vector din 5 elemente 
                                 // fiecare element fa fi
                                 // ini?ializat cu 0/1
   int i;
   for(i=0; i<5; i++)       
             v[i].modif(v[i].numarator()+i+1,(v+i)->numitor()+i+1);
 
   for(i=0; i<5; i++)
      cout << "v[" << i << "]=" << *(v+i) << endl;
 
   delete []v;


?n acest exemplu se creeaz? dinamic un vector din 5 elemente fractie_rationala, fiecare din care se ini?ializeaz? cu valoarea implicit? 0/1.  Apoi,  ?n ciclu se modific?  toate  elementele ale acestui vector prin utilizarea func?iei modif() – membr? a clasei fractie_rationala. ?n fiecare frac?ie la num?r?tor ?i numitor se ad?ug? valoarea indicelui elementului plus 1. Dup? aceasta, elementele vectorului se afi?eaz? pe ecran. ?n sf?r?it, se elibereaz? memoria alocat? pentru acest vector.

Deoarece v este un vector de obiecte, operatorul delete va apela destructorul pentru fiecare obiect al acestui vector. Rezultatul afi?at este:

v[0]=1/2
v[1]=2/3
v[2]=3/4
v[3]=4/5
v[4]=5/6


?n unele cazuri, ?n loc de alocare dinamic? a unui vector de obiecte este mai comod de a crea un vector de pointeri la obiecte. ?n a?a cazuri nu este necesar constructorul f?r? parametri. Ad?ug?m urm?torul fragment ?n func?ia main():

// vector static de pointeri la obiecte
   fractie_rationala *vp[5]; // declar?m un vector static
                             // de pointeri
   int j;
   for(j=0; j<5; j++)
   {
      vp[j] = new fractie_rationala(j+1, j+2);
   }
 
   for(j=0; j<5; j++)
      cout << "*vp[" << j << "]=" << *vp[j]
           << endl;
 
   for(j=0; j<5; j++)
      delete vp[j];


?n acest exemplu cre?m un vector static din 5 pointeri la obiecte fractie_rationala. Apoi, cre?m ?n ciclu c?te un obiect dinamic fractie_rationala, atribuind adresa obiectului de r?nd pointerului-element corespunz?tor. Mai departe, ?n ciclu afi??m obiectele pointate de c?tre elementele vectorului vp. ?n ciclul de finisare eliber?m memoria ocupat? de c?tre aceste obiecte. De fiecare dat? operatorul delete va apela destructorul pentru obiectul de cur?nd. Acest fragment va afi?a urm?torul text:

*vp[0]=1/2
*vp[1]=2/3
*vp[2]=3/4
*vp[3]=4/5
*vp[4]=5/6

Vectorul de pointeri la obiecte poate fi alocat ?i dinamic. Cercet?m ?nc? un fragment cu care vom ?nlocui ?n func?ia main() fragmentul precedent:

// vector dinamic de pointeri la obiecte
   fractie_rationala **vp; // pointer la un pointer la obiecte
 
   int no = 5; // num?rul de obiecte
   vp = new fractie_rationala* [no]; // aloc?m vector
                                     // din no pointeri
 
   int j;
   for(j=0; j<no; j++)
   {
      vp[j] = new fractie_rationala(j+1, j+2);
   }
 
   for(j=0; j<no; j++)
      cout << "*vp[" << j << "]=" << *vp[j]
           << endl;
 
   for(j=0; j<no; j++)
      delete vp[j]; // pentru fiecare obiect va fi apelat
                    // destructorul
 
   delete []vp; // eliber?m memoria ocupat? de c?tre vectorul
                // de pointeri, nu va fi apelat nici un destructor

Acest fragment va afi?a aceea?i ie?ire ca ?i fragmentul precedent.
_________________________
Autorul: dr.conf. S. Pereteatcu

6.4. Supra?nc?rcarea operatorilor de alocare ?i eliberare dinamic? a memoriei

6.4. Supra?nc?rcarea operatorilor de alocare ?i eliberare dinamic? a memoriei

Este posibilitatea de a supra?nc?rca operatorii new ?i delete. Acest lucru poate fi f?cut, de exemplu, pentru a compatibiliza sistemul de alocare a memoriei nou C++ cu cel vechi C sau pentru a introduce un sistem propriu de alocare a memoriei, folosind metode speciale, cum ar fi folosirea fi?ierelor de pe disc ca memorie virtual? c?nd s-a epuizat memoria disponibil? din heap.

Forma general? de supra?nc?rcare a operatorului new ?n declararea clasei este urm?toarea:

void *[nume_clas?::]operator new (size_t marime)

{

   // codul func?iei de alocare

   …

   return pointer_la_memorie;

}

Tipul size_t este tipul predefinit ?n C++ ca un ?ntreg f?r? semn destinat pentru exprimarea m?rimilor zonelor de memorie, fiind capabil s? con?in? m?rimea celui mai mare bloc de memorie continu?. De exemplu, operatorul sizeof ?ntoarce valorile de tipul size_t. Parametrul marime va con?ine automat num?rul de octe?i necesari pentru a memora obiectul pentru care se face alocarea.

Dac? supra?nc?rcarea operatorului se face pentru o clas?, compilatorul va asigura apelul automat al constructorului, adic? nu trebuie de f?cut acest lucru ?n codul de supra?nc?rcare a func?iei de alocare. Codul func?iei de alocare poate face orice lucru de care ave?i nevoie, unicul lucru care trebuie s? fie respectat este ca func?ia de supra?nc?rcare a operatorului new trebuie s? returneze un pointer spre memoria alocat?, sau NULL, dac? apare o eroare de alocare.

Forma general? de supra?nc?rcare a operatorului delete ?n declararea clasei este urm?toarea:

void [nume_clas?::]operator delete (void *pointer)

{

   // codul func?iei de eliberare a blocului de memorie indicat?

   // de pointer

   …

}

Parametrul pointer va indica zona de memorie care a fost alocat? anterior ?i care trebuie s? fie eliberat?. Ar fi de dorit ca func?ia ce supra?ncarc? operatorul delete s? respecte aceste condi?ii. Dac? func?ia elibereaz? zona de memorie ocupat? de un obiect, automat va fi apelat destructorul pentru acest obiect, a?a c? nu trebuie f?cut acest lucru explicit.

Pentru exemplu, supra?nc?rc?m operatorii new ?i delete ?n clasa fractie_rationala, folosind mecanismul de alocare din C. Inser?m ?n sec?iunea public a clasei fractie_rationala urm?torul cod:

void *operator new(size_t marime)
{
   cout << "Sunt in new pentru fr!\n";
   return malloc(marime);
}
 
void operator delete(void *pointer)
{
   cout << "Sunt in delete pentru fr!\n";
   free(pointer);
}


?n func?iile de mai sus special au fost incluse c?te o instruc?iune de afi?are demonstrativ?. Ne asigur?m c? la ?nceputul programului nostru este conectat fi?ierul antet ”stdlib.h”, lans?m programul ?i analiz?m lucrul operatorilor new ?i delete supra?nc?rca?i, prin urm?rirea mesajelor Sunt in new pentru fr! ?i Sunt in delete pentru fr! care vor ap?rea printre ie?irile din exemplele precedente.
_________________________
Autorul: dr.conf. S. Pereteatcu

Translate Переводчик

Подписка на новости

SmartResponder.ru
Ваш e-mail: *
Ваше имя: *

Хостинг для Wordpress сайтов