Шрифт:
}
В этом фрагменте кода мы сначала проверяем самоприсваивание (например,
v=v
); в этом случае ничего делать не надо. С логической точки зрения эта проверка лишняя, но иногда она позволяет значительно оптимизировать программу. Эта проверка демонстрирует использование указателя this
, позволяющего проверить, является ли аргумент a тем же объектом, что и объект, из которого вызывается функция-член (т.е. operator=
). Убедитесь, что этот код действительно работает, если из него удалить инструкцию this==&a
. Инструкция a.sz<=space
также включена для оптимизации. Убедитесь, что этот код действительно работает после удаления из него инструкции a.sz<=space
. 19.2.6. Предыдущая версия класса vector
Итак, мы получили почти реальный класс
vector
для чисел типа double
.
// почти реальный вектор чисел типа double
class vector {
/*
инвариант:
для 0<=n<sz значение elem[n] является n- м элементом
sz<=space;
если sz<space, то после elem[sz–1] есть место
для (space–sz) чисел типа double
*/
int sz; // размер
double* elem; // указатель на элементы (или 0)
int space; // количество элементов плюс количество слотов
public:
vector:sz(0),elem(0),space(0) { }
explicit vector(int s):sz(s),elem(new double[s]),space(s)
{
for (int i=0; i<sz; ++i) elem[i]=0; // элементы
// инициализированы
}
vector(const vector&); // копирующий конструктор
vector& operator=(const vector&); // копирующее присваивание
~vector { delete[] elem; } // деструктор
double& operator[ ](int n) { return elem[n]; } // доступ
const double& operator[](int n) const { return elem[n]; }
int size const { return sz; }
int capacity const { return space; }
void resize(int newsize); // увеличение
void push_back(double d);
void reserve(int newalloc);
};
Обратите внимание на то, что этот класс содержит все основные операции (см. раздел 18.3): конструктор, конструктор по умолчанию, копирующий конструктор, деструктор. Он также содержит операции для доступа к данным (индексирование
[]
), получения информации об этих данных (size
и capacity
), а также для управления ростом вектора (resize
, push_back
и reserve
). 19.3. Шаблоны
Однако нам мало иметь вектор, состоящий из чисел типа
double
; мы хотим свободно задавать тип элементов наших векторов. Рассмотрим пример.
vector<double>
vector<int>
vector<Month>
vector<Window*> // вектор указателей на объекты класса Window
vector< vector<Record> > // вектор векторов из объектов класса Record
vector<char>
vector
и функция sort
(разделы 21.1 и Б.5.4). Это не просто теоретический интерес, поскольку, как обычно, средства и методы, использованные при создании стандартной библиотеки, могут помочь при работе над собственными программами. Например, в главах 21-22 мы покажем, как с помощью шаблонов реализовать стандартные контейнеры и алгоритмы, а в главе 24 продемонстрируем, как разработать класс матриц для научных вычислений.
19.3.1. Типы как шаблонные параметры
vector
. Возьмем класс vector
и заменим ключевое слово double
буквой T
, где T
— параметр, который может принимать значения, такие как double
, int
, string
, vector<Record> и Window*. В языке С++ для описания параметра T
, задающего тип, используется префикс template<class T>
, означающий “для всех типов T
”.