Hlavní
Hlavní strana
Seznam článků
Nejčtenější články
Progres e-mailem
Visual C++ FAQ

Seriály
COM
ISAPI

banner1.gif (2545 bytes)

Nenechte si ujít
Neobdélníková okna
Tisk bez Preview
MFC a DLL
Logo v MDI ploše
Kouzla s kombo-boxem
Výjimky v C++

banner.gif (3305 bytes)

Šablony v C++ díl 1. Jan Odvárko
02.11.1999
[Hlavní stránka]  |  [Rubrika]

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.

  double d = Max(11.1);

Tento případ však můžeme opravit explicitním určením parametru, který zajistí automatickou typovou konverzi.

  double d = Max<double>(11.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ů:

  • Nelze žádným způsobem kontrolovat typy dosazených parametrů.

  • Parametry 'a' a 'b' jsou vyhodnoceny dvakrát. Pokud bychom dosadili například proměnnou s inkrementačním operátorem ++, bude její hodnota zvýšena dvakrát.

  • Protože jsou makra vyhodnocena preprocesorem bude při případné chybě kompilátor odkazovat na místo použití, místo na definici makra.

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...


Podobné články:

 
Článek je zařazen do seriálu Následující>>
Šablony v C++ díl 2.

Kdo Otázka nebo připomínka

Prohlížení příspěvků nebo nový příspěvek

O firmě... Kontakt Ostatní