Чтение онлайн

на главную - закладки

Жанры

Шрифт:

Помимо определений фигур в библиотеке фигур содержатся функции для работы с ними. Например:

void shape_refresh; // рисует все фигуры void stack(shape* p, shape* q); // ставит p на верх q

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

void shape_refresh (* screen_clear; sl_iterator next(shape_list); shape* p; while ( p=next ) p-»draw; screen_refresh; *)

И вот, наконец, настоящая сервисная функция (утилита).

Она кладет одну фигуру на верх другой, задавая, что south одной должен быть сразу над north другой:

void stack(shape* q, shape* p) // ставит p на верх q (* point n = p-»north; point s = q-»south; q-»move(n.x-s.x,n.y-s.y+1);

*)

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

7.6.3 Прикладная программа

Прикладная программа чрезвычайно проста. Определяется новая фигура myshape (на печати она немного похожа на рожцу), а потом пишется главная программа, которая надевает на нее шляпу. Вначале описание myshape:

#include «shape.h»

class myshape : public rectangle (* line* l_eye; // левый глаз line* r_eye; // правый глаз line* mouth; // рот public: myshape(point, point); void draw; void move(int, int); *);

Глаза и рот – отдельные и независимые объекты, которые создает конструктор myshape:

myshape::myshape(point a, point b) : (a,b) (* int ll = neast.x-swest.x+1; int hh = neast.y-swest.y+1; l_eye = new line( point(swest.x+2,swest.y+hh*3/4),2); r_eye = new line( point(swest.x+ll-4,swest.y+hh*3/4),2); mouth = new line( point(swest.x+2,swest.y+hh/4),ll-4); *)

Объекты глаза и рот порознь рисуются заново функцией shape_refresh, и в принципе могут обрабатываться независимо из объекта myshape, которому они принадлежат. Это один способ определять средства для иерархически построенных объектов вроде myshape. Другой способ демонстрируется на примере носа. Никакой нос не определяется, его просто добавляет к картинке функция draw:

void myshape::draw (* rectangle::draw; put_point(point( (swest.x+neast.x)/2,(swest.y+neast.y)/2)); *)

myshape передвигается посредством перемещения базового прямоугольника rectangle и вторичных объектов l_eye, r_eye и mouth (левого глаза, правого глаза и рта):

void myshape::move (* rectangle::move; l_eye-»move(a,b);

r_eye-»move(a,b); mouth-»move(a,b); *)

Мы можем, наконец, построить несколько фигур и немного их подвигать:

main (* shape* p1 = new rectangle(point(0,0),point(10,10)); shape* p2 = new line(point(0,15),17); shape* p3 = new myshape(point(15,10),point(27,18)); shape_refresh; p3-»move(-10,-10); stack(p2,p3); stack(p1,p2); shape_refresh; return 0; *)

Еще раз обратите внимание, как функции вроде shape_refresh и stack манипулируют объектами

типов, опрделяемых гораздо позже, чем были написаны (и, может быть, окомпилированы) сами эти функции.

7.7 Свободная память

Если вы пользовались классом slist, вы могли обнаружить, что ваша программа тратит на заметное время на размещение и освобождение объектов класса slink. Класс slink – это превоходный пример класса, который может значительно выиграть от того, что программист возьмет под контроль управление свобоной памятью. Для этого вида объектов идеально подходит оптмизирующий метод, который описан в #5.5.6. Поскольку каждый slink создается с помощью new и уничтожается с помощью delete членами класса slist, другой способ выделения памяти не представляет никаких проблем.

Если производный класс осуществляет присваивание указтелю this, то конструктор его базового класса будет вызыватся только после этого присваивания, и значение указателя this в конструкторе базового класса будет тем, которое присвоено конструктором производного класса. Если базовый класс присвивает указателю this, то будет присвоено то значение, которое использует конструктор производного класса. Например:

#include «stream.h»

struct base (* base; *);

struct derived : base (* derived; *)

base::base (* cout «„ „\tbase 1: this=“ „„ int(this) «« «\n“; if (this == 0) this = (base*)27; cout «« «\tbase 2: this=“ «« int(this) «« «\n“; *)

derived::derived (* cout «„ „\tderived 1: this=“ „„ int(this) «« «\n“; this = (this == 0) ? (derived*)43 : this; cout «« «\tderived 2: this=“ «« int(this) «« «\n“; *)

main (* cout «„ „base b;\n“; base b; cout „„ „new base b;\n“; new base; cout «« «derived d;\n“; derived d; cout «« «new derived d;\n“; new derived; cout «« «at the end\n“;

*)

порождает вывод

base b; base 1: this=2147478307 base 2: this=2147478307 new base; base 1: this=0 base 2: this=27 derived d; derived 1: this=2147478306 base 1: this=2147478306 base 2: this=2147478306 derived 1: this=2147478306 new derived; derived 1: this=0 base 1: this=43 base 2: this=43 derived 1: this=43 at the end

Если деструктор производного класса осуществляет присвивание указателю this, то будет присвоено то значение, котрое встретил деструктор его базового класса. Когда кто-либо делает в конструкторе присваивание указателю this, важно, чтобы присваивание указателю this встречалось на всех путях в конструкторе*.

– * К сожалению, об этом присваивании легко забыть. Напрмер, в первом издании этой книги (английском – перев.) вторая строка конструктор derived::derived читалась так:

if (this == 0) this = (derived*)43;

И следовательно, для d конструктор базового класса base::base не вызывался. Программа была допустимой и коректно выполнялась, но, очевидно, делала не то, что подразмевал автор. (прим. автора)

7.8 Упражнения

1. (*1) Определите

Поделиться:
Популярные книги

Деревенщина в Пекине 3

Афанасьев Семен
3. Пекин
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Деревенщина в Пекине 3

#Бояръ-Аниме. Газлайтер. Том 36

Володин Григорий Григорьевич
36. История Телепата
Фантастика:
боевая фантастика
аниме
фэнтези
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 36

Светлая тьма. Советник

Шмаков Алексей Семенович
6. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Светлая тьма. Советник

Вперед в прошлое 11

Ратманов Денис
11. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 11

На границе империй. Том 10. Часть 3

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 3

Точка Бифуркации

Смит Дейлор
1. ТБ
Фантастика:
боевая фантастика
7.33
рейтинг книги
Точка Бифуркации

Адвокат Империи 4

Карелин Сергей Витальевич
4. Адвокат империи
Фантастика:
городское фэнтези
аниме
дорама
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Адвокат Империи 4

Назад в будущее

Поселягин Владимир Геннадьевич
5. Зург
Фантастика:
боевая фантастика
5.00
рейтинг книги
Назад в будущее

Отвергнутая невеста генерала драконов

Лунёва Мария
5. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Отвергнутая невеста генерала драконов

Бастард

Осадчук Алексей Витальевич
1. Последняя жизнь
Фантастика:
фэнтези
героическая фантастика
попаданцы
5.86
рейтинг книги
Бастард

Газлайтер. Том 22

Володин Григорий Григорьевич
22. История Телепата
Фантастика:
боевая фантастика
попаданцы
фэнтези
5.00
рейтинг книги
Газлайтер. Том 22

Законы Рода. Том 2

Андрей Мельник
2. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 2

Инквизитор Тьмы 2

Шмаков Алексей Семенович
2. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы 2

Газлайтер. Том 31

Володин Григорий Григорьевич
31. История Телепата
Фантастика:
боевая фантастика
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Газлайтер. Том 31