Главная » Delphi » Delphi 2006 – Перегрузка операций

0

Очень мощная возможность перегрузки различных арифметических, логических и битовых операций, схожая с аналогичными возможностями Си++, открывает перед пользователями Delphi большие перспективы — гораздо более внушительные, нежели может показаться на первый взгляд. Так, сама по себе перегрузка операций позволяет с помощью стандартного синтаксиса записывать в общепринятом виде выражения над произвольными типами данных. Однако на самом деле перегрузка операторов — значительно более глубокая концепция.

Допустим, мы хотим создать в программе новый класс, но выполнять действия над ним желательно не только обращением к его полям и методам, но и с помощью обычных «арифметических» операций, записываемых символами «+»,«-» и тому подобных. При этом смысл таких операций может, конечно, кардинально отличаться от исходного. Пусть наш класс TVector представляет собой вектор произвольной длины (фактически, динамический массив). Мы хотим создать в программе операции сложения, вычитания, умножения и деления таких векторов с помощью наглядной записи.

11- type TVector = claee

public

FVector: array of Double; constructor Create(len: Integers- end;

constructor TVector.Create(len: Integer);

var i: Integer;

begin

inherited Create;

SetLength(FVector, len); // длина массива

// обнуляем:

for i := 0 to len-1 do

FVector[i] := 0; end;

При создании объекта-вектора в конструкторе надо указать количество его элементов.

Теперь в описание класса необходимо включить указание на перегружаемую операцию сложения, применимую для экземпляров данного класса. Для этого с помощью ключевых слов class operator и одного из названий перегружаемой операции надо добавить соответствующий заголовок. Дополним описание класса также функцией len, возвращающей текущее число элементов в нем.

type TVector = class public

FVector: array of Double;

class operator Add( a,b: TVector ): TVector;

constructor Create(len: Integer); function len: Integer;

end;

// длина вектора

function TVector.len: Integer;

begin

Result := Length(FVector); end;

Название перегружаемой функции-оператора Add для операции сложения выбирается не произвольно, а в соответствии с документацией (раздел Operator Overloads .NET). Так, название Add соответствует перегружаемому сложению (реально же может выполняться любое действие, которое разработчик определит для оператора +).

Реализация функции оператора Add может быть такой.

class operator TVector.Add(a, b: TVector): TVector; var

i, n: Integer; v: TVector; begin

n := Math.min(a.len, b.len); v := TVector.Create(n); for i := 0 to n-1 do

v.FVector[i] := a.FVector[i] + b.FVector[i]; Result := v; end;

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

Схожим образом реализуется и операция умножения (перегружаемая функция-оператор Multiply).

type TVector = class public

FVector: array of Double;

class operator Add( a,b: TVector): TVector; class operator Multiply! a,b: TVector): TVector;

constructor Create(len: Integer); function len: Integer; end;

class operator TVector.Multiply(a, b: TVector): TVector; var

i, n: Integer; v: TVector; begin

n := Math.min(a.len, b.len); v := TVector.Create(n); for i := 0 to n-1 do

v.FVector[i] := a.FVector[i] * b.FVector[i]; Result := v; end;

Аналогично создаются операции вычитания (subtract) и деления (Divide). Основное преимущество такого подхода в том, что теперь мы получили новый выразительный прием записи арифметических выражений над переменными-векторами.

var а, Ь, с, d: TVector; begin

а := TVector.Create(5); b := TVector.Create(10); с := TVector.Create(50); d := TVector.Create(0);

// заносим значения в эти векторы // . . .

// вычисляем по формуле: d : = (а + b) * с – b / а;

Приоритеты операций остаются стандартными, то есть в первую очередь рассчи- ^^ тываются выражения в скобках, затем выполняется «умножение» и «деление», а потом — «сложение» и «вычитание».

Данная возможность позволяет реализовывать и гораздо более сложную логику, которая станет «раскручиваться» исполнительной средой автоматически. Например, не очень трудно написать систему аналитического дифференцирования, когда некоторая операция внутри себя развертывается в свой результат-производную по известным правилам, и такой процесс будет развиваться автоматически до получения конечной формулы, так как логика всех операций задана заранее. А запустить ее можно, например, перегрузив стандартный метод Tostring и просто обратившись к нему из формулы, подлежащей дифференцированию.

Write( (х*х + 2*х + 5).ToString );

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

При этом операции умножения и сложения должны выдавать в некотором внутреннем виде результат дифференцирования параметров.

Бобровский С. И. Технологии Delphi 2006. Новые возможности. — СПб.: Питер, 2006. — 288 е.: ил.

По теме:

  • Комментарии