7.3. Definirea ?i supra?nc?rcarea constructorului ?n clasa derivat?

7.3. Definirea ?i supra?nc?rcarea constructorului ?n clasa derivat?

Definind ?i supra?nc?rc?nd constructorii ?n clasa derivat?, trebuie de asigurat ?n ei apelul constructorului clasei de baz?. Dac? constructorul clasei de baz? nu va fi apelat explicit, compilatorul ?l va apela implicit ?i f?r? argumente; ?i ?n cazul c?nd clasa de baz? nu dispune de un a?a constructor, compilatorul va semnala o eroare.

Forma general? de definire ?i supra?nc?rcare a constructorului clasei derivate arat? astfel:

[nume_clas?_derivat?::] nume_clas?_derivat?(list?_parametri)
[: nume_clas?_baz?(list?_argumente)]
{

// codul constructorului clasei derivate  

}

Aceasta a fost forma general? pentru cazul c?nd clasa derivat? mo?tene?te de la o singur? clas? de baz?. Cazul de mo?tenire multipl? va fi descris aparte. Memoriza?i c? mai ?nt?i se apeleaz? constructorul clasei de baz?, apoi se execut? ?nsu?i constructorul clasei derivate. Pentru destructor ordinea este invers?. Adic?, mai ?nt?i se execut? codul destructorului clasei derivate, apoi se apeleaz? destructorul clasei de baz?.

Construc?ia luat? ?n [ ] ?nseamn? c? apelul explicit al constructorului de baz? poate fi omis, ?i ?n acest caz compilatorul va genera codul de apelare a constructorului de baz? f?r? argumente. ?ns?, nimic nu ne ?mpiedic? s? scriem explicit apelul f?r? argumente al constructorului de baz?.

Definim un constructor ?n clasa derivat? rational_fara_semn. Pentru aceasta, inser?m urm?torul cod dup? sec?iunea protected ?n defini?ia acestei clase din exemplul precedent:

public:
rational_fara_semn(unsigned pi_init=0,
                   unsigned n_init=0, unsigned m_init=1):
            fractie_rationala(n_init, m_init)//apel?m constructorul bazei
 {
   part_int = pi_init; // ini?ializ?m c?mpul ad?ugat ?n
                       // clasa derivat?
 }

Constructorul clasei rational_fara_semn are trei parametri (?n mod normal, ace?tia sunt valorile ini?iale, respectiv, pentru partea ?ntreag?, num?r?torul ?i numitorul). Pentru to?i trei am indicat ?i valorile implicite: 0 – pentru partea ?ntreag? ?i numitor ?i 1 – pentru num?r?tor. Subliniem c? valorile implicite pentru num?r?tor ?i numitor ?n clasa derivat? coincid cu valorile implicite pentru aceste c?mpuri la clasa de baz?. ?n principiu, acesta nu este obligatoriu, dar pentru integritatea proiectului nostru a?a va fi mai bine.

Acum avem posibilitatea de a ini?ializa explicit obiectele rational_fara_semn. Pentru a aduce un exemplu mai ilustrativ de un a?a tip de ini?ializare, mai supra?nc?rc?m operatorul de inser?ie <<. Cu acest scop ad?ug?m la codul precedent urm?torul cod:

friend ostream &operator<<(ostream& stream, const rational_fara_semn &rfs) 
{  if(rfs.part_int > 0) stream << rfs.part_int << ",";
         stream << rfs.numarat << "/" << rfs.numit;
 return stream;
}

Adic?, am ad?ugat ?n defini?ia clasei rational_fara_semn supra?nc?rcarea operatorului << ?n forma de func?ia friend, care afi?eaz? (transmite ?n stream) partea ?ntreag?, o virgul?, num?r?torul, caracterul / (slash) ?i numitorul. Partea ?ntreag? ?i virgula vor fi afi?ate numai ?n cazul c?nd partea ?ntreag? este diferit? de zero.

Re?ine?i cum la un obiect rational_fara_semn (parametrul rfs) se face adresarea c?tre c?mpurile numarat ?i numit, de parc? ele au fost declarate ?n defini?ia acestei clase. ?n realitate, ele au fost mo?tenite de la clasa de baz? fractie_rationala.

?nlocuim ?n func?ia main() din programul precedent instruc?iunea:

rational_fara_semn a, b;

cu:

rational_fara_semn a(2, 1, 3), b(0, 3, 5);

?i lans?m programul. Rezultatul afi?at de data aceasta va fi:

