Szablony funkcji
Andrzej Walczak
Konspekt wykładu oparty o literaturę z
sylabusu
Czy możliwe jest, aby funkcja była w
pewnym stopniu inteligentna? Czy
mogłaby samodzielnie dobrać zarówno typ
argumentów, jak typ wyniku czyli samej
funkcji?
Tak. Takie zadanie realizuje szablon
funkcji.
Dzięki temu przy korzystanie ze zmiennych
o typach własnych nie następuje mylenie
typów (klas).
Definiowanie szablonu w programie
template
<class
pewien_typ>
pewien_typ
wieksza(pewien_typ a, pewien_typ b)
{ return(a>b)?a:b; }
template to słowo kluczowe inicjujące proces tworzenia szablonu
pewien_typ to nazwa szablonu
class to słowo kluczowe KONIECZNE aby powstał szablon. Kiedy
parametrów szablonu jest więcej niż jeden, to po przecinku
powtarzamy słowo class i podajemy kolejną nazwę parametru.
wieksza to nazwa przykładowej funkcji, która wybiera większą z
dwóch liczb. Typ argumentów i funkcji jest przy tym dowolny,
wbudowany lub zdefiniowany przez programującego. Oznacza to, że
argumentami funkcji mogą być obiekty.
Główne wymagania i cechy
dotyczące szablonu
Główne wymagania i cechy
dotyczące szablonu cd.
•
Operacja zapisana w funkcji poddana jest takim samym regułom
na poprawność operacji jak we wszystkich innych funkcjach ,
czyli nie wykona się na przykład operacja arytmetyczna na
zmiennych znakowych.
•
Parametr szablonu – nazwany jakoś podczas deklarowania
szablonu – nie musi mieć tej samej nazwy podczas definiowania
szablonu.
•
Dwa szablony o takiej samej nazwy mogą wystąpić w tym samym
kodzie. Należy tylko uważać, aby jeden nie był szczególnym
przypadkiem drugiego. Wówczas linker „nie wie” z którego ma
skorzystać.
•
Szablon wstawiając do wzorca funkcji różne typy
argumentów tworzy tak naprawdę przeładowanie funkcji.
•
Sam szablon też może być przeładowany czyli w tym samym
zakresie ważności może wystąpić dwa lub kilka razy z taką samą
nazwą ale różnymi parametrami:
template <class typ> void funkcja (typ, int);
template <class typ> void funkcja (typ, int, float, char);
Główne wymagania i cechy
dotyczące szablonu
cd.
•Szablon jest deklarowany globalnie, ale stosowany lokalnie.
Dlatego nie powinien używać nazw zmiennych globalnych.
•UWAGA: standaryzacja nie obejmuje jeszcze całości szablonów.
Mogą występować kłopoty.
•W szablonie możemy stosować atrybuty inline, extern, static.
Pamiętajmy jednak, że słowo to odnosi się ostatecznie nie do
szablonu ale do funkcji, która wg tego szablonu zostanie zbudowana:
template <class bb>
inline
bb wieksza (bb z1, bb z2)
{ return (z1>z2)? z1:z2; }
Przykład: (wg Grebosza )
#include <iostream>
template <class nasz_typ>
nasz_typ wieksza(nasz_typ a, nasz_typ b)
{ return (a>b)?a:b;}
///////////////////////////////
void main()
{
int a = 44, b = 88;
double x = 14.2, y = 28.4;
unsigned long la = 987654, lb = 777;
// nigdzie nie ma deklaracji konkretnego typu funkcji i typu
argumentów
cout<<”wiekszy int:” <<wieksza(a,b)<<endl;
cout<<”wiekszy double:” <<wieksza(x,y)<<endl;
cout<<”wiekszy long int:” <<wieksza(la,lb)<<endl;
cout<<”wiekszy kod ASCII:” <<wieksza(‘a’,’b’)<<endl;
}
Jeśli parametrów jest więcej niż jeden to każdy
musi być poprzedzony słowem class (albo słowem
typename). Jeśli typ parametru się powtarza czyli
są np. dwa parametry typu integer, albo dwa
parametry są obiektami tej samej klasy, to
wymienia się je na liście parametrów tylko raz.
Czyli poprawny jest zapis w kodzie:
////
template <class krakow,class warszawa>
void funkcja_opis_miasta(krakow a, krakow b,
krakow c, warszawa d, warszawa e);
///////
Do argumentu funkcji w szablonie możemy się odwołać przez
referencję.
Referencja była zastosowana do argumentów funkcji wtedy,
kiedy zamierzeniem była zmiana wartości pod adresem
zmiennej.
Teraz przy zdefiniowaniu szablonu możemy ten sam kod
wykorzystać szerzej.
#include<iostream>
#include<conio.h>
#include<string.h>
//////////////
template<class sejfik>
void zamiana(sejfik &lewy, sejfik &prawy)
{
sejfik pomocniczy;
pomocniczy=lewy;
lewy=prawy;
prawy=pomocniczy;
}
///////////////////// teraz wg SZABLONU
void main()
{
float a=-7.0,b=23.0;
cout<<”przed zamiana\n”
<<”a=”<<a<<”\tb=”<<b<<endl<<”\n”;
zamiana(a,b);
cout<<”po zamianie\n”
<<”a=”<<a<<”\tb=”<<b<<endl<<”\n”;
zamiana(a,b);
cout<<”po zamianie ponownej\n”
<<”a=”<<a<<”\tb=”<<b<<endl<<”\n”;
char c=‘A’,d=‘B’;
cout<<”przed zamiana\n”
<<”c=”<<c<<”\td=”<<d<<endl<<”\n”;
zamiana(c,d);
cout<<”po zamianie\n”
<<”c=”<<c<<”\td=”<<d<<endl<<”\n”;
zamiana(c,d);
cout<<”po zamianie ponownej\n”
<<”c=”<<c<<”\td=”<<d<<endl<<”\n”;
}
#include <iostream>
#include <conio.h>
/////////////////////
template <class nasz_typ>
nasz_typ wieksza(nasz_typ a, nasz_typ b)
{ return (a>b)?a:b;}
//////////////////////
class nowa {public:
double war;
};
Atrybut obiektu argumentem
funkcji szablonowej
void main(){
double aaaa,bbbb;
nowa rr,rrr;
rr.war=10;
rrr.war=1000;
aaaa=rr.war;
bbbb=rrr.war;
int a=44, b=88;
double x=14.2, y=28.4;
unsigned long la=987654, lb=777;
//char A,B;
cout<<"\ntest"<<wieksza(aaaa,bbbb)<<endl; //atrybut obiektu
argumentem szablonu
cout<<endl<<"\n";
getch();}
Funkcje specjalizowane
• template <class parametr1, class
parametr2> parametr1 sumuj (parametr1
argument1, parametr2 argument2) { return
(argument1 + argument2); }
• char * sumuj (char * argument1, char *
argument2)
//funkcja specjalizowana
• { return (*argument1 + *argument2); }