CPP_RO_4_FUNC?II MEMBRE ?I PRIETENE

4.1. Descrierea func?iilor membre

4.1. Descrierea func?iilor membre

Refacem clasa fractie_rationala, ad?ug?nd c?teva posibilit??i noi. Ad?ug?m metode noi care ne vor da posibilitatea de a vizualiza valoarea obiectului sub forma m/n, de a edita (modifica) con?inutul c?mpurilor, de a ob?ine informa?ii despre acest con?inut. Metodele vor fi descrise ca func?ii membre ale clasei. Constructorul ?i func?ia eroare() r?m?n acelea?i ca ?i ?n varianta precedent?:

include       
#include 
 
class fractie_rationala
{
   protected:
      unsigned int numarat;
      unsigned int numit;
   public:
      fractie_rationala(unsigned int, unsigned int);
      void print(); // func?ia pentru afi?area frac?iei
      void modif(unsigned int numarat_nou=0,
                 unsigned int numit_nou=1);
      unsigned int numarator(); // ?ntoarce valoarea num?r?torului 
      unsigned int numitor(); // ?ntoarce valoarea numitorului
      void reducere(); // reduce num?r?torul ?i numitorul
   private:
      void eroare(char* mesaj);
};
 
fractie_rationala::fractie_rationala(
      unsigned int numarat_init=0,
      unsigned int numit_init=1)
{// codul precedent
}
 
void fractie_rationala::eroare(char* mesaj)
{// codul precedent
}
 
void fractie_rationala::print()
{
   cout << numarat << '/' << numit;
}
 
void fractie_rationala::modif(unsigned numarat_nou,
                              unsigned numit_nou)
{
   if (numit_nou>0)
   {
      numarat=numarat_nou;
      numit=numit_nou;
   }
   else
      eroare("Numitorul este egal cu zero!");
}
 
unsigned int fractie_rationala::numarator()
{
   return numarat;
}
 
unsigned int fractie_rationala::numitor()
{
   return numit;
}
 
void fractie_rationala::reducere()
{
   if(numarat>0)
   {
      unsigned int a, b, dif;
      if (numarat<numit)
      {
         b=numarat;
         a=numit;
      }
      else
      {
         b=numit;
         a=numarat;
      }
      while (a%b)
      {
         dif=a-b;
         if (dif>b)
            a=dif;
         else
         {
            a=b;
            b=dif;
         }
      }
      numarat/=b;
      numit/=b;
   }
   else
      numit=1;
}
 
void main()
{
   fractie_rationala fr(2, 5); // cre?m un obiect numit 
                               // fr reprezentantul clasei 
                               // fractie_rationala 
   cout << "Fractia initiala "; // afi?area unui text
   fr.print();   // apel?m func?ia membr? print() pentru
                 // obiectul fr 
   cout << endl; // cursorul ?n linia urm?toare
 
   fr.modif(4, 8); // apel?m func?ia membr? modif()
                   // pentru obiectul fr
   cout << "Dupa modificare ";
   fr.print();
   cout << endl;
 
   fr.reducere(); // apel?m func?ia membr? reduce()
                  // pentru a reduce obiectul fr
   cout << "Dupa reducere ";
   fr.print();
   cout << endl;
 
   char c; 
cin >> c;
}

 


Dup? cum observ?m, au fost ad?ugate cinci func?ii noi: print(), modif(), numarator(), numitor() ?i reduce().

Rezultatul programului este u?or de ?n?eles:

Fractia initiala 2/5
Dupa modificare 4/8
Dupa reducere 1/2

Acum utilizatorul are acces deplin la p?r?ile componente ale obiectului de tipul fractie_rationala, ?ns? acest acces este asigurat prin intermediul func?iilor membre, ceea ce exclude operarea incorect? cu c?mpurile obiectului. De exemplu, numitorul nu poate lua valoarea zero. Se poate de mers ?i mai departe, excluz?nd cazurile c?nd num?r?torul este mai mare dec?t numitorul (depinde de necesit??ile aplica?iei).

?n exemplul precedent a fost ar?tat modul de declarare ?i definire a func?iilor, iar ?n func?ia main() a fost ar?tat modul de apelare a func?iilor membre.

O func?ie membr? poate fi declarat? ca func?ia generic?.

Exerci?iul 4.1. ?ncerca?i s? transforma?i exemplul precedent cu c?teva func?ii membre generice.
_________________________
Autorul: dr.conf. S. Pereteatcu

4.2. Func?iile membre inline

4.2. Func?iile membre inline

