Šablony v C++

C a C++ C++ Objektově orientované programování Šablony v C++

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Šablony jsou určené k definici několika funkcí, tříd apod., které se liší jen např. datovým typem použitým v deklaraci.

Začneme ukázkou šablony funkce max(), vracející větší hodnotu:

template<typename T> T Max(T a, T b)
{
        return (a > b)?a:b;
}

A teď popis:

template = tímto klíčovým slovem překladači říkáme, že se bude jednat o šablonu
<typename T> = do ostrých závorek píšeme parametry šablony - datové typy
T Max(T a, T b) = hlavička funkce

Parametrů šablony můžeme mít kolik chceme, jejich nová pojmenování můžeme využívat během celé definice. Můžeme jim přidělit i implicitní hodnotu, např. <typename T = int>. Kromě typename můžeme použít i klasické proměnné - např. template<int i, char ch>.

Když teď máme šablonu funkce, pojďme ji využít:

cout << Max(3, 5);

Program samozřejmě vypíše číslo 5. Pokud najedeme myší na název Max, ukáže se nám něco takového:

Šablony v C++ – int Max

Změňme Max(3, 5) na Max('c', 'k'). Výstupem programu bude k (je v abecedě dál). Při najetí myší se nám ukáže toto:

Šablony v C++ – char Max

Můžete si to zkusit i u desetinných čísel, řetězců atd. Uvidíte, že to vždy funguje a pokaždé se nám ukáže něco jiného.

Funkcím, které se nám takto vytvářely, se říká instance šablon a vytváří je pro nás překladač. Ten podle parametrů odhadne, co má do šablony dosadit. Pokud jsou parametry různých typů, ohlásí nám chybu. To proto, že neví, který z nich vybrat. My to můžeme řešit přetypováním jednoho z nich na žádaný typ.

Kromě šablon funkcí můžeme dělat i šablony dalších věcí - tříd, struktur, unií... Nejprve si ukážeme šablonu struktury. Jestli se domníváte, že bude začínat template<typename T>struct, máte pravdu.

template<typename T> struct var {
        T value;

        var(T value)
        {
                this->value = value;
        }
};

Vytvoření instance je u takové struktury složitější, musíme jí totiž předat parametr šablony:

var<int> v(7); // proměnná value bude typu int
cout << v.value << endl;
v.value = 53; // změna hodnoty
cout << v.value << endl;

Výstup by měl být:

7
53

Teď se pustíme do tříd. Bude podobná struktuře z předchozí ukázky, jen bude dodržovat zapouzdření:

template<typename T> class Var{
        T value;
public:
        Var(T value)
        {
                this->value = value;
        }
        T get_value()
        {
                return value;
        }
        void set_value(T value)
        {
                this->value = value;
        }
};

Založení:

Var<int> v2(2); // proměnná value bude typu int
cout << v2.get_value() << endl;
v2.set_value(16); // změna hodnoty
cout << v2.get_value() << endl;

Výstup:

2
16

Vše tedy funguje. Jen jsme nedodrželi správné návyky. Třídu oddělíme do vlastního souboru a definice jejích metod dáme zvlášť.

//Var.h
#pragma once

template<typename T> class Var{
private:
        T value;
public:
        Var(T value);
        T get_value();
        void set_value(T value);
};

template<typename U> Var<U>::Var(T value)
{
        this->value = value;
}
template<typename U> U Var<U>::get_value()
{
        return value;
}
template<typename U> void Var<U>::set_value(U value)
{
        this->value = value;
}

Definice metod musíme u šablon psát do těla třídy, nebo do stejného souboru (musí to být header - .h), jinak nám překladač vynadá. Pokud je umístíme mimo třídu, musí být jejich definice psané také jako šablony.

Teď si napíšeme šablonu třídy, která bude fungovat jako jednoduchá kalkulačka. Bude mít dva atributy - A a B (libovolného typu) a metody na jejich sečtení, odečtení, vynásobení a vydělení.

A teď je tu otázka pro vás: Kde budou definice metod?

  1. V souboru Calculator.cpp
  2. Uvnitř definice třídy
  3. Překladač je doplní sám
  4. Za definicí třídy

Správná odpověď je d. (b by se dalo také považovat za správné, ale metody v C++ píšeme mimo třídu)

Můj kód vypadá takto:

#pragma once

template<typename T = int> class Calculator
{
        T A;
        T B;
public:
        Calculator(T A, T B);
        T add();        // součet
        T subtract();   // rozdíl
        T multiply();   // násobek
        T divide();     // podíl
        T get_A();
        T get_B();
};

