Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

МЕТАКЛАССЫ

Delphi , Технологии , Объектно-ориентированное программирование

МЕТАКЛАССЫ

ССЫЛКИ НА КЛАССЫ

Язык Object Pascal позволяет рассматривать классы как своего рода объекты, которыми можно манипулировать в программе. Такая возможность рождает новое понятие — класс класса; его принято обозначать термином метакласс.
Для поддержки метаклассов введен специальный тип данных — ссылка на класс (class reference). Он описывается с помощью словосочетания class of, например:
Code:
type
TResourceGaugeClass = class of TResourceGauge;
 
Переменная типа TResourceGaugeClass объявляется в программе обычным образом:
Code:
var
ClassRef: TResourceGaugeClass;
 
 
Значениями переменной ClassRef могут быть класс TResourceGauge и все порожденные от него классы. Допустимы, например, следующие операторы:
Code:
ClassRef := TResourceGauge;
ClassRef := TDiskGauge;
ClassRef := TMemoryGauge;
 
По аналогии с тем, как для всех классов существует общий предок TObject, у ссылок на классы существует базовый тип TCIass:
Code:
type TCIass = class of TObject;
 
Переменная типа TCIass может ссылаться на любой класс.
Практическая ценность ссылок на классы состоит в возможности создавать программные модули, работающие с любыми классами объектов, даже с теми, которые еще не разработаны.
 

МЕТОДЫ КЛАССОВ

Метаклассы привели к возникновению нового типа методов — методов класса. Метод класса оперирует не экземпляром объекта, а непосредственно классом. Он объявляется как обычный метод, но перед словом procedure или function записывается зарезервированное слово class, например:
Code:
type
TResourceGauge = class
    ...
   class function GetClassName : string;
end;
 
Псевдопараметр Self, передаваемый в метод класса, содержит не ссылку на объект, а ссылку на класс, поэтому в теле метода нельзя обращаться к полям, методам и свойствам объекта. Зато можно вызывать другие методы класса, например:
Code:
class function TResourceGauge.GetClassName: string;
begin
Result := ClassName;
end;
 
Метод ClassName объявлен в классе TObject и возвращает имя класса, к которому применяется. Очевидно, что надуманный метод GetClassName просто дублирует эту функциональность для класса TResourceGauge и всех его наследников.
Методы класса применимы и к классам, и к объектам. В обоих случаях в параметре Self передается ссылка на класс объекта. Пример:
Code:
var
Gauge: TResourceGauge;
S: string;
begin
{ Вызов метода с помощью ссылки на класс }
S := TDiskGauge.GetClassName; { S получит значение 'TDiskGauge' }
Gauge := TDiskGauge.Create('С');
{ Вызов метода с помощью ссылки на объект }
S := Gauge.GetClassName;    { S получит значение 'TDiskGauge' }
end;
 
Методы классов могут быть виртуальными. Например, в классе TObject определен виртуальный метод класса Newlnstance. Он служит для распределения памяти под объект и автоматически вызывается конструктором. Его можно перекрыть в своем классе, чтобы обеспечить нестандартный способ выделения памяти для экземпляров. Метод Newlnstance должен перекрываться вместе с другим методом Freelnstance, который автоматически вызывается из деструктора и служит для освобождения памяти. Добавим, что размер памяти, требуемый для экземпляра, можно узнать вызовом предопределенного метода класса InstanceSize.
 

ВИРТУАЛЬНЫЕ КОНСТРУКТОРЫ

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

КЛАССЫ ОБЩЕГО НАЗНАЧЕНИЯ В DELPHI

Как показывает практика, в большинстве задач приходится использовать однотипные структуры данных: списки, массивы, множества и т.д. От задачи к задаче изменяются только их элементы, а методы работы сохраняются. Например, для любого списка нужны процедуры вставки и удаления элементов. В связи с этим возникает естественное желание решить задачу «в общем виде», т.е. создать универсальные средства для управления основными структурами данных. Эта идея не нова. Она давно пришла в голову разработчикам инструментальных пакетов, которые быстро наплодили множество вспомогательных библиотек. Эти библиотеки содержали классы объектов для работы со списками, коллекциями (динамические массивы с переменным количеством элементов), словарями (коллекции, индексированные строками) и другими «абстрактными» структурами. Для Delphi тоже разработаны аналогичные классы объектов. Их большая часть сосредоточена в модуле Classes. Наиболее нужными для вас являются списки строк (TStrings, TStringList) и потоки (TSream, THandleSream, TFileStream, TMemoryStream и TBIobStream). Рассмотрим кратко их назначение и применение.
 

КЛАССЫ ДЛЯ ПРЕДСТАВЛЕНИЯ СПИСКА СТРОК

