IPB
ЛогинПароль:

> 

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Перегрузка операций, Компилятор FPC 2.0.x
сообщение
Сообщение #1


Гость






Перегрузка операций

Зачем это нужно?
Очень часто при работе с типами данных, определенных пользователями, не хватает возможности работать с этими типами, как со встроенными в язык, т.е., например для сложения матриц не использовать вызов процедуры
MatrixAdd(C, A, B);

, а записать эту операцию в виде
C := A + B;

Или для сравнения матрицы с нулевой (или единичной) использовать не
If isEqual(mx, mxO) or isEqual(mx, mxE)

, а
If (mx = mxO) or (mx = mxE)...


В решении этой задачи могут помочь перегруженные операции.

Как это сделать?
Прежде всего - чтобы перегрузка была доступна, программа (или модуль, если это делается в модуле) должна компилироваться с ключом {$mode objfpc}. При использовании модулей директива {$mode objfpc} обязательна только для модуля, содержащего реализацию перегрузки, вызывающая программа может такой директивы не иметь...

Ну, и второе: для того, чтобы использовать в программе перегруженные операции, их нужно сначала определить. Это делается так:

Operator {перегружаемая операция} ({список параметров}) {возвращаемое значение};
где:
{перегружаемая операция} - одна из следующих:
  1. арифметическая (+, -, *, /, **, mod, div)
  2. сравнения (=, <, <=, >, >=)
  3. присваивания (:=)
  4. логическая (or, and, xor, not)
{список параметров} - те параметры, к которым будет применяться {перегружаемая операция}. Параметров в списке должно быть ровно 2 (первый параметр - тот что находится слева от знака операции, второй - тот, который находится справа), причем один из них должен обязательно иметь тип, определенный пользователем, т.е. нельзя переопределить, например, свою операцию сложения двух целых чисел, а вот определить операцию сложения матрицы с числом - можно.

{возвращаемое значение} - то, что вернется в вызывающую программу как результат выполнения операции. Например, при операции сложения 2-х матриц, результатом также является матрица:
Operator + (Const m1, m2: TMatrix) R: TMatrix;
Begin
{ Заполняем матрицу R нужными значениями, и она вернется как результат операции }
End;

После этого описания в программе можно делать так:
Var A, B, C: TMatrix;
Begin
...
C := A + B; { матрица - сумма присвоится переменной C }
...
End.


Перегрузка функций
Кроме перегрузки операций (переопределения операций для пользовательских типов) в FPC введена еще и перегрузка функций, т.е. в программе может быть несколько процедур/функций с одинаковыми именами (сюда же относятся и Operator-ы), при условии, что их списки параметров неодинаковы.
Т.е. можно сделать так:
function test(a: integer): integer;
begin
result := 0;
end;

{ Разрешено - список параметров отличается от списка предыдущей функции }
function test(a: double): integer;
begin
result := 0;
end;

{ Ошибка: несмотря на то, что тип результата другой, списки параметров одинаковы, а это недопустимо }
function test(a: integer): double;
begin
result := 0.0;
end;


Эта возможность поможет, например, в таком случае.
Допустим, была переопределена операция + для матриц:
operator + (const mx1, mx2: TMatrix) r: TMatrix;
var i, j: integer;
begin
for i := 1 to n do
for j := 1 to n do
r[i, j] := mx1[i, j] + mx2[i, j];
end;

но иногда модет понадобиться и операция сложения матрицы с числом, т.е. увеличение каждого элемента матрицы на какую-то величину. Без перегрузки функций здесь не обойтись:
operator + (const mx: TMatrix; const X: integer) r: TMatrix;
var i, j: integer;
begin
for i := 1 to n do
for j := 1 to n do
r[i, j] := mx[i, j] + X;
end;

(параметры первой и второй Operator + различны, следовательно ошибки не будет)

Теперь можно использовать как сложение матриц, так и сложение матрицы с числом:
Var A, B, C: TMatrix;
Begin
A := A + 2;
C := A + B;
End.


Внимание: перегруженные операции не являются коммутативными, если типы переменных слева и справа от знака операции различны, т.е. если можно записать
A := A + 2;

это совсем не значит, что можно сделать и
A := 2 + A;

Компилятор сразу сообщит об ошибке: "Operator is not overloaded" ("Операция не перегружена")... Для того, чтобы иметь возможность использовать оба варианта сложения матрицы с числом, придется определить еще одну операцию:
operator + (const X: integer; const mx: TMatrix) r: TMatrix;
begin
r := mx + X; { Пользуемся уже определенным сложением с другим порядком операндов }
end;


Примеры использования:

Здесь:
Как вычислить заданный многочлен от матрицы A приведен пример вычисления заданного многочлена от матрицы A ...

С использованием перегрузки операторов та же программа будет выглядеть вот так:
{$mode objfpc}

const
size = 4;
type
TMatrix = array[1 .. size, 1 .. size] of double;

operator * (const a, b: TMatrix) m: TMatrix;
var i, j, k: integer;
begin
for i := 1 to size do
for j := 1 to size do begin
m[i, j] := 0;
for k := 1 to size do
m[i, j] := m[i, j] + a[i, k] * b[k, j]
end;
end;

operator * (const a: TMatrix; const f: double) m: TMatrix;
var i, j: integer;
begin
for i := 1 to size do
for j := 1 to size do
m[i, j] := f * a[i, j]
end;

operator + (const a, b: TMatrix) m: TMatrix;
var i, j: integer;
begin
for i := 1 to size do
for j := 1 to size do
m[i, j] := a[i, j] + b[i, j]
end;

{ Возведение матрицы в степень }
operator ** (const a: TMatrix; const pow: integer) m: TMatrix;
var i, j: Integer;
begin
if pow = 0 then begin
for i := 1 to size do
for j := 1 to size do
m[i, j] := Byte(i = j);
exit
end;

m := a;
for i := 1 to pred(pow) do
m := m * a;
end;


procedure matrixPrint(a: TMatrix);
var i, j: integer;
begin
for i := 1 to size do begin
for j := 1 to size do
write(a[i, j]:9:2);
writeln
end
end;


const
n = 3;
p: array[1 .. n] of double = (1.0, -2.0, 3.0);

const
a: TMatrix =
(
(10, 11, 14, 16),
(12, 17, 10, 16),
( 8, 12, 12, 7),
( 8, 5, 17, 1)
);
var
Res: TMatrix;
i: Integer;

begin
matrixPrint(a);

for i := 1 to n do
res := res + (a ** (n - i)) * p[i]; { Все вычисление записывается в одну строчку }

matrixPrint(Res)
end.


**********


Еще одно полезное применение перегрузки операций - операции с большими числами... Вот так это может выглядеть:
Прикрепленный файл  vlint.pas ( 7.39 килобайт ) Кол-во скачиваний: 796
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 19.04.2024 20:50
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name