1.1 Co je to Üablona - template?
Mechanismus Üablon v C++ n∞kdy takΘ naz²van² jako genericita, dovoluje
programßtor∙m vytvß°et parametrizovanΘ moduly, jejich₧ parametrem m∙₧e b²t i
n∞jak² blφ₧e neurΦen² (primitivnφ, nebo objektov²) typ. Co p°esn∞ tato
komplikovanß definice znamenß si ukß₧eme na jednoduchΘm p°φkladu. P°edstavme si,
₧e vytvß°φme kolekci objekt∙ a sna₧φme se urΦit typ prvk∙, kterΘ tato kolekce
bude obsahovat. Mßme samoz°ejm∞ n∞kolik mo₧nostφ.
Typ prvk∙ m∙₧e b²t napevno urΦen². Pokud pou₧ijeme
kup°φkladu typ int, z°φkßme se tak mo₧nosti vklßdat do seznamu jinΘ
hodnoty ne₧ celoΦφselnΘ. Pokud budeme chtφt v budoucnu vytvo°it nap°φklad kolekci
Φφsel s pohyblivou desetinnou Φßrkou musφme vytvo°it dalÜφ kolekci. Smφ°it se
asi budeme muset s tφm, ₧e zdrojov² k≤d obou kolekcφ bude velmi podobn² (mo₧nß
skoro ·pln∞ stejn²) a liÜit se bude pouze pou₧it²m typem.
Jako typ m∙₧eme pou₧φt obecn² ukazatel void. V tomto
p°φpad∞ lze sice do kolekce vklßdat r∙znΘ typy objekt∙, ale p°i p°φstupu k
t∞mto objekt∙m musφme v₧dy provßd∞t p°etypovßnφ, co₧ nikdy nenφ bezpeΦnß
akce.
DalÜφ mo₧nostφ je vytvo°enφ abstraktnφho typu (abstraktnφ
t°φdy) a odkazovat se pomocφ n∞j na prvky v kolekci. V tomto okam₧iku m∙₧eme
vklßdat do kolekce instance t∞ch t°φd, kterΘ d∞dφ (p°φmo, nebo nep°φmo) z tΘto
abstraktnφ t°φdy (vyu₧φvßme zde polymorphism). Pro instance t°φd z
jin²ch hierarchiφ vÜak musφme vytvß°et dalÜφ kolekce.
Ideßlnφm °eÜenφm by bylo vytvo°enφ takovΘ t°φdy, kterß by
typ prvk∙ urΦovala ve svΘm parametru. Vytvo°it jak²si parametrizovan² vzor, podle
kterΘho by se vytvß°ely skuteΦnΘ t°φdy. A prßv∞ v tuto chvφli se dostßvajφ ke
slovu Üablony - templates.
V jazyce C++ existujφ dva typy Üablon, Üablony funkcφ
(function templates) a Üablony t°φd (class templates).
M∙₧eme vÜak °φci, ₧e ty pravΘ v²hody pou₧itφ Üablon jsou patrnΘ p°edevÜφm
p°i pou₧itφ Üablon t°φd.
1.2 V²hody Üablon
Jednou z velk²ch v²hod je skuteΦnost, ₧e pouh²m vytvo°enßm Üablony jeÜt∞
nevznikß binßrnφ k≤d. Odpovφdajφcφ binßrnφ k≤d je kompilßtorem vytvo°en² a₧
v okam₧iku dosazenφ parametr∙ a vytvo°enφ instance Üabony (tedy t°φdy, nebo
funkce) a jejφ nßslednΘ pou₧itφ. Tento princip zajiÜ¥uje, ₧e ve v²slednΘm
p°elo₧enΘm souboru je obsa₧en pouze ten k≤d, kter² skuteΦn∞ pou₧φvßme (to
m∙₧e b²t p°i pou₧itφ velk²ch knihoven Üablon ohromnß ·spora). Vzhledem k tomu,
₧e jsou Üablony distribuovßny s kompletnφm zdrojov²m k≤dem, m∙₧e dobr²
kompilßtor dßle optimalizovat k≤d i tφm, ₧e vynechß veÜker² nepou₧it² k≤d
(v₧dy se najde n∞jakß metoda t°φdy, kterou nepou₧ijeme).
P°φkladem knihoven Üablon m∙₧e b²t ATL - Active Template
Library, kterß je urΦena pro v²voj COM objekt∙, nebo STL - Standard template
library, je₧ je distribuovßna s knihovnou MFC.
1.3 èablony funkcφ
Pomocφ Üablon funkcφ m∙₧eme definovat mno₧inu funkcφ se stejn²m k≤dem, kterΘ
pou₧φvajφ r∙znΘ datovΘ typy. Prvnφm p°φkladem bude jednoduchß Üablona funkce
pro zjiÜt∞nφ maxima ze dvou prom∞nn²ch blφ₧e neurΦenΘho typu.
template <typename TYPE> TYPE Max(TYPE a, TYPE b)
{ return (a > b) ? a : b; } |
èablona oΦekßvß jedin² parametr TYPE, kter² urΦuje typ
dvou porovnßvan²ch parametr∙ funkce a typ nßvratovΘ hodnoty funkce. èablona
p°edpoklßdß, ₧e pro dosazen² typ bude definovßn operßtor ">".
PozornΘho Φtenß°e jist∞ napadne, ₧e typ m∙₧e b²t jak primitivnφ, tak u₧ivatelem
definovan² objektov².
Ve starÜφch verzφch se mφsto klφΦovΘho slova typename
pou₧φvalo klφΦovΘ slovo class. Domnφvßm se vÜak, ₧e tato zm∞na byla
provedena sprßvn∞, proto₧e klφΦovΘ slovo class bylo zavßd∞jφcφ.
Pou₧itφ Üablony funkce (tj. vytvo°enφ instance - funkce) je
jednoduchΘ a spoΦφvß v jejφm zavolßnφ. Podφvejme se na krßtkou ukßzku.
int a=10, b=20;
int c = Max(a, b);
double d1=10.1, d2= 20.2;
double d3 = Max(d1, d2);
printf("Maxima: %d, %f\n", c, d3); |
V p°edchozφm p°φkladu je vid∞t pou₧itφ Üablony pro r∙znΘ
datovΘ typy. V tuto chvφli je takΘ kompilßtorem vygenerovan² odpovφdajφcφ k≤d
dvou funkcφ, pro typ int a pro typ double. Pokud explicitn∞ neuvedeme
p°i volßnφ funkce datov² typ (nßÜ p°φpad), neprovßdφ kompilßtor ₧ßdnΘ
p°etypovßnφ a typ parametr∙ musφ b²t samoz°ejm∞ stejn². Nßsledujφcφ ukßzka
zobrazuje chybnΘ pou₧itφ Üablony.
Tento p°φpad vÜak m∙₧eme opravit explicitnφm urΦenφm parametru,
kter² zajistφ automatickou typovou konverzi.
double d = Max<double>(1, 1.1); |
Bez pou₧itφ mechanismu Üablon funkcφ bychom museli definovat dv∞
typov∞-bezpeΦnΘ funkce, viz. nßsledujφcφ ukßzka.
int Max(int a, int b) { return (a < b) ? a : b; }
double Max(double a, double b) { return (a < b) ? a : b; } |
1.4 èablona vs. makro
P°edchozφ p°φklad lze vy°eÜit takΘ pomocφ maker. M∞jme vÜak na pam∞ti zßsadnφ
rozdφl mezi makrem a Üablonou. Makra jsou °eÜena textov²m preprocesorem jazyka, tj.
jednß se pouze o jednoduchΘ dosazovßnφ textu, kde₧to Üablony jsou vyhodnocovßny
kompilßtorem.
Pro zjiÜt∞nφ maxima za dvou prom∞nn²ch bychom mohli pou₧φt
nßsledujφcφ makro.
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) |
Je zde vÜak n∞kolik zßsadnφch rozdφl∙:
1.5 DalÜφ p°φklad Üablony funkce
DalÜφm p°φkladem pou₧itφ Üablony funkce m∙₧e b²t kup°φkladu funkce, kterß
vym∞nφ hodnoty dvou parametr∙. Podφvejme se na nßsledujφcφ p°φklad.
template <class TYPE> void Swap( TYPE& a, TYPE& b )
{
TYPE c(a);
a = b;
b = c;
} |
Pou₧itφ Üablony, kterß °eÜφ v²m∞nu hodnot je ideßlnφ,
proto₧e kompilßtor kontroluje typy parametr∙ a zajiÜ¥uje tak jejich shodnost ji₧ v
okam₧iku kompilace (v naÜem p°φpad∞ je typovß kontrola velice d∙le₧itß).
Pou₧itφ tΘto Üablony je op∞t znßzorn∞no na nßsledujφcφ
ukßzce.
double d = 10.0;
int a=10, b=20;
Swap(a, b); // OK
Swap(a, d); // Error - r∙znΘ typy
printf("a=%d, b=%d\n", a, b); |
Jak ji₧ bylo °eΦeno parametrem Üablony m∙₧e b²t i objektov²,
u₧ivatelem definovan², typ. ProhlΘdn∞me si op∞t nßsledujφcφ ukßzku zdrojovΘho
k≤du.
CMyObject o1, o2;
Swap(o1, o2); |
P°φÜt∞ Üablony t°φd... |