template<typename U> Calculator<U>::Calculator(U A, U B)
{
        this->A = A;
        this->B = B;
}
template<typename U> U Calculator<U>::add()
{
        return A + B;
}
template<typename U> U Calculator<U>::subtract()
{
        return A - B;
}
template<typename U> U Calculator<U>::multiply()
{
        return A * B;
}
template<typename U> U Calculator<U>::divide()
{
        return A / B;
}
template<typename U> U Calculator<U>::get_A()
{
        return A;
}
template<typename U> U Calculator<U>::get_B()
{
        return B;
}

Teď si třídu můžeme vyzkoušet:

//Source.cpp

Calculator<double> c(12.3, 4.1);

cout << c.get_A() << " + " << c.get_B() << " = " << c.add() << endl;
cout << c.get_A() << " - " << c.get_B() << " = " << c.subtract() << endl;
cout << c.get_A() << " * " << c.get_B() << " = " << c.multiply() << endl;
cout << c.get_A() << " / " << c.get_B() << " = " << c.divide() << endl;

Výstup:

Test kalkulačky v C++ s šablonami

Základy už máme za sebou, takže se podíváme na něco zajímavějšího. Donutíme překladač, aby za nás spočítal faktoriál:

template<int N> struct faktorial{
        enum { value = N * faktorial<N - 1>::value };
};

template<> struct faktorial<0>{
        enum { value = 1 };
};

Druhá definice je pro nás novinkou. Je to tzv. externí specifikace. Díky ní se může šablona u určité hodnoty parametru zachovat jinak než normálně. To se dá využít např. k optimalizacím. U nás to ukončí výpočet, který je provedený rekurzí. Co je na něm ale zajímavé je to, že ho nepočítá náš program, ale překladač. Kód otestujeme:

cout << faktorial<1>::value << endl;
cout << faktorial<2>::value << endl;
cout << faktorial<3>::value << endl;
cout << faktorial<4>::value << endl;
cout << faktorial<5>::value << endl;
cout << faktorial<6>::value << endl;
cout << faktorial<7>::value << endl;

Výstup:

Faktoriál v C++

To by bylo k šablonám vše, doufám, že se vám to líbilo. Příště se podíváme na přetěžování operátorů.


 

Stáhnout

Staženo 191x (18.99 MB)
Aplikace je včetně zdrojových kódů v jazyce C++

 

  Aktivity (1)

Článek pro vás napsal Zdeněk Pavlátka
Avatar
Autor se věnuje spoustě zajímavých věcí :)

Jak se ti líbí článek?
Celkem (2 hlasů) :
3.53.53.53.5 3.5


 


Miniatura
Předchozí článek
Výjimky v C++

 

 

Komentáře
Zobrazit starší komentáře (13)

Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Odpovědět 22.2.2014 19:04
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Zdeněk Pavlátka:

Chyby v článku opraveny, čeká se na schválení.

Odpovědět 22.2.2014 19:59
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Lukáš Hruda (Luckin):

Donutit překladač aby něco spočítal, místo toho aby se to počítalo za běhu je zajímavá myšlenka, škoda, že to funguje jenom pro předávání konstant.

 
Odpovědět  +1 25.2.2014 9:45
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Odpovídá na Lukáš Hruda (Luckin)
Zdeněk Pavlátka:

Myšlenka je z knihy 1001 tipů a triků pro C++ od Miroslava Viriuse.

Odpovědět 25.2.2014 13:34
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Samuel Bachar:

Čauko .
V druhej časti článku mi vypísalo toto a nie sa toho zbaviť.

Error C2838 '{ctor}': illegal qualified name in member declaration
Error C2838 'get_value' : illegal qualified name in member declaration
Error C2838 'set_value' : illegal qualified name in member declaration

Celý článok som okopíroval dodržal som všetko aj postup .
Online help : https://msdn.microsoft.com/…8hwed98.aspx
Nič také nevidím v mojom projekte a taktiež v tomto okopirovanom . Používam VS 2015 . Poradí niekto ?

 
Odpovědět 20.10.2015 12:19
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Odpovídá na Samuel Bachar
Zdeněk Pavlátka:

Hodil by se konkrétní kód...

Odpovědět 20.10.2015 17:11
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Zdeněk Pavlátka:

Definice metod - např.

template<typename U> Var<U>::Var(T value)
{
        this->value = value;
}

musí být MIMO tělo třídy, pokud mají být zapsané takto. Ty je máš uvnitř...

Odpovědět 20.10.2015 18:37
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Odpovídá na Zdeněk Pavlátka
Samuel Bachar:

Zabudol som že to je písane v článku ale urobil som to zrejme kvôli tomu aby som sa zbavil týchto chýb aj napriek tomu že to bol chybný ťah.

Editováno 21.10.2015 7:11
 
Odpovědět 21.10.2015 7:10
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 23. Zobrazit vše