CPP_RO_5_SUPRA?NC?RCAREA OPERATORILOR

5.1. Forme de supra?nc?rcare a operatorilor

5.1. Forme de supra?nc?rcare a operatorilor

?n programul precedent de utilizare a clasei fractie_rationala au fost ad?ugate c?teva func?ii de efectuare a calculelor asupra obiectelor acestei clase. ?ns?, utilizarea func?iilor nu este at?t de comod?, mai bine spus – laconic?, precum utilizarea semnelor operatorilor obi?nui?i cu care ne-am deprins. ?n C++ exist? posibilitatea de supra?nc?rcare a operatorilor, similar? cu supra?nc?rcarea func?iilor.

Sunt dou? forme de supra?nc?rcare a operatorilor: prin func?ie membr? a clasei, ?i prin func?ie nemembr?, dar, de obicei,  prieten?(friend) a clasei.

Forma general? de supra?nc?rcare a operatorului prin func?ia membr? este urm?toarea:

Declararea:

tip_returnare [nume_clas?::]operator semn_operator (list?_ parametri);

Definirea:

tip_returnare nume_clas?::operator semn_operator (list?_ parametri)

{

}

Func?ia membr? de supra?nc?rcare a operatorului poate fi desf??urat? inline.

Forma general? de supra?nc?rcare a operatorului prin func?ia prieten? este urm?toarea:

Declararea:

friend tip_returnare operator semn_operator (list?_ parametri);

Definirea:

tip_returnare operator semn_operator (list?_parametri)

{

}

Cercet?m exemplul cu clasa fractie_rationala dezvoltat mai departe:

// Clasa fractie_rationala cu operatorii supra?nc?rca?i
#include <stdlib.h>
#include <stdiostr.h>
 
class fractie_rationala
{
   protected:
      unsigned int numarat;
      unsigned int numit;
   public:
      fractie_rationala(unsigned int numarat_init=0,
                        unsigned int numit_init=1)
      {}
      void print(){}
      void modif(unsigned int numarat_nou=0,
                 unsigned int numit_nou=1) {}
      unsigned int numarator(){}
      unsigned int numitor(){}
      void reducere();
      friend void numitor_comun(fractie_rationala&,
                                fractie_rationala&);
      friend int egale(fractie_rationala x,
                       fractie_rationala y);
      friend fractie_rationala suma(fractie_rationala,
                                    fractie_rationala);
      int operator ==(fractie_rationala);
      friend fractie_rationala operator + (fractie_rationala,
                                           fractie_rationala);
   private:
      void eroare(char* mesaj) {}
};
 
void fractie_rationala::reducere()
{// codul precedent
}
 
void numitor_comun(fractie_rationala &x, fractie_rationala &y)
{// codul precedent
}
 
int egale(fractie_rationala x, fractie_rationala y)
{// codul precedent
}
 
fractie_rationala suma(fractie_rationala x, fractie_rationala y)
{// codul precedent
}
 
int fractie_rationala::operator == (fractie_rationala y)
{
   fractie_rationala x1=*this;
   numitor_comun(x1, y);
   return x1.numarat==y.numarat;
}
 
fractie_rationala operator +(fractie_rationala x,fractie_rationala y)
{
   fractie_rationala u;
   u.numarat=x.numarat*y.numit+x.numit*y.numarat;
   u.numit=x.numit*y.numit;
   u.reducere();
   return u;
}
 
void main()
{
   fractie_rationala fr3(1, 2);
   fractie_rationala fr4(1, 4);
   fractie_rationala fr5(2, 4);
 
   fr3.print();
   cout << " si ";
   fr4.print();
   if(fr3==fr4)
      cout << " sunt egale\n";
   else
      cout << " nu sunt egale\n";
 
   fr3.print();
   cout << " si ";
   fr5.print();
   if(fr3==fr5)
      cout << " sunt egale\n";
   else
      cout << " nu sunt egale\n";
 
   fr3.print();
   cout << " + ";
   fr4.print();
   cout << " = ";
   (fr3+fr4).print();
   cout << endl;
 
   fr3.print(); 
   cout << " + ";
   fr4.print();
   cout << " + ";
   fr5.print();
   cout << " = ";
   (fr3+fr4+fr5).print();
   cout << endl;
 
   char c; 
   cin >> c;
}


