2.9. Func?ii generice

2.9.Func?ii generice

Supra?nc?rcarea func?iilor ne d? posibilitate s? folosim unul ?i acela?i nume de func?ie pentru diferite tipuri de date. Neajunsul totu?i este acela c? pentru fiecare tip trebuie s? scriem o noua defini?ie de func?ie, deoarece sunt dese cazurile c?nd unul ?i acela?i algoritm este potrivit pentru mai multe tipuri de date f?r? descrieri repetate.

O alt? posibilitate ?n C++ de a crea mai multe func?ii cu unul ?i acela?i nume este utilizarea ?abloanelor (engl. template) sau func?iilor generice.

 

Func?ia la declararea c?reia este indicat unul sau mai multe tipuri parametrizate, care vor fi concretizate ?n fiecare loc unde se apeleaz? acest? func?ie, se nume?te func?ie generic? (sau ?ablon, sau de tip template)

 

Forma general? de defini?ie a unei func?iei generice cu un singur tip parametrizat este urm?toarea:

 

template <class tip> tip_retur nume_func?ie(list?_parametri)

{

// Corpul func?iei

}

Observa?ie. Cuv?ntul-cheie class poate fi ?nlocuit cu cuv?ntul-cheie typename. Efectul va fi acela?i, ?ns? ?n cazul ?n care tipul parametrizat tip dup? sens reprezint? un tip simplu, defini?ia func?iei poate fi mai clar?. Aceast? observa?ie se refer? ?i la declararea func?iilor generice cu mai multe tipuri parametrizate,  ?i la declararea claselor generice cu unul sau mai multe tipuri parametrizate.

La apelul func?iei compilatorul folose?te un exemplar de func?ie generat ?n dependen?? de concretizarea tipului.

Concretizarea poate fi explicit? (prin indicarea <tip>)

nume_func?ie<tip>(list?_argumente)

sau implicit? (numai prin lista argumentelor)

nume_func?ie(list?_argumente)

?n calitate de tipul concret tip poate fi folosit orice tip cunoscut ?n locul apelului acestei func?ii.

Cercet?m urm?torul exemplu:

#include "iostream.h"
// afl? ?i returneaz? valoarea maxim? din cele dou?
template <class T> T max(T t1, T t2)
{
   return t1>t2 ? t1 : t2;
}
 
void main()
{
   int i=2, k=10;
   cout << "max(" << i << ", " << k << ")="
        << max(i, k) << endl;
 
   cout << "max(" << 3.14 << ", " << 2.25 << ")="
        << max(3.14, 2.25) << endl;
 
   char c; cin >> c;
}


?n func?ia main() se demonstreaz? apelurile func?iei generice. Programul afi?eaz? urm?torul text:

max(2, 10)=10
max(3.14, 2.25)=3.14

Textul afi?at arat? rezultatele de apelare a func?iei generice. Prelucr?nd apelurile func?iei generice max(i, k), max(3.14, 2.25), compilatorul va genera dup? ?ablon func?ii concrete ?n dependen?? de tipul parametrilor. Acest proces se mai nume?te exemplificarea sau instan?ierea func?iei generice.

Tipul parametrizat tip, indicat la defini?ia unei func?ii generice, este un identificator arbitrar, ?i poate fi folosit sub form? de tip, tip&, tip*, tip** ?n aceast? func?ie astfel:

-        la descriea tipului valorii de retur;

-        la descrierea tipurilor parametrilor;

-        la declararea variabilelor locale ?n corpul func?iei;

-        la operatorii sizeof, new, conversie de tip.

 

?n cazul c?nd corpul func?iei generice nu este potrivit pentru un tip oarecare, ea poate fi supra?nc?rcat? pentru acest tip.

Inser?m ?n programul precedent, ?nainte de func?ia main(), urm?torul cod de supra?nc?rcare a func?iei generice max():

