Putimage(xl,yl,pnt,op)

изобразить на экране битовый образ, ранее сохраненный в памяти с помощью функции getimage О", xl, yl - координаты размещения на экране левого верхнего угла, pnt - указатель на область памяти, где хранится нужное изображение; ор – параметр, определяющий правила выбора цвета для каждого изображаемого пикселя. Выбор цвета осуществляется с учетом имеющегося на экране пикселя и сохраненного в памяти. Па­раметр ор определяет правило сочетания этих цветов в соот­ветствии с табл. 10.2. Необходимо обратить внимание на одну особенность режима xor_put. Если в этом режиме изображе­ние вывести на экран в то же место, где уже было то же самое изображение, то изображение исчезнет с экрана. Именно так убирает с экрана пятно функция hide(). Флажок видимости пятна на экране vis необходим для распознавания необходи­мости повторного применения функции putimage ().

Функция show () выполняется в разных режимах в зависимости от значения признака tag записи изображения в память. Если значение tag равно 0, то рисуется и закрашивается окружность, затем ее образ переписывается в память функцией getimage () и устанавливается в 1 значение tag. Если значение tag равно 1, то образ переносится на эк­ран из той области основной памяти, где он сохранялся,- при помощи функции putimage ().

Действия функции move () понятны из комментариев в тексте про­граммы.

Таблица 10.2

Правила выбора цвета при размещении на экране битового образа с помощью функции putimage ()

Значение параметра ОР Условное обозначение вgraphics.h Смысл преобразования
COPY_PUT Копия без всяких условий
XOR_PUT Исключающее ИЛИ
OR PUT Включающее ИЛИ (дизъюнкция)
AND__PUT Логическое И (конъюнкция)
NOT_PUT Копия с инверсией изображения

Особенностью функции vary() является необходимость не только изменить размеры изображения, но и заново сохранить его битовый образ в основной памяти. При изменении размеров изображения нуж­но изменять и размеры памяти для его образа.

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

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

~имя_класса

У деструктора не может быть параметров (даже типа void), и деструктор не имеет возможности возвращать какой-либо результат, даже типа void. Статус доступа деструктора по умолчанию public (т.е. деструктор доступен во всей области действия определения класса).

В несложных классах деструктор обычно определяется по умолчанию. Например, в классе point деструктор явно не определен, и компилятор предполагает, что он имеет вид

~point() { };

В классе spot деструктор явно определен:

~spot О { hide(); tag = 0; delete [] pspot; }

Его действия: убрать с экрана изображение пятна, обратившись к функции spot ::hide(); установить в нуль признак tag наличия в памяти битового образа пятна; освободить память, выделенную при создании объекта для битового образа пятна и связанную с конкретным экземпляром указателя pspot.

Деструкторы не наследуются, поэтому даже при отсутствии в производном классе (например, в классе spot) деструктора он не передается из базового (например, из point), а формируется компилятором как умалчиваемый со статусом доступа public. Этот деструктор вызывает деструкторы базовых классов. В рассматриваемом примере это будет выглядеть примерно так :

public: ~spot() { ~point(); }

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

Деструкторы базовых классов выполняются в порядке, обратном перечислению классов в определении производного класса. Таким образом, порядок уничтожения объекта противоположен по отношению к порядку его конструирования.

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

Объяснив основные принципы работы деструкторов, приведем программу для работы с объектами класса spot:

//Р10-01.СРР - наследование классов и их деструкторы

#include <graphics.h> // Связь с графической библиотекой

#include <conio.h> // Прототип функции getch()

#include "spot.cpp" // Определение класса spot void main ()

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

int dr = DETECT, mod;

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

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

{ //В этом блоке создаются и используются объекты

// класса spot

spot A(200,50,20); // Создается невидимое пятно А

spot D(500,200,30); // Создается невидимое пятно D

A.show(); // Изобразить пятно А на экране

getch(); // Ждать нажатия клавиши

D.show(); // Изобразить пятно D на экране

getch(); A.move(50,60); // Переместить пятно А

getch(); О.vary (3); // Изменить размеры пятна D

getсh(); // Ждать нажатия клавиши

}

// При выходе из блока для каждого объекта автоматически

// вызывается деструктор, освобождающий выделенную

// память

closegraph(); // Закрыть графический режим

} // Конец программы

Изменение состояний экрана при выполнении программы иллюстрирует рис. 10.2.

Принципиальным отличием этой программы от приведенных выше программ р9-04,срр, Р9-11.СРР для работы с объектами класса point является наличие внутреннего блока, что связано с наличием в классе spot деструктора, при выполнении которого вызывается компонентная функция hide(), использующая функции графики. Эти функции могут выполняться только в графическом режиме, т.е. до выполнения функции closegraph()). Если построить программу без внутреннего блока так же, как упомянутые программы с классом point, то деструктор по умолчанию будет вызываться только при окончании программы, когда графический режим уже закрыт и вы­полнение любых графических функций невозможно. Указанной оши­бочной ситуации можно избежать двумя путями: либо вызывать деструктор явно для уничтожения объектов а и d, а потом закрывать графический режим, либо после инициализации графики ввести внут­ренний блок, в котором определены объекты а и d и при выходе из которого они уничтожаются, для чего деструктор дважды вызывается автоматически. Графический режим закрывается во внешнем блоке, когда объекты A, D уже уничтожены и обращения к деструктору ~spot () не нужны. В программе реализовано второе решение.

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

В качестве несложного упражнения можно удалить скобки ‘()’, выделяющие внутренний блок, и убедиться, что при выполнении из­мененной программы будет выдаваться сообщение об ошибке в гра­фической системе:

BGI Error: Graphics not initialized (use 'initgraph')

Второе решение - явный вызов деструкторов без добавления вло­женного блока:

getch(); D.vary(3); // Изменить размеры пятна D

getch(); // Ждать нажатия клавиши

А.spot::-spot(); // Уничтожить объект А

getch(); // Ждать нажатия клавиши

D. spot: :-spot О ; // Уничтожить объект D

closegraph(); // Закрыть графический режим

} // Конец программы

В данном варианте класса spot при уничтожении объекта с по­мощью деструктора его изображение удаляется с экрана функцией hide ().