Чисто виртуальный метод должен переопределяться в производном классе (возможно, опять как чисто виртуальный).




Простое наследование

Под простым наследованием понимается наследование, при котором дочерний класс имеет только одного родителя.

Задача: создать дочерний класс NPC от класса Player, добавив ему способность самостоятельного мышления.

Пример 2. Простое наследование. class NPC: public Player{ int brain; public: /*Конструкторы*/ NPC(int lBrain = 10){ brain = lBrain; } NPC(maxH, lvlOfHealth, iF): Player(maxH, lvlOfHealth, iF){ brain = 10; } /*Перегрузкаопераций*/ const NPC & operator = (NPC &NP){ if (&NP == this) return *this; brain = NP.brain; Player: operator = (NP); return *this; } /*Метод, меняющий значение полей*/ void think(); /*Иныеметоды*/ void draw(int x, int y, int dx, int dy, int position); };

В результате разработки производного класса было сделано следующее:

        • добавлены поле brain и метод think ();
        • определены собственный конструктор и операция присваивания;
        • переопределён метод отрисовки объекта;
        • унаследованы все поля, операции (за исключением присваивания) и методы унаследованы из класса Player, а деструктор создаётся по умолчанию.

Правила наследования различных методов

Для разных методов класса существуют разные правила наследования. Одно из таких правил говорит о том, что конструкторы не наследуются. Следовательно, дочерний класс должен обладать собственными конструкторами.

Порядок вызова конструкторов:

    1. Если в конструкторе производного класса явный вызов конструктора базового класса отсутствует, автоматически вызывается конструктор базового класса по умолчанию (то есть тот, который можно вызвать без параметров).
    2. Для иерархии, состоящей из нескольких уровней, конструкторы базовых классов вызываются, начиная с самого верхнего уровня, после чего выполняются конструкторы тех элементов класса, которые являются объектами, в порядке их объявления, а затем запускается на исполнение конструктор класса.
    3. В случае нескольких базовых классов их конструкторы вызываются в порядке объявления.

Если конструктор базового класса требует указания параметров, он должен быть явным образом вызван в конструкторе производного класса в списке инициализации!

Следующее правило наследования говорит о том, что операция присваивания не наследуется. Следовательно, её требуется явно определять в дочернем классе.

Важно то, что в теле функции-операции присваивания класса NPC используется явный вызов функции-операции присваивания из базового класса. Для повышения уровня представления синтаксиса вызова, ключевое слово operator вместе с вызовом функции можно интерпретировать как идентификатор функции-операции.

Вызов функции-операции родительского класса имеет более высокий уровень нежели копирование фрагментов программного кода из функции, описанной в базовом классе, в функции производного. Помимо сокращения размера листинга, это позволяет достигнуть упрощение модификации программы, так как изменения нужно вносить только в одну точку программы, а не в сразу несколько, что сокращает количество вероятных ошибок.

Третье правило наследования указывает на то, что деструкторы не наследуются. Если разработчик не описывает в производном классе деструктор, то он формируется по умолчанию и вызывает деструкторы всех базовых классов.

В отличие от конструкторов, при описании деструктора дочернего класса в нём не требуется явно вызывать деструкторы базовых классов, так как это будет сделано автоматически. Для иерархии классов, которая состоит из нескольких уровней, деструкторы вызываются в порядке, строго обратном вызову конструкторов.

Порядок вызова деструкторов имеет следующий вид:

    1. сначала вызывается деструктор класса;
    2. затем деструктор элемента класса;
    3. в конце деструктор базового класса.

Виртуальные методы

Механизм позднего связывания в C++ реализован с помощью виртуальных методов. Под виртуальным методом понимается метод, ссылка на который разрешается на этапе исполнения программы.

Для определения виртуального метода используется ключевое слово virtual. Синтаксисописаниявиртуальногометодаимеетследующийвид:

virtial void draw(int x, int y, int dx, int dy, int position);

Существуют следующие правила описания виртуальных методов:

    1. Если в базовом классе метод определен как виртуальный, метод, определенный в производном классе с тем же именем и набором параметров, автоматически становится виртуальным, а с отличающимся набором параметров — обычным.
    2. Виртуальные методы наследуются, то есть переопределять их в производном классе требуется только при необходимости задать отличающиеся действия.
    3. Если виртуальный метод переопределен в производном классе, объекты этого класса могут получить доступ к методу базового класса с помощью операции доступа к области видимости.
    4. Виртуальный метод не может объявляться с модификатором static, но может быть объявлен как дружественный.
    5. Если в класс вводится описание виртуального метода, то он должен быть определен хотя бы как чисто виртуальный.

Стоит иметь ввиду то, что права доступа при переопределении виртуального метода изменить нельзя.

Чисто виртуальный методметод, содержащий равенство нулю вместо тела:

virtial void func(int) = 0;

Чисто виртуальный метод должен переопределяться в производном классе (возможно, опять как чисто виртуальный).

Если говорить о переопределении, то существует рекомендация о том, что в дочернем классе следует переопределять исключительно виртуальные методы.

Пример 3. Виртуальныеметоды. virtual void draw(int x, int y, int dx, int dy, int position);

В примере 3 представлено определение метода с идентификатором draw в качестве виртуального. Теперь, решение о том, метод какого класса нужно вызвать, будет приниматься в зависимости от типа объекта, на который ссылается указатель.

Рекомендуется делать виртуальными деструкторы для того, чтобы гарантировать правильное освобождение памяти из-под динамического объекта, поскольку в этом случае в любой момент времени будет выбран деструктор, соответствующий фактическому типу объекта.

Абстрактные классы

Под абстрактным классом понимается класс, содержащий хотя бы один чисто виртуальный метод. Такие классы предназначены для представления общих понятий, которые предполагается конкретизировать в производных классах.

Абстрактные классы могут использоваться только в качестве базового для других классов. То есть экземпляры абстрактного класса создавать нельзя. Причина этому очень проста: прямой или косвенный вызов чисто виртуального метода приводит к ошибке при выполнении.

Существует несколько правил работы с абстрактными классами:

    1. абстрактный класс нельзя использовать при явном приведении типов, для описания типа параметра и типа возвращаемого функцией значения;
    2. допускается объявлять указатели и ссылки на абстрактный класс, если при инициализации не требуется создавать временный объект;
    3. если класс, производный от абстрактного, не определяет все чисто виртуальные функции, он также является абстрактным.

Существует возможность создания функции, параметром которой является указатель на абстрактный класс. В таком случае, на место параметра при выполнении программы может передаваться указатель на объект любого производного класса, что позволяет создавать полиморфные функции, которые работают с объектом любого типа в пределах одной иерархии.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2022-10-12 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: