Объектно-ориентированное программирование на C++

       

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


Иногда, когда виртуальная функция объявляется в базовом классе, она не выполняет никаких значимых действий. Это вполне обычная ситуация, поскольку часто базовый класс не определяет законченный тип, или, если рассматривать наш пример, объект базового типа не представляет особой ценности. Речь здесь идет о том, что хотя базовый класс (Point) и содержит базовый набор методов и состояний, который производный класс дополняет всем недостающим, полезность точки, как графического объекта, не велика и, программируя, например, некоторый графический интерфейс, без точки, как объекта, можно вполне обойтись. Однако мы выяснили, что именно Point, как нельзя лучше подходит для роли базового класса, поскольку Point содержит в себе главные атрибуты любых графических объектов. Т.е. мы пришли к пониманию того, что класс Point ценен не своими объектами, а своей способностью выступать в качестве базового класса.

Возвращаясь к виртуальным методам, заметим, что теперь, когда отпала необходимость создавать объекты класса Point, методы виртуальные Show() и Hide() стали нужны только для того, чтобы их обязательно переопределили в производных классах. Для реализации этого положения С++ поддерживает чисто виртуальные методы.

Чисто виртуальные методы не определяются в базовом классе. У них нет тела, а есть только декларации об их существовании.

Для чисто виртуальной функции используется общая форма

virtual тип имя_функции (список параметров) = 0;

Ключевой частью этого объявления является приравнивание функции к нулю.

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

Абстрактным классом можно назвать класс, специально определенный для обеспечения наследования характеристик порожденными классами.

Вот как теперь станет выглядеть наш новый Point.

class Point

{

protected:


 int X;

 int Y;

 Boolean Visible;

public:

 int GetX(void) { return X; }

 int GetY(void) { return Y; }

 Boolean isVisible (){ return Visible;}



 Point (int newX =0, int new Y =0);

 virtual void Show() = 0; // чисто виртуальная функция

 virtual void Hide() = 0; // чисто виртуальная функция

 void MoveTo (int newX, int newY)

 {

  Hide();

  X = newX; Y = newY;

  Show();

 }

};

Класс Point теперь действует как заготовка, из которого все порожденные классы могут взять элементы, общие для всех типов в иерархии, но теперь, при попытке создать объект типа Point, компилятор выдаст сообщение об ошибке.

Заметьте, что необходимость конструктора при этом не отпала, поскольку по-прежнему нужно будет инициализировать X, Y и Visible для производных классов.

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

[назад] [оглавление] [вперед]

Содержание раздела