ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 23.01.2025

Просмотров: 3171

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Процедура GetMem(P, Size) позволяет выделить в динамической памяти область размером Size байт, при этом адрес выделенной области присваивается переменной P.

Процедура FreeMem(P, Size) освобождает занятую область памяти с адресом, задаваемым оператором P и размером Size байт. После выполнения процедуры область памяти становится свободной, а значение указателя оказывается неопределенным.

Значение одного указателя можно присвоить другому. Указатели, ссылающиеся на объекты разных типов, сами являются разнотипными и для них недопустима операция присваивания.

Рассмотрим несколько типичных приемов работы с указателями. Пусть имеется описание:

type

PComplex= ^TComplex; { тип-указатель }

TComplex=record{ определение базового типа }

Re, Im: Real;

end;

AdrInt = ^Integer; { тип-указатель }

var

X: TComplex;

P1,P2,P3,P4: PComplex;

Adr:AdrInt;

тогда возможны следующие операции:

New(P1); { выделение памяти для типа TComplex }

New(Adr); { выделение памяти для типа Integer }

P2:=@X; { определение адреса переменной X }

P3:=P1; { присвоение значения другого указателя }

P4:=nil; { присвоение значения nil – «пустая» ссылка, не указывающая

ни на какой объект, «адресный ноль» }

X:=P1^; { переменной X присваивается значение

элемента, на который указывает P1 }

P3^:=X; { элементу, на который указывает P3,

присваивается значение переменной X }

X:=@Y; { X – адрес параметра Y }

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

Dispose(P1); { освобождение памяти от данных, на которые указывает P1 }

New(Adr);

Нетипизированные указатели. В языке Паскаль существует стандартный тип-указатель Pointer, не связанный с базовым типом. Нетипизированный указатель совместим с любым другим типом-указателем. Переменная типа Pointer содержит адрес объекта неопределенного типа.

Пусть имеются следующие описания:

var

p1: ^Char;

p2: ^Boolean;

pp:Pointer;

Использование указателей типа Pointer позволяет динамически размещать с одного адреса данные различных типов. Напомним, присваивание значения одного указателя другому возможно только между указателями объектов идентичного типа. В примере символьный и булевый тип занимает одинаковый объем памяти (1 байт), однако следующая запись некорректна:

p1:=p2;


Нетипизированный указатель совместим по присваиванию с указателем любого типа, поэтому присваивание между p1 и p2 можно выполнить опосредованно:

pp:=p2;

p1:=pp;

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


    1. Контрольные вопросы

  1. Перечислите порядковые типы. Опишите общие операции над порядковыми типами.

  2. Символьный тип. Как строятся кодовые таблицы?

  3. Приведите примеры создания и использования перечисляемого и интервального типа.

  4. Назначение и представление логического и битового типа.

  5. Перечислите наиболее грубые ошибки численных расчетов.

  6. Создание и применение указателей. Виды указателей и операции.

  1. 3. Объектные типы данных

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

    1. 3.1. Объявление и реализация классов

Для объявления классов (объектных типов) используется зарезервированное слово class. Определим некоторый класс графических примитивов TFigure следующим образом:

TFigure=class

fColor:Byte;

fThickness: Byte;

fCanvas: TCanvas;

procedure SetColor(Value: Byte);

procedure SetThickness(Value: Byte);

procedure PrepareCanvas;

end;

По принятому соглашению имена классов начинаются с заглавной буквы «T», имена полей данных начинаются с буквы «F», и поля класса объявляются до методов. Класс объединяет данные, представленные атрибутами (полями) и алгоритмы (методы) по их обработке.

В примере к полям данных класса относятся: поле fColor, хранящее код цвета, поле fThickness, задающее толщину линий и поле fCanvas, представляющее полотно, на котором будет происходить отображение графических примитивов.

Методы класса определяют действия, выполняемые над данными. Их совокупность характеризует функциональный аспект поведения класса. Методы представляют собой процедуры и функции, принадлежащие классу. К методам класса относится метод PrepareCanvas, выполняющий подготовку полотна к работе и два метода задания значений полей данных – SetColor и SetThickness.

Таким образом, в одной информационной структуре TFigure оказались объединены как исходные параметры, так и необходимые средства по выполнению их реализации. Такое объединение (сокрытие) данных и методов в качестве собственных ресурсов класса получило название инкапсуляции.


Для окончательного оформления шаблона требуется поместить класс в интерфейсный раздел модуля и дать реализацию всех методов:

unit figures;

Interface

type

TFigure = class

fColor: Byte;

fThickness: Byte;

fCanvas: TCanvas;

procedure SetColor(Value: Byte);

procedure SetThickness(Value: Byte);

procedure PrepareCanvas;

end;

Implementation

procedure TFigure.SetColor(Value: Byte);

begin

if fColor <> Value then

fColor:=Color;

end;

procedure TFigure.SetThickness(Value: Byte);

begin

if fThickness <> Value then

fThickness:=Value;

end;

procedure TFigure.PrepareCanvas;

begin

{ Подготовка полотна для рисования }

end;

end.

Методы SetColor и SetThickness выполняют присвоение внутреннему полю fColor и fThickness значения в том случае, если текущее значение отличается от передаваемого. К полям класса никогда не следует обращаться напрямую, а только посредством специальных методов, обеспечивающих корректность выполнения операции присваивания.

Теперь объявим переменную f класса TFigure:

var

f:TFigure;

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

f:=TFigure.Create;

Конструктор не объявлен в классе TFigure, однако присутствует в нем от класса TObject благодаря специальному механизму наследования классов друг от друга. В результате будет выделена область памяти в размере, необходимом для хранения объекта f. Обратите внимание, конструктор вызывается с помощью ссылки на тип, а не на экземпляр типа, в отличие от методов, которые всегда вызываются с помощью ссылки на экземпляр. Связано это с тем, что объект f на момент вызова конструктора еще не создан.

После создания объекта с ним можно работать:

uses figures;

var

f: TCircle;

begin

f:=TCircle.Create;

f.SetColor($FF);

f.SetThickness(1);

f.PrepareCanvas;

f.Free;

end.

После выполнения методов объект f следует удалить, чтобы он не занимал места в памяти. Удаление выполняет метод Destroy, определенный в классе TObject (базовом классе), но лучше использовать Free, т.к. он инкапсулирует вызов Destroy: в начале определяется, существует ли объект и только затем выполняется вызов Destroy. В противном случае метод Free ничего не делает.


Класс Figure можно модифицировать, например, явно добавить к методам конструктор Create с помощью зарезервированного слова constructor и деструктор Destroy с помощью зарезервированного слова destructor:

TFigure = class

...

constructor Create;

destructor Destroy;

end;

В конструкторе присваиваются полям начальные значения и создается объект полотна:

constructor TFigure.Create;

begin

fColor:=$FF;

fThickness:=1;

fCanvas:=TCanvas.Create;

end;

В деструкторе обычно выполняются действия, связанные с освобождением задействованных в течение работы объекта ресурсов:

destructorTFigure.Destroy;

begin

{ Освобождение ресурсов, используемых в работе объекта }

fCanvas.Free;

end;