- •6Vpj7-h3cxh-hbtpt-x4t74-3yvy7
- •Оглавление
- •Предисловие
- •Введение
- •1.1. Понятие класса и объекта. Инкапсуляция
- •1.2. Определение классов. Компоненты. Доступность
- •Class_key /*class_id*/ { /*members_list*/ };
- •Value_type class_id::function_id(parameters) {statements}
- •CPoint point1(100,70); // локальный объект
- •Static cPoint point3(50,120); // статический объект
- •Class_id(parameters) /*:initializer_list*/ {/*statements*/}
- •CString(const char *);
- •Delete[] __thematrix;
- •1.4. Обращение к компонентам объектов
- •1.5. Статические и нестатические компоненты классов
- •1.7. Указатель this
- •В опросы для самопроверки
- •2. Механизм наследования. Полиморфизм
- •2.1. Формы наследования. Базовые и производные классы
- •Class_key class_id: inheritance_specifier base_class_id {member_list};
- •2.3. Абстрактные классы
- •2.4. Множественное наследование и виртуальные классы
- •2.5. Преобразование динамических типов. Динамическая идентификация типов
- •Catch ( std::bad_cast & ) { // обработка исключения
- •Return 0;
- •Вопросы для самопроверки
- •3. Дружественные функции и классы
- •3.1. Дружественные функции
- •3.2. Дружественные классы
- •Вопросы для самопроверки
- •4. Механизм вложения
- •4.1. Вложенные классы
- •4.2. Локальные классы
- •Вопросы для самопроверки
- •5. Объектная модель и шаблоны
- •5.1. Определение, описание и инстанцирование шаблонов
- •::Function_id(function_parameter_list) { statements }
- •5.2. Параметры и аргументы шаблонов
- •Class identifier typename identifier
- •// Key, Data – параметры-типы (типы ключа и данных отображения)
- •// Container – контейнер, где содержится информация отображения class сMap {
- •Class MyTemplate
- •Int array[10]; struct Structure { int m; static int sm; } str;
- •5.3. Шаблоны компонентных функций
- •Value_type function_template_id(function_parameter_list) { statements }
- •::Function_template_id(function_parameter_list) { statements }
- •5.4. Специализация шаблонов
- •Вопросы для самопроверки
- •6. Перегрузка операций
- •Value_type operator @ (parameter_list);
- •Value_type operator @ (parameter_list) { statements }
- •Return fail();
- •6.3. Перегрузка бинарных операций
- •Value_type operator @ (parameter); // компонентная функция
- •Value_type operator @ (parameter, parameter); // глобальная функция friend value_type operator @ (parameter, parameter); // дружественная функция
- •Return *this;
- •Return *this;
- •/* Присваиваем собственные данные класса d */
- •6.4. Перегрузка операций управления памятью
- •Typedef void (*new_handler) ();
- •Extern new_handler set_new_handler( new_handler new_p );
- •Void operator delete(void * memory) {
- •... // Специальная обработка пользователя ::operator delete(memory); // освободить память
- •Вопросы для самопроверки
- •7. Механизм исключений
- •Throw expression
- •7.3. Специальные средства поддержки механизма исключений
- •Unexpected_function set_unexpected(unexpected_function func_name);
- •Typedef void (* unexpected_function) ();
- •Extern char * __throwExceptionName; extern char * __throwFileName; extern unsigned __throwLineNumber;
- •Вопросы для самопроверки
- •8. Подсчет ссылок
- •8.1. Назначение механизма подсчета ссылок
- •8.2. Контекстно-независимая модель счетчика ссылок
- •8.4. Внедрение подсчета ссылок в существующий класс
- •Вопросы для самопроверки
- •9. Стандартная библиотека шаблонов (stl)
- •9.1. Назначение и архитектура stl
- •9.2. Последовательные контейнеры
- •Class vector {
- •// Определение итераторов
- •Sort(first,last); // сортировка вектора в диапазоне итераторов
- •Ifstream ifile ("example.In"); ofstream ofile ("example.Out");
- •OutputIterator copy(
- •InputIterator first, InputIterator last, OutputIterator result );
- •// Заполнение списка
- •Operator- (int)
- •Operator- (random access iterator) operator[] (int)
- •InputIterator find(InputIterator first, InputIterator last, const t & value);
- •InputIterator find(InputIterator first, InputIterator last, const t & value)
- •Return first;
- •OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
- •Return result;
- •OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op)
- •Return result;
- •Void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
- •__Quick_sort_loop(first, last, comp); __final_insertion_sort(first, last, comp);
- •T accumulate(InputIterator first, InputIterator last, t init, Function f);
- •V.Push_back(2); V.Push_back(5);
- •9.5. Функторы
- •T operator()(const t & X) const { return -X; }
- •9.7. Адаптеры
- •S1.Push(1); s1.Push(5);
- •// Записать в вектор числа 1 2 3 4
- •// Сортировать по неубыванию
- •// Записать в вектор числа 4 6 10 3 13 2
- •Вопросы для самопроверки
- •Заключение
- •Библиографический Список
- •6Vpj7-h3cxh-hbtpt-x4t74-3yvy7
Вопросы для самопроверки
Каково назначение вложенных классов? Какие отношения предметной области они позволяют моделировать?
Каким образом дается внешнее определение вложенного класса? Приведите пример.
Как можно обеспечить доступ вложенного класса к открытым нестатическим данным объемлющего класса?
Приведите практически значимый пример определения класса, который содержал бы вложенный класс, производный от какого-то другого класса. В определение включите только существенные компоненты.
Почему вложенные классы часто приходится делать дружественными к объемлющим классам и наоборот? Ответ поясните примером.
Можно ли вложить иерархию классов в класс? Если да, то как это сделать правильно? Ответ сопроводите примером.
Как выполнить определение и инициализацию статического компонента вложенного класса? Ответ сопроводите примером.
Как правильно определить локальный класс? Перечислите основные правила и приведите пример.
Имеется функция с прототипом в виде void func(int a, double b); В нее вложен класс LocalClass. Каким образом компонентная функция этого класса может получить доступ к аргументам функции func? Приведите фрагмент кода.
Возможно ли наличие статических компонент в локальных классах? Если да, то каких статических компонент и как их правильно определить?
Как определить вложенный класс в локальном классе? Ответ поясните примером.
Задачи
Решить задачи из раздела 3, используя механизм вложенных классов.
5. Объектная модель и шаблоны
Шаблоны являются одним из спорных и наиболее тяжело усваиваемых механизмов языка С++. Однако при четком понимании этого механизма и умелом его применении появляется возможность создавать компактный, гибкий и масштабируемый код.
Чтобы понять сущность шаблонов обратимся к примеру. Пусть нам нужно создать класс, инкапсулирующий работу с матрицами. Предположим вначале, что мы создаем класс для своих «внутренних» потребностей. При этом нам известны возможные типы элементов матрицы (например, это может быть int, unsigned, short, unsigned short, float, double, long double). Написав класс для каждого из перечисленных типов элементов, мы можем решить данную задачу. Однако ясно, что это плохое решение, поскольку мы многократно вынуждены повторять по сути один и тот же код16. А теперь допустим, что мы создаем библиотечный класс, который будет многократно использоваться другими программистами. Понятно, что теперь нам неизвестны возможные типы элементов матрицы, поэтому мы не сможем определить классы «на все случаи».
Для того чтобы устранить этот существенный недостаток, в С++ используется понятие шаблонов. Сразу же отметим, что оно относится не только к классам, но и к функциям, в том числе и компонентным, а также к статическим компонентам классов. Однако далее мы будем рассматривать только шаблоны классов и компонент, поскольку содержание данного пособия связано с объектно-ориентированным программированием.
5.1. Определение, описание и инстанцирование шаблонов
Шаблон классов (или шаблонный класс) определяет неограниченное семейство сходных классов. Определив такой шаблон лишь один раз, мы можем автоматически получать (инстанцировать) различные классы на его основе и формировать объекты этих классов17. Причем формироваться будут только те классы, которые реально нужны в программе.
В общем виде шаблон классов определяется в следующем формате:
template <template_parameter_list> template_class_declaration
где template_parameter_list – список параметров шаблона; template_class_declaration – определение самого шаблонного класса. Список параметров шаблона не может быть пустым и обязательно указывается в угловых скобках, причем отдельные параметры в нем перечисляются через запятые. Определение шаблонного класса выполняется практически так же, как и определение обычного класса.
Важнейшим элементом формата шаблона классов является список параметров шаблона. Он представляет те свойства объединяемых шаблоном классов, которыми эти классы отличаются друг от друга. Например, для шаблона, представляющего матрицы, в список параметров попадет тип элементов матрицы. При инстанцировании шаблона вместо параметров подставляются аргументы, которые конкретизируют обобщенные свойства. Так, в шаблон матриц можно передать аргумент int, выделив тем самым класс матриц с целочисленными элементами. Описание каждого параметра шаблона может начинаться одним из служебных слов class, typename или template, либо именем некоторого типа (стандартного или определенного пользователем). Последующее определение шаблонного класса использует имена из списка параметров шаблона, или, как говорят, является параметризованным. Более подробно о параметрах и аргументах шаблонов мы поговорим позднее, а сейчас рассмотрим несложный пример.
В качестве примера ниже приводится определение шаблонного класса CVector, моделирующего свойства векторов с элементами произвольного типа18.
template <class item_t> class CVector {
item_t * __data; // данные вектора
int __size; // длина вектора
public:
explicit CVector(int); // конструктор
~CVector() { delete[] data; } // деструктор
item_t & Item(int i) { // получение i–го элемента
return data[i];
}
...
};
В примере класс CVector параметризуется типом элементов вектора item_t. Этот обобщенный тип используется для определения массива элементов и возвращаемого значения в функции Item. Это, в свою очередь, дает возможность представления векторов с любым типом элементов.
Шаблон классов можно как определять, так и описывать, т.е. для него существует понятие предварительного объявления. При этом и описание, и определение шаблона могут размещаться только на уровне пространства имен или класса; в блоке или функции локализовать шаблон классов нельзя. Компонентные функции шаблона могут определяться как внутри него (см. деструктор ~CVector и функцию Item), так и за его пределами, т.е. могут иметь внешнее определение (конструктор CVector). Внешнее определение компонент при этом также должно быть параметризовано.
Ниже показано, как в общем виде дается внешнее определение компонентной функции шаблонного класса:
template <template_parameter_list>
value_type template_class_id<template_argument_list>