a=2,1/3
b=3/5

Constructorul definit ?n clasa derivat? a ini?ializat toate c?mpurile obiectelor a ?i b. Acum, la afi?area obiectelor a ?i b a lucrat func?ia operator<<() supra?nc?rcat? pentru clasa derivat? ?i a afi?at doi ?ntregi ?i o treime pentru obiectul a ?i trei cincimi pentru obiectul b.

Acela?i lucru ?l facem ?i pentru clasa rational. Anume: inser?m ?n declararea acestei clase urm?torul cod:

public:
 rational(int pi_init=0, unsigned n_init=0, 
          unsigned m_init=1):rational_fara_semn(pi_init>=0 ? 
            (semn='+',pi_init):(semn='-',-pi_init), n_init, m_init)
 {
 
 }
 
 friend ostream &operator<<(ostream& stream, const rational &r)
 {
   if(r.semn=='-')
      stream << '-';
   stream << rational_fara_semn(r.part_int, r.numarat, r.numit);
   return stream;
 }

care reprezint? definirea constructorului ?i supra?nc?rcarea operatorului << pentru clasa rational. Am p?strat la constructor trei parametri, ?ns? primul parametru este acum de tipul int, ceea ce ne va permite s? indic?m semnul num?rului ra?ional. O alt? posibilitate era de a introduce patru parametri, primul fiind destinat numai pentru indicarea semnului num?rului. ?n fine, putem supra?nc?rca ambele versiuni ale constructorului: una cu trei parametri ?i cea de a doua cu patru.

Versiunea cu trei parametri este mai comod?, ?ns? are un neajuns, fiindc? mic?oreaz? de dou? ori intervalul de ini?ializare al p?r?ii ?ntregi. ?n acest exemplu este reprezentat? versiunea constructorului cu trei parametri. Deci, primul parametru aduce informa?ii despre semnul num?rului ra?ional ?i despre valoarea absolut? a p?r?ii ?ntregi a acestui num?r.

Re?ine?i cum ?n acest exemplu se apeleaz? constructorul clasei de baz?. Mai mult, expresia pentru primul argument al lui. Aceast? expresie reprezint? operatorul ternar ?:.

Dac? primul argument al constructorului derivat nu este negativ, atunci ?n c?mpul nou ad?ugat semn se memorizeaz? valoarea '+' ?i primul argument la apelul constructorului de baz? va fi valoarea pozitiv? pi_init. ?n cazul c?nd primul argument al constructorului derivat este negativ, atunci ?n c?mpul nou ad?ugat semn se memorizeaz? valoarea '-', iar primul argument la apelul constructorului de baz? va fi valoarea pozitiv? -pi_init.

Am apelat constructorul clasei de baz?, totodat? am ini?ializat c?mpul semn. De aceea, ?nsu?i corpul constructorului derivat s-a primit gol. Supra?nc?rcarea operatorului << pentru clasa derivat? rational nu este greu de ?n?eles. Re?ine?i cum ?n el a fost apelat acela?i operator pentru clasa de baz?. Pentru verificare inser?m ?n func?ia main() urm?torul fragment de cod:

rational r1(-1, 3, 7), r2(2, 1, 3);
cout << "r1=" << r1 << endl;
cout << "r2=" << r2 << endl;

Textul afi?at de el va fi:

r1=-1,3/7
r2=2,1/3

Versiunea examinat? a constructorului cu trei parametri pentru clasa rational mai are ?nc? un neajuns. Cu acest constructor nu putem ini?ializa numere  ra?ionale negative  din  intervalul (-1, 0). ?ntr-adev?r, cum este posibil de creat, de exemplu, obiectul cu valoarea -1/2? Dac? ?ncerc?m s? scriem:

cout << rational(-0, 1, 2) << endl;

vom ob?ine:

1/2

Ceea ce nu este corect. De aceea, inser?m ?n sec?iunea public a clasei rational ?nc? un constructor:

rational(char semn_init, unsigned pi_init,
         unsigned n_init=0, unsigned m_init=1):
         rational_fara_semn(pi_init, n_init, m_init)
{
 semn = semn_init;
}

Acum avem posibilitatea s? scriem:

cout << rational(’-’, 0, 1, 2) << endl;

cu rezultatul:

-1/2

Este clar c? parametrul semn_init poate fi sau ’-’ sau ’+’. Verificarea acestui fapt, pentru simplicitate, a fost omis?.
_________________________
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 сайтов