Aici au fost supra?nc?rca?i doi operatori pentru a lucra cu obiectele fractie_rationala. Operatorul == a fost supra?nc?rcat sub form? de func?ie membr?, iar operatorul + a fost supra?nc?rcat sub form? de func?ie prieten?. ?n func?ia main() se demonstreaz? utilizarea acestor operatori ?n expresii cu obiectele fractie_rationala.

Fiind rulat, programul dat va afi?a:

1/2 si 1/4 nu sunt egale
1/2 si 2/4 sunt egale
1/2 + 1/4 = 3/4
1/2 + 1/4 + 2/4 = 5/4


?n primul r?nd, discut?m supra?nc?rcarea operatorului sub form? de func?ie membr?. Operatorul == este binar, adic? are doi operanzi, ?ns? func?ia operator ==() are numai un parametru. Care-i cauza? Trebuie s? fie a?a ?n cazul ?n care operatorul se supra?ncarc? prin func?ia membr?. Num?rul de parametri trebuie s? fie cu unul mai mic dec?t num?rul de operanzi ai operatorului. ?n cazul nostru parametrul y va fi al doilea operand, iar rolul primului operand ?l joac? obiectul la care se aplic? func?ia-operator. Adic?, ?n expresia fr3+fr4 func?ia se aplic? la obiectul fr3, iar obiectul fr4 va fi argumentul func?iei. Dac? operatorul care se supra?ncarc? prin func?ia membr? este unar (are un singur operand), atunci func?ia respectiv? va fi f?r? parametri.

Acum s? ne concentr?m la definirea func?iei operator ==(). Mai ?nt?i s? ne aducem aminte c? la apelul egale(fr3, fr4) func?ia egale() prime?te copiile a dou? obiecte fractie_rationala, aduce aceste copii la un numitor comun ?i le compar? num?r?torii. Ne uit?m ce se ?nt?mpl? ?n func?ia operator ==(). Ea prime?te copia obiectului argument care trebuie s? fie adus? la un numitor comun cu primul operand – obiectul la care se aplic? operator.

?ns?, modific?nd copia operandului doi func?ia nu trebuie s? modifice obiectul – primul operand. De aceea, se creeaz? un obiect local x1 – copia obiectului la care se aplic? func?ia. Este un moment important cum se ini?ializeaz? obiectul local x1. Acest lucru poate fi f?cut prin mai multe metode. Esen?a este ca num?r?torul ?i numitorul lui x1 s? devin? egal respectiv cu num?r?torul ?i numitorul obiectului – primul operand. Era posibil de procedat astfel:

   fractie_rationala x1;
   x1.numarat=numarat; // numarat f?r? nimic va fi luat de la
                       // primul operand
   x1.numit=numit; // numit f?r? nimic va fi luat de la primul
                   // operand
sau a?a: 
   fractie_rationala x1;
   x1.numarat=numarator(); // acela?i lucru numai prin
                           // func?ii membre care se
   x1.numit=numitor();     // aplic? la primul operand
sau a?a: 
   fractie_rationala x1(numarat, numit);
//Sunt posibile ?i diferite combin?ri. 
//A fost propus? versiunea:
   fractie_rationala x1=*this;


Cuv?ntul this este cuv?ntul-cheie. El reprezint? un pointer ?ncorporat ?n fiecare obiect ?i con?ine adresa obiectului dat. A?a c? expresia *this reprezint? referin?a la obiectul ?nsu?i ?n func?iile membre care se aplic? la el. Deci, pentru expresia fr3==fr4 ?n codul func?iei operator ==() pointerul this va avea adresa obiectului fr3, iar expresia *this va reprezenta ?nsu?i acest obiect. Acum este clar c? obiectul local x1 va fi ini?ializat cu acela?i con?inut pe care ?l are ?i obiectul – primul operand.

Acum trecem la supra?nc?rcarea operatorului + ?n forma de func?ie prieten? a clasei fractie_rationala. Func?ia are deja doi parametri conform num?rului de operanzi ai acestui operator, adic? a?a ca ?i ?n cazul func?iei suma(). Mai mult ca at?t, codurile func?iilor suma() ?i operator +() sunt identice. De aceea func?ia de supra?nc?rcare a operatorului + ar putea fi definit? mai laconic (?i nu mai efectiv) astfel:

fractie_rationala operator +(fractie_rationala x,
                             fractie_rationala y)
{
   return suma(x, y);
}


Func?ia operator +() ?ntoarce un obiect fractie_rationala. Acest obiect este unul local creat ?n func?ia operator +(). Ob?in?nd valoarea sumei a doi operanzi, el va fi valabil numai p?n? la utilizarea sa ?n expresia ?n care va fi folosit operatorul +. ?ns? aceasta este de ajuns pentru construirea expresiilor mai complicate folosind operatorul +. De exemplu, (fr3+fr4).print(), fr3+fr4+fr5, fr6=fr4+fr5 etc. Este uzual? practica c?nd operatorul supra?nc?rcat, fie ?n form? de func?ie membr? a clasei, fie ?n form? de func?ie prieten? a clasei, ?ntoarce ca rezultat obiectul clasei la care el se aplic?. Aceasta ne d? posibilitatea de a construi expresii mai complicate cu acest operator.

?n exemplul nostru operatorul == a fost supra?nc?rcat sub form? de func?ie membr?, iar operatorul + anume ca func?ie prieten?, numai ?n scopuri demonstrative. Am fi putut proceda ?i invers, sau ?i supra?nc?rc?m pe ambii ?ntr-o form?. De obicei, dac? operatorul poate fi supra?nc?rcat ?n form? de func?ie membr?, se alege anume aceast? form?, fiindc? ea asigur? accesarea mai simpl? a membrilor primului operand (folosind pointerul this).

?n cazul ?n care primul operand nu este obiectul clasei, vom fi nevoi?i s? alegem func?ia prieten? a clasei. De exemplu, dac? vrem s? avem posibilitatea s? scriem expresiile de tipul 7+fr3 sau fr4+2 (adic?, adunarea frac?iilor cu numere ?ntregi), trebuie s? mai supra?nc?rc?m de dou? ori operatorul +. Pentru cazul frac?ie + ?ntreg putem face acest lucru ?i prin func?ia membr?, de exemplu, inser?nd ?n sec?iunea public a clasei fractie_rationala urm?torul cod:

      fractie_rationala operator +(unsigned int k)
      {
         return fractie_rationala(numarat+numit*k,numit);
      }


Iar pentru cazul ?ntreg + frac?ie supra?nc?rcarea poate fi f?cut? numai prin func?ie prieten?, adic? ?n orice sec?iune a clasei fractie_rationala inser?m urm?torul cod:

friend fractie_rationala operator +(unsigned int k,
                                    fractie_rationala f)
      {
         f.numarat+=k*f.numit;
         return f;
      }
//Dup? aceasta vom avea posibilitatea s? scriem codul:
   (fr3+2).print(); // va afi?a 5/2
   cout << endl;
   fr3.print(); // va afi?a 1/2
   cout << endl;
   (2+fr3).print(); // va afi?a 5/2
   cout << endl;
   fr3.print(); // va afi?a 1/2
   cout << endl;


Ne-am convins c? fr3+2 ?i 2+fr3 au dat unul ?i acela?i rezultat. Prin afi?area de dou? ori a fr3 am verificat c? acest obiect nu s-a schimbat.

Majoritatea operatorilor pot fi supra?nc?rca?i at?t sub form? de func?ie membr?, c?t ?i sub form? de func?ie prieten?. ?ns?, trebuie de luat ?n considera?ie c? supra?nc?rc?nd operatorii nu putem schimba aritatea (num?rul de operanzi), prioritatea ?i preceden?a lor (ordinea de executare). Orice func?ie care supra?ncarc? operatorul nu poate avea argumente implicite. Ar fi de dorit ca versiunile supra?nc?rcate ale operatoarelor s? fie ?n concordan?? cu semantica ini?ial? a operatorilor. Acest principiu a fost respectat ?n exemplele precedente ?i va fi respectat ?i ?n cele care vor urma.

