- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
309
Глава 21. Шаблоны, исключения
21.1.Шаблоны
Вязыке C++ предусмотрена возможность создания шаблонов, то есть обобщенных описаний функций или классов, на основе которых компилятором автоматически создаются конкретные функции и конкретные классы. Использование шаблонов позволяет переложить на машину существенную часть рутинной работы по написанию многих схожих функций или классов.
21.2.Шаблоны функций
Шаблоны функций позволяют автоматически создавать функции, которые могут обрабатывать данные разных типов.
В определении шаблона семейства функций используются ключевое слово template. Например, шаблон семейства функций для обмена значений двух аргументов может иметь вид:
template <class T> void swap(T *x, T *y)
{T tmp; tmp = *x; *x = *y; *y = tmp;}
Здесь T – формальный параметр шаблона, обозначаемый ключевым словом class. Параметры шаблона заключаются в угловые скобки < и >. Теперь функцию swap можно использовать для аргументов любых типов. Например,
long k = 4, d = 8; swap(&k, &d);
Компилятор автоматически сформирует определение функции:
void swap(long *x, long *y)
{long tmp; tmp = *x; *x = *y; *y = tmp;}
Имя типа в шаблоне является параметром, вместо которого можно подставлять любые типы.
Параметризовать можно типы аргументов функции и тип возвращаемого значения. Шаблон функции может иметь также и непараметризованные аргументы, например,
template <class T, int n>
310
…
Шаблон может иметь несколько параметров, например,
template <class T1, class T2>
…
Как и для обычных функций можно сначала объявить шаблон, а затем дать его определение. Это демонстрируется в следующей программе.
Программа 65. Объявление и определение шаблона функции
В данной программе сначала объявляется шаблон функции count0 для подсчета числа нулевых элементов массива, затем дается его определение.
// Файл TmplFunc.cpp |
|
|
template<class D> |
// Объявление шаблона функции, |
|
int count0(D *x, int n); |
// подсчитывающей число нулей в массиве |
|
#include <iostream.h> |
|
|
int main() |
// Использование шаблона |
|
{ |
|
|
int x[] = {1, 2, 0, 3, 0, 4, 0, 5, 3, 3, 1, 0, 0}; |
// Массив из 13 int |
|
double y[] = {0.0, 1.0, 2.0, 0.0, 2.3}; |
// Массив из 5 double |
cout << "Число нулей в x: " << count0(x, 13) << endl; cout << "Число нулей в y: " << count0(y, 5) << endl; cin.get();
return 0;
} |
|
// Определение шаблона функции |
|
template<class T> |
|
int count0(T *x, int n) |
// x – массив элементов |
{ |
// n – число элементов в массиве |
int k = 0; |
|
for(int i = 0; i < n; i++) |
|
if(int(x[i]) == 0) |
|
k++; |
|
return k; |
|
} |
|
Программа выводит:
Число нулей в x: 5 Число нулей в y: 2
311
21.3. Классы и шаблоны
Шаблон семейства классов определяется инструкцией:
template <СПИСОК_ПАРАМЕТРОВ_ШАБЛОНА> ОПРЕДЕЛЕНИЕ_КЛАССА
Шаблоны семейства классов определяют способ построения отдельных классов. В следующей программе приведен пример создания шаблона класса для векторов, которые могут состоять из элементов разных типов.
Программа 66. Шаблон классов векторов
В данной программе определен шаблон классов Vect для моделирования векторов, элементы которых могут иметь любой тип.
// Файл TmplVect.cpp |
|
template <class T> |
// T – параметр шаблона |
class Vect{ |
|
T *v; |
// Одномерный массив из элементов типа T |
int n; |
// Размер массива |
public: |
|
Vect(int); |
// Конструктор |
~Vect() |
// Деструктор |
{ delete[] v;} |
|
T& operator[](int i) |
// Доступ к элементу вектора |
{ return v[i]; } |
|
}; |
|
При определении функций-членов шаблона классов следует повторить объявление параметра шаблона с помощью template. Определение конструктора имеет вид:
template <class T> Vect <T>::Vect(int k)
{ n = k; v = new T[n]; }
После введения шаблона классов можно определять конкретные объекты конкретных классов.
#include <iostream.h> |
|
void main() |
|
{ |
|
Vect <int> X(5); |
// Целочисленный вектор из 5 элементов |
Vect<char> S(5); |
// Символьный вектор |
for(int i = 0; i < 5; i++){ |
// Заполнение векторов |
X[i] = i; |
|
312
S[i] = 'A' + i;
}
for(i = 0; i < 5; i++) // Вывод веторов cout << " " << X[i] << ' '<< S[i];
cin.get();
}
Приведенная программа выводит:
0 A 1 B 2 C 3 D 4 E
Значением параметра шаблона может быть стандартный тип (int, double,...) или тип, определённый пользователем.
В списке параметров шаблона могут присутствовать параметры с фиксированным типом, причем параметр шаблона может иметь значение по умолчанию. Это иллюстрируется в следующей программе.
Программа 67. Шаблон классов динамических массивов
Шаблон классов динамических массивов похож на шаблон классов векторов. Добавлена возможность устанавливать размер массива по умолчанию и функция нахождения максимального элемента массива.
// Файл TmplDArr.cpp |
|
#include <stdlib.h> |
// Для rand() |
#include <time.h> |
|
#include <iostream> |
|
#include<Windows.h> |
// Для функции CharToOem |
char Buff[500]; |
// Буфер для преобразования русских букв |
char* Rus(char* in) |
// Функция для преобразования русских букв |
{ |
|
CharToOem(in, Buff); |
// Функция CharToOem преобразует строку in |
return Buff; |
// в строку Buff, используя кодировку DOS |
}
using namespace std;
template <class T, int size = 64> // 64 – значение по умолчанию для size
class DynArr { |
// Шаблон классов динамических массивов |
T* data; |
// Массив элементов |
int n; |
// Количество элементов |
public: |
|
DynArr() |
// Конструктор |
{ data = new T[n = size]; } |
|
~DynArr() |
// Деструктор |
{delete[] data;} |
|
T& operator[](int i) |
// Доступ к элементу |
{ return data[i];} |
|
|
|
313 |
int SizeArr() |
|
// Размер массива |
{return n;} |
|
|
T GetMax(); |
// Возвращает значение максимального элемента |
|
}; |
|
|
// Определение функции-члена шаблона классов |
||
template <class D, int sz> |
// Имена параметров шаблона в определении |
|
D DynArr<D, sz>::GetMax() |
// могут отличатся от их имен в объявлении |
|
{ |
|
|
D max = data[0]; for(int i = 1; i < n; i++)
if(data[i] > max) max = data[i];
return max;
}
В главной функции создаются два динамических массива: x с размером по умолчанию и y заданного размера. Массивы заполняются случайными числами, генерируемыми функцией int rand(void). Для того, чтобы при каждом запуске программы генерировались различные последовательности чисел, вызывается функция
void srand(unsigned seed);
Ее аргумент задает начальную точку в последовательности псевдослучайных чисел, генерируемых rand. Для получения значения seed использована объявленная в time.h функция
time_t time(time_t *timer);
возвращающая количество секунд, прошедших от полуночи 1 января 1970 г. Это значение записывается также по адресу timer или игнорируется, если timer=NULL. Тип time_t – это новое обозначение для long, введенное с помощью typedef.
Обработка созданных массивов состоит в том, что выводятся значения их максимальных элементов.
int main() |
|
{ |
|
srand(unsigned(time(NULL))); |
// Инициализация датчика сл. чисел |
DynArr<double> x; |
// Массив x из 64 double |
DynArr<int, 20> y; |
// Массив y из 20 int |
int i; |
|
for(i = 0; i < x.SizeArr(); i++) |
// Заполнение массива x |
x[i] = rand(); |
|
cout << Rus("Количество элементов в x: ") << x.SizeArr(); cout << Rus(", максимальное из x: ") << x.GetMax() << endl;