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

Можете ли вы перегрузить оператор присваивания для записей 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
  • Новые материалы

    Дрейф концепций в ИИ
    Что такое концептуальный дрейф? Дрейф понятий — это явление в искусственном интеллекте и машинном обучении, при котором основное распределение данных меняется со временем. Это изменение в..

    Изучите Vue перед React. Вот почему
    Сегодняшняя сеть представляет собой запутанный беспорядок из разных языков, библиотек и фреймворков, и начинающие веб-разработчики часто не могут понять, что изучать в первую очередь. Что вы..

    Гл.31 — Помощь слабослышащим с помощью возможностей машинного обучения Apple Watch.
    1 500 000 000  – количество людей с потерей слуха в мире. Это почти 20% населения Земли! (источник: who.int ) Недавно я экспериментировал с Apple Sound Classification API, и результаты на..

    Машинное обучение без кода / Глубокое обучение Каждый специалист по обработке и анализу данных должен знать
    Akkio, Очевидно.ай, DataRobot, Левити, Clarifai, Teachable Machines, Lobe, Pimer, DynaBench, APAflow Teachable Machine- https://teachablemachine.withgoogle.com/ Vertex AI..

    Код, который работает вместе, остается вместе
    Первоначально это было опубликовано в tiagojdf . Когда я только начинал как младший программист, я всегда терялся, глядя на внутренний код. Я предположил, что отчасти это было из-за того,..

    Эта модель Google сочетает в себе рассуждение и действие в рамках одной языковой модели.
    ReAct предоставляет архитектуру, которая инициирует действия на основе путей рассуждений языка. Недавно я запустил образовательный информационный бюллетень, посвященный ИИ, у которого уже..

    Сортировка структур JSON по нескольким полям в JavaScript
    Array.sort() не для слабонервных. Особенно, когда речь идет о сортировке сложных структур данных. Большинство руководств по JavaScript дают только краткое введение в Array.sort() . Обычно..