« Szablony klas, lekcja »
Co to są szablony klas i jak z nich korzystać. (lekcja)
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!
Autor: 'DeBugger'
Kurs C++

Szablony klas

[lekcja] Co to są szablony klas i jak z nich korzystać.

Wstęp

Tym razem przygotuj się na coś trudniejszego - będzie o wiele więcej trudniejszego materiału. Taką mam nadzieję. :)
Będziemy omawiać bardziej zaawansowane rzeczy niż dotychcasz. Tak jak zdanie wyżej, taką mam nadzieję. ;)

Szablony Klas - Wstęp

Najpierw nasz ulubiony szablon:
template < class klasa >
Teraz piszę już cały przykładowy kod. Chcę zaprezentować jak to działa, choć ten kod może być nieużyteczny. Na razie bez szablonów:
C/C++
#include <iostream>
class tablica_typu_int
{
public:
    int zmienna[ 8 ];
    void uzupelnij( int ktora )
    {
        std::cin >> zmienna[ ktora ];
    }
    void pokaz( int ktora )
    {
        std::cout << zmienna[ ktora ] << std::endl;
    }
};
int main()
{
    tablica_typu_int nowa;
    int a = 0;
    while( a < 8 ) //ostatnio pętla for coś mi szwankuje... :D
    {
        nowa.uzupelnij( a );
        nowa.pokaz( a );
        std::cout << a << std::endl;
        a++;
    }
    std::cout << "Operacja ukończona - " << a << std::endl;
}
Nasza tablica ma 8 elementów typu int. Nie możemy jej jednak modyfikować.
Teraz mała modyfikacja. Dzięki niej możemy stworzyć tablicę o podanej przez nas wielkości(niestety na razie typu int. :(, ale do tego wktótce dojdziemy):
C/C++
#include <iostream>
using namespace std;
template < int ilosc >
class tablica_typu_int
{
public:
    int zmienna[ ilosc ]; //nasza ilosc
    int zmienna_zawierajaca_prawidlowa_ilosc; //tym zajmiemy się w jednej funkcji z klasy, przydatna do jednego z warunków w przyszłości
    void uzupelnij( int ktora )
    {
        cin >> zmienna[ ktora ];
    }
    void pokaz( int ktora )
    {
        cout << zmienna[ ktora ] << endl;
    }
    int wielkosc()
    {
        return ilosc;
    }
    void nadaj_prawidlowa_ilosc()
    {
        zmienna_zawierajaca_prawidlowa_ilosc = ilosc;
    }
};
int main()
{
    tablica_typu_int < 11 > nowa; //ustalamy
    nowa.nadaj_prawidlowa_ilosc();
    int a = 0;
    cout << "Nasza tablica to: " << nowa.wielkosc() << " elementow." << endl << endl;
    while( a < nowa.zmienna_zawierajaca_prawidlowa_ilosc ) //właśnie tu
    {
        nowa.uzupelnij( a );
        nowa.pokaz( a );
        cout << a << endl;
        a++;
    }
    cout << "Operacja ukończona - " << a << endl;
}
Ostatnia modyfikacja. Tym razem sami możemy "powiedzieć", jakiego typu jest:
C/C++
#include <iostream>
using namespace std;
template < int ilosc, class typ >
class tablica_typu_int
{
public:
    typ zmienna[ ilosc ];
    int zmienna_zawierajaca_prawidlowa_ilosc;
    void uzupelnij( int ktora )
    {
        cin >> zmienna[ ktora ];
    }
    void pokaz( int ktora )
    {
        cout << zmienna[ ktora ] << endl;
    }
    int wielkosc()
    {
        return ilosc;
    }
    void nadaj_prawidlowa_ilosc()
    {
        zmienna_zawierajaca_prawidlowa_ilosc = ilosc;
    }
};
int main()
{
    tablica_typu_int < 21, char > nowa;
    nowa.nadaj_prawidlowa_ilosc();
    int a = 0;
    cout << "Nasza tablica to: " << nowa.wielkosc() << " elementow." << endl << endl;
    while( a < nowa.zmienna_zawierajaca_prawidlowa_ilosc )
    {
        nowa.uzupelnij( a );
        nowa.pokaz( a );
        cout << a << std::endl;
        a++;
    }
    cout << "Operacja ukończona - " << a << endl;
}
Podsumowując - tworzenie template'a jest takie same zawsze. Jednakże template może służyć do rozmaitych rzeczy.

More Hardcore

Dynamiczne zmienne klas a template

Jest z tym trochę więcej filozofii... Mam nadzieję, że przeczytałeś kurs o dynamiczności w tworzeniu klas? Oto kod:
C/C++
#include <iostream>
using namespace std;
template < class typ >
class nowa_zmienna
{
    typ zmienna;
public:
    nowa_zmienna() //konstruktor
    {
        cout << "Nowy obiekt klasy `tablica` został stworzony" << endl;
    }
    int wyswietl()
    {
        cout << "Wyswietlam cos " << 'd' << endl;
    }
    ~nowa_zmienna() //destruktor
    {
        cout << "Nowy obiekt klasy `tablica` został zniszczony" << endl;
    }
};
int main()
{
    nowa_zmienna < int >* nowa = new nowa_zmienna < int >; //Przypatrz się temu zapisowi
    nowa->wyswietl(); //użycie funkcji ze zwykłym pointerem
    delete nowa; //zwykły delete
}
Ta dynamika prawie niczym się nie różni od zwykłej. Prawie, zauważ jednak, że przy tworzeniu nowego obiektu trzeba dodać template.

Template a... konstruktor

Może się teraz zdziwisz, ale template może częściowo zastępować... konstruktor(z argumentami).
Dlaczego?
C/C++
#include <iostream>
using namespace std;
class tablica //nei będziemy chyba bawić się w układanie nazw
{
    int zmienna;
public:
    tablica( int wartosc )
    {
        zmienna = wartosc;
    }
    int wyswietl()
    {
        return zmienna;
    }
    ~tablica()
    {
    }
};
int main()
{
    tablica * nowa = new tablica( 222 );
   
   
    cout << nowa->wyswietl() << endl;
    delete nowa;
}
Taki zapis możesz zmienić... Tak:
C/C++
#include <iostream>
using namespace std;
template < int wartosc >
class tablica //nei będziemy chyba bawić się w układanie nazw
{
    int zmienna;
public:
    tablica()
    {
        zmienna = wartosc;
    }
    int wyswietl()
    {
        return zmienna;
    }
    ~tablica()
    {
    }
};
int main()
{
    tablica < 222 >* nowa = new tablica < 222 >; //"Nadajemy" wartość zmiennej w klasie
    cout << nowa->wyswietl() << endl;
}
Już nie trzeba bawić się w konstruktory z argumenatami. :)

Definiujemy i deklarujemy z użyciem template'ów osobno

C/C++
#include <iostream>
using namespace std;
template < class typ >
class nowa_zmienna
{
    typ zmienna;
public:
    int wyswietl();
};
template < class typ > //najpierw musisz przekopiować szablon
int nowa_zmienna < typ >::wyswietl() //takie funkcje różnią się tym, że trzeba podać 'zmienną' używając klasy z templatem
{
    cout << "sasasfsadgdfcnfghndfhb" << endl;
}
int main()
{
    nowa_zmienna < int > nowa;
    nowa.wyswietl();
}

Na zakończenie

No to już chyba koniec minikursu... :)
Polecam poeksperymentować z szablonami... :D
Poprzedni dokumentNastępny dokument
Szablony strukturTyp wyliczeniowy enum