Operatorii supra?nc?rca?i (nu conteaz? – prin func?ie membr? sau prieten?) pot fi apela?i ?i sub form? de func?ie. Astfel, expresia fr3+fr4 sau (fr3+fr4) poate fi scris? ca operator+(fr3,fr4).

Nu se admite supra?nc?rcarea sub orice form? a operatorilor . :: .* ?i ?:. Sub form? de func?ie prieten? nu mai pot fi supra?nc?rca?i nici operatorii = () [] ?i ->.

?n cele ce urmeaz? vom cerceta supra?nc?rcarea pentru diferite grupe de operatori.
_________________________
Autorul: dr.conf. S. Pereteatcu

5.2. Supra?nc?rcarea operatorilor de incrementare/decrementare

5.2. Supra?nc?rcarea operatorilor de incrementare/decrementare

Operatorii de incrementare ++ ?i decrementare –– au fiecare c?te dou? forme: una cu prefix ?i cealalt? cu sufix. Supra?nc?rc?nd ace?ti operatori, ?n mod normal, trebuie de scris pentru fiecare c?te dou? func?ii membre sau prietene. Supra?nc?rcarea pentru operatorii ++ ?i -- cu prefix se face ?n mod obi?nuit. \

Posibilitatea de supra?nc?rcare a acelora?i operatori cu sufix a ap?rut ?n versiunile relativ noi ale C++. Este clar c? supra?nc?rcarea cu sufix trebuie cumva s? difere de supra?nc?rcarea respectiv? cu prefix, cel pu?in prin prototipuri. La supra?nc?rcarea versiunilor cu sufix trebuie de ad?ugat un parametru fictiv de tipul int. El nu va fi folosit ?n codul func?iei, ci serve?te numai ca indicator al compilatorului.

Ca exemplu, supra?nc?rc?m operatorul ++ sub formele cu prefix ?i cu sufix prin func?iile membre, iar operatorul -- sub formele cu prefix ?i cu sufix prin func?iile prietene ale clasei fractie_rationala.

Inser?m urm?torul cod ?n sec?iunea public a clasei fractie_rationala din programul precedent:

      fractie_rationala operator ++()
      {
         numarat+=numit;
         return *this;
      }
 
      fractie_rationala operator ++(int fictiv)
      {
         unsigned int numarat_vechi=numarat;
         numarat+=numit;
         return fractie_rationala(numarat_vechi, numit);
      }

Iar la func?ia main() ad?ug?m verificarea operatorului ++ supra?nc?rcat:

   (++fr3).print(); // va afi?a 3/2
   cout << endl;
   fr3.print(); // va afi?a 3/2
   cout << endl;
   (fr3++).print(); // va afi?a 3/2
   cout << endl;
   fr3.print(); // va afi?a 5/2
   cout << endl;


Afi?area ce corespunde codului ad?ugat va fi clar?, dac? vom lua ?n considera?ie c? valoarea precedent? a fr3 era 1/2. Urm?ri?i func?iile ce supra?ncarc? operatorul ++. Ambele ?ntorc un obiect fractie_rationala. Prima func?ie supra?ncarc? ++ cu prefix. Ea modific? obiectul la care se aplic? ?i, ca rezultat, tot pe el ?l ?ntoarce (folosind pointerul this). Acesta, la r?ndul s?u, poate fi folosit la construirea expresiilor mai complicate.

A doua func?ie supra?ncarc? ++ cu sufix. Ea modific? obiectul la care se aplic? ?i ?ntoarce obiectul temporar egal cu valoarea veche a obiectului de aplicare. Func?ia are un parametru fictiv de tipul int, ce reprezint? o excep?ie de la regula de supra?nc?rcare a operatorilor unari prin func?ie membr? (conform regulii, func?ia nu trebuia s? posede nici un parametru).

Urm?torul cod poate fi inserat ?n orice sec?iune a clasei fractie_rationala, fiindc? el supra?ncarc? operatorul ?n form? de func?ii prietene:

  friend fractie_rationala operator –(fractie_rationala &x)
  {
     x.numarat-=x.numit
     return x;
  }
  friend fractie_rationala operator --(fractie_rationala &x, int fictiv)
  {
     unsigned int numarat_vechi=x.numarat;
     x.numarat-=x.numit;
     return fractie_rationala(numarat_vechi, x.numit);
  }


Func?iile din codul ad?ugat reprezint? versiunile simplificate de  supra?nc?rcare  a  operatorului -- cu prefix ?i, respectiv, cu sufix. Aici nu se verific? dac? num?r?torul este mai mare dec?t numitorul ?i este posibil? sc?derea. Deoarece func?iile date au fost incluse ?n ?ntregime cu defini?iile sale ?n defini?ia clasei fractie_rationala, ele vor fi desf??urate inline de c?tre compilator. Pentru verificarea operatorului -- supra?nc?rcat ad?ug?m la func?ia main():

   (--fr3).print(); // va afi?a 3/2
   cout << endl;
   fr3.print(); // va afi?a 3/2
   cout << endl;
   (fr3--).print(); // va afi?a 3/2
   cout << endl;
   fr3.print(); // va afi?a 1/2
   cout << endl;


?in?nd cont c? fr3 are deja valoarea 5/2. Analiz?nd ultimele dou? func?ii, men?ion?m, cum va fi returnat rezultatul de data aceasta ?i c? a doua func?ie are doi parametri, dintre care al doilea este fictiv, dar neap?rat trebuie s? fie de tipul int. Totu?i, cel mai important este faptul c? primul parametru se transmite prin referin?? ?i nu prin valoare, fiindc? obiectul la care se aplic? operatorul ??i schimb? valoarea.
_________________________
Autorul: dr.conf. S. Pereteatcu

5.3. Supra?nc?rcarea operatorilor de atribuire

5.3. Supra?nc?rcarea operatorilor de atribuire

Este posibil? supra?nc?rcarea oric?rui operator de atribuire at?t simpl? =, c?t ?i compus? „opera?ie=”.

A?a cum a fost spus mai ?nainte, pentru orice clas? este definit automat operatorul de atribuire simpl? care copie „pe bi?i” con?inutul obiectului-operand din partea dreapta ?n obiectul-operand din partea st?ng? a semnului de atribuire =. Pentru o clas? oarecare poate ap?rea necesitatea de a redefini acest operator ?n a?a mod ?nc?t operatorul de atribuire supra?nc?rcat va face careva ac?iuni suplimentare sau specifice acestei clase.

De exemplu, pentru clasa fractie_rationala astfel de ac?iune poate fi reducerea frac?iei care a ob?inut valoarea. Ad?ug?m ?n sec?iunea public a clasei fractie_rationala urm?torul cod de supra?nc?rcare a operatorului = :

fractie_rationala operator=(const fractie_rationala &y)
      {
         numarat=y.numarat;
         numit=y.numit;
         reducere();
         return *this;
      }


Men?ion?m c? operatorul de atribuire ?ntoarce ca rezultat operandul care a primit valoarea. Anume aceasta ?i execut? func?ia de mai sus dup? ce a ?nscris valorile noi ?n c?mpurile numarat ?i numit ale destina?iei ?i a apelat func?ia de reducere (acea ac?iune suplimentar? despre care s-a vorbit mai sus). Pentru verificare ad?ugam la func?ia main():

fractie_rationala fr6(3, 6);
   cout << "fr6=";
   fr6.print(); // va afi?a 3/6
   cout << endl;
 
   fractie_rationala fr7;
   fr7=fr6; // atribuirea supra?nc?rcat?
   cout << "fr7=";
   fr7.print(); // va afi?a 1/2
   cout << endl;
 
   fractie_rationala fr8, fr9;
   fr9=fr8=fr6; // ?nl?n?uirea atribuirii supra?nc?rcate 
   fr8.print(); // va afi?a 1/2
   cout << endl;
   fr9.print(); // va afi?a 1/2
   cout << endl;
Este u?or de ?n?eles c? fragmentul ad?ugat afi?eaz? urm?torul text:
fr6=3/6
fr7=1/2
1/2
1/2


La declararea clasei nici unul din operatorii de atribuire compus? nu se creeaz? automat, ?ns? fiecare din ei poate fi supra?nc?rcat prin func?ie membr? sau chiar prieten? a clasei. Pentru exemplu supra?nc?rc?m operatorul += pentru clasa fractie_rationala prin func?ie membr?:

