- •Чистые виртуальные функции и абстрактные классы
- •Производные классы с конструкторами и деструкторами
- •Виртуальные деструкторы
- •Обобщенный пример наследования
- •Модульность классов
- •Расширяющяся иерархия классов
- •Узловые классы
- •Множественное наследование классов
- •Шаблоны
- •Шаблоны функций
- •Перегрузка шаблонов функций
- •Шаблоны классов
- •Друзья Дружественные функции
- •Дружественные классы
- •Статические элементы класса
Обобщенный пример наследования
Мы рассмотрели и исследовали объявленные в начале основополагающие концепции ООП – объект, класс, инкапсуляция, наследование, полиморфизм, абстракция типов. Теперь после изучения возможностей концепции наследования классов (простое, множественное, управление режимами доступа, виртуальные функции, абстрактные классы) на демонстрационных примерах полезно рассмотреть обобщающий пример.
Постановка задачи.
Рассмотрим разработку полного графического примера, в котором выводятся на экран монитора геометрические фигуры, с которыми можно совершать некоторые действия, например, создавать, уничтожать, перемещать по экрану и т. д. Прообразом этой задачи является пример 28.
Вместо ограниченного по своим возможностям класса Location в качестве базового класса опишем свойства и функции "некоторой фигуры" (Figure). Местоположение ее определяется двумя координатами экрана (X, Y), инициализация которых задается встроенным конструктором, а для получения значений текущих координат используются встроенные методы класса GetX(), GetY(). Параметры X, Y объявлены защищенными элементами базового класса, чтобы производные классы могли их наследовать и использовать.
В качестве основных действий, которые можно совершать с этой фигурой, могут быть: показ на экране (Show), удаление (Hide), перемещение (Drag). Описание этих действий представлено чистыми виртуальными функциями без их тел, что делает класс абстрактным. Для этого класса нельзя создать реальный объект на экране, но можно определить указатель или массив указателей на базовый тип и использовать их при создании объектов производных классов. При этом могут применяться только наследуемые виртуальные функции, которые видимы через базовый указатель из производного класса.
Базовому классу наследует производный класс (Figure <- Point), который описывает простейший реальный объект "точка", координаты которой наследуются из базового класса (X, Y), а также задается свой параметр видимости точки на экране как защищенный элемент Visible с булевыми значениями. Объявлены обычные методы: функция Isvisible(), определяющая видимость точки, и функция Moveto(), задающая новые координаты точки. Как невиртуальные методы они могут наследоваться производными классами. Их можно сделать виртуальными, объявив их как virtual, и тогда в производных от Point классах необходимо замещать их "своими" виртуальными методами.
Чистые виртуальные функции класса Figure замещаются конкретными виртуальными функциями (Show(), Hide(), Drag()) в классе Point. Виртуальная функция Drag() использует обычный метод своего класса Moveto(), который определяет новые координаты объекта, а также обычную функцию общего назначения (т.е. не метод класса) Getdelta(). Последняя определяет направление смещения точки (или другой реальной фигуры) на экране по нажатию пользователем клавиш-стрелок клавиатуры (вправо, влево, вверх, вниз) и окончание процесса смещения объекта на экране при нажатии клавиши <Enter>.
В главной функции программы демонстрируется создание и перемещение точки по экрану, создание "звездного" неба с использованием стандартной функции получения случайных чисел X, Y для координат точки random(max), где max – максимальное число для координаты экрана с установленной разрешающей способностью. Обработка программы выполняется в среде компилятора Borlandc 3.1.
Пример 40.
Рассмотрим программу для демонстрации описанной выше постановки задачи.
#include<iostream.h>
#include<conio.h>
#include<graphics.h> // для графической библиотеки
#include<stdlib.h> // для функций random(), srand(), kbhit()
#include<dos.h> // для функции delay()
const char* path= "c:\\borlandc\\bgi"; // путь к библиотеке bgi-файлов
enum Boolean { false, true }; // булевы значения
// прототип обычной функции (не метод), определенной ниже:
Boolean Getdelta (int& Deltax, int& Deltay);
class Figure // абстрактный базовый класс "фигура"
{ protected: // защищенные элементы, доступные в производных классах
int X, Y; // координаты объекта на экране
public:
Figure (int Initx, int Inity) // конструктор базового класса Figure
{ X = Initx, Y = Inity; } // инициализация координат
// встроенные функции-методы получения текущих координат объекта:
int Getx () { return X; }
int Gety () { return Y; }
// чистые виртуальные функции-методы базового класса:
virtual void Show() = 0; // изображение объекта
virtual void Hide() = 0; // стирание объекта с экрана
virtual void Drag ( int Dragby) = 0; // перемещение объекта
};
// производный класс Point с открытым доступом к базовому классу Figure:
class Point: public Figure // класс "точка"
{ protected:
Boolean Visible; // параметр видимости точки
public:
Point (int Initx, int Inity); // конструктор класса Point
// виртуальные функции-методы класса Point:
void Show(); // изображение точки на экране
void Hide(); // стирание точки с экрана
void Drag (int Dragby); // перемещение точки по экрану
// невиртуальные методы класса Point:
Boolean Isvisible() { return Visible;} // проверка точки на видимость
void Moveto (int Newx, int Newy); // смещение точки на новое место
};
// методы класса Point:
Point:: Point (int Initx, int Inity): // конструктор класса Point
Figure (Initx, Inity) // передача аргументов базовому классу
{ Visible = false; // инициализация параметра Point
}
void Point:: Show() // метод изображения точки на экране
{ if ( ! Visible) // если точка невидима, то
{ Visible = true; // установка видимости точки
putpixel (X, Y, getcolor() ); // изображение цветной точки
}
}
void Point:: Hide() // метод стирания точки с экрана
{ if (Visible) // если точка видима, то
{ Visible = false; // установка невидимости точки
putpixel (X, Y, getbkcolor() ); // закрашивание точки цветом фона
}
}
void Point:: Moveto (int Newx, int Newy) // метод смещения точки
{ if (Visible) Hide (); // стирание точки
X = Newx; // новые координаты точки X и Y
Y = Newy;
Show (); // изображение точки
}
void Point:: Drag( int Dragby) // метод смещения фигуры на величину Dragby
{ int Deltax, Deltay; // смещение по X, Y
int Figurex, Figurey; // координаты по X, Y
Show(); // изображение точки
while ( Getdelta ( Deltax, Deltay) ) // цикл перемещения точки:
{ Figurex = Getx()+( Deltax * Dragby ); // смещение по X
Figurey = Gety()+( Deltay * Dragby ); // смещение по Y
Moveto ( Figurex, Figurey); // перемещение точки на новое место
}
}
/* обычная функция (вне классов) определения направления смещения объекта,
которая анализирует код нажатой управляющей клавиши и возвращает
разрешение на смещение (true) в заданном направлении через параметры
ссылки (&), либо отмену смещения (false) при нажатии клавиши <Enter>;
используется в методе Point:: Drag():
*/
Boolean Getdelta (int& Deltax, int& Deltay) // & - ссылки на смещение
{ char Keychar; // переменная символа клавиши
Boolean Quit; // переменная смещения
Deltax = 0; // начальные значения смещений
Deltay = 0;
do { Keychar = getch (); // цикл анализа кода нажатой клавиши:
if ( Keychar == 13) // если код = 13 (<Enter>), то
return ( false); // конец смещения объекта;
if (Keychar == 0) //если код = 0, то это скэн-код клавиши
{ Quit = true; // подтверждение смещения
Keychar = getch (); // чтение 2- го байта кода
switch ( Keychar) // анализ кода управления:
{ case 72: Deltay = -1; break; // стрелка вниз
case 80: Deltay = 1; break; // стрелка вверх
case 75: Deltax = -1; break; // стрелка влево
case 77: Deltax = 1; break; // стрелка вправо
default : Quit = false; // неправильная клавиша
}
}
} while ( ! Quit); // продолжение цикла чтения кода клавиш
return ( true); // разрешение смещения объекта
}
void main() // главная функция:
{ int graphdriver = DETECT, graphmode; // данные режима графики
initgraph (&graphdriver, &graphmode, path); // инициализация графики
int n, i, x, y, maxx, maxy, maxcolor, seed, color; // рабочие переменные
int DelayTime; // временная задержка
x=100; // координаты экрана (х,у)
y=200;
Point Apoint ( x, y); // создание и инициализация точки
Apoint.Show(); // изображение точки
Apoint.Drag(20); // перемещение точки по экрану
getch (); // задержка образа экрана
/*
// изображение статического "звездного неба":
cout<< "Enter number of points (<32000): ";
cin >> n; // ввод количества точек
for (i=0; i<n; i++) // цикл создания точек
{ x = random(639); // случайные коодинаты точки (х, у)
y = random(479);
Point Apoint (x,y); // создание и инициализация точки
Apoint.Show(); // изображение точки
}
*/
/*
// изображение мерцающих цветных точек
maxx = getmaxx(); // количество пикселей по оси Х экрана
maxy = getmaxy(); // количество пикселей по оси Y экрана
maxcolor = getmaxcolor(); // количество цветов
cout<< "Enter number of points (<2000): ";
cin >> n; // ввод количества точек
cout<<"Enter DelayTime (millisecond) = ";
cin >> DelayTime; // ввод временной задержки
while ( ! kbhit() ) // цикл пока не нажата любая клавиша
{ seed = random (RAND_MAX); // начальное случайное число
srand (seed); // запуск генератора случайных чисел
for (i=0; i<n; i++) // цикл создания точек
{ x = random(maxx); // случайные координаты по x
y = random(maxy); // и по y
color = random(maxcolor); // случайное значение цвета
setcolor(color); // установка цвета
Point Apoint ( x, y); // создание и инициализация точки
Apoint.Show(); // изображение точки
}
delay (DelayTime); // задержка по времени
srand ( seed); // запуск генератора случайных чисел
for (i=0; i<n; i++) // цикл создания точек
{ x = random (maxx); // случайные коодинаты точки (х, у)
y = random (maxy);
color = random (maxcolor); // случайное значение цвета
if ( color == getpixel (x, y)) // если цвет точки = случайному, то
{ Apoint.Moveto (x, y); // смещение точки и
Apoint.Hide(); // стирание
}
}
}
getch (); // задержка экрана
closegraph(); // закрытие графического режима
}
