Виды методов классов. Создание и удаление объектов. Размещение данных объектов в памяти. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Виды методов классов. Создание и удаление объектов. Размещение данных объектов в памяти.



Реализация методов

После того как в модуле описан новый класс, в нижеследующей части исходного

текста необходимо описать реализацию всех его методов (если они есть). Чтобы

компилятор понял, к какому классу относится конкретная подпрограмма, перед ее

названием указывается имя соответствующего класса и точка:

function TMyClass.GetCount: Integer;

Begin

Result:= Count

end;

Заголовок подпрограммы должен в точности соответствовать заголовку, указан-

ному в описании класса.

Типы методов

В Паскале каждый метод класса может иметь дополнительные характеристики,

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

Статические методы

Все методы по умолчанию считаются статическими. Это означает, что их вызов

будет происходить в соответствии с принципом полиморфизма.

Например, описаны два класса.

type TCar = class(TObect]

procedure Move;

end;

TMAZ = class(TCar)

procedure Move;

end;

var Car: TCar;

MAZ: TMAZ;

Begin

MAZ:= TMAZ.Create;

Car:= TCar.Create;

MAZ.Move;

// вызовется метод Move класса TMAZ

Car.Move;

// вызовется метод Move класса TCar

Однако переменную Car можно инициализировать объектом типа TMAZ:

Car. Free,-

Car:= TMAZ.Create;

Если теперь обратиться к методу Move:

92 Урок 5. Язык Delphi (Object Pascal) и его использование

Car.Move;

то вызовется метод TCar.Move, так как переменная Саг, реально храня экземпляр

класса TMAZ, описана как ТСаг. Обращаться к методам и полям переменной Саг, как

к методам и полям типа TMAZ, можно, только явно выполнив приведение типа:

TMAZ(Car). Об этом рассказывалось при описании оператора присваивания:

TMAZ(Car].Move;

При этом вызовется метод Move, относящийся к классу TMAZ.

Если при вызове метода Move класса TMAZ необходимо предварительно вызвать роди-

тельский метод, выполняющий общие для всех автомобилей действия, в реализации

метода Move надо указать этот вызов с помощью ключевого слова inherited.

procedure TMAZ.Move,-

begin

inherited Move,-

end;

Виртуальные и динамические методы

Статические _____методы удобны, когда в программе заранее известно, какие типы

объектов будут использоваться, и приведения типов, как правило, не требуется.

Б ряде случаев, особенно в крупных проектах, часто приходится хранить в перемен-

ных объекты-наследники (как в примере с ТСаг и TMAZ), причем конкретный тип

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

методов — виртуальные методы (для их описания существует зарезервированное

слово virtual). Описать виртуальный метод можно так.

type TCar = class(TObect)

procedure Move; virtual;

end;

Перегружаемые методы

Ранее рассматривались перегружаемые подпрограммы, имеющие одинаковые имена,

но различные типы параметров. Компилятор автоматически определяет, какую кон-

кретно подпрограмму надо вызывать в зависимости от типов ее аргументов.

Имеется в Паскале аналогичная возможность и для методов.

type Tl ~ class(TObject)

procedure Sum(X,Y: Integer); overload;

end;

type T2 = class(Tl)

procedure SumfX,Y: Real]; overload;

end;

var CT: T2,-

CT:= T2. Create;

CT.Sum(2,2);

// вызывается Tl.Sum()

CT.Sum(2.0,2.0);

// вызывается T2.Sum()

Перегружаемым может быть и виртуальный метод. Чтобы у компилятора не воз-

никало претензий к программисту по поводу несоответствия заголовков перегружа-

94 Урок 1: Язык Delphi (Object Pascal) него использование

емых виртуальных методов, в наследуемом методе надо дополнительно указать

ключевое слово reintroduce:

type Tl = class(TObjecti

procedure Sum(X,Y: Integer); overload; virtual;

end;

type T2 = class(Tl)

procedure Sura(X,Y: Real); reintroduce; overload;

end,-

Создание и удаление объекта

Помимо обычных методов, в Паскале имеются так называемые методы классов.

Их особенность заключается в том, что методы классов разрешается вызывать,

используя для этого вызова не объект, а класс. Это означает, что подобные методы не

90 Урок 1. Язык Delphi (Objecl Pascal) и его использование

могут обращаться к полям класса — ведь поля существуют, только когда существует

объект (экземпляр класса), а методы в виде программного кода, созданного на этапе

компиляции, присутствуют в памяти компьютера постоянно.

Однако вызывать таким образом можно только методы, описанные с помощью

ключевого слова class, указываемого перед заголовком ] Lсопрограммы. Это нужно,

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

метод, в частности, не происходит ли в нем обращения к полям и свойствам класса.

type TMyClass = class

Item.: integer;

public

class function Sozdanie: integer;

end;

В заголовке реализации функции Sozdanie также надо указать ключевое слово class:

class function TMyClass.Sozdanie: integer;

Begin

end;

Так как методы классов не привязаны к объектам, то их можно вызывать, указы-

вая название класса, а не объекта:

N:= TMyClass.Sozdanie;

Это одна из фундаментальных возможностей Паскаля, благодаря которой можно,

в частности, динамически (во время работы программы) ____________создавать объекты и запи-

сывать ссылки на них в переменные. Данный подход активно используется для

задания переменным-классам начальных значений. У базового класса TObject име-

ется метод Create (в реальности это конструктор, выполняющий вес необходимые

действия по запросу памяти и начальной инициализаций), который практически

всегда применяется при создании объектов.

var MyClass: TMyClass;

MyClags:= TMyClass.Create;

Это стандартный способ создания объектов и инициализации указывающих на них

переменных. Пока таким способом и переменную не записан указатель на объект,

обращаться к этой переменной нельзя.

Когда работа с объектом полностью закончена, занятую им намять необходимо

освободить. Для этого существует специальный метод Free, который уничтожает

объект, автоматически вызывая его деструктор,

MyClass.Free;

Методы

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

procedure TDelimitedReader.SetActive(const AActive: Boolean);begin if AActive then Reset(FileVar) // Открытие файла else CloseFile(FileVar); // Закрытие файлаend;

 

Обратите внимание, что внутри методов обращения к полям и другим методам выполняются как к обычным переменным и подпрограммам без уточнения экземпляра объекта. Такое упрощение достигается путем использования в пределах метода псевдопеременной Self (стандартный идентификатор). Физически Self представляет собой дополнительный неявный параметр, передаваемый в метод при вызове. Этот параметр и указывает экземпляр объекта, к которому данный метод применяется. Чтобы пояснить сказанное, перепишем метод SetActive, представив его в виде обычной процедуры:

procedure TDelimitedReader_SetActive(Self: TDelimitedReader; const AActive: Boolean);begin if AActive then Reset(Self.FileVar) // Открытие файла else CloseFile(Self.FileVar); // Закрытие файлаend;

 

Согласитесь, что метод SetActive выглядит лаконичнее процедуры TDelimitedReader_SetActive.

Практика показывает, что псевдопеременная Self редко используется в явном виде. Ее необходимо применять только тогда, когда при написании метода может возникнуть какая-либо двусмысленность для компилятора, например при использовании одинаковых имен и для локальных переменных, и для полей объекта.

Если выполнить метод SetActive,

Reader.SetActive(True);

то обрабатываемый файл будет открыт. При этом неявный параметр Self будет содержать значение переменной Reader. Такой вызов реализуется обычными средствами процедурного программирования приблизительно так:

TDelimitedReader_SetActive(Reader, True);

Методы, обслуживающие несколько свойств

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

В следующем примере уже известный Вам метод GetItem обслуживает три свойства: FirstName, LastName и Phone:

