7.6. Suprascrierea ?i supra?nc?rcarea func?iilor membre ?n clasa derivat?

7.6. Suprascrierea ?i supra?nc?rcarea func?iilor membre ?n clasa derivat?

Func?iile membre, mo?tenite de la clasa de baz?, lucrul c?rora nu este satisf?c?tor pentru clasa derivat?, trebuie s? fie suprascrise ?n clasa derivat?. Totodat?, func?iile membre mo?tenite pot fi ?i supra?nc?rcate ?n clasa derivat?. At?t suprascrierea, c?t ?i supra?nc?rcarea func?iilor membre ?n clasa derivat? se face la fel ca ?i definirea func?iilor membre: ?n declararea clasei derivate descriem numai antetul func?iei, iar definirea func?iei o scriem dup? declararea clasei sau scriem toat? definirea func?iei ?n declararea clasei.

Trebuie de ?n?eles bine c? func?ia care suprascrie sau supra?ncarc? o func?ie membr? a clasei de baz? nu are, spre deosebire de predecesoarea sa, acces direct la membrii priva?i ai clasei de baz?. ?n func?ia care suprascrie sau supra?ncarc? o func?ie membr? mo?tenit? ultima poate fi apelat? de mai multe ori, folosind operatorul de rezolu?ie :: (se mai nume?te de scop), dar numai ?n cazul c?nd ultima nu este privat? ?n clasa de baz?.

Demonstr?m cele expuse prin dezvoltarea exemplului precedent. Vrem s? supra?nc?rc?m ?n clasa rational_fara_semn func?ia membr? modif() mo?tenit? de la clasa fractie_rationala. Noua func?ie trebuie s? posede trei parametri, d?nd posibilitatea de a modifica nu numai numitorul ?i num?r?torul, dar ?i partea ?ntreag?. Urm?toarea versiune de suprascriere a func?iei modif():

void rational_fara_semn::modif(
         unsigned pi_noua=0, unsigned numar_nou=0,
         unsigned numit_nou=1)
      {
         part_int=pi_noua;
         if(numit_nou!=0)
         {
            numarat=numar_nou;
            numit=numit_nou;
         }
         else
            eroare("numitorul este zero"); // eroarea
                                           // la acces
      }

nu va fi compilat? din cauza acces?rii interzise la func?ia eroare(), care este membrul protejat al clasei de baz?. Compilatorul va afi?a un mesaj de eroare de tipul: ”'fractie_rationala::eroare(char *)' is not accessible”. Vom proceda astfel: vom memoriza valoarea nou? pentru partea ?ntreag? ?n c?mpul part_int, iar argumentele celelalte le vom pasa func?iei modif() a clasei de baz?, care ?i va efectua restul lucrului. Inser?m ?n sec?iunea public din declara?ia clasei rational_fara_semn urm?torul cod:

void rational_fara_semn::modif(
         unsigned pi_noua=0, unsigned numar_nou=0,
         unsigned numit_nou=1)
      {
         part_int=pi_noua;
         fractie_rationala::modif(numar_nou, numit_nou);
      }

Precizarea rational_fara_semn:: ?n antetul func?iei modif() nu este necesar?, dac? func?ia va fi definit? ?n declararea clasei. Dac? ?n declararea clasei l?s?m numai antetul func?iei ?i vom amplasa defini?ia func?iei dup? declararea clasei, atunci precizarea dat? la defini?ia func?iei este strict necesar?. Noua func?ie modif() suprascrie func?ia modif() a clasei de baz? ?n clasa derivat?, datorit? valorilor implicite pentru parametrii s?i.

La func?ia main() ad?ug?m urm?torul fragment:

rational_fara_semn c(5, 1, 3);
   cout << "c=" << c << endl;
   c.modif(4, 2, 3);
   cout << "Dupa modificare c=" << c << endl;

La lansarea programului, fragmentul ad?ugat va afi?a urm?torul text:

c=5,1/3

Dupa modificare c=4,2/3

Obiectul c ini?ial creat a avut valoarea cinci ?ntregi ?i o treime; dup? modificare, obiectul c a devenit patru ?ntregi ?i dou? treimi. Atragem aten?ia la noua func?ie modif(), anume: la modul ?n care se apeleaz? func?ia modif() a clasei de baz?. Construc?ia fractie_rationala:: precizeaz? apartenen?a clasei.

Exerci?iul 7.1. Suprascrie?i func?ia modif() ?n clasa rational.

Declar?nd o clas? derivat?, trebuie de analizat toate func?iile mo?tenite ?i de hot?r?t care din ele trebuie s? fie suprascrise ?i/sau supra?nc?rcate ?i care trebuie l?sate f?r? modificare.

Facem o a?a analiz? pentru clasa rational_fara_semn.

Func?ia membr? print() trebuie s? fie, indubitabil, suprascris?, altfel, fiind aplicat? la obiectele clasei derivate, ea va afi?a numai frac?ia, f?r? partea ?ntreag?. Versiunea suprascris?, care trebuie s? fie ad?ugat? ?n sec?iunea public a clasei derivate rational_fara_semn, arat? astfel:

