2010-07-11 73 views
9

在Delphi中是否有任何解決方法來創建相互引用記錄?下面的代碼的簡化版本:Delphi中的相互引用記錄(Win32)

MyRec1 = record 
    arr: MyRec2Array; 
end; 

MyRec2 = record 
    mr: MyRec1; 
end; 

MyRec2Array = array of MyRec2; 

記錄類型顯然向前聲明

MyRec2 = record; 

不德爾福爲Win32工作。

切換到類而不是記錄不好,因爲這會增加內存消耗和代碼複雜性,所以我寧願留下記錄。

有什麼建議嗎?

+3

可能重複:http://stackoverflow.com/questions/2420650/cross-reference-between-delphi-records – 2010-07-11 10:07:18

+1

這是沒有意義的。如果我們假設每個MyRec2Array的長度是固定的並且非零,那麼您試圖創建一個數據結構,它將佔用無限多個字節... – 2010-07-11 12:52:43

+1

@Andreas Rejbrand - MyRec2Array是* dynamic *數組。 – Alex 2010-07-11 13:47:57

回答

14

記錄是值類型,而不是引用類型。這意味着用作較大數據結構成員的所有記錄都將內聯放置在結構中,而不是作爲指針。試圖創建兩個包含對方的記錄會導致編譯器進入無限循環,同時試圖找出記錄的結構。這可能是你不能轉發聲明記錄的原因,即使你試圖在這裏插入一個引用類型(動態數組),你仍然不能違反語言規則。

但是,你所能做的就是聲明一個指針到記錄類型爲預先聲明,就像這樣:

PMyRec2 = ^MyRec2 
... 
MyRec2 = record 
    ... 
end; 

當然,一旦你開始使用的記錄指針,您不必擔心分配並釋放內存,並且在您的項目中出現不使用類時您試圖避免的代碼複雜性。底線:用類來做。做一個記錄,如果不是他們兩個,就是一個班級。這是最簡單的方法,真的。

而額外的內存開銷可以忽略不計。它出現在指向每個引用的對象的指針,無論如何您都需要指向對象的指針,在D2009之前每個實例還有一個隱藏字段(4個字節),或者D2009或更高版本中有兩個隱藏字段(8個字節)。這根本不是很重要。

+2

用於提及值類型的後果以及使用指針的解決方法 – 2010-07-11 15:03:04

+0

指針解決方法是我正在尋找的。另外我還以爲每個TObject實例都佔用大約30個字節。我不知道我從哪裏得到它,但在閱讀完您的文章後,我在D2007中將其加入,而且它確實是4個字節。所以你絕對正確。非常感謝! – Max 2010-07-11 18:25:31

+0

請注意,值類型限制在此不適用,因爲dynarray已經是動態類型。這可能是「serg」的解決方法起作用的原因。 – 2010-07-12 05:45:27

4

儘管我完全同意梅森,但還是有辦法破解這個限制。基本上,您可以使用記錄幫助程序在MyRec2聲明後定義必要的功能。

type 
    MyRec1 = record 
    arr: array of byte; 
    end; 

    MyRec2 = record 
    mr: MyRec1; 
    end; 

    MyRec1Helper = record helper for MyRec1 
    procedure AllocateMyRec2(numItems: integer); 
    function GetMyRec2(i: integer): MyRec2; 
    procedure SetMyRec2(i: integer; const value: MyRec2); 
    property Rec2[i: integer]: MyRec2 read GetMyRec2 write SetMyRec2; 
    end; 

procedure MyRec1Helper.AllocateMyRec2(numItems: integer); 
begin 
    SetLength(arr, numItems * SizeOf(myRec2)); 
end; 

function MyRec1Helper.GetMyRec2(i: integer): MyRec2; 
begin 
    Move(arr[i*SizeOf(MyRec2)], Result, SizeOf(MyRec2)); 
end; 

procedure MyRec1Helper.SetMyRec2(i: integer; const value: MyRec2); 
begin 
    Move(value, arr[i*SizeOf(MyRec2)], SizeOf(MyRec2)); 
end; 

var 
    my: MyRec2; 

begin 
    my.mr.AllocateMyRec2(2); 
    my.mr.Rec2[0].mr.AllocateMyRec2(3); 
end. 
4

這個問題看起來像我的一個玩笑 - 這是不是互相引用,它是關於一個無限類型定義循環。至於相互引用,他們可以通過記錄中定義的類型加以解決(我使用德爾福2009年):

type 
    MyRec2 = record 
    type 
    MyRec2Array = array of MyRec2; 
    type 
    MyRec1 = record 
     arr: MyRec2Array; 
    end; 
    var 
    mr: MyRec1; 
    end; 

但如何使用上面記錄類型?真搞笑。 :)

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRec2; 

begin 
    SetLength(R.mr.arr, 1); 
// R.mr.arr[0]:= ???; 
end;