2010-03-10 2 views
3

Предположим, у меня есть запись TQuaternion и рекордер. У кватернионов есть несколько методов с параметрами ТВП. С другой стороны, TVector поддерживает некоторые операции с параметрами TQuaternion.Перекрестная ссылка между delphi records

Зная, что Delphi (Win32) не разрешает объявления о прямой записи, как я могу решить эту проблему?

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

На данный момент я просто переместил эти конкретные методы из записей и в отдельные функции, добрый старомодный способ. Лучшие предложения приветствуются.

+0

Перегрузка оператора * никогда * имеет смысл, имхо. YMMV. В этом случае у вас есть определенная проблема, которая легко решается с помощью классов - вы теряете перегрузку оператора, но получаете то, что вам нужно, и единственной «потерей» является возможность обфускации вызова метода с очевидным (но не фактическим) оператором - теми обфусканные вызовы просто должны быть более очевидными (читайте: понятный, понятный, понятный) в коде. В качестве альтернативы используйте указатели для записей ... тогда вам также нужно управлять памятью для записей, на которые указывают эти указатели, и тогда вам действительно просто лучше использовать классы. – Deltics

+1

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

+1

В качестве опоры: Я нахожусь на вашей стороне забора (обычно мы делаем все с помощью объектов + интерфейс), это немного эксперимент, чтобы улучшить переносимость некоторых деталей с интенсивным математическим учетом. Опыт немного отличается от оптимизации «обычного» (что бы это ни значило) кода для удобочитаемости. –

ответ

3

Если операторы а не фактическая проблема, которую вы можете решить с помощью помощника записи.

type 
    TVector = record 
    end; 

    TQuaternion = record 
    procedure UseVector(var V: TVector); 
    end; 

    TVectorHelper = record helper for TVector 
    procedure UseQuaternion(var Q: TQuaternion); 
    end; 

Это позволит решить только круговые зависимости и не работает с операторами. У этого также есть недостаток, что у вас не может быть другого помощника по записи для ТВ-сектора, по крайней мере, оба из них могут быть доступны в одном и том же месте.

+1

Я не знал, что есть класс вспомогательного эквивалента для записей, спасибо! Хотя я не думаю, что на самом деле я использовал эту технику (я предпочитаю резервировать помощников в качестве последнего средства для решения проблем с кодом, который я не могу коснуться), это самый прямой ответ на мой вопрос, и я отмечаю его как например. –

+2

Я бы не использовал это решение по тем же причинам. Но вы можете рассмотреть возможность изменения глобальных функций в (статические) функции класса, чтобы сузить область. –

1

Я думаю, что ваше «хорошее старомодное» решение является лучшим.
в качестве альтернативного решения - но приводит к схеме вашего решения в - что о записи, содержащей ваши две записи и методы, как методы основной записи:

type 
    TQuaternionVector = record 
    Vector: TVector; 
    Quaternion: TQuaternion; 
    procedure F(V: TVector; Q: TQuaternion);  
    end; 
+0

Как два поля относятся к двум параметрам в этом примере? Возможно, некоторые придуманные результаты могут быть достигнуты при таком подходе, если вы объедините его с неявными назначениями, но в остальном я не думаю, что это очень практично. :) –

1

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

Заявления ниже, позволит вам добавить векторы и кватернионы (если это имеет смысл :-)) в любой комбинации (3-я Добавить объявление для TQuaternion является интересным):

type 
    TVector = record 
    class operator Add(v1, v2 : TVector) : TVector; 
    end; 

    TQuaternion = record 
    class operator Add(q1, q2 : TQuaternion) : TQuaternion; 
    class operator Add(q : TQuaternion; v : TVector) : TQuaternion; 
    class operator Add(v : TVector; q : TQuaternion) : TQuaternion; 
    end; 

Предполагая, что соответствующий переменные декларации следующие компилируются:

q1 := q2 + q3; 
v1 := v2 + v3; 

q1 := q2+v2; 
q2 := v2+q2; 

Этого достаточно, чтобы покрыть то, что вам нужно?

+0

Проницательный, но, к сожалению, метод под рукой - это не оператор (я только что упомянул операторов класса, чтобы мотивировать мой выбор прилипания к записям). –

3

Там нет элегантного решения в целом, только старые хаки с нетипизированными ссылками, как это:

type 
    TVector = record 
    procedure UseQuaternion(var Q); 
    end; 

    TQuaternion = record 
    procedure UseVector(var V: TVector); 
    end; 

{ TVector } 

procedure TVector.UseQuaternion(var Q); 
var 
    Quaternion: TQuaternion absolute Q; 

begin 
    Quaternion.UseVector(Self); 
end; 

{ TQuaternion } 

procedure TQuaternion.UseVector(var V: TVector); 
begin 

end; 

Для конкретных случаев следующего шаблон может быть полезным:

type 
    TVectorData = array [0..1] of Double; 
    TQuaternionData = array [0..3] of Double; 

    TVector = record 
    Data: TVectorData; 
    procedure UseQuaternion(var Q: TQuaternionData); 
    end; 

    TQuaternion = record 
    Data: TQuaternionData; 
    procedure UseVector(var V: TVector); 
    end; 
Смежные вопросы