2010-07-11 11 views
9

¿Existe alguna solución para crear registros de referencias mutuas en Delphi? Aquí está la versión simplificada del código:Registros de referencias mutuas en Delphi (Win32)

MyRec1 = record 
    arr: MyRec2Array; 
end; 

MyRec2 = record 
    mr: MyRec1; 
end; 

MyRec2Array = array of MyRec2; 

declaración parecer delante de tipos de registro

MyRec2 = record; 

no funciona en Delphi para Win32.

Cambiar a clases en lugar de registros no es bueno, porque esto aumentará el consumo de memoria y la complejidad del código, por lo que preferiría quedarme con los registros.

¿Alguna sugerencia?

+3

duplicado posible: http://stackoverflow.com/questions/2420650/cross-reference-between-delphi-records –

+1

Esto no tiene sentido. Si suponemos que la longitud de cada MyRec2Array es fija y distinta de cero, entonces está intentando crear una estructura de datos que ocupará infinitamente muchos bytes ... –

+1

@Andreas Rejbrand - MyRec2Array es * dynamic * array. – Alex

Respuesta

14

Los registros son tipos de valores, no tipos de referencia. Esto significa que todos los registros utilizados como miembros de una estructura de datos más grande se colocan en línea en la propia estructura en lugar de como un puntero. Intentar crear dos registros que se contengan arrojaría al compilador en un bucle infinito mientras trata de descubrir la estructura de los registros. Esa es probablemente la razón por la que no puede reenviar-declarar un registro, y aunque está tratando de insertar un tipo de referencia (matriz dinámica) aquí, todavía no puede violar las reglas de idioma.

Pero lo que puede hacer es declarar un tipo puntero a registro como una declaración hacia delante, así:

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

Por supuesto, una vez que empiece a usar punteros a los registros, usted tiene que preocuparse acerca de la asignación y liberar la memoria, y la complejidad del código que intentaba evitar al no usar clases aparece en su proyecto. En pocas palabras: haz esto con las clases. Haga uno de los registros, si no ambos, una clase. Es la forma más simple, realmente.

Y la sobrecarga de memoria adicional es insignificante. Se obtiene un puntero al objeto para cada referencia, que se necesitaría para punteros a objetos de todos modos, más un campo oculto (4 bytes) por instancia antes de D2009 o dos de ellos (8 bytes) en D2009 o posterior. Eso no es mucho en absoluto.

+2

+1 para mencionar las consecuencias del valor-tipo, y la solución usando punteros –

+0

Puntero de solución de problemas es lo que estaba buscando. También estaba pensando que cada instancia de TObject ocupa alrededor de 30 bytes. No sé de dónde lo saco, pero después de leer tu publicación lo di por vencido en D2007 y en realidad es de 4 bytes. Entonces estás absolutamente en lo cierto. ¡Muchas gracias! – Max

+0

Tenga en cuenta que la limitación del tipo de valor no se aplica aquí, porque el dynarray ya es un tipo dinámico. Esta es probablemente la razón por la cual la solución temporal de "serg" funciona. –

4

Aunque estoy totalmente de acuerdo con Mason, hay una manera de hackear la limitación. Básicamente, puede usar un asistente de grabación para definir la funcionalidad necesaria después de que se haya declarado 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

La pregunta parece una broma para mí - no se trata de referencias mutuas, se trata de un bucle definición de tipo infinito. En cuanto a las referencias mutuas, que se pueden resolver mediante la definición de tipos dentro de un registro (utilicé Delphi 2009):

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

Pero cómo usar el tipo de registro de arriba? Muy divertido. :)

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

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