type TDelimitedReader = class... property FirstName: string index 0 read GetItem; property LastName: string index 1 read GetItem; property Phone: string index 2 read GetItem; end;

 

Обращения к свойствам FirstName, LastName и Phone заменяются компилятором на вызовы одного и того же метода GetItem, но с разными значениями параметра Index:

var Reader: TDelimitedReader;... Writeln(Reader.FirstName); // Эквивалентно: Writeln(Reader.GetItem(0)); Writeln(Reader.LastName); // Эквивалентно: Writeln(Reader.GetItem(1)); Writeln(Reader.Phone); // Эквивалентно: Writeln(Reader.GetItem(2));...

 

Обратите внимание, что метод GetItem обслуживает как свойство-массив Items, так и свойства FirstName, LastName и Phone. Удобно, не правда ли!

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

type TDelimitedReader = class // Поля FFile: TextFile; FItems: array of string; FActive: Boolean; FDelimiter: Char; // Методы чтения и записи свойств procedure SetActive(const AActive: Boolean); function GetItemCount: Integer; function GetEndOfFile: Boolean; function GetItem(Index: Integer): string; // Методы procedure PutItem(Index: Integer; const Item: string); function ParseLine(const Line: string): Integer; function NextLine: Boolean; // Конструкторы и деструкторы constructor Create(const FileName: string; const ADelimiter: Char = ';'); destructor Destroy; override; // Свойства property Active: Boolean read FActive write SetActive; property Items[Index: Integer]: string read GetItem; default; property ItemCount: Integer read GetItemCount; property EndOfFile: Boolean read GetEndOfFile; property Delimiter: Char read FDelimiter; end; { TDelimitedReader } constructor TDelimitedReader.Create(const FileName: string; const ADelimiter: Char = ';');begin AssignFile(FFile, FileName); FActive:= False; FDelimiter:= ADelimiter;end; destructor TDelimitedReader.Destroy;begin Active:= False;end; function TDelimitedReader.GetEndOfFile: Boolean;begin Result:= Eof(FFile);end; function TDelimitedReader.GetItem(Index: Integer): string;begin Result:= FItems[Index];end; function TDelimitedReader.GetItemCount: Integer;begin Result:= Length(FItems);end; function TDelimitedReader.NextLine: Boolean;var S: string; N: Integer;begin Result:= not EndOfFile; if Result then // Если не достигнут конец файла begin Readln(FFile, S); // Чтение очередной строки из файла N:= ParseLine(S); // Разбор считанной строки if N <> ItemCount then SetLength(FItems, N); // Отсечение массива (если необходимо) end;end; function TDelimitedReader.ParseLine(const Line: string): Integer;var S: string; P: Integer;begin S:= Line; Result:= 0; repeat P:= Pos(Delimiter, S); // Поиск разделителя if P = 0 then // Если разделитель не найден, то считается, что P:= Length(S) + 1; // разделитель находится за последним символом PutItem(Result, Copy(S, 1, P - 1)); // Установка элемента Delete(S, 1, P); // Удаление элемента из строки Result:= Result + 1; // Переход к следующему элементу until S = ''; // Пока в строке есть символыend; procedure TDelimitedReader.PutItem(Index: Integer; const Item: string);begin if Index > High(FItems) then // Если индекс выходит за границы массива, SetLength(FItems, Index + 1); // то увеличение размера массива FItems[Index]:= Item; // Установка соответствующего элементаend; procedure TDelimitedReader.SetActive(const AActive: Boolean);begin if Active <> AActive then // Если состояние изменяется begin if AActive then Reset(FFile) // Открытие файла else CloseFile(FFile); // Закрытие файла FActive:= AActive; // Сохранение состояния в поле end;end;

 

 

 



Поделиться:


Последнее изменение этой страницы: 2017-02-21; просмотров: 330; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 35.175.232.163 (0.022 с.)