Хобрук: Ваш путь к мастерству в программировании

Можете ли вы перегрузить оператор присваивания для записей Delphi?

У меня есть запись, содержащая динамический массив. Это нормально, когда вы назначаете одну переменную массива другой, фактически назначается только указатель на этот массив. Это означает, что при этом обе переменные указывают на один и тот же массив, пока вы не измените размер одной из них. Поэтому, когда я хочу присвоить переменной отдельную копию массива, я использую функцию Copy ().

Однако в этом случае мой массив представляет собой поле записи:

  TMyRec = record
    Value: integer;
    &Array: array of integer;
  end;

Когда я объявляю две переменные типа TMyRec и затем назначаю одну другой, поля «Массив» в обеих записях будут указывать на один и тот же адрес в памяти.

Чтобы решить такую ​​проблему, я решил перегрузить оператор присваивания следующим образом:

TMyRec = record
  Value: integer;
  &Array: array of integer;
public
  class operator Implicit(Value: TMyRec): TMyRec;
end;

class operator TMyRec.Implicit(Value: TMyRec): TMyRec;
begin
  Result := Value;
  Result.&Array := Copy(Value.&Array);
end;

Если бы это сработало, мне не пришлось бы отдельно копировать все поля массива в моих записях после присвоения переменных TMyRecord друг другу.

Вот что я делаю:

var
  Rec1, Rec2: TMyRec;
begin
  Rec1.Value := 10;
  SetLength(Rec1.Array, 1);

  //I expected the "Implicit" method to be invoked here (but it is not...)
  Rec2 := Rec1;

  //if I do that, the Rec1.Array[0] will also be changed to 1 - I don't want that to happen
  Rec2.Array[0] := 1;
end;

Есть ли способ заставить моего оператора работать так, как я хочу? Дело в том, что я пытаюсь перегрузить оператор присваивания по умолчанию. Разве это не возможно?



Ответы:


1

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

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

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

04.06.2009

2

Вы можете использовать указатель TMyRec:

pMyRec = ^TMyRec;
TMyRec = record
  Value: integer;
  _Array: array of integer;
public
  class operator Implicit(Value: pMyRec): TMyRec;
end;

class operator TMyRec.Implicit(Value: pMyRec): TMyRec;
begin
  Result := Value^;
  Result._Array := Copy(Value^._Array);
end;

procedure TForm1.Button1Click(Sender: TObject);
var R1, R2 : TMyRec;
begin
  R1.Value := 1;
  SetLength( R1._Array, 2);
  R1._Array[0] := 1;
  R1._Array[1] := 2;

  R2 := @R1;
  R2._Array[0] := 3;
end;
21.10.2013

3

Не делайте простых заданий. Стремитесь к удобочитаемости. Сделайте свою собственную процедуру RecCopy, например:

procedure RecCopy( const AFrom, ATo : TMyRec );
var
  I : integer;
begin
  ATo.Value := AFrom.Value;
  SetLength( ATo.Array, Length( AFrom.Array );
  For I := 0 to Length( AFrom.Array )-1 do
    ATo.Array[I] := AFrom.Array[I];
end;

Обратите внимание, что вы можете использовать лучший способ внедрения копии массива :-) Но вы понимаете мою точку зрения.

05.06.2009
  • К сожалению, это должно было прочитать RecCopy (const AFrom: TMyRec; VAR ATo: TMyRec); ИЗВИНИТЕ! 05.06.2009
  • Если целью является удобочитаемость, я думаю, что предпочтительным синтаксисом будет простое присвоение. 05.06.2009
  • Да, такая функция была единственным способом решить мою проблему. Однако я использовал функцию Copy () для копирования своих массивов - ATo.Array: = Copy (AFrom.Array). Я считаю ненужным использовать цикл for, я ошибаюсь? Спасибо за ответы. 05.06.2009
  • Новые материалы

    Как начать получать пассивный доход через блоги по программированию?
    Получение пассивного дохода с помощью блогов по программированию — отличный способ пополнить свой доход и работать из дома. Существует много способов получения пассивного дохода от вашего..

    Как ИИ меняет сельское хозяйство
    Прочтите Статью Кэтлин Уолч в Forbes о том, как ИИ меняет сельское хозяйство . Сельское хозяйство и земледелие - одна из древнейших и важнейших профессий в мире. Человечество прошло долгий..

    Slack: проектирование современных интерфейсов человека и ИИ
    Когда Стюарт Баттерфилд выделил Slack из быстро исчезающей онлайн-игры Tiny Speck, его перспективы были в лучшем случае неопределенными. Существовал очевидный спрос на средства связи на рабочем..

    HTTP1.1 против HTTP2
    Http расшифровывается как HyperText Transfer Protocol, это в основном метод, который компьютеры и серверы используют для запроса и отправки информации. HTTP1.1 - это более старая версия Http, а..

    Радость вырезания
    Радость фрагментов По какой-то причине, когда я начал программировать в колледже, я активно сопротивлялся целому ряду земных благ, которые сделали бы мою жизнь чуточку удобнее. Я в основном..

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

    Буферы протоколов, часть 01: соглашения об именах и файловая организация
    Если вам нравится читать статьи на Medium и вы заинтересованы в том, чтобы стать участником, я буду рад поделиться с вами своей реферальной ссылкой!