char* max(char* s1, char* s2) // afl? ?irul maximal din 
{                             // dou?
   int i=0;
   while( (*(s1+i)!='\0') && (*(s1+i)==*(s2+i)) )
      i++;
   return *(s1+i)>*(s2+i)? s1 : s2;
}


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

char *s1="abcd";
   char *s2="abd";
   cout << "s1=\"" << s1 << "\"" << endl;
   cout << "s2=\"" << s2 << "\"" << endl;
   cout << "max(s1, s2)=\"" << max(s1, s2) << "\""
        << endl;
   cout << "max(\"" << "abdc" << "\", \"" << "abcd"
        << "\")=\"" << max("abdc", "abcd") << "\""
        << endl;


Prelucr?nd apelurile max(s1, s2), max("abdc", "abcd")), compilatorul va apela func?ia care supra?ncarc? func?ia generic? ?i are antetul

char *max(char* s1, char* s2)

Pe ecran va fi afi?at:

s1="abcd"
s2="abd"
max(s1, s2)="abd"
max("abdc", "abcd")="abdc"

Dezvolt?nd ?n continuare exemplul nostru, mai supra?nc?rc?m de dou? ori funcia generic? max(), respectiv cu trei ?i patru parametri:

template <class T> T max(T t1, T t2, T t3)
{
   return max(max(t1, t2), t3);
}
 
template <class T> T max(T t1, T t2, T t3, T t4)
{
   return max(max(t1, t2, t3), t4);
}


Exerci?iul 2.1. Modifica?i de sine st?t?tor ?i func?ia  main() ca s? v? convinge?i c?: max(3, 7, 5) ?ntoarce 7, max(3.2, 2.7, 5.3, 4.1) ?ntoarce 5.3, iar max("abdc", "abcd", "ardc", "abac") ?ntoarce "ardc". Explica?i ?n ce mod compilatorul va rezolva aceste apeluri.

Exerci?iul 2.2. Verifica?i faptul c? la func?ii generice se admite specificarea parametrilor implici?i.

Func?ia generic? poate s? depind? de mai multe tipuri parametrice. Forma de descriere de o asemenea func?ie este urm?toarea:

template <class tip_1[, class tip_2 ...]> tip_retur nume_func?ie (list?_parametri)

{

// Corpul func?iei

}

Pentru exemplu cre?m o func?ie generic? care afl? valoarea maxim? dintre elementele unui vector. Func?ia va depinde de dou? tipuri parametrizate. Unul va parametriza tipul elementelor vectorului dat, cel de al doilea tip va parametriza tipul indicilor.

<#include "iostream.h"
 
template <class T, class U> T max(T vt[], U n)
{
   T vmax=vt[0];
   for (U i=1; i<n; i++)
     if(vt[i]>vmax)
       vmax=vt[i];
   return vmax;
}
 
void main()
{
  double vd[5]={6.2, 9.5, 3.7, -5.2, 2.1};
  cout << "max din double = " << max<double, long>(vd, 5l) << endl;
//  ?ncerca?i ?i a?a
//  cout << "max din double = " << max(vd, 5l) << endl;
 
  int vi[5]={6, 9, 3, -5, 2};
  cout << "max din int = " << max<int, char>(vi,(char)5) << endl;
//  ?ncerca?i ?i a?a
//  cout << "max din int = " << max(vi, (char)5) << endl;
 
  char c; cin >> c;
}


Rezultatul afi?at va ar?ta astfel:

max din double = 9.5
max din int = 9

Exerci?iul 2.3. Examina?i de sine st?t?tor urm?toarea versiune a func?iei generice max():

template <class T=double, class U=int>
T max(T vt[], U n)
{
   T vmax=vt[0];
   for (U i=1; i<n; i++)
     if(vt[i]>vmax)
       vmax=vt[i];
   return vmax;
}


Re?ine?i c? func?ia generic? nu poate folosi o specificare de editare de leg?turi, utiliz?nd doar editoarele de leg?turi din C++.
_________________________
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 сайтов