?n versiunea actual? a clasei fractie_rationala au fost incluse c?teva func?ii membre noi. ?n majoritate ele sunt at?t de mici, ?nc?t ar fi de dorit ca ele s? fie dezvoltate inline.

Pentru a face ca o func?ie membr? s? devin? inline, este de ajuns de a prefixa antetul ei cu cuv?ntul rezervat inline ?ntr-un singur loc (fie la declararea func?iei ?n clas?, fie la definirea func?iei). Adic?:

class fractie_rationala
{inline unsigned int numarator(){return numarat;}
   …
 
};
sau a?a:
inline unsigned int fractie_rationala::numarator()
{
   return numarat;
}


Se poate indica cuv?ntul inline ?i ?n ambele locuri. El poate fi scris ?n orice pozi?ie ?nainte de numele func?iei (inline unsigned int, sau unsigned inline int, sau unsigned int inline, nu conteaz?).

Dezvoltarea inline pentru majoritatea func?iilor membre este practica uzual? ?n C++. De aceea, pentru descrierea func?iilor membre inline a fost introdus? forma special?, c?nd definirea func?iei membre se face ?n declararea clasei. ?n acest caz cuv?ntul rezervat inline poate fi omis.

Lu?nd ?n considera?ie cele expuse, modific?m ?nc? o dat? clasa fractie_rationala, utiliz?nd func?iile membre inline:

#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)
      {
         modif(numarat_init, numit_init);
      }
 
      void print(){cout << numarat << '/'
                        << numit;}
 
      void modif(unsigned int numarat_nou=0,
                 unsigned int numit_nou=1)
      {
         if (numit_nou>0)
         {
            numarat=numarat_nou;
            numit=numit_nou;
         }
         else
            eroare("Numitorul este egal cu zero!");
      }
 
      unsigned int numarator(){return numarat;}
      unsigned int numitor(){return numit;}
      void reducere();
 
   private:
      void eroare(char* mesaj)
      {
         cerr << mesaj;
         exit(1);
      }
};
 
void fractie_rationala::reducere()
{// codul precedent
}


?n acest exemplu toate func?iile membre, ?n afar? de func?ia reducere(), au fost transformate ?n inline. Constructorul la fel a fost transformat ?n inline; totodat?, el a fost simplificat prin apelul func?iei membre modif(). Func?ia reducere() fiind voluminoas? nu a fost transformat? ?n inline. Dac? ad?ug?m la exemplul dat func?ia main() din programul precedent, vom vedea c? rezultatul afi?at de acest program modificat va fi exact acela?i.
_________________________
Autorul: dr.conf. S. Pereteatcu

4.3.Func?ii prietene

4.3.Func?ii prietene

Clasa fractie_rationala nu va fi de mare folos, dac? utilizatorul nu va avea posibilitatea de a efectua diferite calcule cu frac?ii ra?ionale. ?n primul r?nd se cer opera?ii de adunare, sc?dere, comparare la egalitate etc. Aceste opera?ii pot fi realizate prin func?ii separate, care nu sunt membre ale clasei. Orice func?ie de acest tip, av?nd la intrare dou? obiecte fractie_rationala, poate efectua calculele, acces?nd c?mpurile obiectelor prin intermediul func?iilor membre (cum ar fi numarator(), numitor(), modif()). ?ns?, uneori, ar fi de dorit ca func?ia ce efectueaz? calculele s? acceseze direct toate p?r?ile componente ale obiectelor parametri. Acest lucru poate fi f?cut folosind no?iunea de func?ie prieten? a clasei.

Func?ia separat? care nu este membr? a clasei, dar are acces deplin la to?i membrii clasei (inclusiv cei proteja?i ?i cei priva?i), se nume?te func?ie prieten? (engl. friend) a acestei clase. Pentru ca o func?ie s? fie prieten? a unei clase, trebuie de inclus prototipul acestei func?ii precedat de cuv?ntul-cheie friend ?n orice sec?iune din declara?ia clasei respective

Dezvolt?m exemplul cu clasa fractie_rationala mai departe. Anume: cre?m trei func?ii prietene ale acestei clase numitor_comun(), egale(), suma():

// Clasa fractie_rationala cu func?ii prietene
#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);
   private:
      void eroare(char* mesaj) {}
};
 
void fractie_rationala::reducere()
{// codul precedent
}
 
void numitor_comun(fractie_rationala &x, fractie_rationala &y)
{
   if(x.numit!=y.numit)
   {
      x.numarat=x.numarat*y.numit;
      y.numarat=y.numarat*x.numit;
      x.numit=y.numit=x.numit*y.numit;
   }
}
 
int egale(fractie_rationala x, fractie_rationala y)
{
   numitor_comun(x, y);
   return x.numarat==y.numarat;
}
 
fractie_rationala suma(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 fr1(1, 3);
   fractie_rationala fr2(2, 5);
 
   fr1.print();
   cout << " si ";
   fr2.print();
   cout << endl;
   numitor_comun(fr1, fr2);
   cout << "aduse la un numitor comun"
        << " au devenit respectiv\n";
   fr1.print();
   cout << " si ";
   fr2.print();
   cout << endl;
 
   fractie_rationala fr3(1, 2);
   fractie_rationala fr4(1, 4);
   fractie_rationala fr5(2, 4);
 
   fr3.print();
   cout << " si ";
   fr4.print();
   if(egale(fr3,fr4))
      cout << " sunt egale\n";
   else
      cout << " nu sunt egale\n";
 
   fr3.print();
   cout << " si ";
   fr5.print();
   if(egale(fr3,fr5))
      cout << " sunt egale\n";
   else
      cout << " nu sunt egale\n";
 
   fr3.print();
   cout << " + ";
   fr4.print();
   cout << " = ";
   suma(fr3,fr4).print();
   cout << endl;
 
   fr3.print();
   cout << " + ";
   fr4.print();
   cout << " + ";
   fr5.print();
   cout << " = ";
   suma(suma(fr3,fr4),fr5).print();
   cout << endl;
 
   char c; cin >> c; 
}

Func?ia numitor_comun(), av?nd la intrare dou? obiecte fractie_rationala, le aduce la un numitor comun. Atrage?i aten?ia c? obiectele se transmit prin referin??, fapt necesar, fiindc? ele ??i schimb? con?inuturile. ?n func?ia main() este ar?tat apelul func?iei numitor_comun() pentru dou? obiecte fr1 ?i fr2.

Func?ia egale() compar? dou? obiecte fractie_rationala la egalitate. Obiectele se transmit prin valoare. Func?ia ?ntoarce valoarea 1, dac? obiectele reprezint? dou? frac?ii egale, ?i ?ntoarce valoarea 0, dac? frac?iile sunt diferite. Obiectele se compar? dup? regulile pentru frac?ii, de aceea func?ia egale() mai ?nt?i aduce copiile primite ale obiectelor la un numitor comun ?i dup? aceasta compar? numitoarele. Modul de utilizare a func?iei egale() este ar?tat ?n func?ia main().

Func?ia suma() calculeaz? frac?ia ce reprezint? suma a dou? frac?ii-parametri. Atragem aten?ia cum o func?ie prieten? ?ntoarce ca rezultat un obiect fractie_rationala. Acest lucru ?l poate face ?i o func?ie membr? ?i o alt? func?ie arbitrar? (nemembr?). ?n func?ia main() se calculeaz? suma a dou? frac?ii fr3 ?i fr4. Deoarece rezultatul este un obiect fractie_rationala, putem aplica la el func?ia membr? print().

La rularea programului de mai sus va fi afi?at urm?torul rezultat:

1/3 si 2/5

aduse la un numitor comun au devenit respectiv

5/15 si 6/15

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

Cuv?ntul-cheie friend se scrie numai la prototipul func?iei ?n declararea clasei. El poate fi scris ?n orice loc ?nainte de numele func?iei (friend void sau void friend, nu conteaz?). Cuv?ntul-cheie friend nu poate fi scris la definirea func?iei.

Una ?i aceea?i func?ie poate fi prieten? pentru mai multe clase. Aceast? proprietate se folose?te ?n practic? destul de des. Astfel, func?ia prieten? simplific? accesarea datelor obiectelor de diferite tipuri.

O func?ie membr? a unei clase poate fi prieten? a altei clase sau a mai multor clase. Mai mult ca at?t, o clas? ?ntreag? poate fi prieten? a altei clase sau a mai multor clase. Astfel, fiecare func?ie membr? a clasei prieten? are acces direct la toate p?r?ile componente ale claselor respective.

Exerci?iul 4.2. De cercetat de sine st?t?tor ultimele dou? propriet??i utiliz?nd a?a-numit? declarare (sau referire) ulterioar?:

class C1;  // clasa C1 fa vi explicat? mai jos  
class C2   // aici putem referi clasa C1
{};
 class C1   // descrierea clasei C1, aici putem referi clasa C2 
{};


_________________________
Autorul: dr.conf. S. Pereteatcu

Translate Переводчик

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

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

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