
- •«Объектно-ориентированный анализ и проектирование»
- •1. Принципы ооп. Классы.
- •Описание классов.
- •Объекты класса.
- •Конструкторы
- •Конструктор копирования
- •Статические элементы класса
- •Дружественные функции и классы
- •Деструкторы
- •Перегрузка операций
- •Перегрузка унарных операций
- •Перегрузка бинарных операций
- •Перегрузка операции присваивания
- •Рекомендации по составу классов
- •2. Наследование
- •Ключи доступа
- •Простое наследование
- •Пример замещения функций (практикум)
- •Виртуальные методы
- •Множественное наследование
- •3. Отношения между классами. Диаграммы класссов на языке uml.
- •4. Шаблоны классов.
- •4.1. Определения шаблонов классов Queue и QueueItem
- •4.2. Конкретизация шаблона класса
- •4.3. Аргументы шаблона для параметров-констант
- •4.4. Функции-члены шаблонов классов
- •5. Обработка исключительных ситуаций
- •5.1. Общий механизм обработки исключений.
- •5.2 . Синтаксис исключений
- •5.3. Перехват исключений
- •5.4. Исключения в конструкторах и деструкторах
- •Vector(int n) // Конструктор
- •5.5. Список исключений функции.
- •6. Строки
- •Преобразование строк
- •7. Контейнерные классы
- •7.1. Векторы.
- •7.2. Двухсторонние очереди (deque).
- •7.3. Списки (List).
- •7.4. Стеки
- •7.5. Очереди (queue)
- •7.6. Очередь с приоритетами(priority_queue)
- •8. Ассоциативные контейнеры
- •8.1. Словари (map)
- •8.2. Словари с дубликатами (multimap)
- •8.3. Множества (set)
- •8.4. Множества с дубликатами (multiset)
- •8.5. Битовые множества (bitset)
4.4. Функции-члены шаблонов классов
Как и для обычных классов, функция-член шаблона класса может быть определена либо внутри определения шаблона (и тогда называется встроенной), либо вне его. Конструктор Queue является встроенным, так как определен внутри определения шаблона класса:
template < class Type>
class Queue {
// ...
public:
// встроенный конструктор
Queue(): front(0), last(0){ }
// ...
};
При определении функции-члена шаблона вне определения самого шаблона следует применять специальный синтаксис для обозначения того, членом какого именно шаблона является функция. Определению функции-члена должно предшествовать ключевое слово template, за которым следуют параметры шаблона. Так, конструктор Queue можно определить следующим образом:
template < class Type>
class Queue {
public:
Queue();
private:
// ...
};
template < class Type>
inline Queue< Type> ::
Queue( ) { front = last = 0; }
За первым вхождением Queue (перед оператором ::) следует список параметров, показывающий, какому шаблону принадлежит данная функция-член. Второе вхождение Queue в определение конструктора (после оператора ::) содержит имя функции-члена, за которым может следовать список параметров шаблона, хотя это и необязательно. После имени функции идет ее определение;. в нем могут быть ссылки на параметр шаблона Type всюду, где в определении обычной функции использовалось бы имя типа.
Функция-член шаблона класса сама является шаблоном. Стандарт C++ требует, чтобы она конкретизировалась только при вызове либо при взятии ее адреса. (Некоторые более старые компиляторы конкретизируют такие функции одновременно с конкретизацией самого шаблона класса.) При конкретизации функции-члена используется тип того объекта, для которого функция вызвана: Queue< string> qs;
Объект qs имеет тип Queue<string>. При инициализации объекта этого класса вызывается конструктор Queue<string>. В данном случае аргументом, которым конкретизируется функция-член (конструктор), будет string.
От того, в какой именно момент конкретизируется функция-член, зависит разрешение имен в ее определении и объявление ее специализации.
Чтобы понять, как определяются и используются функции-члены шаблонов классов, продолжим изучение шаблонов Queue и QueueItem:
template <class Type>
class Queue {
public:
Queue(): front(0), last(0) { }
~Queue();
Type& remove();
void add( const Type & );
bool empty() const {
return front == 0;
}
private:
QueueItem< Type> *front;
QueueItem< Type> *last;
};
Деструктор, а также функции-члены remove() и add() определены не в теле шаблона, а вне его. Деструктор Queue опустошает очередь:
template < class Type>
Queue< Type> ::~Queue()
{
while (! is_empty() )
remove();
}
Функция-член Queue< Type> ::add() помещает новый элемент в конец очереди:
template <class Type> void Queue< Type> ::add( const Type &val )
{
// создать новый объект QueueItem
QueueItem< Type> *pt = new QueueItem< Type>(val);
if ( is_empty() )
front = last = pt;
else
{
last-> next = pt;
last = pt;
}
}
Функция-член Queue<Type>:: remove() возвращает значение элемента, находящегося в начале очереди, и удаляет сам элемент.
#include < iostream>
#include < stвdlib>
template < class Type> Type Queue< Type> ::remove()
{
if (is_empty() )
{
cerr << "remove() вызвана для пустой очереди\n";
exit(1);
}
QueueItem< Type> *pt = front;
front = front-> next;
Type retval = pt->item;
delete pt;
return retval;
}
Поместим определения функций-членов в заголовочный файл Queue.h, включив его в каждый файл, где возможны конкретизации функций
В следующей программе иллюстрируется использование и конкретизация функции-члена шаблона Queue:
#include < iostream>
#include "Queue.h"
int main()
{
// конкретизируется класс Queue< int>
// оператор new требует, чтобы Queue< int> был определен
Queue< int> *p_qi = new Queue< int>;
int i;
for (i = 0; I < 10; ++i)
// конкретизируется функция-член add()
p_qi-> add(i);
int err_cnt = 0;
for(i = 0; i < 10; ++i) {
// конкретизируется функция-член remove()
int q = p_qi-> remove();
if (i != q) err_cnt++;
}
if (!err_cnt)
cout < < "!! queue executed ok\n";
else cerr << "?? queue errors: " < < err_cnt << endl;
return 0;
}
После компиляции и запуска программа выводит следующую строку:
!! queue executed ok.
В шаблоне класса могут быть объявлены статические данные-члены. Каждый конкретизированный экземпляр имеет собственный набор таких членов.
Определение шаблона статического члена должно быть вынесено за пределы определения самого шаблона класса, которое начинается с ключевого слово template с последующим списком параметров. Определения таких членов помещаются в заголовочный файл Queue.h и должны включаться во все файлы, где производится их конкретизация. Статический член конкретизируется по шаблону только в том случае, когда реально используется в программе. Сам такой член тоже является шаблоном. Определение шаблона для него не приводит к выделению памяти: она выделяется только для конкретизированного экземпляра статического члена. Каждая подобная конкретизация соответствует конкретизации шаблона класса. Таким образом, обращение к экземпляру статического члена всегда производится через некоторый конкретизированный экземпляр класса.