Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / Pascal и Delphi / Иллюстрированный самоучитель по Delphi 6 / Часть II . Язык Object Pascal /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Варианты - Программирование от RIN.RU
Варианты



Пользовательские варианты


Стандартный вариант может хранить только одно из значений, указанных в табл. 10.2. В версии Delphi 6 появились так называемые пользовательские варианты, которые фактически снимают ограничения на характер значений варианта.


Чтобы познакомиться со свойствами новых вариантов, воспользуемся одним из них - вариантом, способным хранить комплексные числа, преобразовывать их в другие типы и осуществлять над ними нужные действия. Как мы увидим дальше, создание пользовательского варианта может быть весьма трудоемким делом - все зависит от сложности хранимых в нем данных. Мы воспользуемся вариантом, созданным разработчиками Delphi и включенным в модуль VarCmplx.


Создайте такой обработчик bbRunClick:


uses VarCmplx; // Эта ссылка обязательна!
procedure TfmExample.bbRunClick(Sender: TObject);


var
VI, V2: Variants- begin
// Создаем два случайных комплексных числа:
VI := VarComplexCreate(Trunc(Random*1000)/100,
Trunc(Random*1000)/100) ;
V2 := VarComplexCreate(Trunc(Random*1000)/100,
Trunc(Random*1000)/100) ;
with mmOutput.Lines do
begin
// Пустая строка-разделитель
Add ( ' ' ) ;
Add('1-e число: '# 9+V1) ;
Add('2-е число: '#9+V2);
Add('Сложение'#9+(V1+V2));
Add('Вычитание'#9+(V1-V2));
Add('Умножение'# 9+(VI*V2)) ;
Add('Деление'#9#9+(V1/V2))
end
end;


Небольшой комментарий: сложная конструкция Trunc (Random*1000) /100 понадобилась только для того, чтобы реальные и мнимые части комплексных чисел содержали по три значащих цифры.


Вид экрана работающей программы показан на рис. 10.1. Как видим, новый вариант легко справляется с поддержкой комплексных чисел: функция VarComplexCreate создает вариант, содержащий комплексное число, а дальнейшее поведение варианта -стандартное (он поддерживает математические операции и преобразование к строковому типу). Однако эта легкость обманчива: исходный текст модуля VarCmplx, который, собственно, и придал варианту дополнительные свойства (по умолчанию располагается в файле Source\Rtl\Common\VarCmplx.pas), содержит более 30000 байт..


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



Рис. 10.1. Демонстрация комплексных вариантов




Создание пользовательского варианта проходит в три этапа.


  1. Сначала в записи rvarData размещаются новые данные или ссылка на них.

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

  3. Создаются вспомогательные методы для объявления потомков нового класса и определения их типов.


В результате перечисленных шагов вы получаете полноценный вариант, обогащенный новыми свойствами: он может хранить не только те значения, которые перечислены в табл. 10.2, но и любые другие, в том числе свойства и методы! (В этом последнем случае наследником для исполняемого класса нового варианта вместо TCustomVariantType является TInvokeableVariantType или TPublishableVariantType.)


Размещение в варианте новых значений


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


TComplexVarData = packed record
VType: TVarType;
Reserved1, Reserved2, Reserved3: Word;
VComplex: TComplexData;
Reserved4: Longint;
end;


Такая запись лишь сохраняет 16-байтную структуру TVarData, помещая в поле VComplex ссылку на объект класса TComplexData. Собственно комплексные числа хранятся в полях достаточно сложного класса:


type
TComplexData = class(TPersistent) private
FReal, FImaginary: Double;
end;


В этом классе предусмотрены многочисленные методы, управляющие новыми данными. Так, простой вызов VarComplexCreate приводит к срабатыванию нескольких методов, создающих объект VComplex и наполняющих его поля:


procedure VarComplexCreateInto (var ADest: Variant;


const AComplex: TComplexData);
begin
VarClear(ADest);
TComplexVarData(ADest).VType := VarComplex;
TComplexVarData(ADest).VComplex := AComplex;
end;


function VarComplexCreate(const AReal, AImaginary: Double): Variant;
begin
VarComplexCreateInto(Result,
TComplexData.Create(AReal, AImaginary)) ;
end;



Примечание

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




Создание наследника TCustomVariantType


Тип TCustomVariantType или его ближайшие Наследники TPublishableVariantType и TInvokeableVariantType Содержат методы и свойства, которые в нужный момент вызывают методы и свойства объекта VComplex для осуществления тех или иных преобразований. В модуле varcmpix объявляется такой класс:


type


TComplexVariantType = class(TPublishableVariantType, IVarStreamable)


protected
function LeftPromotion(const V: TVarData;
const Operator: TVarOp;
out RequiredVarType: TVarType): Boolean; override;
function RightPromotion(const V: TVarData;
const Operator: TVarOp;
out RequiredVarType: TVarType): Boolean; override;
function Getlnstance(const V: TVarData): TObject; override;


public
procedure Clear(var V: TVarData);
override;
function IsClear(const V: TVarData): Boolean; override;
procedure Copy(var Dest: TVarData;
const Source: TVarData;
const Indirect: Boolean);
override;
procedure Cast(var Dest: TVarData;
const Source: TVarData); override;


procedure CastTo(var Dest: TVarData;
const Source: TVarData;
const AVarType: TVarType); override;
procedure BinaryOp(var Left: TVarData;
const Right: TVarData;
const Operator: TVarOp); override;
procedure UnaryOp(var Right: TVarData;
const Operator: TVarOp); override;
function CompareOp(const Left: TVarData;
const Right: TVarData;
const Operator: Integer): Boolean; override;
procedure Streamin(var Dest: TVarData;
const Stream: TStream) ;
procedure StreamOut(const Source: TVarData;
const Stream: TStream) ;
end;


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


Задача этого класса - дать единообразные команды, способные интерпретироваться объектом vcomplex как команды преобразования типа хранящихся данных, их сравнения, реализации над ними тех или иных операций, наконец, записи их в поток и чтения из него. Например, метод cast этого класса вызывается для преобразования других типов значений к комплексному типу, метод castTo - для обратного преобразования, метод BinaryOp реализует бинарную операцию, a Unarydp - унарную и т. д.


Еще раз подчеркну, что основная работа (например, по выполнению бинарных операций) реализуется методами класса TComplex-Data. Класс TCompiexVariantType перекрывает абстрактные методы своего родителя, подключая TComplexData к решению той или иной проблемы.


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


initialization
ComplexVariantType := TCompiexVariantType.Create;
finalization
FreeAndNil(ComplexVariantType);




Создание вспомогательных методов


Несмотря на интенсивное использование классов TCompiexData и TCompiexVariantType, эти классы в конечном счете остаются скрытыми от пользователя нового варианта за счет набора вспомогательных методов, таких как VarComplexCreate, VarIsComplex, VarAsComplex и т. п., которые преобразуют обычные процедурные вызовы в вызовы методов и обращения к свойствам соответствующих классов.

<<<  Назад
 1  2  3 


 8  Комментарии к статье  8 8  Обсудить в чате

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь