- •ВВЕДЕНИЕ
- •КЛАССЫ
- •Описание объектов
- •Указатель this
- •Конструкторы
- •Конструктор копирования
- •Статические элементы класса
- •Статические методы
- •Дружественные функции и классы
- •Дружественные функции
- •Дружественный класс
- •Деструкторы
- •Перегрузка унарных операций
- •Перегрузка бинарных операций
- •Перегрузка операции присваивания
- •Перегрузка операции приведения типа
- •НАСЛЕДОВАНИЕ
- •Ключи доступа
- •Простое наследование
- •Правила наследования методов
- •Абстрактные классы
- •ОБРАБОТКА ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ
- •Синтаксис исключений
- •Перехват исключений
- •Список исключений
- •Иерархии исключений
- •СТАНДАРТНАЯ БИБЛИОТЕКА
- •Форматирование данных
- •Флаги и форматирующие методы
- •Манипуляторы
- •Методы обмена с потоком
- •Файловые потоки
- •СТРОКИ
- •Операции
- •Функции
- •Преобразование строк
- •Поиск подстрок
- •Сравнение частей строк
- •Получение характеристик строк
- •КОНТЕЙНЕРНЫЕ КЛАССЫ
- •Последовательные контейнеры
- •Векторы
- •Двусторонние очереди
- •Списки
- •Ассоциативные контейнеры
- •Словари
- •Словари с дубликатами (multimap)
- •ПРИЛОЖЕНИЕ 1. ШАБЛОНЫ ФУНКЦИЙ
- •ПРИЛОЖЕНИЕ 2. ШАБЛОНЫ КЛАССОВ
- •БИБЛИОГРАФИЧЕСКИЙ СПИСОК
monstr :: operator =(M);
return *this;
}
//
void think ( );
//
void draw (int x, int y, int scale, int position);
}
//
void daemon :: think ( ) {/* */}
void daemon :: draw (int x, int y, int scale, int position) {/* */}
!!! В классе daemon введено поле brain и метод think, определены собственные конструкторы и операция присваивания, а также переопределен метод draw. Все поля класса monstr, операции (кроме присваивания) и методы get_health, get_ammo и change_health наследуются в классеdaemon, а дест-
руктор формируется по умолчанию.
Правила наследования методов
Конструкторы не наследуются, поэтому производный класс должен иметь собственные конструкторы. Порядок вызова конструкторов определяется следующими правилами:
–если в конструкторе производного класса явный вызов конструктора базового класса отсутствует, автоматически вызывается конструктор базового класса по умолчанию (т. е. тот, который можно вызвать по умолчанию; пример
–первый из конструкторов класса daemon);
–для иерархии, состоящей из нескольких уровней, конструкторы базовых классов вызываются, начиная с самого верхнего уровня. После этого выполняются конструкторы тех элементов класса, которые являются объектами, в порядке их объявления в классе, а затем исполняется конструктор класса;
–в случае нескольких базовых классов их конструкторы вызываются в порядке объявления.
Не наследуется операция присваивания, поэтому ее следует также явно определить в производном классе.
Для деструкторов существуют следующие правила наследования:
–деструкторы не наследуются, и если программист не описал в производном классе деструктор, он формируется по умолчанию и вызывает деструкторы всех базовых классов;
25
–в отличие от конструкторов при написании деструкторов производного класса в нем не требуется явно вызывать деструкторы базовых классов;
–для иерархии классов, состоящей из нескольких уровней, деструкторы вызываются в порядке, строго обратном вызову конструкторов: сначала вызывается деструктор класса, затем деструкторы элементов класса, затем деструктор базового класса.
Поля, унаследованные из классаmonstr, недоступны функциям производного класса, поскольку они определены в базовом классе какprivate. Если функциям, определенным в daemon, требуется работать с этими полями, можно либо описать их в базовом классе какprotected, либо обращаться к ним с помощью функций из monstr, либо явно переопределить их в daemon.
В классе daemon описан метод draw, переопределяющий метод с тем же именем в классе monstr. Доступ к переопределяющему методу базового класса для производного класса выполняется через имя, уточненное с помощью операции доступа к области видимости (::).
Задание
Образуйте производный класс от созданного вами класса, который в дополнение к родительским методам может вычислять тригонометрические функции, степенную функцию (степень – вещественное число), экспоненциальную функцию и десятичный логарифм.
Виртуальные методы и механизм позднего связывания
Работа с объектами ведется чаще всего через указатели. Указателю на базовый класс можно присвоить значение адреса объекта любого производного класса, например:
monstr *p;
p = new daemon;
Вызов методов объекта производится в соответствии с типом указателя, а не фактическим типом объекта, на который он ссылается.
Пример
p -> draw (1, 1, 1, 1); // вызывается метод класса monstr, а не класса daemon.
Этот процесс называется ранним связыванием и выполняется на этапе компоновки программы. Для того чтобы вызвать метод классаdaemon, можно использовать явное преобразование типа указателя:
((daemon *p)) - > draw (1, 1, 1, 1);
Это не всегда возможно, поскольку указатель в разное время может ссылаться на разные объекты разных классов иерархии.
В С++ реализован механизм позднего связывания, когда разрешение ссылок на метод происходит на этапе выполнения программы в зависимости от конкретного типа объекта, вызвавшего метод. Этот механизм реализован с помощью виртуальных методов.
26
Для определения виртуального метода используется спецификатор virual:
virtual void draw (int x, int y, int scale, int position);
Правила описания и использования виртуальных методов:
–если в базовом классе метод определен как виртуальный, метод, определенный в производном классе с тем же именем и набором параметров, автоматически становится виртуальным, а с отличающимся набором параметров– обычным.
–виртуальные методы наследуются;
–если виртуальный метод переопределен в производном классе, объекты этого класса могут получить доступ к методу базового класса с помощью операции доступа к области видимости;
–виртуальный метод не может объявляться с модификатором static, но может быть объявлен как дружественный;
–если в классе вводится описание виртуального метода, он должен быть определен как чисто виртуальный (см. далее «Абстрактные классы»);
Чисто виртуальный метод содержит признак = 0 вместо тела, например: virtual void f (int) = 0;
Если определить метод draw в классе как виртуальный, решение о том, метод какого класса вызывать, решается в зависимости от типа объекта, на который ссылается указатель:
monstr *r, *p;
r = new monstr;
p = new daemon;
r - > draw (1, 1, 1, 1); // вызывается метод класса monstr
p - > draw (1, 1, 1, 1) // вызывается метод класса daemon
p - > monstr :: draw (1, 1, 1, 1); // обход механизма виртуальных методов
Если объект класса daemon будет вызывать методdraw не непосредственно, а косвенно (т. е. из другого метода, определенного в классе monstr), будет вызван метод draw класса daemon.
Абстрактные классы
Класс, содержащий хотя бы один чисто виртуальный метод, называется абстрактным. Абстрактные классы предназначены для представления общих понятий, которые предполагается конкретизировать в производных классах.
Абстрактный класс может использоваться только в качестве базового класса для других классов – нельзя создавать объекты абстрактного класса.
27