void rational_fara_semn::print()
      {
         if (part_int)
            cout << part_int << ",";
         fractie_rationala::print();
      }
//Acum:
   c.print(); 
   cout << endl;
//sau:
   c.rational_fara_semn::print(); // aici precizarea este
   cout << endl;                  // inutil?
 
//va afi?a 4,2/3
//pe c?nd: 
   c.fractie_rationala::print(); // la c se aplic? 
   cout << endl;                 // print() a bazei
 
//va afi?a 2/3.
 
//Se poate de scris ?i ceva de felul urm?tor:
   rational_fara_semn(3, 1, 3).print(); 
   cout<<endl;
//sau:
   rational_fara_semn(3, 1, 3).rational_fara_semn::print();
   cout << endl;
//va fi afi?at 3,1/3 
//iar:
   rational_fara_semn(3, 1, 3).fractie_rationala::print();
   cout << endl;
//va afi?a 1/3
 
//Fragmentul:
   fractie_rationala(2, 3).print(); 
   cout << endl;
//sau:
   fractie_rationala(2, 3).fractie_rationala::print();
   cout << endl;
//va afi?a 2/3
//iar expresia: 
   fractie_rationala(2, 3).rational_fara_semn::print(); 
//nu va fi compilat?, fiindc? func?ia membr? a clasei 
//derivate nu poate fi aplicat? la obiectul clasei de baz?.

Suprascriind func?ia print() ?n clasa derivat?, am folosit func?ia print() a clasei de baz?, fiindc? a?a era mai comod pentru noi. ?ns?, apelarea func?iei membre a clasei de baz? ?n func?ia care suprascrie sau care supra?nc?rc? deloc nu este obligatorie.

Func?iile care suprascriu ?i cele care supra?nc?rc? pot fi definite independent de cea de baz? ?i pot face orice lucru care nu este legat de lucrul pe care ?l face func?ia de baz?.

Dac? ve?i fi mai aten?i, ve?i observa c? ?n clasa de baz? fractie_rationala mai este o func?ie print(), versiunea de supra?nc?rcare a acestei func?ii fiind la fel ?n clas? de baz?. Cea de-a doua are antetul:

ostream &print(ostream &stream)

Ar fi de dorit ca ?i aceast? versiune a func?iei print() s? fie suprascris? ?n clasa derivat?. ?n loc s? suprascriem ?n clasa derivat? rational_fara_semn ambele versiuni ale func?iei print() a clasei de baz? fractie_rationala, putem proceda astfel:

  • Elimin?m din clasa derivat? rational_fara_semn (din exemplul nostru) codul de suprascriere al func?iei print(). El a fost deja inserat.
  • ?n loc de codul eliminat, inser?m urm?torul cod de suprascriere ?n clasa derivat? a func?iei print() mo?tenit? de la clasa de baz?:
ostream &print(ostream &stream=cout)
      {
         if (part_int)
            stream << part_int << ",";
         return fractie_rationala::print(stream);
      }

Dup? cum observ?m, ?n aceast? versiune a func?iei print() a fost introdus? valoarea implicit? cout pentru parametrul stream. Numai pentru comoditate, s-a folosit a doua func?ie print() din clasa de baz? (versiunea cu parametru).

Dup? aceste modific?ri, acela?i fragment:

c.print(); cout << endl;
   c.rational_fara_semn::print(); cout << endl;
   c.fractie_rationala::print();  cout << endl;
   rational_fara_semn(3, 1, 3).print(); cout<<endl;
   rational_fara_semn(3, 1, 3).rational_fara_semn::print();
   cout << endl;
   rational_fara_semn(3, 1, 3).fractie_rationala::print();
   cout << endl;
   fractie_rationala(2, 3).print(); cout << endl;
   fractie_rationala(2, 3).fractie_rationala::print();
   cout << endl;

al func?iei main(), care a fost cercetat ?n cazul precedent, va afi?a ?i de data aceasta exact aceea?i ie?ire:

4,2/3
4,2/3
2/3
3,1/3
3,1/3
1/3
2/3
2/3

?ns?, acum acest fragment de program poate fi scris ?i astfel:

   c.print() << endl;
   c.rational_fara_semn::print() << endl;
   c.fractie_rationala::print(); cout << endl;
   rational_fara_semn(3,1,3).print() << endl;
   rational_fara_semn(3,1,3).rational_fara_semn::print() << endl;
   rational_fara_semn(3,1,3).fractie_rationala::print();
   cout << endl;
   fractie_rationala(2, 3).print(); cout << endl;
   fractie_rationala(2, 3).fractie_rationala::print();
   cout << endl; 
Rezultatul va fi exact acela?i.

Exerci?iul 7.2. ?ncerca?i s? v? descurca?i ?n urm?torul fragment:

   c.fractie_rationala::print(c.rational_fara_semn::
          print(c.print()<<endl)<<endl)<<endl;
   rational_fara_semn(3,1,3).fractie_rationala::
      print(rational_fara_semn(3, 1, 3).rational_fara_semn::
      print(rational_fara_semn(3, 1, 3).print() << endl) 
       << endl) << endl;
   fractie_rationala(2,3).fractie_rationala::
     print(fractie_rationala(2, 3).print(cout) << endl) 
     << endl;

