- •Логические данные
- •Символьные данные
- •Хранение текста
- •Арифметические данные
- •Данные с фиксированной точкой
- •1111111101000111(2) - Инвертируем биты - 0000000010111000(2)
- •Данные с плавающей точкой
- •Простейшие приемы анализа погрешностей.
- •Методы оптимизации
- •Данные системы Turbo Pascal
- •Способы вычисления логических операций
- •Подпрограммы и их параметры
- •Способы передачи параметров
- •Структурное программирование, управляющие конструкции, пошаговая детализация.
- •Рекурсия и итерация
- •Метод итераций (повторений)
- •Метод инварианта цикла.
- •Метод инвариантной функции.
- •Метод индуктивной функции.
- •Защитное программирование
- •Абстрактные типы данных
- •Использование объектных средств
- •Динамические структуры данных
- •Языки и грамматики
- •Расширение нотации Бэкуса-Наура.
- •Интерпретатор математических формул, реализованный на основе метода Дейкстры.
- •Абстрактные структуры данных.
- •Часть 2 Последовательность.
- •Динамический вектор.
- •Множество
- •Нагруженное множество
- •Итераторы.
Использование объектных средств
Во-первых, не нужно путать объектное программирование и объектно-ориентированное программирование(ООП). Первое является лишь частью такого общего понятия как ООП. ООП базируется на таких понятиях как инкапсуляция, наследование и полиморфизм. В смысл всех этих слов вам вникать пока не нужно, поэтому вы можете сразу их забыть.
В объектном программировании используется лишь понятие объекта. Что он из себя представляет? Подобно обыкновенной записи Record, объект содержит данные различных типов. Но в отличие от записи он может содержать процедуры и функции Паскаля для работы с полями объекта (эти функции и процедуры называют методами работы над объектом). Свойство объектов содержать и поля данных и подпрограммы их обработки называют инкапсуляцией.
Надо учесть, что желательно запрещать доступ к полям данных кроме как через методы этого объекта (иначе это считается плохим тоном). Правда, есть исключения (т.к. это ограничение иногда может существенно сказаться на эффективности программы и замедлить ее), поэтому иногда открывают доступ к полям. Перепишем модуль из прошлого параграфа с использованием объектного программирования:
unit ATable;
interface
{$N+}
Type _Month = (jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec);
_ind1 = _Month;
_ind2 = integer;
_elem = single;
PTab = ^CTab;
CTab = object
public {общеоступные поля данных и методы объекта, они могут
свободно вызываться программистом в его программах}
constructor Init(Low1,High1:_Ind1; Low2,High2:_Ind2; x:_elem);
destructor Done; virtual;
function GetLow1:_ind1;
function GetLow2:_ind2;
function GetHigh1:_ind1;
function GetHigh2:_ind2;
procedure Get(i1:_ind1; i2:_ind2;x:_elem);
procedure put(i1:_ind1; i2:_ind2;x:_elem);
private {эта директива в описании объекта открывает секцию
описания скрытых полей и методов. Перечисленные в этой
секции элементы объекта "не видны" программисту,если
этот объект он получил в рамках TPU-модуля. Скрываются
те поля и методы к которым программист (в его же
интересах!) не должен иметь непосредственного доступа.
В нашем примере он не может произвольно менять значения
индексов и указатель на массив, т.к. это может привести
к печальным последствиям. Кроме этого пользователь не
может сам вызвать служебную процедуру Failure}
procedure failure(n:word);
private
l1, h1:_ind1;
l2, h2:_ind2;
size1, size2:word;
p:pointer;
end;
Implementation
{$Q+,R-}
uses crt; {подключаем библиотеку crt для пользования процедурой
очистки экрана}
type
al = array[0..0] of _elem; {тип-массив для хранения строк массива}
pal = ^al; {указатель на строку массива}
apal = array[0..0] of pal; {тип массив для хранения указателей на
строки массива}
papal = ^apal; {указатель на apal, нужен в этой программе
исключительно для приведения типов, см.ниже}
procedure CTab.Failure;
{Обратите внимание, что при описании методов имя метода дополняется
спереди именем объекта, т.е. используется составное имя метода.
Кроме этого список аргументов передаваемых подпрограмме можно
здесь опускать}
begin
ClrScr; {очистим экран, хотя надо ли это делать - вопрос весьма
спорный, иногда надо видеть, что было на экране до того
как программа выдала ошибку}
writeln('Ошибка # ',n:1); {печатаем номер ошибки}
case n of {расшифровываем код ошибки}
1:writeln('Недостаточно памяти для инициализации таблицы');
2:writeln('Неверные границы');
3:writeln('Неверные индексы при чтении');
4:writeln('Неверные индексы при записи');
end;
halt(1);{выходим мз программы}
{можно улучшить эту процедуру, если она будет выводить метод
объекта в котором возникла ошибка}
end;
constructor CTab.Init;
{Конструктор - это особый вид процедур. Конструкторы предназначены
для создания конкретного экземпляра объекта. Объет может иметь
достаточно много конструкторов, например, можно создать конструктор
копирования объета. Конкретная задача конструктора - заполнение
полей объекта данными}
var k:longint;
i,j:word;
begin
{проверим индексы на соответствие}
if (Low1>High1) or (Low2>High2) then Failure(2);
{заполняем поля объекта}
l1:=Low1; h1:=High1; size1:=ord(h1)-ord(l1)+1;
l2:=Low2; h2:=High2; size2:=ord(h2)-ord(l2)+1;
{делаем стандартные проверки на вмещение массива в сегмент}
k:=longint(size1)*Sizeof(pal);
if (k>65520) or (k>MaxAvail) then Failure(1);
GetMem(p,k); {выделяем память для массива указателей}
k:=longint(size2)*Sizeof(_elem);
if k>65520 then Failure(1);
{выделяем память для size1 строк матрицы каждая размером, k-байт}
for i:=0 to (size1-1) do
begin
if k>MaxAvail then Failure(1);
GetMem(papal(p)^[i],k);
end;
{Заполняем матрицу элементом x}
for i:=0 to (size1-1) do
for j:=0 to (size2-1) do papal(p)^[i]^[j]:=x;
end;
destructor CTab.Done;
{Деструктор нужен для уничтожения экземпляра объекта, вся память
которую взяли в конструкторе должна быт возвращена в деструкторе}
var k:longint;
i,j:word;
begin
{освобождаем память}
k:=size2*Sizeof(_elem);
for i:=0 to (size1-1) do FreeMem(papal(p)^[i],k);
k:=Size1*Sizeof(pal);
FreeMem(p,k);
{следующие операторы не обязательны и введены для того, чтобы
объект смог при вызове его методов выдать ошибку}
p:=nil; size1:=0; size2:=0; l1:=_ind1(1); h1:=_ind1(0);
l2:=_ind2(1); h2:=_ind2(0);
end;
function CTab.GetLow1;
{Функция возвращает нижнюю границу первого индекса}
begin GetLow1:=l1; end;
function CTab.GetLow2;
{Функция возвращает нижнюю границу второго индекса}
begin GetLow2:=l2; end;
function CTab.GetHigh1;
{Функция возвращает верхнюю границу первого индекса}
begin GetHigh1:=h1; end;
function CTab.GetHigh2;
{Функция возвращает верхнюю границу второго индекса}
begin GetHigh2:=h2; end;
procedure CTab.Get;
{Функция возвращает элемент}
begin
{Проверяем индексы на принадлежность матрице}
if (i1<l1) or (i1>h1) or (i2<l2) or (i2<h2) then Failure(3);
x:=papal(p)^[ord(i1)-ord(l1)]^[ord(i2)-ord(l2)];
{Т.к. p - нетипизированный указатель, то мы сначала приводим его к
типу papal, а потом обращаемся к получившемуся оператору так, как
будто это был бы указатель типа papal}
end;
procedure CTab.Put;
{Функция кладет элемент в матрицу}
begin
{Проверяем индексы на принадлежность матрице}
if (i1<l1) or (i1>h1) or (i2<l2) or (i2<h2) then Failure(4);
papal(p)^[ord(i1)-ord(l1)]^[ord(i2)-ord(l2)]:=x;
end;
begin
{часть инициализации пустая}
end.