Типы данных в языке C++__________________________________729

или соответствующим образом используем операцию разрешения области, то вы-
зывается функция базового класса.

Если бы в классе — наследнике Circl отсутствовала функция Draw, то все при-
веденные операторы вызывали бы функцию базового класса.

Таким образом, механизм наследования позволят использовать функции базо-
вого класса или переопределять их.

Теперь рассмотрим другую задачу. Пусть мы имеем несколько классов, насле-
дующих Shape: Circl (круг), Rectangle (прямоугольник), Square (квадрат) и т.п.
Каждый из этих классов имеет свою функцию Draw, которая умеет рисовать соот-
ветствующую форму. Мы хотим работать с объектами этих фигур, как с объектами
базового класса Shape, не разбираясь в истинной природе каждого объекта. И при
этом хотим, чтобы программа сама понимала, что это за объект и как его рисовать.
Например, мы хотим создать массив указателей на объекты различных форм:

Shape *ShapeArray[10];

загрузить его указателями на объекты разных фигур:

ShapeArray[0] = new Circl;

ShapeArray[1] = new Rectang;

ShapeArray[2] = new Square;

и затем в цикле выполнять рисование этих фигур:

for(int i = 0; i < 3; i++)
ShapeArray[i]->Draw();

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

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

Синтаксически это оформляется следующим образом. В базовом классе Shape
функция объявляется следующим образом:

virtual void Draw(void);

И это все! Если функция была однажды объявлена виртуальной, она остается
виртуальной и во всех классах наследниках. Таким образом для решения задачи
полиморфизма хватило одного спецификатора virtual. Правда, обычно предпочи-
тают для большей ясности программы в классах — наследниках тоже вводить спе-
цификатор virtual, чтобы была ясна суть этих функций для тех, кто будет строить
наследников данного класса. Но с точки зрения языка C++ это не обязательно.

Иногда в базовом классе определяют чистую виртуальную функцию (абстрак-
тную функцию). Это функция, для которой не указана реализация. Для того, что-
бы определить такую функцию, достаточно указать, что ее тело равно нулю:

virtual void Draw(void)=0;

В нашем примере именно так целесообразно объявить функцию Draw в базо-
вом классе Shape, поскольку непонятно, как можно нарисовать просто абстракт-
ную фигуру. Реализация для чистой полиморфной функции не пишется.

Класс, в котором имеется хоть одна чистая виртуальная функция, называется
абстрактным. Для абстрактного класса невозможно создать объект. Такие клас-