Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
umm_3690.pdf
Скачиваний:
24
Добавлен:
30.04.2015
Размер:
364.53 Кб
Скачать

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]