Шрифт:
Интервал:
Закладка:
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>


19.3.1. Типы как шаблонные параметры

Рассмотрим пример.
// почти реальный вектор элементов типа 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]; }
int size() const { return sz; } // текущий размер
int capacity() const { return space; }
void resize(int newsize); // увеличивает вектор
void push_back(const T& d);
void reserve(int newalloc);
};
Это определение класса vector совпадает с определением класса vector, содержащего элементы типа double (см. раздел 19.2.6), за исключением того, что ключевое слово double теперь заменено шаблонным параметром T. Этот шаблонный класс vector можно использовать следующим образом:
vector<double> vd; // T — double
vector<int> vi; // T — int
vector<double*> vpd; // T — double*
vector< vector<int> > vvi; // T — vector<int>, в котором T — int

class vector_char {
int sz; // размер
char* elem; // указатель на элементы
int space; // размер + свободная память
public:
vector_char();
explicit vector_char(int s);
vector_char(const vector_char&); // копирующий конструктор
vector_char& operator=(const vector_char &); // копирующее
// присваивание
~vector_char (); // деструктор
char& operator[] (int n); // доступ: возвращает ссылку
const char& operator[] (int n) const;
int size() const; // текущий размер
int capacity() const;
void resize(int newsize); // увеличение
void push_back(const char& d);
void reserve(int newalloc);
};
Для класса vector<double> компилятор генерирует аналог класса vector, содержащий элементы типа double (см. раздел 19.2.6), используя соответствующее внутреннее имя, подходящее по смыслу конструкции vector<double>).

Конкретизация шаблона (генерирование шаблонных специализаций) осуществляется на этапе компиляции или редактирования связей, а не во время выполнения программы.
Естественно, шаблонный класс может иметь функции-члены. Рассмотрим пример.
void fct(vector<string>& v)
{
int n = v.size();
v.push_back("Norah");
// ...
}
При вызове такой функции-члена шаблонного класса компилятор генерирует соответствующую конкретную функцию. Например, когда компилятор видит вызов
v.push_back("Norah"), он генерирует функцию
void vector<string>::push_back(const string& d) { /* ... */ }
используя шаблонное определение
template<class T> void vector<T>::push_back(const T& d) { /* ... */ };
Итак, вызову v.push_back("Norah") соответствует конкретная функция. Иначе говоря, если вам нужна функция с конкретным типом аргумента, компилятор сам напишет ее, основываясь на вашем шаблоне.
Вместо префикса template<class T> можно использовать префикс template <typename