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

рассказать друзьям и получить подарок

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Translate Переводчик

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

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

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