Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
}
double* p = new double[a.sz]; // выделяем новую память
for (int i = 0; i<a.sz; ++i) p[i] = a.elem[i]; // копируем
// элементы
delete[] elem; // освобождаем старую память
space = sz = a.sz; // устанавливаем новый размер
elem = p; // устанавливаем указатель на новые
// элементы
return *this; // возвращаем ссылку на целевой объект
}
В этом фрагменте кода мы сначала проверяем самоприсваивание (например,
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
”. Рассмотрим пример.
// почти реальный вектор элементов типа T
template<class T> class vector {
// читается как "для всех типов T" (почти так же, как
// в математике)
int sz; // размер
T* elem; // указатель на элементы
int space; // размер + свободная память
public:
vector:sz(0),elem(0),space(0) { }
explicit vector(int s);
vector(const vector&); // копирующий
конструктор
vector& operator=(const vector&); // копирующее
присваивание
~vector { delete[] elem; } // деструктор
T& operator[](int n) { return elem[n]; } // доступ: возвращает
// ссылку
const T& operator[](int n) const { return elem[n]; }
Поделиться с друзьями: