Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Методическое пособие 555

.pdf
Скачиваний:
4
Добавлен:
30.04.2022
Размер:
2.33 Mб
Скачать

где round – функция округления до ближайшего целого (округление необходимо, поскольку координаты пикселя могут быть только целочисленными). Выражения для x0 и y0 отличаются знаками + и -, поскольку координаты пикселя по вертикали увеличиваются сверху вниз.

Итак, закрашивать пиксели при построении графика мы будем следующим образом:

PutPixel(x0+round(scaleX*x), y0-round(scaleY*f(x)),clRed);

Разумеется, эта процедура PutPixel должна быть расположена внутри цикла, в котором значение x увеличивается на каждом шаге на величину step.

Полный текст программы представлен ниже.

program func_plot;

uses GraphABC; var

x,step: Real; xmax,xmin,fmax,fmin: Real;

xLeft,yLeft,xRight,yRight: Integer; x0,y0: Integer;

scaleX,scaleY : Real;

function f(x : Real) : Real; begin

f := 1 + x*x*sin(x); end;

begin

//Получаем значения xmin и xmax //от пользователя

write(' Введите xmin: '); readln(xmin); write(' Введите xmax: '); readln(xmax);

//определяем величину шага по x step := (xmax - xmin) / 10000;

131

//Определяем значения fmin и fmax x := xmin;

fmin := f(x); fmax := fmin; repeat

if (fmin > f(x)) then fmin := f(x)

else if (fmax < f(x)) then fmax := f(x); x := x + step;

until x > xmax;

//Определяем положение области вывода графика xLeft := 40;

yLeft := 40;

xRight := WindowWidth - 40;

yRight := WindowHeight - 40;

//Определяем коэффициенты масштабирования scaleX := (xRight - xLeft)/(xmax - xmin); scaleY := (yRight - yLeft)/(fmax - fmin);

//Определяем положение точки (0,0) //в графическом окне

x0 := xLeft - round(xmin*scaleX);

y0 := yLeft + round(fmax*scaleY);

//Очищаем окно и отображаем область вывода //графика в виде прямоугольника

ClearWindow;

Rectangle(xLeft,yLeft,xRight,yRight);

//Строим график

SetPenColor(clRed); x := xmin;

repeat

PutPixel(x0+round(scaleX*x), y0-round(scaleY*f(x)),clRed);

x := x + step; until x > xmax;

end.

Задание 8. Модифицируйте предыдущую программу таким образом, чтобы на график была нанесена координатная

132

сетка и рядом с осями координат были указаны числовые значения для соответствующих линий сетки (примерный вид показан на рис. 7.5.) Шаг сетки по осям x и y задает пользователь.

Рис. 7.5

3.Контрольные вопросы и задания

1.Для чего предназначен модуль GraphABC? Как его подключить к программе?

2.Что такое пиксель?

3.Как отсчитываются координаты пикселя в графическом окне?

4.Что определяют свойства Пера? Свойства Кисти?

5.Как задать цвет и толщину пера, цвет кисти?

6.Как изменить размеры графического окна?

7.Поясните принцип формирования цвета функцией RGB.

8.Можно ли для построения изображения фрактала Кантора (задание 5) вместо рекурсии использовать цикл?

9.Подробно поясните код программы из задания 7.

133

Лабораторная работа № 8

ВВЕДЕНИЕ В ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ

Цель работы: знакомство с основными принципами и понятиями объектно-ориентированного программирования

1.Теоретические сведения

1.1.Методология объектно-ориентированного

программирования

Объектно-ориентированное программирование (ООП) объединило лучшие идеи структурированного программиро-

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

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

134

1.2. Инкапсуляция, полиморфизм, наследование

Все языки ООП характеризуются тремя общими признаками: инкапсуляцией, полиморфизмом и наследованием.

Инкапсуляция – это такой механизм программирования, который связывает воедино код и данные, которые он обрабатывает, чтобы обезопасить их от внешнего вмешательства и неправильного использования. В объектно-ориентированном языке при таком связывании кода и данных создается объект.

Внутри объекта код, данные или обе эти составляющие могут быть закрытыми в “рамках” этого объекта или открытыми. Закрытый (private) код (или данные) известен и доступен только другим частям того же объекта. Другими словами, к закрытому коду или данным не может получить доступ та часть программы, которая существует вне этого объекта. Открытый (public) код (или данные) доступен любым другим частям программы, даже если они определены в других объектах. Обычно открытые части объекта используются для предоставления управляемого интерфейса взаимодействия с закрытыми элементами объекта.

Полиморфизм – это свойство, позволяющее использовать один интерфейс для целого класса действий. Благодаря полиморфизму можно создать один общий набор подпрограмм (один интерфейс), который подходит для различных конкретных ситуаций, в то время как без использования ООП программисту пришлось бы создавать различные наборы подпрограмм с различными именами и интерфейсами. Концепция полиморфизма выражается фразой “один интерфейс — много методов”. Полиморфизм позволяет понизить уровень сложности за счет возможности применения одного и того же интерфейса для задания целого класса действий. Выбор же конкретного действия применительно к той или иной ситуации осуществляется компилятором.

Наследование – это процесс, благодаря которому один объект может приобретать свойства другого. Благодаря наследованию поддерживается концепция иерархической

135

классификации. В виде управляемой иерархической (нисходящей) классификации организуется большинство областей знаний. Например, яблоки антоновки являются частью классификации яблоки, которая в свою очередь является частью класса фрукты, а тот – частью еще большего класса пища. Таким образом, класс пища обладает определенными качествами (съедобность, питательность и пр.), которые применимы и к подклассу фрукты. Помимо этих качеств, класс фрукты имеет специфические характеристики (сочность, сладость и пр.), которые отличают их от других пищевых продуктов. В классе яблоки определяются качества, специфичные для яблок (растут на деревьях, не тропические и пр.). Класс антоновки наследует качества всех предыдущих классов и при этом определяет качества, которые являются уникальными для этого сорта яблок.

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

1.2. Объекты и классы

Перейдем к краткому обзору реализации принципов ООП в языке PascalABC.Net1. Тип данных, задающий формат объекта, называется классом. Описание класса имеет следующий вид:

1 Более подробную информацию можно найти в разделе «Классы» спра-

вочной системы PascalABC.Net.

136

type

имя_класса = class(базовый_класс) private

{приватные поля, методы и свойства} public

{публичные поля, методы и свойства}

...

end;

Базовый класс (класс-предок) может быть не задан, в этом случае будет использован самый общий базовый класс

Object.

Ключевые слова private (закрытый) и public (открытый) являются модификаторами доступа, задающими пра-

вила видимости членов класса, объявленных в данной секции1.

К члену класса, имеющему атрибут public, можно обратиться из любого места программы, члены класса с атрибутом private доступны только внутри методов этого класса. Кроме того, в PascalABC.Net private члены видны отовсюду в пределах модуля, в котором определен класс.

После описания класса в разделе var можно объявить объектную переменную данного класса:

var

объектная_переменная: имя класса;

Класс в PascalABC.Net является ссылочным типом, т.е. объектная переменная хранит ссылку на данные объекта в памяти. Память для данных объекта выделяется динамически с

помощью следующего конструктора класса:

объектная_переменная := new имя_класса;

1 В PascalABC.Net имеется еще два модификатора доступа: protected (защищенный) и internal (внутренний) (см. справочную систему).

137

При этом в объектную переменную будет записана ссылка на область памяти, выделенную под данные объекта оператором new. При присваивании объектных переменных типа класс копируется только ссылка на объект, таким образом на один и тот же объект может ссылаться несколько объектных переменных.

1.3. Поля, методы и свойства

Членами класса в PascalABC.Net могут быть поля, методы и свойства.

Поле – это переменная, входящая в состав объекта. Поля описываются в классе аналогично описанию обычных переменных. Каждый объект данного класса содержит свой уникальный экземпляр поля. Обращение к конкретному полю осуществляется так:

объектная_переменная.имя_поля

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

Все объекты данного класса имеют одни и те же методы. Для вызова метода используется оператор вида

объектная_переменная.имя_метода(параметры);

Рассмотрим следующий пример:

type

complex = class public

Re: Real; //поле Im: Real; //поле

function a_b_s: Real; //метод end;

var

z: complex; //объектная переменная

138

//описание метода a_b_s function complex.a_b_s: Real; begin

a_b_s := sqrt(Re*Re + Im*Im); end;

begin

z := new complex; //создаем объект z.Re := -0.3; //Изменяем поля Re и Im z.Im := 0.2; writeln(z.a_b_s);//вызываем метод a_b_s

end.

Здесь был объявлен класс complex, членами которого являются поля Re и Im (действительная и мнимая часть комплексного числа) и метод a_b_s (функция, возвращающая модуль комплексного числа). Тело функции a_b_s можно было описать сразу внутри интерфейса класса. В данном примере показан другой вариант, когда полное описание метода дано вне класса, при этом имя метода должно предваряться именем класса с последующей точкой.

Методы делятся на классовые и экземплярные. Объявление классового метода начинается с ключевого слова class. Экземплярные методы можно вызывать только через пере- менную-объект класса (как в предыдущем примере). Классовые же методы не связаны с конкретным экземпляром класса; их следует вызывать в виде:

имя_класса.имя_метода(параметры)

Свойство – это интерфейс доступа к полю, позволяющий выполнить некоторые действия при доступе к полю на чтение или запись. Со свойством ассоциированы спецификаторы доступа read и write, определяющие соответственно, что происходит при чтении и записи поля.

Свойство объявляется в классе следующим образом:

property имя_свойства: тип read get_метод write set_метод;

139

В каждом объявлении свойства должен присутствовать по меньшей мере один спецификатор чтения или записи. Как правило, каждое свойство связано с некоторым полем класса и возвращает значение этого поля с помощью функции чтения (get-метод), а меняет – с помощью процедуры записи (setметод). Фактически, значение свойства хранится в поле свойства (т.е. в экземпляре поля объекта). Свойства сами по себе не хранят никаких значений и только служат интерфейсом между приватными данными объекта и кодом остальной части программы. Таким способом осуществляется сокрытие данных: к приватным членам объекта некоторого класса доступ осуществляется только при помощи методов данного класса. Большинство свойств делают публичными, поскольку к ним необходим доступ из любой части программы.

Функция чтения и процедура записи должны быть методами данного класса, они должны иметь следующий вид:

//функция чтения

function имя_get_метода: тип; begin

имя_метода := имя_поля; end;

//процедура записи

procedure имя_set_метода(значение: тип); begin

имя_поля := значение; end;

Метод get вызывается всякий раз, когда осуществляется чтение значения свойства, например, когда это свойство стоит справа от оператора присваивания:

Переменная:= объектная_переменная.имя_свойства;

Метод set вызывается каждый раз при изменении свойства, например, при выполнении оператора присваивания

140