Шаблони на класове.

10. Шаблони на класове.

Структурата от данни стек е независима от типа на данните, които съдържа. Типът трябва да бъде зададен тогава, когато стекът се създава фактически. Това дава възможност за създаване на универсални програми. Достатъчно е общо описание на стек и на тази основа( родов клас ) +да се създават класове - специфични версии за конкретния тип данни. В С++ това се реализира с шаблони на класове. Често се наричат параметризирани типове, тъй като има един или повече параметър на тип, определящи настройката на родовия тип на класа..

За да се използват шаблони на класове е достатъчно веднъж да се опише шаблонът. Всеки път, когато се иска реализация на клас за нов тип данни се съобщава на компилатора за това. Този нов клас може да бъде от напълно произволен тип: Stack<data>, Stack<int>, Stack<char *>, Stack<employee> …

Описанието на шаблона на класа Stack изглежда като традиционното описание на класа. Разликата - предшества се от заглавието template <class T> - указва, че това е описание на шаблон на клас с параметър на типа Т, който определя типа на елементите на класа Stack.

Редакторският екип на fmi.wikidot.com иска да предостави искрени извинения по повод факта, че стуктурата Стек се дава за пример преди реално да бъде обяснена. Просто наистина така е било преподавано. Дефиницията за стек може да бъде намерена тук.

#include <iostream>
 
using std :: cout;
using std :: cin;
using std :: endl;
 
template <class T>
class Stack
{
    public:
        Stack(int = 10);
        ~Stack();
        {    delete [] stackPtr;    }
 
        bool push( const T& );
        bool pop( T& );
    private:
        int size;
        int top;
        T *stackPtr;
        bool isEmpty() const
        {    return top == -1;    }
        bool isFull() const
        {    return top == size - 1;    }
};
 
template <class T>
Stack<T> :: Stack( int s = 10)
{
    size = s > 0 ? s : 10;
    top = -1;
    stackPtr = new T[size];
}
 
template <class T>
bool Stack<T> :: push( const T& pushValue )
{
    if ( !isFull() )
    {
        stackPtr[++top] = pushValue;
        return true;
    }
 
    return false;
}
 
template <class T>
bool Stack<T> :: pop( T& popValue )
{
    if ( !isEmpty() )
    {
        popValue = stackPtr[ top-- ];
        return true;
    }
 
    return false;
}
 
void main()
{
    Stack<double> doubleStack(5);
    double f = 1.1;
    cout << "Добавяне на елемент в doubleStack" << endl;
    while( doubleStack.push( f ) )
    {
        cout << f << " ";
        f += 1.1;
    }
 
    cout << " Стекът е пълен, не може да се добави " << f << endl;
 
    while( doubleStack.pop(f) )
        cout << f << " ";
 
    cout << " Стекът е празен, невъзможно изключване.." << endl;
 
    Stack<int> intStack;
    int i = 1;
 
    cout << "Добавяне на елемент в intStack" << endl;
    while( intStack.push( i ) )
    {
        cout << i << " ";
        i++;
    }
 
    cout << " Стекът е пълен, не може да се добави " << i << endl;
 
    while( intStack.pop( i ) )
        cout << i << " ";
 
    cout << " Стекът е празен, невъзможно изключване.." << endl;
}

Забележка: Стек не се пише така. Това е само опростена, примерна реализация без динамична памет, за да не се занимаваме с твърде много указатели.

Всяко описание на член функция извън шаблона на класа започва с template <class T>. Описанието на всяка от функциите прилича на стандартното описание, с тази разлика, че за тип на елемента на класа Stack винаги се задава Т. За да се свърже всяко описание на член - функция с областта на действие на шаблона, се използва :: с името на шаблона на класа Stack<T> :: . Когато се създава обект doubleStack от клас Stack<double>, конструкторът на класа Stack създава масив с елементи от тип double - елементи на стека. Операторът new T[size] в описанието на шаблона на класа, се заменя от компилатора в Stack<double> с оператора stackPtr = new double[size]. В main() прави впечатление, че обработките за doubleStack, intStack са почти идентични, което показва, че може да се приложи използване на шаблон на функция.

template <class T>
void testStack (Stack <T>&s, T value, T increment, const char *sname)
{
    cout << “Добавяне на елементи в “ << sname << ":" << endl;
    while ( s.push ( value ) )
    {
        cout << value << " ";
        value += increment;
    }
    cout << “Стекът е пълен. “ << value << “ не е добавен.” <<endl;
    cout << “Премахване на елементи от “ << sname << endl;
    while ( s.pop ( value ) )
    cout << value << ‘ ‘;
    cout << endl;
    cout << “Стекът е празен.” << endl;
}
 
void main ()
{
    Stack <double> doubleStack (5);
    Stack <int> intStack;
    testStack (doubleStack, 1.1, 1.1, “doubleStack);
    testStack (intStack, 1, 1, “intStack);
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License