fractie_rationala operator +=(fractie_rationala y)
      {
         numarat=numarat*y.numit+numit*y.numarat;
         numit=numit*y.numit;
         reducere();
         return *this;
      }


Este clar c? codul dat trebuie s? fie inserat ?n sec?iunea public a clasei fractie_rationala. Iar la func?ia main() ad?ug?m:

fractie_rationala fr10(1,4);
   fractie_rationala fr11(1,4);
   fractie_rationala fr12(1,4);
   fr12+=fr11+=fr10; // lan? de atribuiri cu + 
   cout << "fr10=";
   fr10.print(); // va afi?a 1/4
   cout << endl;
   cout << "fr11=";
   fr11.print(); // va afi?a 1/2 fiindc? 1/4+1/4=1/2
   cout << endl;
   cout << "fr12=";
   fr12.print(); // va afi?a 3/4 fiindc? 1/4+1/2=3/4
   cout << endl;
 
Fragmentul acesta afi?eaz?: 
 
fr10=1/4
fr11=1/2
fr12=3/4
 
Exact acela?i rezultat va fi dac? ?n fragmentul precedent vom ?nlocui:
 
   fr12+=fr11+=fr10; 
 
cu:
 
fr11=fr11+fr10;
fr12=fr12+fr11;


_________________________
Autorul: dr.conf. S. Pereteatcu

5.4. Supra?nc?rcarea operatorilor << ?i >>

5.4. Supra?nc?rcarea operatorilor << ?i >>

Ne-am plictisit s? scriem r?nduri ?i r?nduri de tipul:

  cout << "fr12=";
   fr12.print();
   cout << endl;

Vrem s? avem posibilitatea de a scrie laconic ?i frumos:

cout << "fr12=" << fr12 << endl;

Din fericire, este u?or de transformat acest vis ?n realitate.

Cum a fost spus mai ?nainte, supra?nc?rc?nd orice operator, este de dorit ca semantica operatorului supra?nc?rcat s? fie ?n concordan?? cu semantica ini?ial? a acestui operator. ?ns?, orice regul? are ?i excep?ii. Un bun exemplu de a?a excep?ii reu?ite este supra?nc?rcarea ?n C++ a operatorilor de deplasare a bi?ilor << ?i >> pentru opera?ii de I/O f?cut? ?n fi?ierul antet "iostream.h" pentru tipurile de date de baz? ?i clasele ostream ?i istream destinate pentru crearea stream-urilor capabile s? ob?in?, respectiv, s? introduc? informa?ii. Putem supra?nc?rca ace?ti operatori astfel ca ei s? efectueze opera?ii de I/O asupra claselor noastre.

?n limbajul C++ operatorul << supra?nc?rcat pentru opera?ii de ie?ire se nume?te operator de inser?ie, ?n sens c? el trimite octe?ii (caractere) ?ntr-un ostream, iar operatorul >> supra?nc?rcat pentru opera?ii de ie?ire se nume?te operator de extragere, ?n sens c? el ob?ine octe?ii (caractere) dintr-un istream. Utilizatorul supra?ncarc? operatorii de inser?ie ?i de extragere prin func?ii nemembre, de obicei, totu?i prietene ale clasei pentru care va fi folosit operatorul respectiv.

Forma general? de supra?nc?rcare a unui operator de inser?ie este urm?toarea:

ostream &operator<<(ostream &stream, tip_clas? obiect)

{

   // codul func?iei de inser?ie

   …

   return stream;

}

sau

ostream &operator<<(ostream &stream,  const tip_clas? &obiect)

{

   // codul func?iei de inser?ie

   …

   return stream;

}

Primul operand aici este o referin?? spre un ostream care va fi ?i ?ntoars? ca rezultat al opera?iei, ceea ce ne va da posibilitatea de a ?nl?n?ui operatorii de inser?ie.

Ca exemplu, supra?nc?rc?m operatorul de inser?ie pentru clasa fractie_rationala prin func?ie prieten?.

?n sec?iunea public a clasei noastre inser?m antetul:

friend ostream &operator<<(ostream& stream, const fractie_rationala &fr);

Iar dup? definirea clasei inser?m definirea func?iei:

