Из урока 29 вы узнали, как в C++ использовать шаблоны функций для создания общих, или типонезависимых, функций. Определяя шаблоны функций вы заставляете компилятор C++ создавать в случае необходимости функции, которые отличаются типом возвращаемого значения или типами параметров. Если возникает необходимость создавать подобные функции, отличающиеся только используемыми типами, то может возникнуть необходимость и создания общих классов. А если так, то ваши программы могут определять шаблоны классов. В этом уроке рассмотрены действия вашей программы, необходимые для объявления и дальнейшего использования шаблонов классов. К концу данного урока вы освоите следующие основные концепции:

  • Используя ключевое слово template и символы типов (например, Т, T1 и Т2) ваши программы могут создать шаблон класса — определение шаблона класса может использовать эти символы для объявления элементов данных, указания типов параметров и возвращаемого значения функций-элементов и т.д.
  • Для создания объектов класса с использованием шаблонов ваши программы просто ссылаются на имя класса, за которым внутри угловых скобок следуют типы (например, ), каждому из которых компилятор назначает символы типов и имя переменной.
  • Если у класса есть конструктор, с помощью которого вы инициализируете элементы данных, вы можете вызвать этот конструктор при создании объекта с использованием шаблона, например class_namevalues(200);.
  • Если компилятор C++ встречает объявление объекта, он создает класс из шаблона, используя соответствующие типы.

Как и в случае с шаблонами функций, шаблоны классов на первый взгляд могут показаться достаточно сложными, однако если вы хоть раз создали и использовали пару шаблонов классов, то обнаружили, что дело это вполне простое.

СОЗДАНИЕ ШАБЛОНА КЛАССА

Предположим, к примеру, вы создаете класс массива, в котором есть методы для вычисления суммы и среднего значения хранимых в массиве чисел. Предположим, что вы работаете с массивом типа int, и ваш класс мог бы выглядеть так:

class array

{
public:
   array(int size);
   long sum(void);
   int average_value(void);
   void show_array(void);
   int add_value(int);
private:
   int *data;
   int size;
   int index;
};

Следующая программа I_ARRAY.CPP использует класс array ддя работы со значениями типа int.

#include  

#include

class array

{
public:
   array(int size);
   long sum(void);
   int average_value(void);
   void show_array(void);
   int add_value(int) ;
private:
   int *data;
   int size;
   int index;
};

array::array(int size)

{
   data = new int [size];
   if (data == NULL)

   {
      cerr << "Недостаточно памяти - программа завершается " << endl;
      exit(l);
   }

   array:: size = size;
   array::index = 0;
}

long array::sum(void)

{
   long sum = 0;
   for (int i = 0; i < index; i++) sum += data[i];
   return(sum);
}

int array::average_value(void)

{
   long sum = 0;
   for (int i = 0; i < index; i++) sum += data[i];
   return (sum / index);
}

void array::show_array(void)

{
   for (int i = 0; i < index; i++) cout << data[i] << ' ';
   cout << endl;
}

int array::add_value(int value)

{
   if (index == size) return(-1); // массив полон
   else

   {
      data[index] = value;
      index++;
      return(0); // успешно
   }
}

void main(void)

{
   array numbers (100); // массив из 100 эл-тов
   int i;
   for (i = 0; i < 50; i++) numbers.add_value(i);
   numbers.show_array();
   cout << "Сумма чисел равна " << numbers.sum () << endl;
   cout << "Среднее значение равно " << numbers.average_value() << endl;
}

Как видите, программа распределяет 100 элементов массива, а затем заносит в массив 50 значений с помощью метода add_value. В классе array переменная index отслеживает количество элементов, хранимых в данный момент в массиве. Если пользователь пытается добавить больше элементов, чем может вместить массив, функция add_value возвращает ошибку. Как видите, функция average_value использует переменную index для определения среднего значения массива. Программа запрашивает память для массива, используя оператор new, который подробно рассматривается в уроке 31.

Шаблоны классов

По мере того как количество создаваемых вами классов растет, вы обнаруживаете, что некоторый класс, созданный для одной программы (или, возможно, для этой), очень похож на требующийся вам сейчас. Во многих случаях классы могут отличаться только типами. Другими словами, один класс работает с целочисленными значениями, вто время как требующийся вам сейчас должен работать со значениями типа. float. Чтобы увеличить вероятность повторного использования существующего кода, C++ позволяет вашим программам определять шаблоны классов. Если сформулировать кратко, то шаблон классаопределяет типонезависимый класс, который в дальнейшем служит для создания объектов требуемых типов. Если компилятор C++ встречает объявление объекта, основанное на шаблоне класса, то для построения класса требуемого типа он будет использовать типы, указанные при объявлении. Позволяя быстро создавать классы, отличающиеся только типом, шаблоны классов сокращают объем программирования, что, в свою очередь, экономит ваше время.

Пойдем дальше. Теперь предположим, что вашей программе необходимо работать с массивом значений с плавающей точкой, кроме того, что она работает с целочисленным массивом. Один из способов обеспечить поддержку массивов различных типов состоит в создании разных классов. С другой стороны, используя шаблоны классов, вы можете избавиться от необходимости дублировать классы. Ниже представлен шаблон класса, который создает общий класс array:

template class array

{
public:
   array(int size);
   T1 sum (void);
   T average_value(void);
   void show_array(void);
   int add_value(T);
private:
   T *data;
   int size;
   int index;
};

Этот шаблон определяет символы типов T и T1. В случае массива целочисленных значений Т будет соответствовать int, а T1 — long. Аналогичным образом для массива значений с плавающей точкой значения Т и Т1 равны float. Теперь потратьте время, чтобы убедиться, что вы поняли, как компилятор С++ будет подставлять указанные вами типы вместо символов Т и Т1.

Далее, перед каждой функцией класса вы должны указать такую же запись со словом template. Кроме того, сразу же после имени класса вы должны указать типы класса, например array ::average_value. Следующий оператор иллюстрирует определение функции average_value для этого класса:

template Т array::average_value(void)

{
   T1 sum = 0;
   int i;
   for (i = 0; i < index; i++) sum += data[i] ;
   return (sum / index);
}

После создания шаблона вы можете создавать класс требуемого типа, указывая имя класса, а за ним в угловых скобках необходимые типы, как показано ниже:

Имя шаблона //---->array numbers (100); <------//Типы шаблона
                                    array values(200);

Программа GENARRAY.CPP использует шаблон класса array для создания двух классов, один из которых работает со значениями типа int, а второй — со значениями типа float.

#include  

#include

template class array

{
public:
   array(int size);
   T1 sum(void);
   T average_value(void);
   void show_array(void);
   int add_value(T);
private:
   T *data;
   int size;
   int index;
};

template array::array(int size)

{
   data = new T[size];
   if (data == NULL)

   {
      cerr << "Недостаточно памяти - программа завершается" << endl;
      exit(l);
   }

   array::size = size;
   array::index = 0;
}

template Tl array::sum(void)

{
   T1 sum = 0;
   for (int i = 0; i < index; i++) sum += data[i];
   return(sum);
}

template T array::average_value(void)

{
   Tl sum =0;
   for (int i = 0; i < index; i++) sum += data[i];
   return (sum / index);
}

template void array::show_array(void)

{
   for (int i = 0; i < index; i++) cout << data[i] << ' ';
   cout << endl;
}

template int array::add_value(T value)

{
   if (index == size)
   return(-1); // Массив полон
   else

   {
      data[index] = value;
      index++;
      return(0); // Успешно
   }
}

void main(void)

{
   // Массив из 100 элементов
   array numbers(100)7
   // Массив из 200 элементов
   array values(200);
   int i;
   for (i = 0; i < 50; i++) numbers.add_value(i);
   numbers.show_array();
   cout << "Сумма чисел равна " << numbers.sum () << endl;
   cout << "Среднее значение равно " << numbers.average_value() << endl;
   for (i = 0; i < 100; i++) values.add_value(i * 100);
   values.show_array();
   cout << "Сумма чисел равна." << values.sum() << endl;
   cout << "Среднее значение равно" << values.average_value() << endl;
}

Лучшим способом понять шаблоны классов будет напечатать две копии этой программы. В первой копии замените все символы T и Т1 на int и long. A во второй замените Т и Т1 на float.

Объявление объектов, основанных на шаблоне класса

Для создания объектов с использованием шаблона класса вы просто должны указать имя шаблона класса, за которым между левой и правой угловыми скобками укажите типы, которыми компилятор заменит символы Т, T1, T2 и т. д. Затем ваша программа должна указать имя объекта (переменной) со значениями параметров, которые вы хотите передать конструктору класса, как показано ниже:

template_class_name object_name( parameter1, parameter2);

Когда компилятор C++ встречает такое объявление, он создает класс, основанный на указанных типах. Например, следующий оператор использует шаблон класса array для создания массива типа char, в котором хранится 100 элементов:

array small_numbers(100) ;

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

Из этого урока вы узнали, что шаблоны классов помогут вам избавиться от дублирования кода программы, если вам необходимы объекты похожих классов, которые отличаются только типом. Поскольку шаблоны классов могут быть сложными, они могут вас смутить. Когда вы определяете ваш класс, начните с определения, как будто бы вы создаете класс для конкретного типа. После того как вы полностью опишете класс, определите какие элементы необходимо изменить, чтобы работать с объектами различных типов. Теперь замените типы этих элементов такими символами, как, например, Т, Т1, Т2 и т.д.

    1. Программы, представленные в данном уроке, использовали оператор C++ new для динамического (во время выполнения программы) распределения памяти для массива. В уроке 31 вы подробно ознакомитесь с оператором new. Прежде чем перейти к уроку 31, убедитесь, что вы изучили следующее:
    2. Шаблоны классов позволяют избавиться от дублирования кода для таких классов, чьи объекты отличаются только типом их элементов.
    3. Для создания шаблона класса предварите определение класса ключевым словом template и символами типов, например Т и T1.
    4. Далее вы должны предварить определение каждой функции класса таким же оператором с ключевым словом template. Кроме того, укажите типы шаблона между левой и правой угловыми скобками, а выражение в угловых скобках поместите между именем класса и оператором разрешения области видимости, например class_name::function_name.
    5. Для создания класса с использованием шаблона укажите имя класса и замещающие значения для типов между левой и правой угловыми скобками, например class_name object.