Выбрать главу

queue<addr> obj;

На примере класса queue нетрудно убедиться, что обобщенные функции и классы представляют собой мощные средства, которые помогут увеличить эффективность работы программиста, поскольку они позволяют определить общий формат объекта, который можно затем использовать с любым типом данных. Обобщенные функции и классы избавляют вас от утомительного труда по созданию отдельных реализаций для каждого типа данных, подлежащих обработке единым алгоритмом. Эту работу сделает за вас компилятор: он автоматически создаст конкретные версии определенного вами класса.

Пример класса с двумя обобщенными типами данных

Шаблонный класс может иметь несколько обобщенных типов данных. Для этого достаточно объявить все нужные типы данных в template-спецификации в виде элементов списка, разделяемых запятыми. Например, в следующей программе создается класс, который использует два обобщенных типа данных.

/* Здесь используется два обобщенных типа данных в определении класса.

*/

#include <iostream>

using namespace std;

template <class Type1, class Type2>

class myclass {

  Type1 i;

  Type2 j;

 public:

  myclass(Type1 a, Type2 b) { i = a; j = b; }

  void show() { cout << i << ' ' << j << '\n'; }

};

int main()

{

 myclass<int, double> ob1(10, 0.23);

 myclass<char, char *> ob2('x', "Это тест.");

 ob1.show(); // отображение int- и double-значений

 ob2.show(); // отображение значений типа char и char *

 return 0;

}

Эта программа генерирует такие результаты.

10 0.23

X Это тест.

В данной программе объявляется два вида объектов. Объект ob1 использует данные типа int и double, а объект ob2 — символ и указатель на символ. Для этих ситуаций компилятор автоматически генерирует данные и функции, соответствующие способу создания объектов.

Создание обобщенного класса безопасного массива

Прежде чем двигаться дальше, рассмотрим еще одно приложение для обобщенного класса. Как было показано в главе 13, можно перегружать оператор "[]", что позволяет создавать собственные реализации массивов, в том числе и "безопасные массивы", которые обеспечивают динамическую проверку нарушения границ. Как вы знаете, в C++ во время выполнения программы возможен выход за границы массива без выдачи сообщения об ошибке. Но если создать класс, который бы содержал массив, и разрешить доступ к этому массиву только через перегруженный оператор индексации ("[]"), то можно перехватить индекс, соответствующий адресу за пределами адресного пространства массива.

Объединив перегрузку оператора с обобщенным классом, можно создать обобщенный тип безопасного массива, который затем будет использован для создания безопасных массивов, предназначенных для хранения данных любого типа. Такой тип массива и создается в следующей программе.

// Пример создания и использования обобщенного безопасного массива.

#include <iostream>

#include <cstdlib>

using namespace std;

const int SIZE = 10;

template <class AType>

class atype {

  AType a[SIZE];

 public:

  atype() {

   register int i;

   for(i=0; i<SIZE; i++) a[i] = i;

  }

  AType &operator[](int i);

};

// Обеспечение контроля границ для класса atype.

 template <class АТуре>

АТуре &atype<AType>::operator[](int i)

{

 if(i<0 || i> SIZE-1) {

  cout << "\n Значение индекса ";

  cout << i << " за пределами границ массива.\n";

 }

 return a [i];

}