ostream &operator<<(ostream& stream, const fractie_rationala &fr)
{
   stream << fr.numarat;
   stream << "/";
   stream << fr.numit;
 
   return stream;
}


care face practic acela?i lucru ca ?i func?ia membr? print(), numai c? pentru orice ostream, ?i poate fi ?nl?n?uit?.

La func?ia main() ad?ug?m fragmentul:

fractie_rationala fr13(1, 2);
   cout << "fr13 = " << fr13 << endl;
 
   fractie_rationala fr14(2, 5);
   cout << "fr14 = " << fr14 << endl;
 
   cout << fr13 << " + "<< fr14 << " = " 
        << (fr13+fr14) << endl;
Acest fragment va afi?a:
fr13 = 1/2
fr14 = 2/5
1/2 + 2/5 = 9/10


S? ?inem seama de luarea ?n paranteze a expresiei (fr13+fr14). Mai subliniem c? ?i operatorul << supra?nc?rcat poate fi scris ?n form? de func?ie. De exemplu, instruc?iunea:

cout << "fr13 = " << fr13 << endl;

poate fi scris? ?i astfel:

operator<<(cout << "fr13 = ", fr13) << endl;

Func?ia print() membr? a clasei fractie_rationala poate fi supra?nc?rcat? pentru orice ostream, de exemplu, astfel:

ostream &print(ostream &stream)
      {
         stream << numarat << '/' << numit;
         return stream;
      }
Cu apelurile de tipul:
   cout << "fr13 = ";
   fr13.print(cout);
   cout << endl;
   cout << "fr14 = ";
   fr14.print(cout);
   cout << endl;
   fr13.print(cout);
   cout <<  " + ";
   fr14.print(cout);
   cout << " = ";
   (fr13+fr14).print(cout);
   cout << endl;


Aceasta versiune supra?nc?rcat? a func?iei print() poate fi folosit? la supra?nc?rcarea operatorului de inser?ie pentru clasa fractie_rationala prin func?ie care poate ?i s? nu fie prieten?, de exemplu, astfel:

ostream &operator<<(ostream& stream,
                    const fractie_rationala &fr)
{
   return fr.print(stream);
}


Rezultatul va fi acela?i ca ?i pentru func?ia prieten?.

?n exemplele ulterioare, pentru afi?area obiectelor ?n majoritatea de cazuri vom folosi operatorul << supra?nc?rcat, ?ns? func?ia membr? print() o vom l?sa totu?i ?n clasa fractie_rationala.

Forma general? de supra?nc?rcare a unui operator de extragere este urm?toarea:

istream &operator>>(istream &stream, tip_clas? &obiect)

{

   // codul func?iei de extragere

   …

   return stream;

}

Primul operand aici este o referin?? spre un istream care va fi ?ntoars? ca rezultat al opera?iei, ceea ce ne va da posibilitatea de a ?nl?n?ui operatorii de extragere. Parametrul doi numaidec?t se transmite prin referin??, fiindc? obiectul ??i va schima con?inutul.

Ca exemplu, supra?nc?rc?m operatorul de extragere pentru clasa fractie_rationala prin func?ie prieten?.

?n sec?iunea public a clasei noastre inser?m antetul:

friend istream &operator>>(istream& stream, fractie_rationala &fr);

Iar dup? definirea clasei inser?m definirea func?iei:

istream &operator>>(istream& stream,
                    fractie_rationala &fr)
{
   char str[50];
   stream >> str;
   fr.numarat=0;
   int i=-1;
   while(str[++i]!='/')
      fr.numarat = fr.numarat*10 + str[i]-'0';
 
   fr.numit=0;
   while(str[++i])
      fr.numit = fr.numit*10 + str[i]-'0';
 
   return stream;
}


care asigur? nu numai introducerea datelor, dar ?i ?nl?n?uirea operatorilor >>. Pentru verificare, ad?ug?m la func?ia main() urm?torul fragment:

