Void main(void)

Public point

{ public:

// Конструктор абстрактного класса figure:

figure (point p) : point (p.givex () , p.givey()) { }

// Чистая виртуальная функция для будущего

// изображения фигур:

virtual void show() = 0;

// Функция для удаления изображения фигуры:

void hide()

{ int bk, cc;

bk as getbkcolor () ; cc = getcolor () ; setcolor(bk);

show(); // Обращение к чистой виртуальной функции setcolor(cc); }

void move(point p) // Перемещение фигуры в точку "р" { hide (); х = p.givex() ; у = p.givey(); show() ; } };

На базе класса figure определим неабстрактные классы:

//ELLIPS.FIG - конкретный класс "эллипс" на основе figure class ellips : public figure {

int rx,ry; public:

// Конструктор:

ellips (point d, int radx, int rady): figure(d)

{ rx = radx; ry = rady; }

void *how()

{ ellipse(x,y,0,360,rx,ry);

return; } };

//CIRC.FIG - конкретный класс "окружность"

class circ: public figure {

int radius; public:

// Конструктор:

circ(point e, int rad): figure(e) { radius = rad; )

void show() { circle(x,y,radius); } };

В следующей программе используются все три класса:

//Р10-08.СРР - абстрактные классы и чистые виртуальные

// функции

#include <graphics.h>

#include "figure.cpp"

#include "circ.fig"

#include "ellips.fig"

#include <conio.h> // Для функции getch()

{ point A{100,80), B(300,200);

circ С(A,60);

ellips E(B,200,100); { // Переменные для инициализации графики:

int dr = DETECT, mod;

// Инициализация графической системы:

initgraph(&dr, &mod,"c:\\borlandc\\bgi");

// Изобразить точку - point::show():

A.show(); getch ();

// Изобразить точку - point::show() :

В.show(); getch();

// Показать окружность - circ::show():

С.show(); getch();

// Показать эллипс - ellips::show():

E.show() ; getch() ;

// Совместить фигуры - circ: :figure: :move() :

С. move (B) ; getch () ;

// Убрать эллипс - ellips::figure::hide():

E.hide() ; getch () ;

// Убрать окружность - circ::figure::hide():

C.hide() ; getch() ;

} closegraph() ;

}

Графические результаты выполнения показаны на рис. 10.6.

 

Рис. 10.6. Последовательность изображений на экране при выполнении программы Р10-08. СРР

В программе на базе класса figure определены два производных класса: circ (окружность) и ellips(эллипс). Для обоих классов уна­следованный класс point определяет центры фигур. В обоих классах определены конкретные методы show()и из абстрактного класса figure унаследованы функции move ()и hide(). Комментарии к опера­торам основной программы содержат полные (квалифицированные) имена исполняемых функций.

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

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

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

В класс chain входят (рис. 10.7) в качестве компонентов: статиче­ский указатель на последний элемент, уже включенный в список (last), статический указатель на начало списка (begin), указатель в объекте на следующий элемент списка (next), указатель в объекте на абстрактный базовый класс figure (pfig). Параметр конструктора класса chain пусть имеет тип указателя на абстрактный базовый класс figure. В качестве фактических параметров будем использовать ссылки на конкретные объекты классов, производных от абстрактно­го класса figure. Тем самым в односвязный список включаются (рис. 10.7) конкретные фигуры (окружность - класс circ, эллипс - класс ellips).

Рис 10.7. Схема односвязного списка (класс chain,/, объединяющего объекты разных классов.

Текст программы со всеми включениями и определениями:

//Р10-09.СРР - односвязный список объектов разных классов

#include <stdlib.h> // NULL, malloc,...

#include <conio.h> // getch(),...

//#include <iostream.h> // cout,...

#include "point.cpp" // Базовый класс для figure

// Абстрактный класс, производный от point:

#include "figure.cpp"

// Класс, производный от абстрактного figure:

#include "circ.fig"

// Класс, производный от абстрактного figure:

#include "ellips.fig"

// Объекты класса - фигуры, включенные в односвязный

// список:

class chain { // Объект - элемент в односвязном списке

// Указатель на последний элемент в списке:

static chain *last;

// Указатель в объекте на следующий элемент:

chain *next; public:

// Указатель на фигуру, входящую в элемент списка:

figure *pfig;

// Указатель на начало списка:

static chain *begin;

// Конструктор:

chain(figure *p);

// Функция изображает все фигуры списка:

static void showAll(void);

}; // Конец определения класса

// Внешнее описание и инициализация статических // компонентов класса:

chain *chain::begin = NULL; // Начало списка

chain *chain::last = NULL; // Последний элемент в списке

void chain::showAll(void) // Изображение элементов списка

( chain *uk = begin; // Настройка на начало списка

while (uk != NULL) // Цикл до конца списка

{ uk->pfig->show(); // Нарисовать конкретную фигуру

uk - uk->next; // Настройка на следующий элемент } }

// Конструктор создает и включает в список объект,

// связав его с конкретной фигурой из класса, производного

// от абстрактного:

chain:: chain(figure *p) // р - адрес включаемой фигуры

{ if (begin == NULL) // Определили начало списка

begin = this;

else last->next = this; // Связь с предыдущим элементом

pfig = p; // Запоминаем адрес включаемой фигуры

next = NULL; // Пометим окончание списка

last — this; // Запоминаем адрес последнего элемента

// списка }

void main()

{ point А(100,80), В(300,200); circ С(А,60); ellips Е(В,200,100) ;

{ // Переменные для инициализации графики:

int dr = DETECT, mod;

// Инициализация графической системы:

initgraph (fidr, &mod, "с: \\borlandc\\bgi") ;

A. show (); getchO; // Изобразить точку – point:: show ()

В.show(); getchO; // Изобразить точку // Показать окружность - circ::show():

С.show(); getch();

// Включить в список первый элемент - окружность С: chain са(&С);

Е.show(); getch(); // Показать эллипс –

ellips::show(); chain ce(&E); // Включить в список эллипс

// Совместить фигуры –

circ::figure::move():С.move(В); getch();

// Убрать эллипс –

ellips::figure::hide():E.hide() ; getch() ;

// Убрать окружность –

circ::figure::hide():C.hide () ; getch() ;

// Изобразить все фигуры из списка: c

hain::showAll(); getch(); }

closegraph(); }

Рис. 10.8. Последовательность изображений на экране при выполнении программы Р10-09. СРР

Статическая компонентная функция chain:: showAll () обеспечи­вает вывод на экран изображений всех конкретных фигур, включен­ных в односвязный список. Важно отметить последовательность передач управления в этой функции. Указатель uk типа chain * по­зволяет обратиться к компоненту pfig - указателю на абстрактный базовый класс figure. После выполнения конструктора chain () зна­чением pf ig является ссылка на объект некоторого производного от figure класса. Именно оттуда выбирается соответствующая функция show(), подменяющая чистую виртуальную функцию figure::show(). Тем самым на экран выводится изображение конкретной фигуры. Например, функция circ::show() изобразит окруж­ность и т.д.

В основной программе формируются точки а, в и на них, как на цен­трах, создаются объекты с (окружность) и Е (эллипс). В графическом ре­жиме выводятся на экран и убираются с экрана изображения всех созданных объектов. Затем функцией showAll() рисуются все объекты, включенные в список. Результат выполнения программы показан на рис. 10.8.