2010-07-11 71 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;