fractie_rationala fr15;
   cout << "Introdu o fractie: ";
   cin >> fr15;
 
   fractie_rationala fr16;
   cout << "Mai introdu inca o fractie: ";
   cin >> fr16;
 
   cout << "fr15 = "  << fr15 << endl;
   cout << "fr16 = "  << fr16 << endl;
 
   cout << "fr15 + fr16 =  "  << (fr15+fr16)
        << endl;
 
   cout << "Introdu inca doua fractii prin spatiu: ";
   cin >> fr15 >> fr16;
   cout << fr15 << " + " << fr16 << " = " 
        << (fr15+fr16) <<endl;


La executarea acestui fragment va trebui s? introducem frac?ii de la tastatur?. Rezultatul va fi aproximativ urm?torul:

Introdu o fractie: 3/10
Mai introdu inca o fractie: 5/10
fr15 = 3/10
fr16 = 5/10
fr15 + fr16 =  4/5
Introdu inca doua fractii prin spatiu: 1/7 3/7
1/7 + 3/7 = 4/7


Exist? ?i alt? posibilitate. Putem insera ?n clasa fractie_rationala o func?ie membr? public? pentru introducerea din orice istream, de exemplu, astfel:

istream &input(istream &stream)
{
   char c;
   stream >> numarat >> c >> numit;
   return stream;
}


Apoi folosim aceast? func?ie la supra?nc?rcarea operatorului de extragere >> prin func?ia care poate ?i s? nu fie prieten? a clasei noastre:

istream &operator>>(istream& stream, fractie_rationala &fr)
{
   return fr.input(stream);
}


Rezultatul va fi acela?i ca ?i pentru func?ia prieten?.
_________________________
Autorul: dr.conf. S. Pereteatcu

5.5. Supra?nc?rcarea operatorului de conversie

5.5. Supra?nc?rcarea operatorului de conversie

?n orice clas? putem defini ?n form? de func?ii membre un set de operatori de conversie, care va transforma ?n expresii obiectele acestei clase la tipul de date corespunz?tor.

Forma general? a unei func?ii-operator de conversie este urm?toarea:

 

[nume_clas?::]operator tip()

{

   // codul func?iei de conversie

   …

   return expresie;

}

sau

[nume_clas?::]operator tip();

?n defini?ia clasei, ?i defini?ia func?iei

nume_clas?::operator tip()

{

   // codul func?iei de conversie

   …

   return expresie;

}

dup? defini?ia clasei.

Pentru clasa fractie_rationala se cere operatorul de conversie care va transforma obiecte-frac?ii ?n valoarea respectiv? ?n virgul? mobil?. Modific?m din nou clasa fractie_rationala inser?nd ?n sec?iunea public a ei urm?toarea func?ie membr?:

operator double()
 {
    return (double)numarat/(double)numit;
 }


Aceasta ne va da posibilitatea de a folosi obiectele fractie_rationala ?n expresii ?n orice loc unde se admite o valoare de tipul double. De exemplu, ad?ug?m la func?ia main() urm?torul fragment de cod:

fractie_rationala fr17(2,5);
   cout << "fr17=" << fr17 << "=" << (double)fr17 << endl;
 
   double x, y;
   int k;
 
   x=fr17;
   cout << "x=" << x << endl;
 
   y=fr17*fr17;
   cout << "y=" << y << endl;
 
   k=++fr17;
   cout << "k=" << k << endl;
 
//Fragmentul ad?ugat va afi?a urm?toarea ie?ire:
 
fr17=2/5=0.4
x=0.4
y=0.16
k=1


Facem o analiz?.

Expresia (double)fr17 reprezint? conversia obiectului fr17 la valoarea double prin apelul explicit al func?iei de conversie respectiv?.

La atribuirea x=fr17 func?ia de conversie va fi apelat? implicit, ceea ce este echivalent cu x=(double)fr17.

Expresia y=fr17*fr17 este echivalent? cu expresia y=(double)fr17*(double)fr17, fiindc? operatorul * nu este cunoscut ?n clasa fractie_rationala.

Expresia k=++fr17 este echivalent? cu expresia k=(double)(++fr17), fiindc? operatorul de incrementare a fost supra?nc?rcat ?n clasa fractie_rationala.

?n mod analog putem defini ?n clasa fractie_rationala operatorii de conversie, dup? necesitate, ?i pentru alte tipuri de date standard.
_________________________
Autorul: dr.conf. S. Pereteatcu

Translate Переводчик

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

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

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