Для работы со списками строк служат классы TStrings и TStringList. Они используются в библиотеке VCL повсеместно и имеют гораздо большую универсальность, чем та, что можно почерпнуть из их названия. Классы TStrings и TStringList служат для представления не просто списка строк, а списка элементов, каждый из которых представляет собой пару строка-объект. Если со строками не ассоциированы объекты, получается обычный список строк.
Класс TStrings используется визуальными компонентами и является абстрактным. Он не имеет собственных средств хранения строк и определяет лишь интерфейс для работы с элементами. Класс TStringList является наследником TStrings и служит для организации списков строк, которые используются отдельно от управляющих элементов. Объекты TStringList хранят строки и объекты в динамической памяти.
 
Свойства класса TStrings описаны ниже.
Count: Integer — число элементов в списке.
Strings[lndex: Integer]: string — обеспечивает доступ к массиву строк по индексу. Первая строка имеет индекс, равный 0. Свойство Strings является основным свойством объекта.
Objects[lndex: Integer]: TObject — обеспечивает доступ к массиву объектов. Свойства Strings и Objects позволяют использовать объект TStrings как хранилище строк и ассоциированных с ними объектов произвольных классов.
Text: string — позволяет интерпретировать список строк как одну большую строку, в которой элементы разделены символами #13#10 (возврат каретки и перевод строки),
 
Наследники класса TStrings иногда используются для хранения строк вида Имя=3начение, в частности, строк INI-файлов (см. гл. 6). Для удобной работы со строками такой структуры в классе TStrings дополнительно имеются следующие свойства.
Names[lndex: Integer]: string — обеспечивает доступ к той части строки, в которой содержится имя.
Values[const Name: string]: string — обеспечивает доступ к той части строки, в которой содержится значение. Указывая вместо Name ту часть строки, которая находится слева от знака равенства, вы получаете ту часть, что находится справа.
 
Управление элементами списка осуществляется с помощью следующих методов:
Add(const S: string): Integer — добавляет новую строку S в список и возвращает ее позицию. Новая строка добавляется в конец списка.
Add0bject(const S: string; AObject: TObject): Integer — добавляет в список строку S и ассоциированный с ней объект AObject. Возвращает индекс пары строка—объект.
AddStrings(Strings: TStrings) — добавляет группу строк в существующий список. Append(const S: string) — делает то же, что и Add, но не возвращает значения. Clear — удаляет из списка все элементы.
Delete(lndex: Integer) — удаляет строку и ассоциированный с ней объект. Метод Delete, так же как метод Clear, не разрушает объектов, т.е. не вызывает у них деструктор. Об этом вы должны позаботиться сами.
Equals(Strings: TStrings): Boolean — возвращает True, если список строк в точности равен тому, что передан в параметре Strings.
Exchange(lndex1, lndex2: Integer) — меняет два элемента местами.
GetText: PChar — возвращает все строки списка в виде одной большой нуль-терминированной строки.
lndex0f(const S: string): Integer — возвращает позицию строки S в списке. Если заданная строка в списке отсутствует, функция возвращает значение —1.
lndexOfName(const Name: string): Integer — возвращает позицию строки, которая имеет вид Имя=3начение и содержит в себе Имя, равное Name.
lndexOfObject(AObject: TObject): Integer — возвращает позицию объекта AObject в массиве Objects. Если заданный объект в списке отсутствует, функция возвращает значение —1.
lnsert(lndex: Integer; const S: string) — вставляет в список строку S в позицию Index.
lnsert0bject(lndex: Integer; const S: string; AObject: TObject) — вставляет в список строку S и ассоциированный с ней объект AObject в позицию Index.
LoadFromFile(const FileName: string) — загружает строки списка из текстового файла.
LoadFromStream(Stream: TStream) — загружает строки списка из потока данных (см. ниже).
Move(Curlndex, Newlndex: Integer) — изменяет позицию элемента (пары строка-объект) в списке.
SaveToFile(const FileName: string) — сохраняет строки списка в текстовом файле.
SaveToStream(Stream: TStream) — сохраняет строки списка в потоке данных.
SetText(Text: PChar) — загружает строки списка из одной большой нуль-терминированной строки.
 
Класс TStringList добавляет к TStrings несколько дополнительных свойств и методов, а также два свойства-события для уведомления об изменениях в списке. Они описаны ниже.
Свойства:
Duplicates: TDuplicates — определяет, разрешено ли использовать дублированные строки в списке. Свойство может принимать следующие значения: duplgnore (дубликаты игнорируются), dupAccept (дубликаты разрешены), dupError (дубликаты запрещены, попытка добавить в список дубликат вызывает ошибку).
Sorted: Boolean — если имеет значение True, то строки автоматически сортируются в алфавитном порядке.
 
Методы:
Find(const S: string; var Index: Integer): Boolean — выполняет поиск строки S в списке строк. Если строка найдена, Find помещает ее позицию в переменную, переданную в параметре Index, и возвращает True.
Sort — сортирует строки в алфавитном порядке.
 
События:
OnChange: TNotifyEvent — указывает на обработчик события, который выполнится при изменении содержимого списка. Событие OnChange генерируется после того, как были сделаны изменения.
OnChanging: TNotifyEvent — указывает на обработчик события, который выполнится при изменении содержимого списка. Событие OnChanging генерируется перед тем, как будут сделаны изменения.
Ниже приводится фрагмент программы, демонстрирующий создание списка строк и манипулирование его элементами:
Code:
var
Items: TStrings;
I: Integer;
begin
{ Создание списка }
Items := TStringList.Create;
Items.Add('Туризм');
Items.Add('Наука');
Items.Insert(1, 'Бизнес');
...
{ Работа со списком }
for I := 0 to Items. Count - 1 do
  Items[I] := Uppercase(Items [I]);
...
 { Удаление списка }
  Items.Free;
end;
 
 

КЛАССЫ ДЛЯ ПРЕДСТАВЛЕНИЯ ПОТОКА ДАННЫХ

В Delphi существует иерархия классов для хранения и последовательного ввода-вывода данных. Классы этой иерархии называются потоками. Потоки лучше всего представлять как файлы. Классы потоков обеспечивают различное физическое представление данных:
файл на диске, раздел оперативной памяти, поле в таблице базы данных (см. табл. 1).
 
Таблица 1.
Класс
Описание
TStream
Абстрактный поток, от которого наследуются все остальные. Свойства и методы класса TStream образуют базовый интерфейс потоковых объектов.
THandleStream
Поток, который хранит свои данные в файле. Для чтения-записи файла используется дескриптор (handle), поэтому поток называется дескрипторным. Дескриптор - это номер открытого файла в операционной системе. Его возвращают низкоуровневые функции создания и открытия файла.
TFileStream
Поток, который хранит свои данные в файле. Отличается от ThandleStream тем, что сам открывает (создает) файл по имени, переданному в конструктор.
TMemoryStream
Поток, который хранит свои данные в оперативной памяти. Моделирует работу с файлом. Используется для хранения промежуточных результатов, когда файловый поток не подходит из-за низкой скорости передачи данных.
TResourceStream
Поток, обеспечивающий доступ к ресурсам в Windows-приложении.
TBIobStream
Обеспечивает последовательный доступ к большим полям таблиц в базах данных.

 
Общие свойства:
Position: Longint — текущая позиция чтения-записи.
Size: Longint — текущий размер потока в байтах.
 
Общие методы:
CopyFrom(Source: TStream; Count: Longint): Longint — копирует Count байт из потока Source в свой поток.
Read(var Buffer; Count: Longint): Longint — читает Count байт из потока в буфер Buffer, продвигает текущую позицию на Count байт вперед и возвращает число прочитанных байт. Если значение функции меньше значения Count, то в результате чтения был достигнут конец потока.
ReadBuffer(var Buffer; Count: Longint) — читает из потока Count байт в буфер Buffer и продвигает текущую позицию на Count байт вперед. Если выполняется попытка чтения за концом потока, то генерируется ошибка.
Seek(0ffset: Longint; Origin: Word): Longint — продвигает текущую позицию в потоке на Offset байт относительно позиции, заданной параметром Origin. Параметр Origin может иметь одно из следующих значений: 0 — смещение задается относительно начала потока; 1 — смещение задается относительно текущей позиции в потоке; 2 — смещение задается относительно конца потока.
Write(const Buffer; Count: Longint): Longint — записывает в поток Count байт из буфера Buffer, продвигает текущую позицию на Count байт вперед и возвращает реально записанное количество байт. Если значение функции отличается от значения Count, то при записи была ошибка.
WriteBuffer(const Buffer; Count: Longint) — записывает в поток Count байт из буфера Buffer и продвигает текущую позицию на Count байт вперед. Если по какой-либо причине невозможно записать все байты буфера, то генерируется ошибка.
Ниже приводится фрагмент программы, демонстрирующий создание файлового потока и запись в него строки:
Code:
var
Stream: TStream;
S: AnsiString;
StrLen: Integer;
begin
{ Создание файлового потока }
Stream := TFileStream.Create('Sample.Dat', fmCreate);
...
{ Запись в поток некоторой строки }
StrLen := Length(S) * SizeOf(Char);
Stream.Write (StrLen, SizeOf (Integer) ) ; { запись длины строки }
Stream.Write (S, StrLen);              { запись символов строки }
...
{ Закрытие потока }
Stream.Free;
end;
 

итоги

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

Метаклассы и классы класса в языке Object Pascal позволяют создавать программные модули, которые могут работать с любыми классами объектов, даже если они еще не разработаны. Метаклассы также позволяют создавать виртуальные конструкторы, которые могут быть


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Объектно-ориентированное программирование ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-11-21 14:23:32/0.0072128772735596/0