2013-01-16 9 views
8

Mam dwa rekordy z tymi samymi polami, a jeden z nich ma zestaw procedur. Dlaczego rozmiar obu rekordów jest taki sam?Dlaczego rozmiar rekordu Delphi nie jest zwiększany, gdy dołączona jest procedura?

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils; 

type 
    TData = record 
    Age : Byte; 
    Id : Integer; 
    end; 

    TData2 = record 
    Age : Byte; 
    Id : Integer; 
    procedure foo1; 
    procedure foo2; 
    procedure foo3; 
    end; 

procedure TData2.foo1; 
begin 

end; 

procedure TData2.foo2; 
begin 

end; 

procedure TData2.foo3; 
begin 

end; 

begin 
    try 
    Writeln('SizeOf(TData) = '+ IntToStr(SizeOf(TData))); 
    Writeln('SizeOf(TData2) = '+ IntToStr(SizeOf(TData2))); 
    Readln; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 

end. 
+0

Dodawanie metod nigdy nie zwiększa rozmiaru instancji, dotyczy zarówno rejestracji instancji, jak i obiektów. – kludg

+0

@DavidHeffernan - nie, nie ma. Zwiększa tylko metadane klasy, rozmiar instancji się nie zmienia. Jedynym sposobem zwiększenia rozmiaru instancji poza polami jest użycie interfejsów. – kludg

+0

@Serg Masz rację, jestem w błędzie. Przepraszam. Myślałem, że każda instancja ma kopię VMT. Zakładam, że z powodu wirtualnego przechwytywacza metody. Ale to działa, tworząc kopię VMT. Oczywiście muszę sprawdzić moje fakty, zanim otworzę usta. –

Odpowiedz

10

Dzieje się tak dlatego, że sam rekord zawiera jedynie dane, które składają się na zapis i nie zawierają żadnych procedur ani funkcji. Procedury i funkcje są rodzaju cukru syntaktycznego, aby uniknąć podania samego rekordu jako parametru: zmienna , która jest automagicznie dodana przez kompilator dla ciebie.

Każda metoda zadeklarować w rekordzie mieć inny parametr dla samego rekordu, na przykład:

TData2 = record 
    Age : Byte; 
    Id : Integer; 
    procedure Foo1; 
    procedure Foo2(SomeParam: Integer); 
    end; 

zmienia się na coś co odpowiada:

PData2 = ^TData2; 

    TData2 = record 
    Age : Byte; 
    Id : Integer; 
    end; 

    procedure TData2_Foo1(Self: PData2); 
    procedure TData2_Foo2(Self: PData2; SomeParam: Integer); 

koniec każdej rozmowy dokonać także zmieniono na przykład:

var 
    Data: TData2; 
begin 
    Data.Foo1; 
    Data.Foo2(1); 
end; 

został zmieniony na coś równoważnego:

var 
    Data: TData2; 
begin 
    TData2_Foo1(@Data); 
    TData2_Foo1(@Data, 1); 
end; 

nie mam Delphi pod ręką, aby sprawdzić, czy parametr jest dodawany na początku lub na końcu listy parametrów, ale mam nadzieję, że masz pomysł.

Oczywiście nie ma prawdziwej składni tego, ponieważ jest wykonywana w locie przez kompilator, a zatem, na przykład, nazwy procedur nie są zmieniane. Zrobiłem to, starając się, aby moja odpowiedź była łatwa do zrozumienia.

+3

+1 Niejawny parametr własny jest pierwszy na liście parametrów –

+1

O strukturze pamięci w wywołaniach funkcji/metod, patrz http://docwiki.embarcadero.com/RADStudio/XE3/en/Program_Control, który wyraźnie stwierdza "Metody używają tych samych konwencji wywoływania, co zwykłe procedury i funkcje, z tym wyjątkiem, że każda metoda ma dodatkowy niejawny parametr Self, który jest odwołaniem do instancji lub klasy, w której wywoływana jest metoda. Parametr Self jest przekazywany jako wskaźnik 32-bitowy. Zgodnie z konwencją rejestru, funkcja Self zachowuje się tak, jakby była zadeklarowana przed wszystkimi innymi parametrami. Dlatego zawsze jest przekazywana do rejestru EAX: " –

+1

@ArnaudBouchez: Zakładam, że przy 64-bitowym celu, wskaźnik Self przekazany do metody byłby wskaźnikiem 64-bitowym –

0

Procedury nie zajmują miejsca. Kompilator odpowiednio je podłącza. Ich adresy nie muszą znajdować się w pamięci w czasie wykonywania dla każdego rekordu. Jeśli spojrzysz na reprezentację TData2 w pamięci, nie znajdziesz procedur.

+1

To jest trochę nieprecyzyjne. Procedury zabierają pamięć. Kod zajmuje pamięć. Ta odpowiedź powtarza fakty zawarte w pytaniu, nie wyjaśniając dlaczego. Odpowiedź jest taka, że ​​adresy kodu są statyczne i znane w czasie kompilacji, a więc nie muszą być przechowywane w rekordzie. –

Powiązane problemy