- •Содержание
- •ВВЕДЕНИЕ
- •1.ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ ПОДХОД
- •2. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
- •2.1. Абстрактные типы данных
- •2.2. Базовые принципы объектно-ориентированного программирования
- •2.3. Основные достоинства языка С++
- •2.4. Особенности языка С++
- •2.4.1. Ключевые слова
- •2.4.2. Константы и переменные
- •2.4.3. Операции
- •2.4.4. Типы данных
- •2.4.5. Передача аргументов функции по умолчанию
- •2.5.1. Объект cin
- •2.5.2. Объект cout
- •2.5.3. Манипуляторы
- •3.1. Объекты
- •3.2. Понятие класса
- •3.3. Конструктор копирования
- •3.4. Конструктор explicit
- •3.5. Указатель this
- •3.6. Встроенные функции (спецификатор inline)
- •3.7. Организация внешнего доступа к локальным компонентам класса (спецификатор friend)
- •3.8. Вложенные классы
- •3.9. Static-члены (данные) класса
- •3.10. Компоненты-функции static и const
- •3.11. Proxi-классы
- •3.12. Ссылки
- •3.12.1. Параметры ссылки
- •3.12.2. Независимые ссылки
- •3.13. Пространства имен
- •3.13.3. Ключевое слово using как объявление
- •3.13.4. Псевдоним пространства имен
- •3.14. Практические приемы ограничения числа объектов класса
- •4. НАСЛЕДОВАНИЕ
- •4.1.1. Конструкторы и деструкторы при наследовании
- •4.2. Виртуальные функции
- •4.3. Абстрактные классы
- •4.4. Виртуальные деструкторы
- •4.6. Виртуальное наследование
- •5.2. Перегрузка операторов
- •5.2.2. Перегрузка унарного оператора
- •5.2.3. Дружественная функция operator
- •5.2.4. Особенности перегрузки операции =
- •5.2.5. Перегрузка оператора []
- •5.2.6. Перегрузка оператора ()
- •5.2.7. Перегрузка оператора ->
- •5.2.8. Перегрузка операторов new и delete
- •5.3. Преобразование типа
- •5.3.1. Явные преобразования типов
- •6. ШАБЛОНЫ
- •6.1. Параметризированные классы
- •6.2. Передача в шаблон класса дополнительных параметров
- •6.3. Шаблоны функций
- •6.4. Совместное использование шаблонов и наследования
- •6.5. Шаблоны класса и friend-функции
- •6.6. Некоторые примеры использования шаблона класса
- •6.6.1. Реализация smart-указателя
- •6.6.2. Задание значений параметров класса по умолчанию
- •7.2. Состояние потока
- •7.3. Строковые потоки
- •7.4. Организация работы с файлами
- •7.5. Организация файла последовательного доступа
- •7.6. Создание файла произвольного доступа
- •7.7. Основные функции классов ios, istream, ostream
- •8. ИСКЛЮЧЕНИЯ В С++
- •8.2. Перенаправление исключительных ситуаций
- •8.3. Исключительная ситуация, генерируемая оператором new
- •8.6. Спецификации исключительных ситуаций
- •8.7. Задание собственного неожиданного обработчика
- •9. СТАНДАРТНАЯ БИБЛИОТЕКА ШАБЛОНОВ (STL)
- •9.3. Категории итераторов
- •9.4. Операции с итераторами
- •9.5. Контейнеры последовательностей
- •9.5.2. Контейнер последовательностей list
- •9.5.3. Контейнер последовательностей deque
- •9.6. Ассоциативные контейнеры
- •9.6.1. Ассоциативный контейнер multiset
- •9.6.2. Ассоциативный контейнер set
- •9.6.3. Ассоциативный контейнер multimap
- •9.7.1. Адаптер stack
- •9.7.2. Адаптер queue
- •9.7.3. Адаптер priority_queue
- •9.8. Алгоритмы
- •9.8.1. Алгоритмы сортировки sort, partial_sort, sort_heap
- •9.8.2. Алгоритмы поиска find, find_if, find_end, binary_search
- •9.8.3. Алгоритмы fill, fill_n, generate и generate_n
- •9.8.4. Алгоритмы equal, mismatch и lexicographical_compare
- •9.8.6. Алгоритмы работы с множествами
- •9.8.7. Алгоритмы swap, iter_swap и swap_ranges
- •9.8.8. Алгоритмы copy, copy_backward, merge, unique и reverse
- •10. ПРИМЕРЫ РЕАЛИЗАЦИИ КОНТЕЙНЕРНЫХ КЛАССОВ
- •10.1. Связанные списки
- •10.1.1. Реализация односвязного списка
- •10.2. Реализация бинарного дерева
- •11. ПРОГРАММИРОВАНИЕ ДЛЯ WINDOWS
- •11.1. Система, управляемая сообщениями
- •11.2. Управление графическим выводом
- •11.3. Контекст устройства
- •11.3.1. Экран
- •11.3.2. Принтер
- •11.3.3. Объект в памяти
- •11.3.4. Информационный контекст
- •11.4. Архитектура, управляемая событиями
- •11.5. Исходный текст программы
- •11.7. Некоторые новые типы данных
- •11.8. Венгерская нотация
- •11.9. Точка входа программы
- •11.11. Создание окна
- •11.12. Цикл обработки сообщений
- •11.13. Оконная процедура
- •11.14. Обработка сообщений
- •11.15. Обработка сообщений функцией DefWindowProc
- •11.16. Синхронные и асинхронные сообщения
- •11.17. Еще один метод получения описателя контекста устройства
- •11.19. Полосы прокрутки
- •Литература
6.3. Шаблоны функций
В С++, так же как и для класса, для функции (глобальной, т.е. не являю- щейся компонентой-функцией) может быть описан шаблон. Это позволит снять достаточно жесткие ограничения, накладываемые механизмом формальных и фактических параметров при вызове функции. Рассмотрим это на примере функции, вычисляющей сумму нескольких аргументов.
#include <iostream> using namespace std; #include <string.h>
|
template <class T1,class T2> |
|
|
|
|
Р |
|||||
|
T1 sm(T1 a,T2 b) |
// описание шаблона |
|
||||||||
|
{ return (T1)(a+b); |
|
|
|
|
|
|||||
|
// функции c двумя параметрами |
||||||||||
|
} |
|
|
|
|
|
|
|
|
И |
|
|
template <class T1,class T2,class T3> |
|
|
||||||||
|
|
У |
|
||||||||
|
T1 sm(T1 a,T2 b,T3 c) |
|
|
|
|
||||||
|
// описание шаблона функции |
|
|||||||||
|
{ return (T1)(a+b+c); |
// функции c тремя параметрами |
|||||||||
|
} |
|
|
|
|
|
|
Г |
|
|
|
|
|
|
|
|
|
|
Б |
|
|
|
|
|
int main() |
|
|
|
|
|
|
|
|||
|
{cout<<"вызов функции sm(int,int) |
= "<<sm(4,6)<<endl; |
|||||||||
|
|
cout<<"вызов функции sm(int,int,int)а= "<<sm(4,6,1)<<endl; |
|||||||||
|
|
cout<<"вызов функции sm(int,double) = "<<sm(5,3)<<endl; |
|||||||||
|
|
|
|
|
|
к |
|
|
|
|
|
|
|
cout<<"вызов функции sm(double,int,short)= " << |
|
|
|||||||
|
|
sm(.4,6,(short)1)<<endl;е |
|
|
|
|
|
||||
|
// cout<<sm("я изучаю","язык С++")<<endl; error cannot add two pointers |
||||||||||
|
} |
return 0; |
|
т |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
о |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
||
|
Резу ьтат работы программы будет иметь вид: |
|
|
||||||||
|
вызов функ |
|
sm(int,int) |
|
= |
10 |
|
|
|
||
|
|
|
ции |
|
|
= |
11 |
|
|
|
|
|
вызов функции sm(int,int,int) |
|
|
|
|||||||
|
|
л |
|
|
|
= |
5 |
|
|
|
|
|
вызов функции sm(int,double) |
|
|
|
|||||||
|
вызов функции sm(double,int,short)= |
7.4 |
|
|
|
||||||
|
б |
|
|
|
|
|
|
|
|
|
|
|
В программе описана перегруженная функция sm(), первый экземпляр ко- |
||||||||||
торойимеет 2, а второй 3 параметра. |
Тип формальных параметров функции оп- |
||||||||||
Б |
|
|
|
|
|
|
|
|
|
|
|
ределяется компилятором при каждой встрече вызова функции типом ее факти- ческих параметров. Компилятор заменяет параметры T1,T2 (при вызове функ- ции с двумя параметрами) или T1,T2,T3 (с тремя параметрами) на типы переда- ваемых в функцию значений. После этого полученная шаблонная функция ком- пилируется. Используемые в функциях типы Т1, Т2, Т3 заданы как параметры для шаблона функции с помощью выражения template <class T1,class T2> или template <class T1,class T2,class T3>.
133
Имя каждого формального параметра заголовка шаблона может исполь- зоваться в заголовке только один раз. Одно и то же имя формального параметра шаблона может использоваться в нескольких заголовках шаблонов.
В случае попытки передачи в функцию sm() двух строк, т.е. типов, для ко- торых не определена данная операция, компилятор выдаст ошибку. Чтобы из- бежать этого, можно ограничить использование шаблона функции sm(), описав явным образом функцию sm() для некоторых конкретных типов данных. В на-
шем случае: |
|
|
|
|
|
|
|
|
|
|
|
|
|
char *sm(char *a,char *b) |
|
|
// |
явное описание функции объединения |
|||||||||
{ char *tmp=a; |
|
|
|
|
// |
двух строк |
|
|
|
Р |
|||
|
a=new char[strlen(a)+strlen(b)+1]; |
|
|
|
|
|
|||||||
|
strcpy(a,tmp); |
|
|
|
|
|
|
|
|
|
|
||
|
strcat(a,b); |
|
|
|
|
|
|
|
|
|
|
|
|
} |
return a; |
|
|
|
|
|
|
|
|
|
|
И |
|
|
|
|
|
|
|
|
|
|
|
|
|||
Добавление в main() инструкции, например, |
|
У |
|
||||||||||
cout<<sm("я изучаю"," язык С++")<<endl; |
|
|
|||||||||||
Г |
|
|
|||||||||||
приведет к выводу кроме указанных выше сообщения: |
|
|
|||||||||||
я изучаю язык С++ |
|
|
|
|
|
|
|
|
|||||
Рассмотрим случай, когда имеются несколькоБшаблонов перегруженных |
|||||||||||||
функций с одинаковым числом аргументов. |
а |
|
|
|
|
||||||||
template <class T1,class T2> |
|
|
|
|
|
|
|
||||||
T1 sm(T1 a,T2 b) |
|
|
|
// описа кшаблона первой |
|
|
|
||||||
{ return (T1)(a+b); |
|
|
// функции c двумя параметрами |
|
|
||||||||
} |
|
|
|
|
|
|
ние |
|
|
|
|
|
|
template <class T1,class T2> |
|
|
|
|
|
|
|
|
|||||
T1 sm(T2 a,T1 b) |
|
|
т// писание шаблона второй |
|
|
|
|||||||
{ return (T1)(a+b); |
|
|
// функции c двумя параметрами |
|
|
||||||||
} |
|
|
|
о |
|
|
|
|
|
|
|
||
|
|
и |
|
|
|
|
|
|
|
|
|
||
int main() |
|
|
|
|
|
|
|
|
|
|
|||
{ sm(1.,2) //лerror 'sm' : none of 2 overload have a best conversion |
|
||||||||||||
|
|
// 'sm' : ambiguous call to overloaded function |
|
|
|
||||||||
|
б |
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
|
} |
и |
|
|
|
|
|
|
|
|
|
|
|
|
В этом случае компилятор должен сгенерировать оба экземпляра шаб- |
|||||||||||||
лонныхБфункций. Возникает неоднозначность: какую из двух шаблонных функ- |
|||||||||||||
ций требуется выполнить. |
|
|
|
|
|
|
|
|
|
|
|||
Шаблон функции может быть перегружен также, если описать другую |
(нешаблонную функцию), имя которой совпадает с именем шаблона функции. Следует отметить, что шаблон функции не является ее экземпляром.
Только при обращении к функции с аргументами конкретного типа происходит генерация конкретной функции.
134
6.4. Совместное использование шаблонов и наследования
Шаблонные классы, как и обычные, могут использоваться повторно. Шаблоны и наследование представляют собой механизмы повторного исполь- зования кода и могут включать полиморфизм. Шаблоны и наследования связа- ны между собой следующим образом:
- шаблон класса может быть порожден от обычного класса; - шаблонный класс может быть производным от шаблонного класса;
- обычный класс может быть производным от шаблона класса.
|
Ниже приведен пример простой программы, демонстрирующей наследо- |
|||||||||
вание |
|
|
|
|
|
|
|
|
|
ИР |
|
using namespace std; |
|
|
|
|
|||||
|
template <class T> |
|
|
|
|
У |
||||
|
class vect |
|
|
|
|
|
Г |
|||
|
|
|
|
// класс-вектор |
|
|||||
|
{protected: |
|
|
|
|
|
Б |
|
||
|
|
|
T *ms; |
|
|
|
// массив-вектор |
|
||
|
|
|
int size; |
|
|
|
// размерность массива-вектора |
|||
|
public: |
|
|
|
|
|
|
|
||
|
|
|
vect(int n) : size(n) |
|
|
|
// конструктор |
|||
|
|
|
{ ms=new T[size];} |
|
а// деструктор |
|||||
|
|
|
|
|
|
е |
||||
|
|
|
~vect(){delete [] ms;} |
|
||||||
|
|
|
T &operator[](const intкind) // доопределение операции [] |
|||||||
|
|
|
|
|
т |
|
|
|
|
|
|
|
|
{ if((ind>0) && (ind<size)) return ms[ind]; |
|
||||||
|
|
|
else return ms[0]; |
|
|
|
|
|||
|
|
|
} |
о |
|
|
|
|
|
|
|
}; |
|
и |
|
|
|
|
|
|
|
|
|
|
л |
|
|
|
|
|
|
|
|
template <class T> |
|
|
|
|
|
||||
|
class oper : public vect<T> // класс операций над вектором |
|||||||||
|
{ public: |
|
|
|
|
|
|
|
||
и |
oper(int n): vect<T>(n) {} |
|
// конструктор |
|||||||
~oper(){} |
|
|
|
|
// деструктор |
|
||||
Б |
бvoid print() |
|
|
|
|
// функция вывода содержимого вектора |
||||
|
|
|
{ for(int i=0;i<size;i++) |
|
|
|
||||
|
|
|
cout<<ms[i]<<' '; |
|
|
|
|
|
||
|
|
|
cout<<endl; |
|
|
|
|
|
||
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main() |
|
|
|
|
|
|
|
||
|
{ oper <int> v_i(4); |
|
|
// |
int-вектор |
|
||||
|
|
oper <double> v_d(4); |
|
// |
double-вектор |
|||||
|
|
v_i[0]=5; v_i[1]=3; |
v_i[2]=2; v_i[3]=4; // инициализация int |
|||||||
|
|
|
|
|
|
|
|
|
|
135 |