care mai mult seam?n? cu un puzzle. Totu?i, el lucreaz? ?i d? exact acela?i rezultat ca ?i cel precedent.

Exerci?iul 7.3. Acest exerci?iu se reduce la modificarea clasei de baz? fractie_rationala. ?n loc de dou? func?ii supra?nc?rcate print(), face?i numai una, d?nd valoarea implicit? cout parametrului stream, apoi convinge?i-v? c? fragmentul precedent va lucra, d?nd acela?i rezultat. Simplifica?i acest fragment.

Exerci?iul 7.4. Suprascrie?i ?n clasa rational func?ia print() cu un singur parametru, d?nd acestuia valoarea implicit? cout.

La func?ia print() vom reveni c?nd vom cerceta func?iile virtuale, dar acum continu?m cu analiza func?iilor membre ale clasei de baz?.

Func?ia reducere() poate fi l?sat?, ?n principiu, nesuprascris?, atunci obiectele de tipul 1,10/4 vor fi reduse la 1,5/2. Dorim ca ele s? fie reduse la 3,1/2, de aceea inser?m ?n sec?iunea public a clasei rational_fara_semn urm?torul cod:

void rational_fara_semn::reducere()
      {
         part_int+=numarat/numit;
         numarat=numarat%numit;
         fractie_rationala::reducere();
      }

Pentru verificare, ?n func?ia main() inser?m urm?torul fragment:

   rational_fara_semn d(1,10,4), e(1,10,4);
   cout << "d=" << d << endl;
   d.reducere();
   cout << "d dupa reducere=" << d << endl;
   cout << "e=" << e << endl;
   e.fractie_rationala::reducere();
   cout << "e dupa reducere=" << e << endl;

Fragmentul de mai sus va afi?a urm?toarea ie?ire:
d=1,10/4
d dupa reducere=3,1/2
e=1,10/4
e dupa reducere=1,5/2

care confirm? spusele mai sus.

Func?iile numarator() ?i numitor() nu trebuie suprascrise, fiindc? a?a cum ele ?ntorc valorile curente, respectiv, ale num?r?torului ?i numitorului pentru obiectele clasei de baz?, a?a vor face ?i pentru obiectele clasei derivate. ?ns?, ?n clasa derivat? s-a mai ad?ugat c?mpul part_int.

De aceea, pentru a asigura func?ionalitatea complet? a clasei derivate, trebuie de inclus ?n ea func?ia membr?, asem?n?toare cu numarator() ?i numitor(), pentru c?mpul part_int. Vom numi-o, de exemplu, parteaint(). Deci, inser?m ?n sec?iunea public a clasei rational_fara_semn urm?toarea definire:

unsigned int parteaint() {return part_int;}

Subliniem ?nc? o dat?, c? aceasta nu este nici suprascriere ?i nici supra?nc?rcare, ci definirea unei func?ii membre noi ?n clasa derivat?.

?n sec?iunea public a clasei rational introducem func?ia membr? care ?ntoarce informa?ii despre semnul num?rului ra?ional ?i are urm?torul cod:

char rational::semnul() {return semn;}

Suprascriem func?ia input() ?n clasa rational_fara_semn, inser?nd ?n sec?iunea public a ei urm?torul cod:

istream &input(istream &stream=cin)
      {
         char c;
         return stream >> part_int >> c >> numarat >> c >>numit;
      }
//sau:
      istream &input(istream &stream=cin)
      {
         char c;
         stream >> part_int >> c;
         return this->fractie_rationala::input(stream);
      }

Verifica?i de sine st?t?tor c? ambele variante lucreaz? la fel. S? nu uit?m c? versiunile propuse de suprascriere a func?iei input() sunt simplificate ?i nu elimin? posibilit??i de introducere gre?it?.

Exerci?iul 7.5. Suprascrie?i func?ia input() ?n clasa rational.

Cum de procedat cu func?ia eroare(), care este un membru privat al clasei fractie_rationala? Func?ia aceasta a fost definit? ?n sec?iunea private a clasei de baz? numai ?n scopuri demonstrative, pentru ca aceast? clas? s? posede un membru privat. Locul mai potrivit pentru ea este ?n sec?iunea protected. Pentru a proceda mai departe, alege?i o solu?ie din urm?toarele:

  • ?n declararea clasei fractie_rationala (fi?ierul fr.cpp) ?nlocui?i tipul sec?iunii private cu tipul protected.
  • Defini?i func?ia eroare() ?n clasa rational_fara_semn ca membru protejat, folosind acela?i cod ca ?i ?n clasa de baz?.
  • Defini?i func?ia eroare()ca membru privat ?n clasa rational_fara_semn ?i func?ia eroare()ca membru privat ?n clasa rational, utiliz?nd acela?i cod ca ?i ?n clasa de baz? respectiv?.

Ne-am descurcat cu suprascrierea ?i supra?nc?rcarea func?iilor membre mo?tenite; acum trecem la analiza, suprascrierea ?i supra?nc?rcarea operatorilor mo?teni?i.
_________________________
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 сайтов